fix: hide expired session token errors on login
This commit is contained in:
@@ -105,6 +105,19 @@ test('exposes only account and password login on the public sign-in screen', asy
|
|||||||
expect(screen.getByRole('button', { name: '登录工作台' })).toBeDisabled();
|
expect(screen.getByRole('button', { name: '登录工作台' })).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('silently clears an expired stored session without exposing token errors on the account login page', async () => {
|
||||||
|
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||||
|
setAccessToken('expired-session-token');
|
||||||
|
mocks.session.mockRejectedValue(new Error('需要有效的访问令牌'));
|
||||||
|
|
||||||
|
render(<QueryClientProvider client={client}><AuthGate><ProtectedWorkspace onAbort={() => undefined} /></AuthGate></QueryClientProvider>);
|
||||||
|
|
||||||
|
expect(await screen.findByRole('form', { name: '账号密码登录' })).toBeInTheDocument();
|
||||||
|
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText(/访问令牌/)).not.toBeInTheDocument();
|
||||||
|
await waitFor(() => expect(getAccessToken()).toBe(''));
|
||||||
|
});
|
||||||
|
|
||||||
test('an expired protected request returns to login and removes the active user cache', async () => {
|
test('an expired protected request returns to login and removes the active user cache', async () => {
|
||||||
mocks.logout.mockResolvedValue({ loggedOut: true });
|
mocks.logout.mockResolvedValue({ loggedOut: true });
|
||||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||||
|
|||||||
@@ -107,6 +107,11 @@ export function AuthGate({ children }: { children: ReactNode }) {
|
|||||||
window.addEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout);
|
window.addEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout);
|
||||||
return () => window.removeEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout);
|
return () => window.removeEventListener(PLATFORM_UNAUTHORIZED_EVENT, finishLogout);
|
||||||
}, [finishLogout]);
|
}, [finishLogout]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!session.isError || loginPending || loginError || !getAccessToken()) return;
|
||||||
|
clearAccessToken();
|
||||||
|
setAttempted(false);
|
||||||
|
}, [loginError, loginPending, session.isError]);
|
||||||
|
|
||||||
const login = async (event: FormEvent) => {
|
const login = async (event: FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -129,7 +134,7 @@ export function AuthGate({ children }: { children: ReactNode }) {
|
|||||||
return <AuthLoadingState />;
|
return <AuthLoadingState />;
|
||||||
}
|
}
|
||||||
if (!session.data) {
|
if (!session.data) {
|
||||||
const error = loginError || (attempted && session.error ? session.error.message : '');
|
const error = loginError || (attempted && session.error && !getAccessToken() ? session.error.message : '');
|
||||||
return <div className="v2-auth-screen">
|
return <div className="v2-auth-screen">
|
||||||
<section className="v2-auth-intro" aria-labelledby="v2-auth-intro-title">
|
<section className="v2-auth-intro" aria-labelledby="v2-auth-intro-title">
|
||||||
<header>
|
<header>
|
||||||
|
|||||||
Reference in New Issue
Block a user