Golden-master tests pinning the CURRENT behavior of high-value modules that had no coverage — integration seams, security helpers, two API route handlers, and complex pure utils. 111 tests across 12 files. New tests: - auth-crypto / session-cookie: AES-256-GCM session encryption roundtrip, tamper/version/missing-secret handling; cookie-slot naming. - unified-mailbox: multi-account fan-out, sort, totals, per-account error isolation, personal-vs-shared JMAP target resolution, counts/roles. - account-state-manager: snapshot/restore across the six real Zustand stores; clearAllStores reset shape; evict. - mdn: RFC 5322 MDN assembly (CRLF, RFC2047, base64 wrap, headers). - tnef: winmail.dat binary parsing from hand-built fixtures. - download-filename / subject-prefix / birthday-calendar / eml-import: filename templating, multilingual prefix stripping, birthday event generation, .eml/.zip import. - webdav / caldav-discover route handlers: auth guards, path validation, upstream URL construction, candidate probing. - helpers/factories.ts: shared makeEmail/makeMailbox/makeFakeJmapClient. Tests follow the repo's existing patterns (route-import, fake IJMAPClient, fetch spy, real store singletons). Where current behavior looks buggy it is pinned and flagged with a // CHARACTERISATION: comment (see PR for the suspected-bugs list); no production code is changed.
68 lines
2.4 KiB
TypeScript
68 lines
2.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
||
import {
|
||
stripSubjectPrefixes,
|
||
buildReplySubject,
|
||
buildForwardSubject,
|
||
} from '@/lib/subject-prefix';
|
||
|
||
describe('stripSubjectPrefixes', () => {
|
||
it('strips a chain of mixed-language prefixes', () => {
|
||
expect(stripSubjectPrefixes('Re: AW: WG: foo')).toBe('foo');
|
||
});
|
||
|
||
it('strips the Outlook [N] counter and Eudora *N counter', () => {
|
||
expect(stripSubjectPrefixes('Re[2]: foo')).toBe('foo');
|
||
expect(stripSubjectPrefixes('Re*3: foo')).toBe('foo');
|
||
expect(stripSubjectPrefixes('Re*: foo')).toBe('foo');
|
||
});
|
||
|
||
it('is case-insensitive and idempotent', () => {
|
||
expect(stripSubjectPrefixes('RE: Re: foo')).toBe('foo');
|
||
expect(stripSubjectPrefixes(stripSubjectPrefixes('RE: Re: foo'))).toBe('foo');
|
||
});
|
||
|
||
it('strips a Cyrillic reply token', () => {
|
||
expect(stripSubjectPrefixes('Ответ: foo')).toBe('foo');
|
||
});
|
||
|
||
it('strips a Chinese token followed by an ASCII colon', () => {
|
||
expect(stripSubjectPrefixes('回复: foo')).toBe('foo');
|
||
});
|
||
|
||
it('CHARACTERISATION: does NOT strip a token followed by a full-width colon', () => {
|
||
// The colon in the regex is ASCII ":"; a full-width ":" (U+FF1A), as some
|
||
// CJK mail clients emit, is left untouched. Likely a bug — see follow-ups.
|
||
expect(stripSubjectPrefixes('回复:foo')).toBe('回复:foo');
|
||
});
|
||
|
||
it('does NOT strip a bare single-letter "R:" (would eat real subjects)', () => {
|
||
expect(stripSubjectPrefixes('R: budget 2024')).toBe('R: budget 2024');
|
||
});
|
||
|
||
it('returns "" for empty / null / undefined', () => {
|
||
expect(stripSubjectPrefixes('')).toBe('');
|
||
expect(stripSubjectPrefixes(null)).toBe('');
|
||
expect(stripSubjectPrefixes(undefined)).toBe('');
|
||
});
|
||
|
||
it('leaves a prefix-free subject untouched', () => {
|
||
expect(stripSubjectPrefixes('foo')).toBe('foo');
|
||
});
|
||
});
|
||
|
||
describe('buildReplySubject / buildForwardSubject', () => {
|
||
it('replaces an existing prefix chain with the given prefix', () => {
|
||
expect(buildReplySubject('AW: WG: foo', 'Re:')).toBe('Re: foo');
|
||
expect(buildForwardSubject('Re: foo', 'Fwd:')).toBe('Fwd: foo');
|
||
});
|
||
|
||
it('prepends the prefix to a prefix-free subject', () => {
|
||
expect(buildReplySubject('foo', 'AW:')).toBe('AW: foo');
|
||
});
|
||
|
||
it('returns just the bare prefix for an empty subject', () => {
|
||
expect(buildReplySubject('', 'AW:')).toBe('AW:');
|
||
expect(buildForwardSubject(null, 'Fwd:')).toBe('Fwd:');
|
||
});
|
||
});
|