Files
technitium-console/dev/master-switch-signal.test.mjs
T
DenozordecandClaude Sonnet 5.5 f3531c64f9 Move the console onto ReUI PRO
Install ReUI (MCP, skill, @reui registry, Tailwind v4, shadcn base-nova) and move
the shared UI onto it: Button, Tag, Check, Input/Textarea, Segmented, Alert, Panel,
Dialog, Tooltip, Menu and Select (Popover), Toast (sonner), the Table frame
(DataGrid), the Dashboard KPI strip, the shnt Ops palette, Geist and the type scale.

Design only: behaviour, texts and roles are unchanged. Tests that asserted the old
DOM were updated; the tests now format numbers in English wherever they run.
docs/reui-migration-plan.md records the plan and its decisions.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 00:06:06 +07:00

88 lines
3.6 KiB
JavaScript

/*
The two guards of the master-switch signal that are checked against the SOURCE
CODE, not against a render.
They live here and not next to `master.test.tsx` for a mechanical reason: they
read files, and everything under `src/` compiles with `types: ["vite/client"]`
(without node's types), so a `node:fs` in there passes the suite and **breaks the
build**. That is exactly what happened: 1039 tests green and `tsc -b` red with four
errors. It is the same hole as the time `grep -cE "^error"` said "build 0" while
the build was failing, and that is why the gate is read by its exit code.
What they check is not a render matter either: jsdom does not apply CSS modules and
there is no screen on which to see either of the two things.
*/
import { describe, expect, it } from 'vitest'
import { readFileSync, readdirSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const here = dirname(fileURLToPath(import.meta.url))
const src = resolve(here, '../src')
/*
The rule mark must not take grid space.
With `border-left: 2px solid var(--acc)` the five dependent rows of
`/settings/general/` measured `210px 540px 360px` against the `210px 542px 360px`
of the other 34: the border eats two pixels of the box and **shifts the control**.
In a dense form that is a column that stops being aligned, and `dev/uniformity.js`
caught it as a third `grid-panel` signature that existed only on that route. A
state signal must not move the content it marks.
*/
describe('the master rule mark does not shift the grid', () => {
const css = readFileSync(resolve(src, 'ui/Form.module.css'), 'utf8')
const rule = /\.dependent\s*\{([^}]*)\}/.exec(css)?.[1] ?? ''
it('the rule exists and paints the amber mark', () => {
expect(rule).toMatch(/var\(--acc(-ink)?\)/)
})
it('and paints it with an inset shadow, not with a border that takes box space', () => {
expect(rule).toMatch(/box-shadow:\s*inset/)
expect(rule).not.toMatch(/border/)
expect(rule).not.toMatch(/padding/)
})
})
/*
The amber pill and the `warn` pill must never meet on one screen.
Measured on 2026-09-03 with the function in `dev/palette-distance.mjs`: against
`warn`, the `acc` tone gives ΔE00 **8.8** on the text, **8.9** on the border and
**0.0** on the background. That same tool's collision threshold is 10, so by the
project's own criterion **they are the same colour**. And it has to be: the pill
goes with the amber mark of the row and the two are ONE signal; giving it another
amber would split it.
That this costs nothing depends on a fact, not on luck: today the two families do
not meet (the seven `warn` pills live in cluster, sessions, apps and zones; the
`acc` one only in the `Settings` forms). If a screen ever painted both, the user
would see two identical pills meaning "you can" and "careful".
*/
describe('the amber of "you can" never meets the amber of "careful"', () => {
const files = (pattern) => {
const found = []
const walk = (dir) => {
for (const e of readdirSync(dir, { withFileTypes: true })) {
const p = resolve(dir, e.name)
if (e.isDirectory()) walk(p)
else if (e.name.endsWith('.tsx') && !e.name.includes('.test.')) {
if (pattern.test(readFileSync(p, 'utf8'))) found.push(p.slice(src.length + 1))
}
}
}
walk(src)
return found.sort()
}
it('no file paints both', () => {
const withAcc = files(/dependsOn=|tone="acc"/)
const withWarn = files(/tone="warn"/)
expect(withAcc.length).toBeGreaterThan(0)
expect(withWarn.length).toBeGreaterThan(0)
expect(withAcc.filter((f) => withWarn.includes(f))).toEqual([])
})
})