mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 18:07:47 +08:00
fix(frontend): recover login redirect navigation
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { createMemoryHistory, createRouter, type Router } from 'vue-router'
|
||||
|
||||
import { navigateAfterLogin } from '../loginRedirect'
|
||||
|
||||
function createRouterMock(push: Router['push']): Router {
|
||||
return { push } as Router
|
||||
}
|
||||
|
||||
async function createDuplicatedNavigationFailure(path: string) {
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{
|
||||
path,
|
||||
component: {},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await router.push(path)
|
||||
return router.push(path)
|
||||
}
|
||||
|
||||
async function createAbortedNavigationFailure(path: string) {
|
||||
const router = createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{
|
||||
path,
|
||||
component: {},
|
||||
},
|
||||
],
|
||||
})
|
||||
router.beforeEach(() => false)
|
||||
|
||||
return router.push(path)
|
||||
}
|
||||
|
||||
describe('navigateAfterLogin', () => {
|
||||
it('treats duplicated Vue Router navigation as a completed login navigation', async () => {
|
||||
const push = vi.fn<Router['push']>().mockResolvedValue(await createDuplicatedNavigationFailure('/dashboard'))
|
||||
const documentNavigate = vi.fn()
|
||||
|
||||
const result = await navigateAfterLogin(createRouterMock(push), '/dashboard', documentNavigate)
|
||||
|
||||
expect(push).toHaveBeenCalledWith('/dashboard')
|
||||
expect(documentNavigate).not.toHaveBeenCalled()
|
||||
expect(result).toBe('already-there')
|
||||
})
|
||||
|
||||
it('falls back to document navigation when route chunk loading rejects during SPA navigation', async () => {
|
||||
const push = vi.fn<Router['push']>().mockRejectedValue(new Error('Failed to fetch dynamically imported module'))
|
||||
const documentNavigate = vi.fn()
|
||||
|
||||
const result = await navigateAfterLogin(createRouterMock(push), '/admin/dashboard', documentNavigate)
|
||||
|
||||
expect(push).toHaveBeenCalledWith('/admin/dashboard')
|
||||
expect(documentNavigate).toHaveBeenCalledWith('/admin/dashboard')
|
||||
expect(result).toBe('document')
|
||||
})
|
||||
|
||||
it('falls back to document navigation when the router reports a real navigation failure', async () => {
|
||||
const push = vi.fn<Router['push']>().mockResolvedValue(await createAbortedNavigationFailure('/dashboard'))
|
||||
const documentNavigate = vi.fn()
|
||||
|
||||
const result = await navigateAfterLogin(createRouterMock(push), '/dashboard', documentNavigate)
|
||||
|
||||
expect(push).toHaveBeenCalledWith('/dashboard')
|
||||
expect(documentNavigate).toHaveBeenCalledWith('/dashboard')
|
||||
expect(result).toBe('document')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { isNavigationFailure, NavigationFailureType, type Router } from 'vue-router'
|
||||
|
||||
export type LoginNavigationResult = 'router' | 'already-there' | 'document'
|
||||
|
||||
type DocumentNavigate = (targetPath: string) => void
|
||||
|
||||
function defaultDocumentNavigate(targetPath: string) {
|
||||
window.location.assign(targetPath)
|
||||
}
|
||||
|
||||
export async function navigateAfterLogin(
|
||||
router: Router,
|
||||
targetPath: string,
|
||||
documentNavigate: DocumentNavigate = defaultDocumentNavigate,
|
||||
): Promise<LoginNavigationResult> {
|
||||
try {
|
||||
const navigationFailure = await router.push(targetPath)
|
||||
|
||||
if (isNavigationFailure(navigationFailure, NavigationFailureType.duplicated)) {
|
||||
return 'already-there'
|
||||
}
|
||||
|
||||
if (navigationFailure) {
|
||||
documentNavigate(targetPath)
|
||||
return 'document'
|
||||
}
|
||||
|
||||
return 'router'
|
||||
} catch {
|
||||
documentNavigate(targetPath)
|
||||
return 'document'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user