- 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).
69 lines
2.9 KiB
TypeScript
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');
|
|
});
|
|
});
|