Files
numolus/app/frontend/data/__tests__/help.spec.ts
T
wkh 0fca61eb65 Add in-app help, formula reference outlines, underline and auto-closing
- Help dialog (?, F1, Datei > Hilfe): user topics, all shortcuts and the
  formula functions with one search over everything. Topics and shortcuts
  are plain data in data/help.ts; the function list comes from
  codeReference.ts so new built-ins appear by themselves.
- While a formula is edited, the grid outlines each referenced cell/range
  in the colour of its position in the text, and the outline can be
  dragged to move or resize the reference, as in Excel. Point-mode picks
  (click, drag, arrow keys) are outlined too, so keyboard picking is no
  longer blind.
- Underline as a cell format, plus Mod+Shift+B/I/U toggles that switch on
  unless every selected cell already has the format.
- A formula committed with open parentheses or an open text literal gets
  the missing closers appended; anything that still doesn't parse is left
  alone so the usual error shows instead of a guess.
- Cells and tables with a fill but no text colour get dark or light text
  by WCAG contrast instead of the theme colour (no black on black).
2026-10-24 00:38:01 +02:00

57 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { HELP_TOPICS, SHORTCUT_GROUPS, shortcutKeys } from '../help';
describe('in-app help content', () => {
it('topics have unique ids that never clash with the fixed pages', () => {
const ids = HELP_TOPICS.map((t) => t.id);
expect(new Set(ids).size).toBe(ids.length);
expect(ids).not.toContain('shortcuts');
expect(ids).not.toContain('functions');
});
it('no empty topics, sections, items or shortcuts', () => {
for (const t of HELP_TOPICS) {
expect(t.title.trim()).not.toBe('');
expect(t.sections.length).toBeGreaterThan(0);
for (const s of t.sections) {
expect(s.items.length).toBeGreaterThan(0);
for (const i of s.items) expect(i.trim()).not.toBe('');
}
}
for (const g of SHORTCUT_GROUPS) {
expect(g.shortcuts.length).toBeGreaterThan(0);
for (const s of g.shortcuts) {
expect(s.keys.trim()).not.toBe('');
expect(s.description.trim()).not.toBe('');
}
}
});
it('inline markup is balanced, so nothing renders half-bold', () => {
const all = HELP_TOPICS.flatMap((t) => t.sections.flatMap((s) => s.items));
for (const text of all) {
expect((text.match(/`/g) ?? []).length % 2, text).toBe(0);
expect((text.match(/\*\*/g) ?? []).length % 2, text).toBe(0);
}
});
it('names the keys per platform: Strg on Windows/Linux, ⌘/⌥ and the Mac overrides on a Mac', () => {
expect(shortcutKeys({ keys: 'Mod+Umschalt+U' }, 'pc')).toBe('Strg+Umschalt+U');
expect(shortcutKeys({ keys: 'Mod+Umschalt+U' }, 'mac')).toBe('⌘+Umschalt+U');
expect(shortcutKeys({ keys: 'Alt+Enter oder Mod+Enter' }, 'mac')).toBe('⌥+Enter oder ⌘+Enter');
expect(shortcutKeys({ keys: 'Pos1 / Ende', mac: 'fn+← / fn+→' }, 'pc')).toBe('Pos1 / Ende');
expect(shortcutKeys({ keys: 'Pos1 / Ende', mac: 'fn+← / fn+→' }, 'mac')).toBe('fn+← / fn+→');
// running text: only whole words are key names
expect(shortcutKeys('Alter mit Mod', 'mac')).toBe('Alter mit ⌘');
});
it('no Windows/Linux key text is left with a Mac-only symbol, and vice versa', () => {
for (const g of SHORTCUT_GROUPS) {
for (const s of g.shortcuts) {
expect(shortcutKeys(s, 'pc'), s.keys).not.toMatch(/[⌘⌥⌫]|\bfn\b/);
expect(shortcutKeys(s, 'mac'), s.keys).not.toMatch(/\b(Strg|Mod|Alt)\b/);
}
}
});
});