test(auth): Vitest coverage for logout action
Three tests: happy path POSTs to backend with the session cookie and clears both fa_session and legacy auth_token; cookies are cleared even when the backend call rejects (best-effort logout); skips the backend call when no session cookie is present. Addresses PR #612 / Sara S1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
63
frontend/src/routes/logout/page.server.test.ts
Normal file
63
frontend/src/routes/logout/page.server.test.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('$env/dynamic/private', () => ({
|
||||||
|
env: { API_INTERNAL_URL: 'http://backend:8080' }
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { actions } from './+page.server';
|
||||||
|
|
||||||
|
type ActionsRecord = Record<string, (e: never) => unknown>;
|
||||||
|
|
||||||
|
function makeCookies(sessionId?: string) {
|
||||||
|
return {
|
||||||
|
get: vi.fn((name: string) => (name === 'fa_session' ? sessionId : undefined)),
|
||||||
|
set: vi.fn(),
|
||||||
|
delete: vi.fn()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('logout action', () => {
|
||||||
|
beforeEach(() => vi.restoreAllMocks());
|
||||||
|
|
||||||
|
it('calls backend /api/auth/logout with the session cookie and redirects to /login', async () => {
|
||||||
|
const mockFetch = vi.fn().mockResolvedValue(new Response(null, { status: 204 }));
|
||||||
|
const cookies = makeCookies('opaque-id');
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
(actions as ActionsRecord).default({ cookies, fetch: mockFetch } as never)
|
||||||
|
).rejects.toMatchObject({ status: 303, location: '/login' });
|
||||||
|
|
||||||
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
|
'http://backend:8080/api/auth/logout',
|
||||||
|
expect.objectContaining({
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Cookie: 'fa_session=opaque-id' }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(cookies.delete).toHaveBeenCalledWith('fa_session', { path: '/' });
|
||||||
|
expect(cookies.delete).toHaveBeenCalledWith('auth_token', { path: '/' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears cookies even when the backend logout call fails', async () => {
|
||||||
|
const mockFetch = vi.fn().mockRejectedValue(new Error('connection refused'));
|
||||||
|
const cookies = makeCookies('opaque-id');
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
(actions as ActionsRecord).default({ cookies, fetch: mockFetch } as never)
|
||||||
|
).rejects.toMatchObject({ status: 303, location: '/login' });
|
||||||
|
|
||||||
|
expect(cookies.delete).toHaveBeenCalledWith('fa_session', { path: '/' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips the backend call when no session cookie is present', async () => {
|
||||||
|
const mockFetch = vi.fn();
|
||||||
|
const cookies = makeCookies(undefined);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
(actions as ActionsRecord).default({ cookies, fetch: mockFetch } as never)
|
||||||
|
).rejects.toMatchObject({ status: 303, location: '/login' });
|
||||||
|
|
||||||
|
expect(mockFetch).not.toHaveBeenCalled();
|
||||||
|
expect(cookies.delete).toHaveBeenCalledWith('fa_session', { path: '/' });
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user