Files
webmail/lib/__tests__/settings-search.test.ts
T
Linus Rath d61511bdc1 Merge branch 'main' into ux/settings-admin
# Conflicts:
#	components/settings/address-book-management-settings.tsx
2026-10-28 06:02:59 +01:00

99 lines
4.8 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import en from '@/locales/en/common.json';
import {
type SettingsSearchTab,
descriptionKeyFor,
getByPath,
matchesAllWords,
tabKeywords,
settingsSubResults,
tabSearchEntries,
withAppName,
} from '../settings-search';
const labelsFor = (tab: SettingsSearchTab) => settingsSubResults(en, tab, 'Bulwark').map((r) => r.label);
const resultsFor = (tab: SettingsSearchTab, query: string) =>
settingsSubResults(en, tab, 'Bulwark').filter((r) => matchesAllWords(`${r.label} ${r.description ?? ''}`, query));
describe('settings search index (English messages)', () => {
it('every entry names a label that exists, without a raw placeholder', () => {
const broken: string[] = [];
for (const entries of Object.values(tabSearchEntries)) {
for (const entry of entries) {
const label = getByPath(en, entry.label);
if (typeof label !== 'string' || /\{(?!appName\})/.test(label)) broken.push(entry.label);
}
}
expect(broken).toEqual([]);
});
it('finds a description next to its label', () => {
expect(descriptionKeyFor('settings.email_behavior.send_delay.label', en)).toBe('settings.email_behavior.send_delay.description');
expect(descriptionKeyFor('settings.contacts.group_by_letter_label', en)).toBe('settings.contacts.group_by_letter_description');
expect(descriptionKeyFor('calendar.settings.calendar_free_scroll', en)).toBe('calendar.settings.calendar_free_scroll_desc');
});
it('lists each setting under the page that draws it', () => {
expect(labelsFor('calendar')).toContain('Free scrolling');
expect(labelsFor('calendar')).toContain('Show week numbers');
expect(labelsFor('notifications')).toContain('Unread count on the tab and app icon');
expect(labelsFor('message_list')).toContain('Sender favicons');
expect(labelsFor('message_list')).toContain('Clear search when switching folders');
expect(labelsFor('reading')).toContain('Trusted senders');
expect(labelsFor('composing')).toContain('Undo send / send delay');
expect(labelsFor('general')).toContain('Time zone');
expect(labelsFor('organize')).toContain('Nested tags');
});
// SET-5: whole namespaces were indexed, so results led to pages without
// the row (Sender Favicons under Backup & reset, Phone under Contacts,
// Default Mail Program under Composing) or showed "Level {n} criterion".
it('does not list settings a page does not draw', () => {
expect(labelsFor('backup')).not.toContain('Sender favicons');
expect(labelsFor('backup')).not.toContain('Keyboard shortcuts');
expect(labelsFor('contacts')).not.toContain('Phone');
expect(labelsFor('composing')).not.toContain('Default Mail Program');
for (const tab of Object.keys(tabSearchEntries) as SettingsSearchTab[]) {
expect(labelsFor(tab).filter((l) => l.includes('{'))).toEqual([]);
}
});
// SET-6: these found nothing, or not the right row.
it('finds the settings people searched for', () => {
expect(resultsFor('message_list', 'inbox type').map((r) => r.label)).toEqual(['Inbox type']);
expect(resultsFor('calendar', 'import calendar').map((r) => r.label)).toContain('Import calendar');
expect(resultsFor('composing', 'mention').map((r) => r.label).slice(0, 2)).toEqual(['Mention recipients with @', 'Contacts in @ mentions']);
expect(resultsFor('security', 'two-factor').map((r) => r.label)).toContain('Two-factor authentication');
expect(resultsFor('filters', 'new rule').map((r) => r.label)).toEqual(['New rule']);
// "add rule" finds the Filters page itself.
expect(matchesAllWords(tabKeywords.filters, 'add rule')).toBe(true);
});
it('matches every word of a query, in any order', () => {
const text = 'Signature Position Where to insert your signature in replies';
expect(matchesAllWords(text, 'replies signature')).toBe(true);
expect(matchesAllWords(text, 'signature replies')).toBe(true);
expect(matchesAllWords(text, 'signature forwarding')).toBe(false);
expect(resultsFor('composing', 'reply signature').map((r) => r.label)).toContain('Signature position');
});
it('marks the rows the Advanced switch hides', () => {
const advanced = settingsSubResults(en, 'message_list', 'Bulwark').filter((r) => r.advanced).map((r) => r.label);
expect(advanced).toContain('Emails per page');
expect(advanced).not.toContain('Sender favicons');
});
});
describe('{appName} in the index (#1314)', () => {
it('fills in the configured name', () => {
const results = settingsSubResults(en, 'general', 'Rath Mail');
const text = results.map((r) => `${r.label} ${r.description ?? ''}`).join(' ');
expect(text).not.toContain('{appName}');
expect(text).toContain('Rath Mail');
});
it('leaves other values alone', () => {
expect(withAppName({ a: 'x {appName} y', b: ['{appName}'], c: 3 }, 'N')).toEqual({ a: 'x N y', b: ['N'], c: 3 });
});
});