Skip to content
Open
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
328 changes: 173 additions & 155 deletions packages/theme/src/cli/services/dev-override.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {createThemePreview, updateThemePreview} from '../utilities/theme-preview
import {describe, expect, test, vi} from 'vitest'
import {renderSuccess} from '@shopify/cli-kit/node/ui'
import {collectedLogs, clearCollectedLogs} from '@shopify/cli-kit/node/output'
import {fileExistsSync, readFile} from '@shopify/cli-kit/node/fs'
import {fileExistsSync, readFile, writeFile, inTemporaryDirectory} from '@shopify/cli-kit/node/fs'
import {joinPath} from '@shopify/cli-kit/node/path'

vi.mock('../utilities/theme-environment/dev-server-session.js')
vi.mock('../utilities/theme-previews/preview.js')
vi.mock('./dev.js', () => ({openURLSafely: vi.fn()}))
vi.mock('@shopify/cli-kit/node/ui')
vi.mock('@shopify/cli-kit/node/fs')

const adminSession = {token: 'token', storeFqdn: 'store.myshopify.com'}
const mockSession = {
Expand All @@ -25,187 +25,205 @@ const expectedPreviewId = 'abc123'

describe('devWithOverrideFile', () => {
test('throws when override file does not exist', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(false)

// When/Then
await expect(
devWithOverrideFile({adminSession, overrideJson: '/missing.json', themeId: '123', open: false}),
).rejects.toThrow('Override file not found: /missing.json')
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'missing.json')

// When/Then
await expect(
devWithOverrideFile({adminSession, overrideJson, themeId: '123', open: false}),
).rejects.toThrow(`Override file not found: ${overrideJson}`)
})
})

test('creates a preview when no previewIdentifier is provided', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
const expectedThemeId = '789'

// When
await devWithOverrideFile({adminSession, overrideJson: '/overrides.json', themeId: expectedThemeId, open: false})

// Then
expect(fetchDevServerSession).toHaveBeenCalledWith(expectedThemeId, adminSession, undefined)

// Then
expect(createThemePreview).toHaveBeenCalledWith(
expect.objectContaining({
session: mockSession,
themeId: expectedThemeId,
}),
)
expect(updateThemePreview).not.toHaveBeenCalled()
expect(renderSuccess).toHaveBeenCalledWith(
expect.objectContaining({
body: [
{
list: {
title: 'Preview is ready',
items: [{link: {url: expectedPreviewUrl}}, `Preview ID: ${expectedPreviewId}`],
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
const expectedThemeId = '789'

// When
await devWithOverrideFile({adminSession, overrideJson, themeId: expectedThemeId, open: false})

// Then
expect(fetchDevServerSession).toHaveBeenCalledWith(expectedThemeId, adminSession, undefined)

// Then
expect(createThemePreview).toHaveBeenCalledWith(
expect.objectContaining({
session: mockSession,
themeId: expectedThemeId,
}),
)
expect(updateThemePreview).not.toHaveBeenCalled()
expect(renderSuccess).toHaveBeenCalledWith(
expect.objectContaining({
body: [
{
list: {
title: 'Preview is ready',
items: [{link: {url: expectedPreviewUrl}}, `Preview ID: ${expectedPreviewId}`],
},
},
},
],
}),
)
],
}),
)
})
})

test('updates a preview when previewIdentifier is provided', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(updateThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
const expectedThemeId = '789'

// When
await devWithOverrideFile({
adminSession,
overrideJson: '/overrides.json',
themeId: expectedThemeId,
previewIdentifier: expectedPreviewId,
open: false,
json: false,
})

// Then
expect(updateThemePreview).toHaveBeenCalledWith(
expect.objectContaining({
session: mockSession,
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(updateThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
const expectedThemeId = '789'

// When
await devWithOverrideFile({
adminSession,
overrideJson,
themeId: expectedThemeId,
previewIdentifier: expectedPreviewId,
}),
)
expect(createThemePreview).not.toHaveBeenCalled()
expect(renderSuccess).toHaveBeenCalledWith(
expect.objectContaining({
body: [
{
list: {
title: 'Preview updated',
items: [{link: {url: expectedPreviewUrl}}, `Preview ID: ${expectedPreviewId}`],
open: false,
json: false,
})

// Then
expect(updateThemePreview).toHaveBeenCalledWith(
expect.objectContaining({
session: mockSession,
themeId: expectedThemeId,
previewIdentifier: expectedPreviewId,
}),
)
expect(createThemePreview).not.toHaveBeenCalled()
expect(renderSuccess).toHaveBeenCalledWith(
expect.objectContaining({
body: [
{
list: {
title: 'Preview updated',
items: [{link: {url: expectedPreviewUrl}}, `Preview ID: ${expectedPreviewId}`],
},
},
},
],
}),
)
],
}),
)
})
})

