Files
urbanLifeline/dify/web/service/utils.spec.ts

171 lines
6.0 KiB
TypeScript
Raw Normal View History

2025-12-01 17:21:38 +08:00
/**
* Test suite for service utility functions
*
* This module provides utilities for working with different flow types in the application.
* Flow types determine the API endpoint prefix used for various operations.
*
* Key concepts:
* - FlowType.appFlow: Standard application workflows (prefix: 'apps')
* - FlowType.ragPipeline: RAG (Retrieval-Augmented Generation) pipelines (prefix: 'rag/pipelines')
*
* The getFlowPrefix function maps flow types to their corresponding API path prefixes,
* with a fallback to 'apps' for undefined or unknown flow types.
*/
import { flowPrefixMap, getFlowPrefix } from './utils'
import { FlowType } from '@/types/common'
describe('Service Utils', () => {
describe('flowPrefixMap', () => {
/**
* Test that the flowPrefixMap object contains the expected mappings
* This ensures the mapping configuration is correct
*/
it('should have correct flow type to prefix mappings', () => {
expect(flowPrefixMap[FlowType.appFlow]).toBe('apps')
expect(flowPrefixMap[FlowType.ragPipeline]).toBe('rag/pipelines')
})
/**
* Test that the map only contains the expected flow types
* This helps catch unintended additions to the mapping
*/
it('should contain exactly two flow type mappings', () => {
const keys = Object.keys(flowPrefixMap)
expect(keys).toHaveLength(2)
})
})
describe('getFlowPrefix', () => {
/**
* Test that appFlow type returns the correct prefix
* This is the most common flow type for standard application workflows
*/
it('should return "apps" for appFlow type', () => {
const result = getFlowPrefix(FlowType.appFlow)
expect(result).toBe('apps')
})
/**
* Test that ragPipeline type returns the correct prefix
* RAG pipelines have a different API structure with nested paths
*/
it('should return "rag/pipelines" for ragPipeline type', () => {
const result = getFlowPrefix(FlowType.ragPipeline)
expect(result).toBe('rag/pipelines')
})
/**
* Test fallback behavior when no flow type is provided
* Should default to 'apps' prefix for backward compatibility
*/
it('should return "apps" when flow type is undefined', () => {
const result = getFlowPrefix(undefined)
expect(result).toBe('apps')
})
/**
* Test fallback behavior for unknown flow types
* Any unrecognized flow type should default to 'apps'
*/
it('should return "apps" for unknown flow type', () => {
// Cast to FlowType to test the fallback behavior
const unknownType = 'unknown' as FlowType
const result = getFlowPrefix(unknownType)
expect(result).toBe('apps')
})
/**
* Test that the function handles null gracefully
* Null should be treated the same as undefined
*/
it('should return "apps" when flow type is null', () => {
const result = getFlowPrefix(null as any)
expect(result).toBe('apps')
})
/**
* Test consistency with flowPrefixMap
* The function should return the same values as direct map access
*/
it('should return values consistent with flowPrefixMap', () => {
expect(getFlowPrefix(FlowType.appFlow)).toBe(flowPrefixMap[FlowType.appFlow])
expect(getFlowPrefix(FlowType.ragPipeline)).toBe(flowPrefixMap[FlowType.ragPipeline])
})
})
describe('Integration scenarios', () => {
/**
* Test typical usage pattern in API path construction
* This demonstrates how the function is used in real application code
*/
it('should construct correct API paths for different flow types', () => {
const appId = '123'
// App flow path construction
const appFlowPath = `/${getFlowPrefix(FlowType.appFlow)}/${appId}`
expect(appFlowPath).toBe('/apps/123')
// RAG pipeline path construction
const ragPipelinePath = `/${getFlowPrefix(FlowType.ragPipeline)}/${appId}`
expect(ragPipelinePath).toBe('/rag/pipelines/123')
})
/**
* Test that the function can be used in conditional logic
* Common pattern for determining which API endpoint to use
*/
it('should support conditional API routing logic', () => {
const determineEndpoint = (flowType?: FlowType, resourceId?: string) => {
const prefix = getFlowPrefix(flowType)
return `/${prefix}/${resourceId || 'default'}`
}
expect(determineEndpoint(FlowType.appFlow, 'app-1')).toBe('/apps/app-1')
expect(determineEndpoint(FlowType.ragPipeline, 'pipeline-1')).toBe('/rag/pipelines/pipeline-1')
expect(determineEndpoint(undefined, 'fallback')).toBe('/apps/fallback')
})
/**
* Test behavior with empty string flow type
* Empty strings should fall back to default
*/
it('should handle empty string as flow type', () => {
const result = getFlowPrefix('' as any)
expect(result).toBe('apps')
})
})
describe('Type safety', () => {
/**
* Test that all FlowType enum values are handled
* This ensures we don't miss any flow types in the mapping
*/
it('should handle all FlowType enum values', () => {
// Get all enum values
const flowTypes = Object.values(FlowType)
// Each flow type should return a valid prefix
flowTypes.forEach((flowType) => {
const prefix = getFlowPrefix(flowType)
expect(prefix).toBeTruthy()
expect(typeof prefix).toBe('string')
expect(prefix.length).toBeGreaterThan(0)
})
})
/**
* Test that returned prefixes are valid path segments
* Prefixes should not contain leading/trailing slashes or invalid characters
*/
it('should return valid path segments without leading/trailing slashes', () => {
const appFlowPrefix = getFlowPrefix(FlowType.appFlow)
const ragPipelinePrefix = getFlowPrefix(FlowType.ragPipeline)
expect(appFlowPrefix).not.toMatch(/^\//)
expect(appFlowPrefix).not.toMatch(/\/$/)
expect(ragPipelinePrefix).not.toMatch(/^\//)
expect(ragPipelinePrefix).not.toMatch(/\/$/)
})
})
})