dify/web/service/__tests__/base.spec.ts
Coding On Star 2c4d8ef098
fix(auth): preserve redirect URL across auth flows (#38905)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
2026-07-14 07:47:34 +00:00

133 lines
3.8 KiB
TypeScript

import {
buildSigninUrlWithRedirect,
buildWebAppSigninUrlWithRedirect,
isWebAppSigninPath,
} from '../base'
vi.mock('@/utils/var', () => ({
basePath: '/app',
API_PREFIX: '/console/api',
PUBLIC_API_PREFIX: '/api',
IS_CE_EDITION: false,
}))
describe('buildSigninUrlWithRedirect', () => {
const originalLocation = globalThis.location
beforeEach(() => {
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',
},
writable: true,
configurable: true,
})
})
afterEach(() => {
Object.defineProperty(globalThis, 'location', {
value: originalLocation,
writable: true,
configurable: true,
})
})
it('should preserve the current internal URL for Console pages', () => {
const url = buildSigninUrlWithRedirect()
expect(url).toBe(
`https://example.com/app/signin?redirect_url=${encodeURIComponent('/app/apps?category=agent#recent')}`,
)
})
it('should append redirect_url for OAuth authorize pages', () => {
const oauthHref = 'https://example.com/account/oauth/authorize?client_id=abc&state=xyz'
Object.defineProperty(globalThis, 'location', {
value: {
origin: 'https://example.com',
pathname: '/account/oauth/authorize',
search: '?client_id=abc&state=xyz',
hash: '',
href: oauthHref,
},
writable: true,
configurable: true,
})
const url = buildSigninUrlWithRedirect()
expect(url).toBe(`https://example.com/app/signin?redirect_url=${encodeURIComponent(oauthHref)}`)
})
it('should treat other paths containing a partial OAuth match as Console pages', () => {
Object.defineProperty(globalThis, 'location', {
value: {
origin: 'https://example.com',
pathname: '/settings/oauth',
search: '',
hash: '',
href: 'https://example.com/settings/oauth',
},
writable: true,
configurable: true,
})
const url = buildSigninUrlWithRedirect()
expect(url).toBe(
`https://example.com/app/signin?redirect_url=${encodeURIComponent('/settings/oauth')}`,
)
})
it.each(['/app/signin', '/app/signin/'])(
'should not create a self-referential redirect for the signin page: %s',
(pathname) => {
Object.defineProperty(globalThis, 'location', {
value: {
origin: 'https://example.com',
pathname,
search: '?redirect_url=%2Fapp%2Fapps',
hash: '',
href: `https://example.com${pathname}?redirect_url=%2Fapp%2Fapps`,
},
writable: true,
configurable: true,
})
expect(buildSigninUrlWithRedirect()).toBe('https://example.com/app/signin')
},
)
})
describe('buildWebAppSigninUrlWithRedirect', () => {
it('should encode the internal redirect target exactly once', () => {
const url = buildWebAppSigninUrlWithRedirect(
'https://example.com',
'/chatbot/share-app',
'?foo=bar',
)
expect(url).toBe(
'https://example.com/app/webapp-signin?redirect_url=%2Fchatbot%2Fshare-app%3Ffoo%3Dbar',
)
expect(new URL(url).searchParams.get('redirect_url')).toBe('/chatbot/share-app?foo=bar')
})
})
describe('isWebAppSigninPath', () => {
it.each(['/app/webapp-signin', '/app/webapp-signin/'])(
'should recognize the web app signin route behind basePath: %s',
(pathname) => {
expect(isWebAppSigninPath(pathname)).toBe(true)
},
)
it.each(['/webapp-signin', '/app/webapp-signin-extra', '/app/webapp-signin/check-code'])(
'should not match a different path: %s',
(pathname) => {
expect(isWebAppSigninPath(pathname)).toBe(false)
},
)
})