dify/cli/src/api/app-dsl.test.ts

124 lines
3.9 KiB
TypeScript

import type { StubServer } from '@test/fixtures/stub-server'
import { testHttpClient } from '@test/fixtures/http-client'
import { jsonResponder, startStubServer } from '@test/fixtures/stub-server'
import { afterEach, describe, expect, it } from 'vite-plus/test'
import { isHttpClientError } from '@/errors/base'
import { AppDslClient } from './app-dsl.js'
const DSL_YAML = `app:\n mode: chat\n name: Test\nversion: '0.1.4'\n`
const COMPLETED_IMPORT = { id: 'imp-1', status: 'completed', app_id: 'app-1', app_mode: 'chat' }
function makeClient(host: string): AppDslClient {
return new AppDslClient(testHttpClient(host, 'dfoa_test'))
}
describe('AppDslClient.exportDsl', () => {
let stub: StubServer
afterEach(async () => {
await stub?.stop()
})
it('returns the data string from the response', async () => {
stub = await startStubServer((cap) => jsonResponder(200, { data: DSL_YAML }, cap))
const yaml = await makeClient(stub.url).exportDsl('app-1')
expect(stub.captured.method).toBe('GET')
expect(stub.captured.url?.split('?')[0]).toBe('/openapi/v1/apps/app-1/dsl')
expect(yaml).toBe(DSL_YAML)
})
it('throws when response has no data field', async () => {
stub = await startStubServer((cap) => jsonResponder(200, { wrong: 1 }, cap))
await expect(makeClient(stub.url).exportDsl('app-1')).rejects.toThrow(
'export response missing data field',
)
})
it('propagates 404 as a classified HttpClientError', async () => {
stub = await startStubServer((cap) => jsonResponder(404, { error: 'not_found' }, cap))
await expect(makeClient(stub.url).exportDsl('missing')).rejects.toSatisfy(
(err) => isHttpClientError(err) && err.httpStatus === 404,
)
})
})
describe('AppDslClient.importApp', () => {
let stub: StubServer
afterEach(async () => {
await stub?.stop()
})
it('POST to /workspaces/:id/apps/imports with body and returns Import', async () => {
stub = await startStubServer((cap) => jsonResponder(200, COMPLETED_IMPORT, cap))
const result = await makeClient(stub.url).importApp('ws-1', {
mode: 'yaml-content',
yaml_content: DSL_YAML,
})
expect(stub.captured.method).toBe('POST')
expect(stub.captured.url).toBe('/openapi/v1/workspaces/ws-1/apps/imports')
expect(result.status).toBe('completed')
expect(result.app_id).toBe('app-1')
})
it('returns pending import on 202', async () => {
const pending = {
id: 'imp-1',
status: 'pending',
current_dsl_version: '0.1.4',
imported_dsl_version: '0.0.9',
}
stub = await startStubServer((cap) => jsonResponder(202, pending, cap))
const result = await makeClient(stub.url).importApp('ws-1', {
mode: 'yaml-content',
yaml_content: DSL_YAML,
})
expect(result.status).toBe('pending')
expect(result.id).toBe('imp-1')
})
})
describe('AppDslClient.confirmImport', () => {
let stub: StubServer
afterEach(async () => {
await stub?.stop()
})
it('POST to confirm URL and returns completed Import', async () => {
stub = await startStubServer((cap) => jsonResponder(200, COMPLETED_IMPORT, cap))
const result = await makeClient(stub.url).confirmImport('ws-1', 'imp-1')
expect(stub.captured.method).toBe('POST')
expect(stub.captured.url).toBe('/openapi/v1/workspaces/ws-1/apps/imports/imp-1:confirm')
expect(result.status).toBe('completed')
})
})
describe('AppDslClient.checkDependencies', () => {
let stub: StubServer
afterEach(async () => {
await stub?.stop()
})
it('returns empty leaked_dependencies on healthy app', async () => {
stub = await startStubServer((cap) => jsonResponder(200, { leaked_dependencies: [] }, cap))
const result = await makeClient(stub.url).checkDependencies('app-1')
expect(stub.captured.url?.split('?')[0]).toBe('/openapi/v1/apps/app-1/dependencies:check')
expect(result.leaked_dependencies).toEqual([])
})
})