Skip to content

test: cover the eleven components we wrote that nothing tested - #519

Merged
IgorShevchik merged 3 commits into
mainfrom
test/cover-our-untested-components
Aug 31, 2026
Merged

test: cover the eleven components we wrote that nothing tested#519
IgorShevchik merged 3 commits into
mainfrom
test/cover-our-untested-components

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Linked issue

Refs #86 — one slice of it, not the whole inventory.

Type of change

  • Documentation (updates to the documentation or readme)
  • Bug fix (a non-breaking change that fixes an issue)
  • Enhancement (improving an existing functionality)
  • New feature (a non-breaking change that adds functionality)
  • Chore (updates to the build process or auxiliary tools and libraries)
  • Revert (undoing a merged change — retitle this PR revert(Scope): ...)
  • Breaking change (fix or feature that would cause existing functionality to change)

How the slice was chosen

#86 lists everything untested. Re-measured, its June figures have moved — 66 components without a spec of their own rather than 76, 13 untested composables rather than 19, and tv.ts, which the issue calls out as "the theme merge engine!", has had a spec for a while.

The measure that mattered was different: 68 components are imported by no spec at all, and of those, all but thirteen exist in nuxt/ui@v4 — where they have no specs either. Writing those would be testing somebody else's code twice, in a file we re-sync from them. The thirteen that are ours have no coverage anywhere.

Eleven are covered here. ModalDialogClose is left out: a nineteen-line DialogClose passthrough that needs a dialog around it before it can say anything.

lines what it gets
PageCardGroup 377 selection, key mapping, grouping, colour fallback, axe, snapshots
SidebarLayout 275 loading state, slot-driven regions, axe, snapshots
SidebarBody/Footer/Header/Heading/Section/Spacer ~55 each the as / class / slot contract
Navbar 58 landmark element, composition, axe, snapshots
NavbarDivider/Section/Spacer ~57 each the as / class contract

Two defects found while writing them

SidebarLayout rendered its data-state as a literal string. The binding was written without its colon:

data-state="isLoading ? 'loading' : 'show'"

so every layout put the source of the expression into the DOM instead of its value, always. It is the only unbound data-state in src/runtime/components. Fixed, with a test that reddens when the colon is removed again.

offContentScrollbar is a public prop that does nothing. Both branches of its variant in src/theme/sidebar-layout.ts are empty strings, and the one compound that reads it has its entire class block commented out:

offContentScrollbar: { false: '', true: '' },

{ inner: true, offContentScrollbar: false, class: {
    // pageWrapper: 'scrollbar-thin scrollbar-transparent overflow-y-scroll'
} }

Not fixed here. Restoring those classes or removing the prop is a decision about public API shape, not a test change. No case is added for it either — one would be byte-identical to with isInner and would read as coverage of a prop that does not work.

Three things in the specs worth copying

  • Only useRoute is mocked in SidebarLayout.spec.ts, not the router. Installing one fails the other project every time: the nuxt project has none, so useRoute() warns about a missing injection on every mount; the vue project's shim already installs one, so a second plugin re-registers RouterLink. Each project's fix is the other's console-gate failure.
  • Element assertions read through [data-slot="root"]. A template that opens with an HTML comment renders as a fragment, and wrapper.element is then Vue Test Utils' own wrapper. Navbar looked like it rendered a div until that was accounted for — the component was fine, the assertion was not.
  • The generated size and columns matrices skip the default value, because a case for it is byte-identical to with items (test: fourteen specs assert a default because the fixture never reaches the branch #454).

What the #454 guard caught in the first draft

Three cases that asserted nothing, and it was right about all three: two default-valued variants of PageCardGroup, and a SidebarLayout fixture too thin for useLightContent to have any content to shape. Fixed by narrowing the matrices and giving the fixture a slot, not by regenerating the baseline — the baseline is unchanged.

Mutation-checked throughout. Where a claim could not be made to fail — categoryKey: '' short-circuits to the same output as looking the empty key up, and icon-over-avatar is enforced twice, in getItemAvatar and again in PageCard — the spec says so instead of carrying a test that cannot go red.

Gate

lint, typecheck, 328 test files / 7618 tests, test:module, and coverage 71.89 → 74.31% statements, 69.93 → 71.53 branches, 71.19 → 73.35 functions, 71.44 → 73.80 lines, against thresholds of 70 / 68 / 70 / 70.

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Generated by Claude Code

#86 is an inventory of everything untested; this is one slice of it, chosen by
provenance. Re-measured against `nuxt/ui@v4`: of the 68 components no spec
imports, all but thirteen are upstream's, and upstream does not test them
either. Writing those would be testing somebody else's code twice. The thirteen
are ours, and nothing anywhere covers them.

Eleven of them are covered here — `PageCardGroup`, `SidebarLayout` with its six
wrappers, and `Navbar` with its three. `ModalDialogClose` is left: it is a
nineteen-line `DialogClose` passthrough that needs a dialog around it to say
anything.

`PageCardGroup` carries the logic worth the most: single versus multiple
selection, the four key-mapping props, grouping by category, and the colour
fallbacks. Every behavioural claim it makes in JSDoc now has a test, and each
was mutation-checked.

Two defects came out of writing them.

`SidebarLayout` rendered `data-state="isLoading ? 'loading' : 'show'"` as a
literal string — the binding was written without its colon, so the attribute
carried the source of the expression rather than its value, on every layout,
always. It is the only unbound `data-state` in `src/runtime/components`.

`offContentScrollbar` is a public prop on `SidebarLayout` that does nothing.
Both branches of its variant in `src/theme/sidebar-layout.ts` are empty strings,
and the single compound reading it has its whole `class` block commented out.
No test is added for it — a case would be byte-identical to `with isInner` and
would read as coverage of a prop that does not work. Left as a finding rather
than fixed: restoring those classes or dropping the prop is a decision about
public API, not a test change.

Three things the specs do that are worth copying:

- Only `useRoute` is replaced in `SidebarLayout.spec.ts`, not the router.
  Installing one fails the other project every time: the `nuxt` project has no
  router, so `useRoute()` warns about a missing injection, and the `vue`
  project's shim already installs one, so a second plugin re-registers
  `RouterLink`. Each project's fix is the other's console-gate failure.
- Element assertions read through `[data-slot="root"]`. A template that opens
  with an HTML comment renders as a fragment, and `wrapper.element` is then Vue
  Test Utils' own wrapper — `Navbar` looked like it rendered a `div` until that
  was accounted for.
- The generated `size` and `columns` matrices skip the default value, because a
  case for it is byte-identical to `with items` (#454). The collision guard
  caught three such cases in the first draft, and a fixture too thin to let two
  content props differ.

Coverage 71.89% to 74.31% of statements.

Refs #86
IgorShevchik pushed a commit that referenced this pull request Aug 31, 2026
The backfilled log's cross-reference was written before the PR existed and
guessed #519; it is #520. A log that points at the wrong PR is the dead
reference the pairing guard exists to prevent, one level up.
@IgorShevchik
IgorShevchik merged commit f40e261 into main Aug 31, 2026
2 checks passed
@IgorShevchik
IgorShevchik deleted the test/cover-our-untested-components branch August 31, 2026 07:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants