test(theme): compile the popup-cap arbitrary values instead of only reading them - #564
Merged
Conversation
…eading them Every assertion this repository makes about theme classes is a string assertion: `test/utils/*.spec.ts` reads the theme sources, the component snapshots record the rendered `class` attribute, and nothing compiles CSS. An arbitrary value was therefore only ever proved to be written. `theme-css-compiles.spec.ts` runs the token entry through the installed `tailwindcss` engine with the candidate classes read out of `src/theme/*.ts`, and asserts a `max-height` declaration is emitted for each and that the `--max-height-popup-*` tokens they reference reach the compiled output. The incident behind it is #430, which moved the popup caps from literals into tokens: the mechanism had to be checked by hand during that review, by exactly this compile. It confirmed the caps worked, and nothing kept them working. Candidates are extracted rather than restated, so a class that is edited stays covered and one that is deleted trips the floor assertion instead of thinning the list in silence. The compile happens once at module scope, not inside an `it()` — the shape that flaked in #561. What the guard cannot catch is recorded in the file, measured against the engine rather than assumed: Tailwind v4 does not validate the meaning of an arbitrary value. It emits a rule for `max-h-[not a length]` and for an unbalanced `max-h-[min(var(--x)]`; it refuses an empty value or an unknown utility. So the first failure mode is caught only in its total form, while the second — the token dropping out of `:root` — is caught exactly, verified by deleting `--max-height-popup-list` from `sizes.css`. A `the guard itself` block pins that `ruleFor` reports absence as well as presence, so a matcher that always found something could not pass the file vacuously. Closes #457 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Closes #457
Type of change
revert(Scope): ...)Description
Every assertion this repository makes about theme classes is a string assertion — the theme sources are read, the snapshots record the rendered
class, and nothing compiles CSS. So an arbitrary value was only ever proved to be written.The new spec runs
src/runtime/air-design-tokens/tw-style/index.cssthrough the installedtailwindcssengine with candidates read out ofsrc/theme/*.ts, and asserts both halves the issue asks for: amax-heightdeclaration per candidate, and the--max-height-popup-*tokens reaching the compiled output.The incident is #430 — it moved the popup caps from literals into tokens, and the mechanism had to be verified by hand during review, by exactly this compile. That confirmed the caps worked; nothing kept them working.
Six classes, four distinct values
Extracted rather than restated, so an edited class stays covered and a deleted one trips the floor assertion instead of thinning the list in silence:
context-menu,dropdown-menu,editor-suggestion-menu--max-height-popup-menuinput-menu,select-menu,select--max-height-popup-listWhat it catches — measured, not claimed
--max-height-popup-listfromsizes.csskeeps --max-height-popup-list in the compiled output, and only that!!into an arbitrary valueThat second row is the interesting one, and it is in the file's own comment rather than left as an implied promise. Probed against the installed engine:
Tailwind v4 does not validate the meaning of an arbitrary value. So the issue's first failure mode is caught only in its total form — the utility ceasing to exist, or the value going empty — while a value that still parses but no longer means anything is not this file's to find. The second failure mode, the token dropping out of
:root, is caught exactly.Stating that plainly matters more than the guard looking stronger than it is: the whole point of #457 is that a green suite was certifying something it never checked.
Method notes
Two wrong turns, both recorded because both looked convincing:
RegExpfrom the candidate and reported "no rule emitted" for all six while the rules were sitting in the output. It had to escape for the regex and match text that is itself backslash-escaped, and got the depth wrong. Replaced with a literalindexOfover a selector built the way Tailwind escapes one — no second layer to get wrong.!!mutation staying green briefly read as a broken guard. It was a broken mutation: Tailwind emits that class quite happily. Same lesson as test(stringified-props): scan the corpus once, outside the timed test #561 — a mutation that fails to go red is a claim about the mutation before it is a claim about the test.The compile runs once at module scope, not inside an
it(), which is the shape that flaked in #561. Athe guard itselfblock pins that the matcher reports absence as well as presence.Upstream
Nothing to compare against:
nuxt/uicompiles no CSS in its test suite, and the--max-height-popup-*tokens do not exist there — they are Air's. Entirely b24ui's own surface, so no divergence and nothing a port could revert.Checks
pnpm lint,pnpm typecheckgreengit checkout --Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_012MsMuj8Fic9tjWVjyEyrxc
Generated by Claude Code