Files
numolus/app/frontend/store/__tests__/format.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

69 lines
2.9 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { dateToSerial, timeSerial } from '../../engine';
import { formatValue, readableTextOn } from '../format';
describe('formatValue: date/time', () => {
const day = dateToSerial(2026, 9, 2); // a Wednesday
const noon = timeSerial(12, 0, 0);
const dayAtNoon = day + noon;
it('renders a date per locale', () => {
expect(formatValue(day, 'de-DE', 'date')).toBe('02.09.2026');
expect(formatValue(day, 'en-US', 'date')).toBe('09/02/2026');
expect(formatValue(day, 'plain', 'date')).toBe('2026-09-02');
});
it('renders a time per locale', () => {
expect(formatValue(noon, 'de-DE', 'time')).toBe('12:00');
expect(formatValue(noon, 'plain', 'time')).toBe('12:00');
});
it('renders date + time together', () => {
expect(formatValue(dayAtNoon, 'de-DE', 'datetime')).toBe('02.09.2026 12:00');
expect(formatValue(dayAtNoon, 'plain', 'datetime')).toBe('2026-09-02 12:00');
});
it('date + time shows only the time for a bare time of day (no 1899 date)', () => {
expect(formatValue(timeSerial(12, 23, 0), 'de-DE', 'datetime')).toBe('12:23');
});
it('"duration" keeps counting hours past 24', () => {
expect(formatValue(37.5 / 24, 'de-DE', 'duration')).toBe('37:30');
expect(formatValue(timeSerial(8, 5, 0), 'de-DE', 'duration')).toBe('08:05');
expect(formatValue((100 * 3600 + 30) / 86400, 'de-DE', 'duration')).toBe('100:00:30');
expect(formatValue(-1.5 / 24, 'de-DE', 'duration')).toBe('-01:30');
expect(formatValue(0, 'de-DE', 'duration')).toBe('00:00');
});
it('empty cell / error still short-circuit before any date formatting', () => {
expect(formatValue(null, 'de-DE', 'date')).toBe('');
});
it('"dateiso" renders YYYY-MM-DD regardless of the active locale', () => {
expect(formatValue(day, 'de-DE', 'dateiso')).toBe('2026-09-02');
expect(formatValue(day, 'en-US', 'dateiso')).toBe('2026-09-02');
expect(formatValue(day, 'fr-FR', 'dateiso')).toBe('2026-09-02');
expect(formatValue(day, 'plain', 'dateiso')).toBe('2026-09-02');
});
});
describe('readableTextOn', () => {
it('light text on dark fills, dark text on light fills', () => {
expect(readableTextOn('#000000')).toBe('#f5f5f7');
expect(readableTextOn('#000')).toBe('#f5f5f7');
expect(readableTextOn('#1b1b1b')).toBe('#f5f5f7');
expect(readableTextOn('#0057ff')).toBe('#f5f5f7');
expect(readableTextOn('#ffffff')).toBe('#1d1d1f');
expect(readableTextOn('#ffd400')).toBe('#1d1d1f');
expect(readableTextOn('#FFF')).toBe('#1d1d1f');
});
it('ignores what it cannot read, and mostly transparent fills', () => {
expect(readableTextOn(undefined)).toBeNull();
expect(readableTextOn('red')).toBeNull();
expect(readableTextOn('#12345')).toBeNull();
expect(readableTextOn('#00000020')).toBeNull();
expect(readableTextOn('#000000cc')).toBe('#f5f5f7');
});
});