test('throws when override file contains invalid JSON', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from('not valid json'))

// When/Then
const error = await devWithOverrideFile({
adminSession,
overrideJson: '/bad.json',
themeId: '123',
open: false,
json: false,
}).catch((err) => err)
expect(error.message).toBe('Failed to parse override file: /bad.json')
expect(error.tryMessage).toMatch(/not valid json/i)
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'bad.json')
await writeFile(overrideJson, 'not valid json')

// When/Then
const error = await devWithOverrideFile({
adminSession,
overrideJson,
themeId: '123',
open: false,
json: false,
}).catch((err) => err)
expect(error.message).toBe(`Failed to parse override file: ${overrideJson}`)
expect(error.tryMessage).toMatch(/not valid json/i)
})
})

test('opens the preview URL when open is true', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({adminSession, overrideJson: '/overrides.json', themeId: '789', open: true})

// Then
expect(openURLSafely).toHaveBeenCalledWith(expectedPreviewUrl, 'theme preview')
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({adminSession, overrideJson, themeId: '789', open: true})

// Then
expect(openURLSafely).toHaveBeenCalledWith(expectedPreviewUrl, 'theme preview')
})
})

test('does not open the preview URL when open is false', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({adminSession, overrideJson: '/overrides.json', themeId: '789', open: false})

// Then
expect(openURLSafely).not.toHaveBeenCalled()
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({adminSession, overrideJson, themeId: '789', open: false})

// Then
expect(openURLSafely).not.toHaveBeenCalled()
})
})

test('passes password to fetchDevServerSession when provided', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({
adminSession,
overrideJson: '/overrides.json',
themeId: '789',
open: false,
json: false,
password: 'shptka_abc123',
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})

// When
await devWithOverrideFile({
adminSession,
overrideJson,
themeId: '789',
open: false,
json: false,
password: 'shptka_abc123',
})

// Then
expect(fetchDevServerSession).toHaveBeenCalledWith('789', adminSession, 'shptka_abc123')
})

// Then
expect(fetchDevServerSession).toHaveBeenCalledWith('789', adminSession, 'shptka_abc123')
})

test('outputs JSON when json flag is true', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
clearCollectedLogs()

// When
await devWithOverrideFile({adminSession, overrideJson: '/overrides.json', themeId: '789', open: false, json: true})

// Then
const expectedJson = JSON.stringify({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
expect(collectedLogs.info).toContainEqual(expectedJson)
expect(renderSuccess).not.toHaveBeenCalled()
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
clearCollectedLogs()

// When
await devWithOverrideFile({adminSession, overrideJson, themeId: '789', open: false, json: true})

// Then
const expectedJson = JSON.stringify({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
expect(collectedLogs.info).toContainEqual(expectedJson)
expect(renderSuccess).not.toHaveBeenCalled()
})
})

test('renders success body by default when json flag is omitted', async () => {
// Given
vi.mocked(fileExistsSync).mockReturnValue(true)
vi.mocked(readFile).mockResolvedValue(Buffer.from(JSON.stringify({templates: {}})))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
clearCollectedLogs()

// When
await devWithOverrideFile({adminSession, overrideJson: '/overrides.json', themeId: '789', open: false})

// Then
expect(renderSuccess).toHaveBeenCalled()
await inTemporaryDirectory(async (tmpDir) => {
// Given
const overrideJson = joinPath(tmpDir, 'overrides.json')
await writeFile(overrideJson, JSON.stringify({templates: {}}))
vi.mocked(fetchDevServerSession).mockResolvedValue(mockSession)
vi.mocked(createThemePreview).mockResolvedValue({url: expectedPreviewUrl, preview_identifier: expectedPreviewId})
clearCollectedLogs()

// When
await devWithOverrideFile({adminSession, overrideJson, themeId: '789', open: false})

// Then
expect(renderSuccess).toHaveBeenCalled()
})
})
})
Loading