Files
familienarchiv/frontend/src/lib/shared/cookies.spec.ts
Marcel b607677f30 refactor(auth): extract extractFaSessionId to \$lib/shared/cookies
Move the Set-Cookie parser out of login/+page.server.ts into a shared module
with its own Vitest coverage (single-header, multi-header getSetCookie path,
missing-header, attribute-stripping, prefix-match-rejection). An Undici or
Node upgrade that changes header shape now trips its own test instead of
silently breaking login. Addresses PR #612 / Felix F2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 22:43:09 +02:00

39 lines
1.4 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { extractFaSessionId } from './cookies';
describe('extractFaSessionId', () => {
it('extracts the opaque id from a single Set-Cookie header', () => {
const headers = ['fa_session=abc123; Path=/; HttpOnly; SameSite=Strict'];
expect(extractFaSessionId(headers)).toBe('abc123');
});
it('extracts the value when multiple Set-Cookie headers are present (getSetCookie path)', () => {
const headers = [
'JSESSIONID=legacy; Path=/',
'fa_session=xyz789; Path=/; Max-Age=28800; HttpOnly',
'XSRF-TOKEN=ignored; Path=/'
];
expect(extractFaSessionId(headers)).toBe('xyz789');
});
it('returns null when no header carries fa_session', () => {
expect(extractFaSessionId(['Other=foo; Path=/'])).toBeNull();
});
it('returns null for an empty header list', () => {
expect(extractFaSessionId([])).toBeNull();
});
it('strips all attributes after the first semicolon', () => {
const headers = ['fa_session=opaque-token-with.dots_and-dashes; Path=/; Secure; HttpOnly'];
expect(extractFaSessionId(headers)).toBe('opaque-token-with.dots_and-dashes');
});
it('only matches a cookie whose name is exactly fa_session', () => {
// A different cookie name that happens to contain "fa_session" as a substring
// must not match — anchored to start of header.
const headers = ['xfa_session=should-not-match; Path=/'];
expect(extractFaSessionId(headers)).toBeNull();
});
});