Good first issue, and a friendly one: a single self-contained unit test file, no production code to touch, and the functions under test are pure (just strings in, strings out). A solid first PR if you are new to the project.
Context
src/lib/buttonStyles.ts is the single source of truth for button and chip class strings, shared by Button.tsx, Button.astro, and the exam review grids. It has zero test coverage today. The two riskiest composers are pure functions that return a class string for a given state, so they are easy to assert on and a regression in them silently changes how controls look across the app.
What to do
Add a new file src/lib/buttonStyles.test.ts (Vitest). These are pure functions: no DOM, no React, no network, no mocks. Import each one, call it with a state, and assert on the returned string with expect(str).toContain(...).
filterChipClass({ active, surface }) (src/lib/buttonStyles.ts:90)
- when
active: true, the result includes the inverted selection classes (bg-text-primary and text-bg-dark)
- when
active: false, it includes the quiet surface classes, and surface: 'card' vs surface: 'dark' produce different output (this guards the documented "active chip goes invisible when the header bg equals the page bg" drift noted in the source comment)
reviewCellClass({ correct, current, flagged, inSet }) (src/lib/buttonStyles.ts:199)
- includes
text-success when correct: true, and text-danger when correct: false
- adds the brand ring (
ring-brand) only when current: true
- adds the warning ring (
ring-warning) only when flagged: true
- includes
opacity-40 only when inSet: false
Acceptance criteria
Running it locally
For a fast feedback loop you can run just this file:
npx vitest run src/lib/buttonStyles.test.ts
Vitest is already installed, so please do not add any packages. CONTRIBUTING.md has the 2-minute setup and the PR flow. Comment here to claim it, open a PR with Closes #<this issue number>, and ask if anything is unclear - happy to help you land your first one.
Good first issue, and a friendly one: a single self-contained unit test file, no production code to touch, and the functions under test are pure (just strings in, strings out). A solid first PR if you are new to the project.
Context
src/lib/buttonStyles.tsis the single source of truth for button and chip class strings, shared byButton.tsx,Button.astro, and the exam review grids. It has zero test coverage today. The two riskiest composers are pure functions that return a class string for a given state, so they are easy to assert on and a regression in them silently changes how controls look across the app.What to do
Add a new file
src/lib/buttonStyles.test.ts(Vitest). These are pure functions: no DOM, no React, no network, no mocks. Import each one, call it with a state, and assert on the returned string withexpect(str).toContain(...).filterChipClass({ active, surface })(src/lib/buttonStyles.ts:90)active: true, the result includes the inverted selection classes (bg-text-primaryandtext-bg-dark)active: false, it includes the quiet surface classes, andsurface: 'card'vssurface: 'dark'produce different output (this guards the documented "active chip goes invisible when the header bg equals the page bg" drift noted in the source comment)reviewCellClass({ correct, current, flagged, inSet })(src/lib/buttonStyles.ts:199)text-successwhencorrect: true, andtext-dangerwhencorrect: falsering-brand) only whencurrent: truering-warning) only whenflagged: trueopacity-40only wheninSet: falseAcceptance criteria
src/lib/buttonStyles.test.tscovering the cases above.npm run testpasses andnpm run lintis clean.buttonStyles.tsor any other production file; no new dependencies.Running it locally
For a fast feedback loop you can run just this file:
Vitest is already installed, so please do not add any packages.
CONTRIBUTING.mdhas the 2-minute setup and the PR flow. Comment here to claim it, open a PR withCloses #<this issue number>, and ask if anything is unclear - happy to help you land your first one.