mirror of
https://github.com/langgenius/dify.git
synced 2026-07-21 18:58:35 +08:00
160 lines
4.2 KiB
TypeScript
160 lines
4.2 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const createUnauthorizedResponse = () =>
|
|
new Response(
|
|
JSON.stringify({
|
|
code: 'unauthorized',
|
|
message: 'Invalid Authorization token.',
|
|
status: 401,
|
|
}),
|
|
{
|
|
status: 401,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
},
|
|
)
|
|
|
|
async function loadServerRequest() {
|
|
vi.resetModules()
|
|
|
|
const mockBaseFetch = vi.fn(async () => {
|
|
throw createUnauthorizedResponse()
|
|
})
|
|
const mockRefreshAccessTokenOrReLogin = vi.fn()
|
|
|
|
vi.doMock('@/utils/client', () => ({
|
|
isClient: false,
|
|
isServer: true,
|
|
}))
|
|
vi.doMock('../fetch', () => ({
|
|
base: mockBaseFetch,
|
|
ContentType: {
|
|
audio: 'audio/mpeg',
|
|
download: 'application/octet-stream',
|
|
downloadZip: 'application/zip',
|
|
json: 'application/json',
|
|
},
|
|
getBaseOptions: vi.fn(() => ({})),
|
|
}))
|
|
vi.doMock('../refresh-token', () => ({
|
|
refreshAccessTokenOrReLogin: mockRefreshAccessTokenOrReLogin,
|
|
}))
|
|
|
|
const { request } = await import('../base')
|
|
|
|
return {
|
|
request,
|
|
mockRefreshAccessTokenOrReLogin,
|
|
}
|
|
}
|
|
|
|
type ClientRequestOptions = {
|
|
response: Response
|
|
refreshError?: Error
|
|
}
|
|
|
|
async function loadClientRequest({ response, refreshError }: ClientRequestOptions) {
|
|
vi.resetModules()
|
|
|
|
const mockBaseFetch = vi.fn(async () => {
|
|
throw response
|
|
})
|
|
const mockRefreshAccessTokenOrReLogin = refreshError
|
|
? vi.fn().mockRejectedValue(refreshError)
|
|
: vi.fn()
|
|
|
|
vi.doMock('@/utils/client', () => ({
|
|
isClient: true,
|
|
isServer: false,
|
|
}))
|
|
vi.doMock('@/utils/var', () => ({
|
|
basePath: '/app',
|
|
}))
|
|
vi.doMock('../fetch', () => ({
|
|
base: mockBaseFetch,
|
|
ContentType: {
|
|
audio: 'audio/mpeg',
|
|
download: 'application/octet-stream',
|
|
downloadZip: 'application/zip',
|
|
json: 'application/json',
|
|
},
|
|
getBaseOptions: vi.fn(() => ({})),
|
|
}))
|
|
vi.doMock('../refresh-token', () => ({
|
|
refreshAccessTokenOrReLogin: mockRefreshAccessTokenOrReLogin,
|
|
}))
|
|
|
|
const { request } = await import('../base')
|
|
|
|
return {
|
|
request,
|
|
mockRefreshAccessTokenOrReLogin,
|
|
}
|
|
}
|
|
|
|
describe('request 401 handling', () => {
|
|
const originalLocation = globalThis.location
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
Object.defineProperty(globalThis, 'location', {
|
|
value: {
|
|
origin: 'https://example.com',
|
|
pathname: '/app/apps',
|
|
search: '?category=agent',
|
|
hash: '#recent',
|
|
href: 'https://example.com/app/apps?category=agent#recent',
|
|
reload: vi.fn(),
|
|
},
|
|
writable: true,
|
|
configurable: true,
|
|
})
|
|
})
|
|
|
|
afterEach(() => {
|
|
Object.defineProperty(globalThis, 'location', {
|
|
value: originalLocation,
|
|
writable: true,
|
|
configurable: true,
|
|
})
|
|
vi.resetModules()
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('should not run browser auth recovery when handling 401 on the server', async () => {
|
|
const { request, mockRefreshAccessTokenOrReLogin } = await loadServerRequest()
|
|
|
|
await expect(request('/account/profile')).rejects.toMatchObject({ status: 401 })
|
|
|
|
expect(mockRefreshAccessTokenOrReLogin).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should preserve the current URL when a 401 response cannot be parsed', async () => {
|
|
const response = new Response('not-json', { status: 401 })
|
|
const { request, mockRefreshAccessTokenOrReLogin } = await loadClientRequest({ response })
|
|
|
|
await expect(request('/account/profile')).rejects.toBe(response)
|
|
|
|
expect(globalThis.location.href).toBe(
|
|
`https://example.com/app/signin?redirect_url=${encodeURIComponent('/app/apps?category=agent#recent')}`,
|
|
)
|
|
expect(mockRefreshAccessTokenOrReLogin).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should preserve the current URL when token refresh fails', async () => {
|
|
const response = createUnauthorizedResponse()
|
|
const { request, mockRefreshAccessTokenOrReLogin } = await loadClientRequest({
|
|
response,
|
|
refreshError: new Error('refresh failed'),
|
|
})
|
|
|
|
await expect(request('/account/profile')).rejects.toBe(response)
|
|
|
|
expect(mockRefreshAccessTokenOrReLogin).toHaveBeenCalledOnce()
|
|
expect(globalThis.location.href).toBe(
|
|
`https://example.com/app/signin?redirect_url=${encodeURIComponent('/app/apps?category=agent#recent')}`,
|
|
)
|
|
})
|
|
})
|