Files
webmail/lib/__tests__/subject-prefix.test.ts
T
dealerweb d6ae84f5e8 fix: keep the fresh-compose tab title clear of the selected email subject
The Pro-mode bridge that turns an inline compose intent into a compose
tab derived its working title from the draft subject or, failing that,
the selected email's subject - regardless of mode. For reply/forward the
selected email is the message being acted on; for a fresh compose it is
whatever happens to be highlighted in the list, so "New Email" opened
with an unrelated subject in the tab strip (#856). Extract the rule into
buildComposeTabTitle: a fresh compose only ever uses its own draft
subject (mailto, resumed draft) and otherwise starts on the "New
message" fallback. Typing a subject already renames the tab live via
handleSaveState, so nothing else changes.
2026-08-18 15:48:05 +02:00

88 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from 'vitest';
import {
stripSubjectPrefixes,
buildReplySubject,
buildForwardSubject,
buildComposeTabTitle,
} 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] and Eudora *N counters', () => {
expect(stripSubjectPrefixes('Re[2]: foo')).toBe('foo');
expect(stripSubjectPrefixes('Re*3: 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 token and an ASCII-colon Chinese token', () => {
expect(stripSubjectPrefixes('Ответ: foo')).toBe('foo');
expect(stripSubjectPrefixes('回复: foo')).toBe('foo');
});
it('strips a token followed by a full-width colon (CJK clients)', () => {
expect(stripSubjectPrefixes('回复:foo')).toBe('foo');
expect(stripSubjectPrefixes('回覆:foo')).toBe('foo');
expect(stripSubjectPrefixes('Re:foo')).toBe('foo');
});
it('still does not strip a bare single-letter "R:"', () => {
expect(stripSubjectPrefixes('R: budget 2024')).toBe('R: budget 2024');
});
it('returns "" for empty / null / undefined and leaves clean subjects alone', () => {
expect(stripSubjectPrefixes('')).toBe('');
expect(stripSubjectPrefixes(null)).toBe('');
expect(stripSubjectPrefixes(undefined)).toBe('');
expect(stripSubjectPrefixes('foo')).toBe('foo');
});
});
describe('buildReplySubject / buildForwardSubject', () => {
it('replaces a prefix chain (incl. a full-width colon) with the given prefix', () => {
expect(buildReplySubject('回复:foo', 'Re:')).toBe('Re: foo');
expect(buildForwardSubject('Re: foo', 'Fwd:')).toBe('Fwd: foo');
});
it('prepends to a clean subject and returns the bare prefix for empty input', () => {
expect(buildReplySubject('foo', 'AW:')).toBe('AW: foo');
expect(buildReplySubject('', 'AW:')).toBe('AW:');
});
});
describe('buildComposeTabTitle', () => {
const prefixes = { replyPrefix: 'Re:', forwardPrefix: 'Fwd:', fallback: 'New message' };
it('never inherits the selected email subject for a fresh compose (#856)', () => {
expect(buildComposeTabTitle({ mode: 'compose', sourceSubject: 'Invoice August 2026', ...prefixes }))
.toBe('New message');
});
it('uses the draft subject for a fresh compose when one exists (mailto, draft edit)', () => {
expect(buildComposeTabTitle({ mode: 'compose', draftSubject: 'Lunch?', sourceSubject: 'Invoice August 2026', ...prefixes }))
.toBe('Lunch?');
});
it('derives reply and forward titles from the source subject', () => {
expect(buildComposeTabTitle({ mode: 'reply', sourceSubject: 'Invoice August 2026', ...prefixes }))
.toBe('Re: Invoice August 2026');
expect(buildComposeTabTitle({ mode: 'replyAll', sourceSubject: 'AW: Invoice', ...prefixes }))
.toBe('Re: Invoice');
expect(buildComposeTabTitle({ mode: 'forward', sourceSubject: 'Invoice', ...prefixes }))
.toBe('Fwd: Invoice');
});
it('prefers a resumed draft subject over the source and falls back when both are blank', () => {
expect(buildComposeTabTitle({ mode: 'reply', draftSubject: 'Re: edited', sourceSubject: 'Original', ...prefixes }))
.toBe('Re: edited');
expect(buildComposeTabTitle({ mode: 'reply', sourceSubject: ' ', ...prefixes }))
.toBe('New message');
});
});