mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-19 22:24:11 +00:00
37fab6a12d
A maintenance pass over the view, aimed at the places where a later change would go wrong quietly rather than fail. Every option default existed three times: the declaration the params editor renders, the fallback the parser applies, and a fallback in the stylesheet that nothing could reach because the view always sets the variable. Editing one left the editor showing a value the view was not using. Defaults and bounds now live in one object which both the declaration and the parser read, and the dead stylesheet copies are gone. A test asserts that parsing an empty query returns exactly what the editor declares, so the two cannot drift apart again. That test found the first case immediately: the script source declared a default of none but parsed to null. It is now none in both, which also takes a null out of the options type and a branch out of the view. The speed step was a constant in the keymap and a literal in the overlay, so the buttons would have kept stepping by two if the constant ever changed. Both now read the same export. The line height was measured by looking up an element by a data attribute set in another file. Removing that attribute would not have failed, it would have fallen back to a guess which happens to be correct at the default line height and wrong at any other. The measurement now reads the element the hook already holds, which is where the stylesheet sets the line height. Confirmed against the browser: at double the line height the script travels 1.98 times as far. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cb8RVPNQ2ETPJxdy4b8CHf
113 lines
4.3 KiB
TypeScript
113 lines
4.3 KiB
TypeScript
import { getOptionsFromParams, getTeleprompterOptions } from '../teleprompter.options';
|
|
import { DEFAULT_SPEED, MAX_SPEED, MIN_SPEED } from '../teleprompter.scroll';
|
|
|
|
describe('getOptionsFromParams()', () => {
|
|
test('provides sensible defaults with no params', () => {
|
|
const options = getOptionsFromParams(new URLSearchParams());
|
|
|
|
expect(options).toMatchObject({
|
|
scriptSource: 'none',
|
|
heading: 'title',
|
|
hideEmpty: true,
|
|
showGroups: true,
|
|
speed: DEFAULT_SPEED,
|
|
autoplay: false,
|
|
followLoaded: true,
|
|
fontSize: 64,
|
|
lineHeight: 1.5,
|
|
textWidth: 90,
|
|
align: 'left',
|
|
dimPast: true,
|
|
readingLine: 'line',
|
|
readingLinePos: 40,
|
|
flipH: false,
|
|
flipV: false,
|
|
});
|
|
});
|
|
|
|
test('reads the script source verbatim so it can be handed to getPropertyValue', () => {
|
|
const options = getOptionsFromParams(new URLSearchParams('script=custom-prompter'));
|
|
expect(options.scriptSource).toBe('custom-prompter');
|
|
});
|
|
|
|
test('booleans which default to true can be turned off', () => {
|
|
const options = getOptionsFromParams(
|
|
new URLSearchParams('hideEmpty=false&showGroups=false&followLoaded=false&dimPast=false'),
|
|
);
|
|
|
|
expect(options).toMatchObject({
|
|
hideEmpty: false,
|
|
showGroups: false,
|
|
followLoaded: false,
|
|
dimPast: false,
|
|
});
|
|
});
|
|
|
|
test('booleans which default to false can be turned on', () => {
|
|
const options = getOptionsFromParams(new URLSearchParams('autoplay=true&flipH=true&flipV=true'));
|
|
|
|
expect(options).toMatchObject({
|
|
autoplay: true,
|
|
flipH: true,
|
|
flipV: true,
|
|
});
|
|
});
|
|
|
|
test('clamps the speed to the usable range', () => {
|
|
expect(getOptionsFromParams(new URLSearchParams('speed=1000')).speed).toBe(MAX_SPEED);
|
|
expect(getOptionsFromParams(new URLSearchParams('speed=0')).speed).toBe(MIN_SPEED);
|
|
});
|
|
|
|
test('falls back to the default for a non numeric value', () => {
|
|
// Number(null) is 0, so a naive parse would silently produce a speed of zero
|
|
expect(getOptionsFromParams(new URLSearchParams('speed=fast')).speed).toBe(DEFAULT_SPEED);
|
|
expect(getOptionsFromParams(new URLSearchParams('speed=')).speed).toBe(DEFAULT_SPEED);
|
|
expect(getOptionsFromParams(new URLSearchParams('fontSize=huge')).fontSize).toBe(64);
|
|
});
|
|
|
|
test('rejects an unknown value for an enumerated option', () => {
|
|
expect(getOptionsFromParams(new URLSearchParams('heading=banana')).heading).toBe('title');
|
|
expect(getOptionsFromParams(new URLSearchParams('readingLine=banana')).readingLine).toBe('line');
|
|
expect(getOptionsFromParams(new URLSearchParams('align=banana')).align).toBe('left');
|
|
});
|
|
|
|
test('adds the hash back to colour params', () => {
|
|
const options = getOptionsFromParams(new URLSearchParams('keyColour=112233&textColour=ffee00'));
|
|
expect(options.keyColour).toBe('#112233');
|
|
expect(options.textColour).toBe('#ffee00');
|
|
});
|
|
|
|
test('preset values take precedence over the search params', () => {
|
|
const options = getOptionsFromParams(
|
|
new URLSearchParams('speed=10&script=custom-a'),
|
|
new URLSearchParams('speed=50&script=custom-b'),
|
|
);
|
|
|
|
expect(options.speed).toBe(50);
|
|
expect(options.scriptSource).toBe('custom-b');
|
|
});
|
|
});
|
|
|
|
describe('getTeleprompterOptions()', () => {
|
|
/**
|
|
* The params editor renders the declared defaults while the view runs the
|
|
* parsed ones. If they drift the editor shows a value the view is not using,
|
|
* and nothing else would notice.
|
|
*/
|
|
test('every declared default is what parsing an empty query produces', () => {
|
|
const parsed = getOptionsFromParams(new URLSearchParams()) as Record<string, unknown>;
|
|
// the parser exposes the script source under a different name to its param
|
|
const parsedByParamId: Record<string, unknown> = { ...parsed, script: parsed.scriptSource };
|
|
|
|
const declared = getTeleprompterOptions({}).flatMap((section) => section.options);
|
|
expect(declared.length).toBeGreaterThan(0);
|
|
|
|
for (const field of declared) {
|
|
if (!('defaultValue' in field) || field.defaultValue === undefined) continue;
|
|
// colours are declared bare and parsed with the hash added back
|
|
const expected = field.type === 'colour' ? `#${field.defaultValue}` : field.defaultValue;
|
|
expect({ id: field.id, value: parsedByParamId[field.id] }).toEqual({ id: field.id, value: expected });
|
|
}
|
|
});
|
|
});
|