dify/web/features/deployments/create-guide/state/__tests__/index.spec.ts

203 lines
5.6 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createQueryAtomTestStore } from '@/test/query-atom'
import {
dslFileAtom,
effectiveMethodAtom,
instanceNameAtom,
methodAtom,
releaseNameAtom,
selectedAppAtom,
stepAtom,
} from '../primitives'
import {
dslDefaultAppNameAtom,
dslReadErrorAtom,
isReadingDslAtom,
sourceAppsQueryAtom,
} from '../source'
import {
continueFromSourceAtom,
selectDslFileAtom,
selectMethodAtom,
sourceCanGoNextAtom,
} from '../workflow'
type QueryOptions = {
enabled?: boolean
input?: unknown
queryKey?: readonly unknown[]
retry?: boolean
}
type InfiniteQueryOptions = QueryOptions & {
input?: (pageParam: number) => unknown
}
const queryOptionsMocks = vi.hoisted(() => ({
sourceApps: vi.fn(),
}))
vi.mock('@/service/client', () => ({
consoleQuery: {
apps: {
get: {
infiniteOptions: (options: InfiniteQueryOptions) => {
queryOptionsMocks.sourceApps(options)
return {
...options,
queryKey: ['sourceApps'],
queryFn: async () => ({ data: [], has_more: false, page: 1 }),
}
},
},
},
enterprise: {
appInstanceService: {
listAppInstances: {
infiniteOptions: (options: InfiniteQueryOptions) => ({
...options,
queryKey: ['existingInstanceNames'],
queryFn: async () => ({ appInstances: [], pagination: {} }),
}),
queryOptions: (options: QueryOptions) => ({
...options,
queryKey: ['instanceNameConflict'],
queryFn: async () => ({ appInstances: [] }),
}),
},
},
environmentService: {
listEnvironments: {
queryOptions: (options: QueryOptions) => ({
...options,
queryKey: ['environments'],
queryFn: async () => ({ environments: [] }),
}),
},
},
releaseService: {
computeDeploymentOptions: {
queryOptions: (options: QueryOptions) => ({
...options,
queryKey: ['deploymentOptions'],
queryFn: async () => ({ options: { credentialSlots: [], envVarSlots: [] } }),
}),
},
precheckRelease: {
queryOptions: (options: QueryOptions) => ({
...options,
queryKey: ['precheckRelease'],
queryFn: async () => ({ canCreate: false, unsupportedNodes: [] }),
}),
},
},
},
},
}))
function workflowDsl() {
return ['app:', ' mode: workflow', ' name: Imported guide'].join('\n')
}
describe('create deployment guide state', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should keep the guide on source app mode when DSL import is disabled', () => {
const { store } = createQueryAtomTestStore()
store.set(selectMethodAtom, 'importDsl')
expect(store.get(methodAtom)).toBe('bindApp')
expect(store.get(effectiveMethodAtom)).toBe('bindApp')
})
it('should keep source app loading enabled if stale state points to DSL import', () => {
const { store } = createQueryAtomTestStore()
store.set(methodAtom, 'importDsl')
store.get(sourceAppsQueryAtom)
expect(store.get(effectiveMethodAtom)).toBe('bindApp')
expect(queryOptionsMocks.sourceApps).toHaveBeenLastCalledWith(
expect.objectContaining({ enabled: true }),
)
})
it('should continue from source app mode and auto-fill unique release metadata', () => {
const { queryClient, store } = createQueryAtomTestStore()
queryClient.setQueryData(['sourceApps'], {
pages: [
{
data: [
{
id: 'source-app-1',
name: 'Customer Service',
mode: 'workflow',
},
],
},
],
pageParams: [1],
})
queryClient.setQueryData(['precheckRelease'], {
canCreate: true,
unsupportedNodes: [],
})
queryClient.setQueryData(['deploymentOptions'], {
options: {
credentialSlots: [],
envVarSlots: [],
},
})
queryClient.setQueryData(['existingInstanceNames'], {
pages: [
{
appInstances: [
{ displayName: 'Customer Service' },
{ displayName: 'Customer Service 1' },
],
},
],
pageParams: [1],
})
expect(store.get(sourceCanGoNextAtom)).toBe(true)
store.set(continueFromSourceAtom, {
defaultDslAppName: 'Imported DSL',
defaultReleaseName: 'Initial Release',
})
expect(store.get(selectedAppAtom)).toMatchObject({
id: 'source-app-1',
name: 'Customer Service',
})
expect(store.get(instanceNameAtom)).toMatch(/^Customer Service-[a-z]{4}$/)
expect(store.get(releaseNameAtom)).toBe('Initial Release')
expect(store.get(stepAtom)).toBe('release')
})
it('should read selected DSL file content through the file content query', () => {
const { queryClient, store } = createQueryAtomTestStore()
const text = vi.fn().mockResolvedValue(workflowDsl())
const file = new File([], 'workflow.yml', { type: 'text/yaml' })
Object.defineProperty(file, 'text', { value: text })
store.set(selectDslFileAtom, file)
queryClient.setQueryData(
['createGuideDslFileContent', 1, file, file.name, file.size, file.lastModified],
workflowDsl(),
)
expect(text).not.toHaveBeenCalled()
expect(store.get(dslFileAtom)).toBe(file)
expect(store.get(dslDefaultAppNameAtom)).toBe('Imported guide')
expect(store.get(isReadingDslAtom)).toBe(false)
expect(store.get(dslReadErrorAtom)).toBe(false)
})
})