mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-13 23:11:06 +00:00
239 lines
6.9 KiB
TypeScript
239 lines
6.9 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const originalWindow = globalThis.window
|
|
const originalDocument = globalThis.document
|
|
|
|
function setMockWindow(runtimeConfig?: Window['__SKILLHUB_RUNTIME_CONFIG__']) {
|
|
Object.defineProperty(globalThis, 'window', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: {
|
|
__SKILLHUB_RUNTIME_CONFIG__: runtimeConfig,
|
|
} satisfies Pick<Window, '__SKILLHUB_RUNTIME_CONFIG__'>,
|
|
})
|
|
}
|
|
|
|
// Mock i18n before importing client
|
|
vi.mock('@/i18n/config', () => ({
|
|
default: { resolvedLanguage: 'en' },
|
|
}))
|
|
|
|
// Mock api-error before importing client
|
|
vi.mock('@/shared/lib/api-error', () => ({
|
|
ApiError: class ApiError extends Error {
|
|
status: number
|
|
serverMessage?: string
|
|
serverMessageKey?: string
|
|
constructor(message: string, status: number, serverMessage?: string, serverMessageKey?: string) {
|
|
super(message)
|
|
this.status = status
|
|
this.serverMessage = serverMessage
|
|
this.serverMessageKey = serverMessageKey
|
|
}
|
|
},
|
|
handleApiError: vi.fn(),
|
|
}))
|
|
|
|
import {
|
|
WEB_API_PREFIX,
|
|
buildApiUrl,
|
|
fetchText,
|
|
getDirectAuthRuntimeConfig,
|
|
getSessionBootstrapRuntimeConfig,
|
|
namespaceApi,
|
|
} from './client'
|
|
|
|
beforeEach(() => {
|
|
setMockWindow()
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
|
|
if (originalDocument) {
|
|
Object.defineProperty(globalThis, 'document', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: originalDocument,
|
|
})
|
|
} else {
|
|
Reflect.deleteProperty(globalThis, 'document')
|
|
}
|
|
|
|
if (originalWindow) {
|
|
Object.defineProperty(globalThis, 'window', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: originalWindow,
|
|
})
|
|
return
|
|
}
|
|
|
|
Reflect.deleteProperty(globalThis, 'window')
|
|
})
|
|
|
|
describe('WEB_API_PREFIX', () => {
|
|
it('uses the /api/web prefix for web-facing endpoints', () => {
|
|
expect(WEB_API_PREFIX).toBe('/api/web')
|
|
})
|
|
})
|
|
|
|
describe('buildApiUrl', () => {
|
|
it('returns the path as-is when no runtime base URL is configured', () => {
|
|
expect(buildApiUrl('/api/v1/auth/me')).toBe('/api/v1/auth/me')
|
|
})
|
|
|
|
it('prepends the runtime base URL when one is set', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: 'https://api.example.com' }
|
|
const url = buildApiUrl('/api/v1/auth/me')
|
|
expect(url).toBe('https://api.example.com/api/v1/auth/me')
|
|
})
|
|
|
|
it('handles a trailing slash on the base URL', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: 'https://api.example.com/' }
|
|
const url = buildApiUrl('/api/v1/auth/me')
|
|
expect(url).toBe('https://api.example.com/api/v1/auth/me')
|
|
})
|
|
|
|
it('preserves base URL path prefixes', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: 'https://api.example.com/skill_hub' }
|
|
const url = buildApiUrl('/api/v1/auth/me')
|
|
expect(url).toBe('https://api.example.com/skill_hub/api/v1/auth/me')
|
|
})
|
|
|
|
it('supports relative base URL path prefixes', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: '/skill_hub' }
|
|
const url = buildApiUrl('/api/v1/auth/me')
|
|
expect(url).toBe('/skill_hub/api/v1/auth/me')
|
|
})
|
|
})
|
|
|
|
describe('fetchText', () => {
|
|
it('applies base URL path prefixes for fetch requests', async () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: 'https://api.example.com/skill_hub' }
|
|
const fetchMock = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
text: async () => 'ok',
|
|
})
|
|
vi.stubGlobal('fetch', fetchMock)
|
|
|
|
await fetchText('/api/v1/auth/me')
|
|
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
'https://api.example.com/skill_hub/api/v1/auth/me',
|
|
expect.objectContaining({
|
|
headers: expect.any(Headers),
|
|
}),
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('namespaceApi.delete', () => {
|
|
it('sends a DELETE request to the normalized namespace endpoint', async () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = { apiBaseUrl: 'https://api.example.com' }
|
|
Object.defineProperty(globalThis, 'document', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: {
|
|
cookie: 'XSRF-TOKEN=test-token',
|
|
},
|
|
})
|
|
|
|
const fetchMock = vi.fn().mockResolvedValue({
|
|
ok: true,
|
|
json: async () => ({
|
|
code: 0,
|
|
msg: 'ok',
|
|
data: null,
|
|
timestamp: '2026-05-07T00:00:00Z',
|
|
requestId: 'req-test',
|
|
}),
|
|
})
|
|
vi.stubGlobal('fetch', fetchMock)
|
|
|
|
await namespaceApi.delete('@team-delete')
|
|
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
'https://api.example.com/api/web/namespaces/team-delete',
|
|
expect.objectContaining({
|
|
method: 'DELETE',
|
|
headers: expect.any(Headers),
|
|
}),
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('getDirectAuthRuntimeConfig', () => {
|
|
it('returns disabled when no runtime config is present', () => {
|
|
const config = getDirectAuthRuntimeConfig()
|
|
expect(config.enabled).toBe(false)
|
|
expect(config.provider).toBeUndefined()
|
|
})
|
|
|
|
it('returns enabled with provider when both flag and provider are set', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authDirectEnabled: 'true',
|
|
authDirectProvider: 'ldap',
|
|
}
|
|
const config = getDirectAuthRuntimeConfig()
|
|
expect(config.enabled).toBe(true)
|
|
expect(config.provider).toBe('ldap')
|
|
})
|
|
|
|
it('returns disabled when the flag is true but the provider is missing', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authDirectEnabled: 'true',
|
|
}
|
|
const config = getDirectAuthRuntimeConfig()
|
|
expect(config.enabled).toBe(false)
|
|
})
|
|
|
|
it('returns disabled when the flag is false', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authDirectEnabled: 'false',
|
|
authDirectProvider: 'ldap',
|
|
}
|
|
const config = getDirectAuthRuntimeConfig()
|
|
expect(config.enabled).toBe(false)
|
|
})
|
|
|
|
it('treats various truthy flag values correctly', () => {
|
|
for (const flag of ['1', 'yes', 'on', 'TRUE', ' True ']) {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authDirectEnabled: flag,
|
|
authDirectProvider: 'ldap',
|
|
}
|
|
expect(getDirectAuthRuntimeConfig().enabled).toBe(true)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('getSessionBootstrapRuntimeConfig', () => {
|
|
it('returns disabled when no runtime config is present', () => {
|
|
const config = getSessionBootstrapRuntimeConfig()
|
|
expect(config.enabled).toBe(false)
|
|
expect(config.auto).toBe(false)
|
|
expect(config.provider).toBeUndefined()
|
|
})
|
|
|
|
it('returns fully enabled config when all flags and provider are set', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authSessionBootstrapEnabled: '1',
|
|
authSessionBootstrapProvider: 'sso',
|
|
authSessionBootstrapAuto: 'true',
|
|
}
|
|
const config = getSessionBootstrapRuntimeConfig()
|
|
expect(config.enabled).toBe(true)
|
|
expect(config.provider).toBe('sso')
|
|
expect(config.auto).toBe(true)
|
|
})
|
|
|
|
it('returns disabled when the provider is blank', () => {
|
|
window.__SKILLHUB_RUNTIME_CONFIG__ = {
|
|
authSessionBootstrapEnabled: 'true',
|
|
authSessionBootstrapProvider: ' ',
|
|
}
|
|
const config = getSessionBootstrapRuntimeConfig()
|
|
expect(config.enabled).toBe(false)
|
|
})
|
|
})
|