Skip to content
Closed
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import adminSpec, {AdminConfigType} from './admin.js'
import {ExtensionInstance} from '../extension-instance.js'
import {inTemporaryDirectory, mkdir, touchFile} from '@shopify/cli-kit/node/fs'
import {joinPath} from '@shopify/cli-kit/node/path'
import {describe, expect, test} from 'vitest'

function createAdminExtensionInstance(directory: string, staticRoot?: string): ExtensionInstance<AdminConfigType> {
return {
directory,
configuration: {
name: 'test-admin',
type: 'admin',
admin: staticRoot ? {static_root: staticRoot} : undefined,
},
} as unknown as ExtensionInstance<AdminConfigType>
}

describe('admin buildValidation', () => {
test('passes when static_root is not configured', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const extension = createAdminExtensionInstance(tmpDir, undefined)

// Should not throw
await expect(adminSpec.buildValidation!(extension)).resolves.toBeUndefined()
})
})

test('passes when static_root exists and contains index.html', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const distDir = joinPath(tmpDir, 'dist')
await mkdir(distDir)
await touchFile(joinPath(distDir, 'index.html'))

const extension = createAdminExtensionInstance(tmpDir, './dist')

// Should not throw
await expect(adminSpec.buildValidation!(extension)).resolves.toBeUndefined()
})
})

test('throws when static_root is configured but index.html is missing', async () => {
await inTemporaryDirectory(async (tmpDir) => {
// Create the dist directory but without index.html
const distDir = joinPath(tmpDir, 'dist')
await mkdir(distDir)

const extension = createAdminExtensionInstance(tmpDir, './dist')

await expect(adminSpec.buildValidation!(extension)).rejects.toThrow(
'The admin extension requires an index.html file in the static_root directory (./dist), but it was not found.',
)
})
})

test('throws when static_root directory does not exist', async () => {
await inTemporaryDirectory(async (tmpDir) => {
const extension = createAdminExtensionInstance(tmpDir, './dist')

await expect(adminSpec.buildValidation!(extension)).rejects.toThrow(
'The admin extension requires an index.html file in the static_root directory (./dist), but it was not found.',
)
})
})
})

describe('admin devSessionWatchConfig', () => {
test('returns empty paths when static_root is not configured', () => {
const extension = createAdminExtensionInstance('/tmp/test', undefined)
const watchConfig = adminSpec.devSessionWatchConfig!(extension)

expect(watchConfig).toEqual({paths: []})
})

test('returns watch paths when static_root is configured', () => {
const extension = createAdminExtensionInstance('/tmp/test', './dist')
const watchConfig = adminSpec.devSessionWatchConfig!(extension)

expect(watchConfig).toBeDefined()
expect(watchConfig!.paths).toHaveLength(1)
expect(watchConfig!.paths[0]).toContain('dist')
expect(watchConfig!.paths[0]).toContain('**/*')
})
})
16 changes: 16 additions & 0 deletions packages/app/src/cli/models/extensions/specifications/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {createExtensionSpecification} from '../specification.js'
import {BaseConfigType, ZodSchemaType} from '../schemas.js'
import {zod} from '@shopify/cli-kit/node/schema'
import {joinPath} from '@shopify/cli-kit/node/path'
import {fileExists} from '@shopify/cli-kit/node/fs'
import {AbortError} from '@shopify/cli-kit/node/error'

export const AdminSpecIdentifier = 'admin'

Expand Down Expand Up @@ -31,6 +33,20 @@ const adminSpecificationSpec = createExtensionSpecification<AdminConfigType>({
const path = joinPath(extension.directory, staticRoot, '**/*')
return {paths: [path], ignore: []}
},
buildValidation: async (extension) => {
const staticRoot = extension.configuration.admin?.static_root
if (!staticRoot) return

const indexHtmlPath = joinPath(extension.directory, staticRoot, 'index.html')
const indexExists = await fileExists(indexHtmlPath)

if (!indexExists) {
throw new AbortError(
`The admin extension requires an index.html file in the static_root directory (${staticRoot}), but it was not found.`,
`This usually means the build step has not completed yet. Make sure your app runs a build command (e.g., via a predev hook in your web configuration) before starting the dev server.`,
)
}
},
transformRemoteToLocal: (remoteContent) => {
return {
admin: {
Expand Down
Loading