Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 37 additions & 21 deletions packages/theme/src/cli/utilities/notifier.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import {Notifier} from './notifier.js'
import {vi, describe, expect, test} from 'vitest'
import {vi, describe, expect, test, beforeEach} from 'vitest'
import {outputWarn} from '@shopify/cli-kit/node/output'
import {inTemporaryDirectory, readFile, mkdir} from '@shopify/cli-kit/node/fs'
import {joinPath} from '@shopify/cli-kit/node/path'
import {stat} from 'node:fs/promises'

import fs from 'fs/promises'

vi.mock('fs/promises')
vi.mock('@shopify/cli-kit/node/output')

describe('Notifier', () => {
let notifier: Notifier

beforeEach(() => {
vi.restoreAllMocks()
})

test('updates notifyPath via POST request when path is a URL', async () => {
const mockFetch = vi.spyOn(global, 'fetch').mockResolvedValue(new Response())
const url = 'https://example.com/notify'
Expand All @@ -26,13 +30,23 @@ describe('Notifier', () => {
})

test('updates file atime and mtime when path is not a URL', async () => {
const path = 'theme.update'
notifier = new Notifier(path)
const fileName = 'announcement.liquid'

await notifier.notify(fileName)

expect(fs.writeFile).toHaveBeenCalledWith(path, fileName)
await inTemporaryDirectory(async (tmpDir) => {
// Given
const path = joinPath(tmpDir, 'theme.update')
notifier = new Notifier(path)
const fileName = 'announcement.liquid'
const startTime = Date.now()

// When
await notifier.notify(fileName)

// Then
expect(await readFile(path)).toBe(fileName)
const stats = await stat(path)
// File system timestamps might have lower precision (seconds), so we subtract 1000ms to avoid flakiness
expect(stats.atime.getTime()).toBeGreaterThanOrEqual(startTime - 1000)
expect(stats.mtime.getTime()).toBeGreaterThanOrEqual(startTime - 1000)
})
})

test('does not update if path is empty', async () => {
Expand All @@ -43,7 +57,6 @@ describe('Notifier', () => {
await notifier.notify(fileName)

expect(fetchSpy).not.toHaveBeenCalled()
expect(fs.appendFile).not.toHaveBeenCalled()
})

test('does not notify file when path is URL', async () => {
Expand All @@ -55,7 +68,6 @@ describe('Notifier', () => {
await notifier.notify(fileName)

expect(mockFetch).toHaveBeenCalled()
expect(fs.appendFile).not.toHaveBeenCalled()
})

test('prints error if response is not successful', async () => {
Expand Down Expand Up @@ -85,15 +97,19 @@ describe('Notifier', () => {
})

test('outputs error if file update fails', async () => {
const invalidPath = 'dir/file:theme.update'
vi.spyOn(fs, 'writeFile').mockRejectedValue(new Error('No such file or directory'))
notifier = new Notifier(invalidPath)
const fileName = 'announcement.liquid'
await inTemporaryDirectory(async (tmpDir) => {
// Create a directory where the file should be, to cause writeFile to fail
const path = joinPath(tmpDir, 'theme.update')
await mkdir(path)

await notifier.notify(fileName)
notifier = new Notifier(path)
const fileName = 'announcement.liquid'

expect(outputWarn).toHaveBeenCalledWith(
`Failed to notify filechange listener at ${invalidPath}: No such file or directory`,
)
await notifier.notify(fileName)

expect(outputWarn).toHaveBeenCalledWith(
expect.stringContaining(`Failed to notify filechange listener at ${path}`),
)
})
})
})
Loading