b92dd5dda1
Drei while ((m = re.exec(t)) !== null)-Schleifen (dkv-parser.service.ts, dkv-parser.validate.ts, icon-discovery.service.ts) sind die korrekte Standardform fuer globale Regexe - kein verrutschtes "=". Umgeschrieben auf eine verhaltensgleiche for-Schleife, die ohne noAssignInExpressions- Unterdrueckung auskommt: Zuweisung wandert in Initialisierung und Fortschaltung der for-Schleife, Bedingung prueft weiterhin auf null. Abfolge der exec-Aufrufe, lastIndex-Fortschritt und Rumpfinhalte unveraendert. Neue Spezifikation dkv-parser.service.spec.ts deckt parseDkvText erstmals eigenstaendig ab (zwei Fahrzeugbloecke, Rechnungsnummer und -datum aus einer gemockten pdf-parse-Attrappe) - das Rueckfall-Tor fuer diesen Umbau. dkv-parser.validate.ts bleibt bei 27 Fahrzeugbloecken/66 Transaktionen gegen die reale invoice.pdf identisch. LdapService.escapeLdapFilterValue bleibt zeichengleich: der NUL-Treffer in der Regel ist die von RFC 4515 vorgeschriebene \00-Maskierung, kein Fehler. Ein biome-ignore-Kommentar dokumentiert das, statt die Funktion zu aendern. locale-switcher.tsx setzt jetzt SameSite=Lax auf dem NEXT_LOCALE-Cookie - path=/ und max-age waren bereits korrekt, es lag also kein Persistenzdefekt vor. Ohne SameSite haengt die Uebertragung am Browservorgabewert statt an einer Festlegung. Neue Spezifikation locale-switcher.test.tsx haelt die vollstaendige geschriebene Cookie-Zeichenkette fest. Biome-Warnungen 446 -> 434 (noControlCharactersInRegex/useIterableCallbackReturn/ noGlobalIsNan auf 0, noAssignInExpressions auf 4 und noDocumentCookie auf 17 - beide Reste ausschliesslich in Testdateien, suppressions/unused auf 0). Quick-Vorgang 260921-i8x, Task 3/3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import { cleanup, render, screen } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { LocaleSwitcher } from './locale-switcher';
|
|
|
|
/**
|
|
* locale-switcher.test — SameSite-Luecke im Sprachumschalter-Cookie
|
|
* (quick-260921-i8x, Task 3 Teil C, T-i8x-05, RED first).
|
|
*
|
|
* Muster: header.test.tsx fuer next-intl/next-navigation-Mocks. Der Setter
|
|
* von `document.cookie` wird per `Object.defineProperty` durch eine
|
|
* Attrappe ersetzt, die jede geschriebene Zeichenkette sammelt — vor der
|
|
* Aenderung faellt nur die SameSite-Zusicherung durch, das ist beabsichtigt
|
|
* und zeigt genau die Luecke (T-i8x-05).
|
|
*/
|
|
|
|
vi.mock('next-intl', () => ({
|
|
useTranslations: () => (key: string) => {
|
|
const translations: Record<string, string> = {
|
|
de: 'Deutsch',
|
|
en: 'English',
|
|
};
|
|
return translations[key] ?? key;
|
|
},
|
|
useLocale: () => 'de',
|
|
}));
|
|
|
|
const refreshMock = vi.fn();
|
|
vi.mock('next/navigation', () => ({
|
|
useRouter: () => ({ refresh: refreshMock }),
|
|
}));
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('LocaleSwitcher', () => {
|
|
it('schreibt beim Klick genau ein Cookie mit NEXT_LOCALE, path=/, max-age=31536000 und SameSite=Lax', async () => {
|
|
const writtenCookies: string[] = [];
|
|
Object.defineProperty(document, 'cookie', {
|
|
configurable: true,
|
|
get: () => '',
|
|
set: (value: string) => {
|
|
writtenCookies.push(value);
|
|
},
|
|
});
|
|
|
|
const user = userEvent.setup();
|
|
render(<LocaleSwitcher />);
|
|
|
|
await user.click(screen.getByRole('button'));
|
|
|
|
expect(writtenCookies).toHaveLength(1);
|
|
const written = writtenCookies[0];
|
|
expect(written).toContain('NEXT_LOCALE=en');
|
|
expect(written).toContain('path=/');
|
|
expect(written).toContain('max-age=31536000');
|
|
expect(written).toContain('SameSite=Lax');
|
|
});
|
|
});
|