oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1// fixtures/sizes.test.mjs — the font-size vocabulary, under plain Node.
2//
3// fonts.test.mjs's counterpart. Importing this module is also what makes
4// sizes.mjs's own module-load guard run in the gate — the same
5// arrangement align.test.mjs and fonts.test.mjs have, and for the reason
6// their comments give at length: a guard that only executes when a
7// browser mounts the editor is dead code in CI, so a drifted vocabulary
8// would pass the whole gate and then throw for every user.
9
10import { test } from 'node:test'
11import assert from 'node:assert/strict'
12
13import {
14 SIZES,
15 DEFAULT_SIZE,
16 SIZE_MARKS,
17 LEGACY_SIZES,
18 sizeMark,
19 sizeForMarks,
20} from './sizes.mjs'
21
22test('the default is offered, is first, and carries no mark', () => {
23 assert.ok(SIZES.includes(DEFAULT_SIZE))
24 assert.equal(SIZES[0], DEFAULT_SIZE)
25 // The literal null is the assertion, not a derivation of sizeMark's
26 // own definition. fonts.mjs's guard has a long comment about an
27 // assertion that compared a value to itself and could not fail for
28 // any input; this is where that expectation belongs — in a test,
29 // against a literal.
30 assert.equal(sizeMark(DEFAULT_SIZE), null)
31 assert.equal(sizeMark(12), null)
32})
33
34test('every other size maps to its own mark', () => {
35 assert.equal(sizeMark(8), 'size_8')
36 assert.equal(sizeMark(14), 'size_14')
37 assert.equal(sizeMark(72), 'size_72')
38})
39
40test('a size string works, because that is what a <select> gives you', () => {
41 assert.equal(sizeMark('14'), 'size_14')
42 assert.equal(sizeMark('12'), null)
43})
44
45test('a size this build does not offer is undefined, never null', () => {
46 // undefined and null are different answers: null clears the group,
47 // which is a real edit. A stale page sending 13 must not silently
48 // reset a person's text to 12.
49 assert.equal(sizeMark(13), undefined)
50 assert.equal(sizeMark(0), undefined)
51 assert.equal(sizeMark('enormous'), undefined)
52 assert.equal(sizeMark(''), undefined)
53})
54
55test('no marks means the default size', () => {
56 assert.equal(sizeForMarks([]), DEFAULT_SIZE)
57 assert.equal(sizeForMarks(['strong', 'em']), DEFAULT_SIZE)
58})
59
60test('a mark reports its own size', () => {
61 assert.equal(sizeForMarks(['size_18']), 18)
62 assert.equal(sizeForMarks(['strong', 'size_9', 'em']), 9)
63})
64
65// The legacy marks are the reason this module has a mapping at all, and
66// the reason the control could not simply slice the prefix off a mark
67// name the way it used to.
68test('the four-step scale still reports a size on the ladder', () => {
69 assert.equal(sizeForMarks(['size_sm']), 10)
70 assert.equal(sizeForMarks(['size_lg']), 14)
71 assert.equal(sizeForMarks(['size_xl']), 18)
72 for (const pt of Object.values(LEGACY_SIZES)) {
73 assert.ok(SIZES.includes(pt), `${pt}pt is not on the ladder, so the control could not show it`)
74 }
75})
76
77test('the legacy marks are in the group the toolbar clears', () => {
78 // If they were not, choosing a size on a run carrying an old mark
79 // would leave it in place and the run would be at two sizes at once —
80 // which the schema forbids and POST /d/{sqid}/updates does not.
81 for (const mark of Object.keys(LEGACY_SIZES)) {
82 assert.ok(SIZE_MARKS.includes(mark), `${mark} is not cleared when a size is chosen`)
83 }
84})
85
86test('the ladder wins over a legacy mark on the same run', () => {
87 // Impossible through the editor (the schema's excludes), reachable
88 // through POST /d/{sqid}/updates. The answer has to be stable rather
89 // than whichever was found first, and internal/export/pdf.go's
90 // sizeOrder makes the same choice so the screen and the PDF agree.
91 assert.equal(sizeForMarks(['size_lg', 'size_24']), 24)
92 assert.equal(sizeForMarks(['size_24', 'size_lg']), 24)
93})
94