Fix MainContainer beforeRouteEnter missing try-catch and next() call
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ import Loading from '@/components/Loading.vue';
|
|||||||
import { leaveFilter, leaveConformance } from '@/module/alertModal.js';
|
import { leaveFilter, leaveConformance } from '@/module/alertModal.js';
|
||||||
import PageAdminStore from '@/stores/pageAdmin.js';
|
import PageAdminStore from '@/stores/pageAdmin.js';
|
||||||
import LoginStore from "@/stores/login.ts";
|
import LoginStore from "@/stores/login.ts";
|
||||||
import { getCookie } from "@/utils/cookieUtil.js";
|
import { getCookie, setCookie } from "@/utils/cookieUtil.js";
|
||||||
import ModalContainer from './AccountManagement/ModalContainer.vue';
|
import ModalContainer from './AccountManagement/ModalContainer.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -109,8 +109,19 @@ export default {
|
|||||||
|
|
||||||
if (!getCookie("isLuciaLoggedIn")) { //這裡不要用pinia的isLoggedIn來檢查,因為會有重新整理時撈不到Persisted value的值的bug
|
if (!getCookie("isLuciaLoggedIn")) { //這裡不要用pinia的isLoggedIn來檢查,因為會有重新整理時撈不到Persisted value的值的bug
|
||||||
if (getCookie('luciaRefreshToken')) {
|
if (getCookie('luciaRefreshToken')) {
|
||||||
await loginStore.refreshToken();
|
try {
|
||||||
loginStore.setIsLoggedIn(true);
|
await loginStore.refreshToken();
|
||||||
|
loginStore.setIsLoggedIn(true);
|
||||||
|
setCookie("isLuciaLoggedIn", "true");
|
||||||
|
next();
|
||||||
|
} catch(error) {
|
||||||
|
next({
|
||||||
|
path: '/login',
|
||||||
|
query: {
|
||||||
|
'return-to': btoa(window.location.href),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
next({
|
next({
|
||||||
path: '/login',
|
path: '/login',
|
||||||
|
|||||||
89
tests/views/MainContainerGuard.test.js
Normal file
89
tests/views/MainContainerGuard.test.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||||
|
import { setActivePinia, createPinia } from 'pinia';
|
||||||
|
|
||||||
|
// Mock all heavy imports that MainContainer.vue pulls in
|
||||||
|
vi.mock('@/stores/loading.js', () => ({
|
||||||
|
default: () => ({ isLoading: false }),
|
||||||
|
}));
|
||||||
|
vi.mock('@/stores/allMapData.js', () => ({
|
||||||
|
default: () => ({}),
|
||||||
|
}));
|
||||||
|
vi.mock('@/stores/conformance.js', () => ({
|
||||||
|
default: () => ({}),
|
||||||
|
}));
|
||||||
|
vi.mock('@/stores/pageAdmin.js', () => ({
|
||||||
|
default: () => ({}),
|
||||||
|
}));
|
||||||
|
vi.mock('@/module/alertModal.js', () => ({
|
||||||
|
leaveFilter: vi.fn(),
|
||||||
|
leaveConformance: vi.fn(),
|
||||||
|
}));
|
||||||
|
vi.mock('@/module/apiError.js', () => ({
|
||||||
|
default: vi.fn(),
|
||||||
|
}));
|
||||||
|
vi.mock('@/router/index.ts', () => ({
|
||||||
|
default: { push: vi.fn(), currentRoute: { value: { path: '/' } } },
|
||||||
|
}));
|
||||||
|
vi.mock('@/module/cytoscapeMap.js', () => ({}));
|
||||||
|
|
||||||
|
import LoginStore from '@/stores/login.ts';
|
||||||
|
import * as cookieUtil from '@/utils/cookieUtil.js';
|
||||||
|
|
||||||
|
// Import the component definition to access beforeRouteEnter
|
||||||
|
import MainContainer from '@/views/MainContainer.vue';
|
||||||
|
|
||||||
|
describe('MainContainer beforeRouteEnter', () => {
|
||||||
|
let loginStore;
|
||||||
|
let next;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setActivePinia(createPinia());
|
||||||
|
loginStore = LoginStore();
|
||||||
|
loginStore.$router = { push: vi.fn() };
|
||||||
|
next = vi.fn();
|
||||||
|
vi.clearAllMocks();
|
||||||
|
// Clear cookies
|
||||||
|
document.cookie.split(';').forEach((c) => {
|
||||||
|
const name = c.split('=')[0].trim();
|
||||||
|
if (name) {
|
||||||
|
document.cookie = name + '=; Max-Age=-99999999; path=/';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const callGuard = () => {
|
||||||
|
const guard = MainContainer.beforeRouteEnter;
|
||||||
|
return guard({}, {}, next);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('calls next() after successful refreshToken', async () => {
|
||||||
|
// Not logged in, but has refresh token
|
||||||
|
document.cookie = 'luciaRefreshToken=some-token';
|
||||||
|
vi.spyOn(loginStore, 'refreshToken').mockResolvedValue();
|
||||||
|
|
||||||
|
await callGuard();
|
||||||
|
|
||||||
|
expect(loginStore.refreshToken).toHaveBeenCalled();
|
||||||
|
expect(next).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('redirects to login when refreshToken fails', async () => {
|
||||||
|
// Not logged in, has refresh token, but refresh fails
|
||||||
|
document.cookie = 'luciaRefreshToken=some-token';
|
||||||
|
vi.spyOn(loginStore, 'refreshToken').mockRejectedValue(new Error('401'));
|
||||||
|
|
||||||
|
await callGuard();
|
||||||
|
|
||||||
|
expect(next).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ path: '/login' }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls next() when already logged in', async () => {
|
||||||
|
document.cookie = 'isLuciaLoggedIn=true';
|
||||||
|
|
||||||
|
await callGuard();
|
||||||
|
|
||||||
|
expect(next).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user