Public Access
feat(auth): tell the user when the session expired
Every 401 from Auth or Core now goes through useSessionExpired: the login page says the session expired and returns to the last page after login. App no longer removes a token that only the browser clock calls expired, so a backend 401 is the one signal. A 403 on the profile now shows an error instead.
This commit is contained in:
1 parent
03259d0515
commit
d4c0f8d8f3
19 files changed
+351
-35
No files matched your search
@@ -0,0 +1,49 @@
|
||||
// @vitest-environment jsdom
|
||||
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
||||
import {cleanup, render, screen, waitFor} from '@testing-library/react';
|
||||
import {MemoryRouter, Route, Routes, useLocation} from 'react-router-dom';
|
||||
import Dashboard from './Dashboard.jsx';
|
||||
|
||||
vi.mock('react-i18next', () => import('../test/i18n-mock.js'));
|
||||
vi.mock('../hooks/useLibrarySync.js', () => ({default: () => ({status: 'OK', lastSyncedAt: null, isRunning: false})}));
|
||||
vi.mock('../hooks/useForceSync.js', () => ({default: () => ({trigger: vi.fn(), busy: false})}));
|
||||
|
||||
const current = {location: null};
|
||||
|
||||
function Spy() {
|
||||
current.location = useLocation();
|
||||
return null;
|
||||
}
|
||||
|
||||
const ok = (body) => ({ok: true, status: 200, json: async () => body});
|
||||
const unauthorized = () => ({ok: false, status: 401, json: async () => ({})});
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.setItem('tbp_jwt', 'token');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
describe('Dashboard', () => {
|
||||
it('opens the login page when the core API answers 401', async () => {
|
||||
globalThis.fetch = vi.fn(async (url) =>
|
||||
url.includes('/api/users/me') ? ok({email: 'a@b.de', steamId: '76561198000000000'}) : unauthorized());
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route path="/dashboard" element={<><Dashboard/><Spy/></>}/>
|
||||
<Route path="/login" element={<Spy/>}/>
|
||||
</Routes>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
await waitFor(() => expect(fetch.mock.calls.length).toBeGreaterThanOrEqual(5));
|
||||
|
||||
await waitFor(() => expect(current.location.pathname).toBe('/login'));
|
||||
expect(current.location.state).toEqual({sessionExpired: true, from: '/dashboard'});
|
||||
expect(screen.queryByText('LIBRARY.EMPTY')).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user