mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-07 08:30:06 +00:00
- Create TypeScript interfaces for header providers - Implement header registry with priority-based ordering - Add network client adapters that integrate with the registry - Add comprehensive unit tests Co-Authored-By: Claude <noreply@anthropic.com>
254 lines
7.4 KiB
TypeScript
254 lines
7.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { headerRegistry } from '@/services/headerRegistry'
|
|
import type {
|
|
HeaderProviderContext,
|
|
IHeaderProvider
|
|
} from '@/types/headerTypes'
|
|
|
|
describe('headerRegistry', () => {
|
|
beforeEach(() => {
|
|
headerRegistry.clear()
|
|
})
|
|
|
|
describe('registerHeaderProvider', () => {
|
|
it('should register a header provider', () => {
|
|
const provider: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Test': 'value' })
|
|
}
|
|
|
|
const registration = headerRegistry.registerHeaderProvider(provider)
|
|
|
|
expect(registration).toBeDefined()
|
|
expect(registration.id).toMatch(/^header-provider-\d+$/)
|
|
expect(headerRegistry.providerCount).toBe(1)
|
|
})
|
|
|
|
it('should return a disposable registration', () => {
|
|
const provider: IHeaderProvider = {
|
|
provideHeaders: vi.fn()
|
|
}
|
|
|
|
const registration = headerRegistry.registerHeaderProvider(provider)
|
|
expect(headerRegistry.providerCount).toBe(1)
|
|
|
|
registration.dispose()
|
|
expect(headerRegistry.providerCount).toBe(0)
|
|
})
|
|
|
|
it('should insert providers in priority order', async () => {
|
|
const provider1: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Priority': 'low' })
|
|
}
|
|
const provider2: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Priority': 'high' })
|
|
}
|
|
const provider3: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Priority': 'medium' })
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider1, { priority: 1 })
|
|
headerRegistry.registerHeaderProvider(provider2, { priority: 10 })
|
|
headerRegistry.registerHeaderProvider(provider3, { priority: 5 })
|
|
|
|
const context: HeaderProviderContext = {
|
|
url: 'https://api.example.com',
|
|
method: 'GET'
|
|
}
|
|
|
|
const headers = await headerRegistry.getHeaders(context)
|
|
|
|
// Higher priority provider should override
|
|
expect(headers['X-Priority']).toBe('high')
|
|
})
|
|
})
|
|
|
|
describe('getHeaders', () => {
|
|
it('should combine headers from all providers', async () => {
|
|
const provider1: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({
|
|
'X-Header-1': 'value1',
|
|
'X-Common': 'provider1'
|
|
})
|
|
}
|
|
const provider2: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({
|
|
'X-Header-2': 'value2',
|
|
'X-Common': 'provider2'
|
|
})
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider1, { priority: 1 })
|
|
headerRegistry.registerHeaderProvider(provider2, { priority: 2 })
|
|
|
|
const context: HeaderProviderContext = {
|
|
url: 'https://api.example.com',
|
|
method: 'GET'
|
|
}
|
|
|
|
const headers = await headerRegistry.getHeaders(context)
|
|
|
|
expect(headers).toEqual({
|
|
'X-Header-1': 'value1',
|
|
'X-Header-2': 'value2',
|
|
'X-Common': 'provider2' // Higher priority wins
|
|
})
|
|
})
|
|
|
|
it('should resolve function header values', async () => {
|
|
const provider: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({
|
|
'X-Static': 'static',
|
|
'X-Dynamic': () => 'dynamic',
|
|
'X-Async': async () => 'async-value'
|
|
})
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider)
|
|
|
|
const context: HeaderProviderContext = {
|
|
url: 'https://api.example.com',
|
|
method: 'GET'
|
|
}
|
|
|
|
const headers = await headerRegistry.getHeaders(context)
|
|
|
|
expect(headers).toEqual({
|
|
'X-Static': 'static',
|
|
'X-Dynamic': 'dynamic',
|
|
'X-Async': 'async-value'
|
|
})
|
|
})
|
|
|
|
it('should handle async providers', async () => {
|
|
const provider: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockImplementation(async () => {
|
|
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
return { 'X-Async': 'resolved' }
|
|
})
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider)
|
|
|
|
const context: HeaderProviderContext = {
|
|
url: 'https://api.example.com',
|
|
method: 'GET'
|
|
}
|
|
|
|
const headers = await headerRegistry.getHeaders(context)
|
|
|
|
expect(headers).toEqual({ 'X-Async': 'resolved' })
|
|
})
|
|
|
|
it('should apply filters when provided', async () => {
|
|
const provider1: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Api': 'api-header' })
|
|
}
|
|
const provider2: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Other': 'other-header' })
|
|
}
|
|
|
|
// Only apply to API URLs
|
|
headerRegistry.registerHeaderProvider(provider1, {
|
|
filter: (ctx) => ctx.url.includes('/api/')
|
|
})
|
|
|
|
// Apply to all URLs
|
|
headerRegistry.registerHeaderProvider(provider2)
|
|
|
|
const apiContext: HeaderProviderContext = {
|
|
url: 'https://example.com/api/users',
|
|
method: 'GET'
|
|
}
|
|
|
|
const otherContext: HeaderProviderContext = {
|
|
url: 'https://example.com/assets/image.png',
|
|
method: 'GET'
|
|
}
|
|
|
|
const apiHeaders = await headerRegistry.getHeaders(apiContext)
|
|
const otherHeaders = await headerRegistry.getHeaders(otherContext)
|
|
|
|
expect(apiHeaders).toEqual({
|
|
'X-Api': 'api-header',
|
|
'X-Other': 'other-header'
|
|
})
|
|
|
|
expect(otherHeaders).toEqual({
|
|
'X-Other': 'other-header'
|
|
})
|
|
})
|
|
|
|
it('should continue with other providers if one fails', async () => {
|
|
const provider1: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockRejectedValue(new Error('Provider error'))
|
|
}
|
|
const provider2: IHeaderProvider = {
|
|
provideHeaders: vi.fn().mockReturnValue({ 'X-Header': 'value' })
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider1)
|
|
headerRegistry.registerHeaderProvider(provider2)
|
|
|
|
const context: HeaderProviderContext = {
|
|
url: 'https://api.example.com',
|
|
method: 'GET'
|
|
}
|
|
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
|
|
const headers = await headerRegistry.getHeaders(context)
|
|
|
|
expect(headers).toEqual({ 'X-Header': 'value' })
|
|
expect(consoleSpy).toHaveBeenCalledWith(
|
|
expect.stringContaining('Error getting headers from provider'),
|
|
expect.any(Error)
|
|
)
|
|
|
|
consoleSpy.mockRestore()
|
|
})
|
|
})
|
|
|
|
describe('clear', () => {
|
|
it('should remove all providers', () => {
|
|
const provider1: IHeaderProvider = {
|
|
provideHeaders: vi.fn()
|
|
}
|
|
const provider2: IHeaderProvider = {
|
|
provideHeaders: vi.fn()
|
|
}
|
|
|
|
headerRegistry.registerHeaderProvider(provider1)
|
|
headerRegistry.registerHeaderProvider(provider2)
|
|
|
|
expect(headerRegistry.providerCount).toBe(2)
|
|
|
|
headerRegistry.clear()
|
|
|
|
expect(headerRegistry.providerCount).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('providerCount', () => {
|
|
it('should return the correct count of providers', () => {
|
|
expect(headerRegistry.providerCount).toBe(0)
|
|
|
|
const provider: IHeaderProvider = {
|
|
provideHeaders: vi.fn()
|
|
}
|
|
|
|
const reg1 = headerRegistry.registerHeaderProvider(provider)
|
|
expect(headerRegistry.providerCount).toBe(1)
|
|
|
|
const reg2 = headerRegistry.registerHeaderProvider(provider)
|
|
expect(headerRegistry.providerCount).toBe(2)
|
|
|
|
reg1.dispose()
|
|
expect(headerRegistry.providerCount).toBe(1)
|
|
|
|
reg2.dispose()
|
|
expect(headerRegistry.providerCount).toBe(0)
|
|
})
|
|
})
|
|
})
|