9.2 KiB
id, title, status, wave, depends_on, plan, spec
| id | title | status | wave | depends_on | plan | spec | |
|---|---|---|---|---|---|---|---|
| 02-frontend-regression-coverage | Frontend regression coverage | done | 2 |
|
plan.md | ../../specs/plugins/requirements/plugin-nav-sidebar-footer.md |
Task 02: Frontend regression coverage
Prove, with component-level tests, that the desktop plugin rail, the phone
Plugins group, the desktop sidebar footer, and the phone Utilities group all
render section: "insights" plugin items correctly — placement, exclusion
from the plugins surfaces, ordering, test id, and the no-cap capacity
guarantee — without any component code change (they already read the
navigation manifest generically; task 01 is what makes the manifest resolve
"insights" correctly). No production code in apps/web/components/**
should need to change for this task; if you find one that does, that is a
signal task 01 missed something and the plan needs revisiting before
continuing here.
Files to change
-
apps/web/components/plugins/plugin-nav-items.test.tsx(desktop rail) — addit("keeps insights items out of the main plugin rail", ...), following the existing"omits a nav item registered for a non-main section"pattern (register one item withsection: "insights", assert noplugin-nav-item-<id>testid renders). -
apps/web/components/plugins/mobile-plugin-nav-section.test.tsx(phone Plugins group) — extend the existing test"omits non-main sections: integrations belongs to MobileIntegrationsSection, and settings is rendered nowhere"with a third registration,section: "insights", and confirm the assertion (container.innerHTMLis empty) still holds with all three non-main sections registered. If adding the third registration changes what the test needs to assert, split it into a dedicatedit("also excludes insights-section items", ...)case instead of forcing it into the existing one. -
apps/web/components/app-sidebar/app-sidebar-footer.test.tsx(desktop footer) — the file mocksuseStaticDestinationsto return a fixedstats-only array; add:- A test that a plugin
insightsdestination in that mocked array renders as an icon button withdata-testid="sidebar-plugin:acme:board-button"(built fromsidebar-${destination.id}-button, wheredestination.idis already the namespacedplugin:acme:board— no template change needed), accessible name equal to the destination'slabel, and that clicking it calls the mocked router'spushwith the destination'shref. - A test (or two, expanded + collapsed) asserting the Capacity and
overflow guarantee: mock
useStaticDestinationsto returnstatsplus eight synthetic plugininsightsdestinations, renderAppSidebarFooterwithcollapsed={false}, assert eightsidebar-plugin:*-buttontestids are present (getAllByTestIdon a regex-matched selector or by iterating the known ids) and the footer's outer container carries the wrapping-row classes it already applies when expanded. Render again withcollapsed={true}and assert the same eight buttons are present with the column classes applied instead. Do not assert anything about visible height/clipping — the spec explicitly does not guarantee that (see Capacity and overflow / Out of scope).
- A test that a plugin
-
apps/web/components/navigation/app-nav-sheet.test.tsx(AppNavSections, phone Utilities group) — the file currently mocksusePluginRegistryas() => ({ getNavRegistrations: () => [] }). Change this to read a mutable module-level array (e.g.let navRegistrations: PluginNavRegistration[] = [], reset to[]in the existingbeforeEachblocks), then add a test indescribe("AppNavSections", ...):- Set
navRegistrationsto one{ pluginId: "acme", id: "board", label: "Acme Board", path: "/plugins/acme", section: "insights" }, render<SectionsHost/>, and assert the relative order ofStats,Settings, andAcme Boardamongscreen.getAllByRole("link")matches that sequence (spec Ordering, phone scenario — the plugin row followsSettings, notStats). Do not assert the full role-name sequence including Status/theme/Improve Kandev/Health — those are non-manifest controls the spec explicitly says a conformance test must not fail on.
- Set
Acceptance
- All four test files above pass with the new/extended cases.
- No file under
apps/web/components/**other than the test files listed changes. If one does, stop and reconcile with task 01 / the plan before proceeding — that would mean a surface is not as generic asplan.md's Overview assumes.
Verification
cd apps && pnpm --filter @kandev/web test -- components/plugins/plugin-nav-items.test.tsx components/plugins/mobile-plugin-nav-section.test.tsx components/app-sidebar/app-sidebar-footer.test.tsx components/navigation/app-nav-sheet.test.tsx
Files likely touched
apps/web/components/plugins/plugin-nav-items.test.tsxapps/web/components/plugins/mobile-plugin-nav-section.test.tsxapps/web/components/app-sidebar/app-sidebar-footer.test.tsxapps/web/components/navigation/app-nav-sheet.test.tsx
Dependencies
01-contract-and-mapping (needs pluginDestinations() to resolve "insights"
correctly before any of these assertions can pass).
Parallelism
parallel-safe with 03-e2e-coverage — disjoint files (this task touches only
apps/web/components/** test files; task 03 touches the Go fixture bundle,
its packaged artifact, and Playwright spec files under apps/web/e2e/**).
Inputs
- Spec Scenarios section (the desktop-rail-exclusion, phone-group-order, and eight-plugin capacity scenarios map directly to the tests above).
- Spec Ordering section's "What order means" subsection — a conformance test must constrain only the manifest rows' relative order, not the full visible row sequence.
- Existing patterns:
plugin-nav-items.test.tsx's"omits a nav item registered for a non-main section",mobile-plugin-nav-section.test.tsx's non-main-section test,app-sidebar-footer.test.tsx'suseStaticDestinationsmock,app-nav-sheet.test.tsx'sSectionsHosthelper.
Output contract
Summary of every test added/changed, files touched, exact commands run with
outcomes, and any surface found to be non-generic (a blocker requiring a plan
update). Update this file's status to done and this plan's Wave 2
checkbox and Verification Results section in the same change.
Results
No production code under apps/web/components/** changed — confirmed the
plan's assumption that every surface already reads the manifest generically.
plugin-nav-items.test.tsx: added"keeps insights items out of the main plugin rail".mobile-plugin-nav-section.test.tsx: added"also excludes insights-section items: they belong to the Utilities group, not here"(kept as a dedicated case rather than folding into the existing non-main-sections test, per the task's fallback instruction).app-sidebar-footer.test.tsx: changed theuseStaticDestinationsmock from a fixed array to a mutableinsightDestinations(reset inresetFooterState), addedrenderFooter(collapsed)parameter, and added a newdescribe("AppSidebarFooter plugin insights items", …)block: testid + accessible name + click-navigates for one plugin destination, and two capacity tests (8 synthetic plugin destinations, expanded/flex-wrapand collapsed/flex-col, all 8 testids present in both).app-nav-sheet.test.tsx: changed theusePluginRegistrymock to read a mutablenavRegistrationsarray (reset in all threebeforeEachblocks), added a test asserting the Utilities group's manifest-row order isStats→Settings→ plugininsightsitem.
Commands run (from apps/):
pnpm --filter @kandev/web test -- components/plugins/plugin-nav-items.test.tsx components/plugins/mobile-plugin-nav-section.test.tsx components/app-sidebar/app-sidebar-footer.test.tsx— 3 files, 34 tests passed.pnpm --filter @kandev/web test -- components/navigation/app-nav-sheet.test.tsx— 1 file, 12 tests passed.cd web && pnpm run typecheck— passed.pnpm --filter @kandev/web lint -- <8 touched files>— 0 errors, 0 warnings after fixing the two warnings surfaced in task 01's files.pnpm run i18n:ratchet(fromapps/web) — clean.- Combined rerun:
pnpm --filter @kandev/web test -- lib/navigation/plugin-destinations.test.ts lib/navigation/resolve-destinations.test.ts components/plugins/plugin-nav-items.test.tsx components/plugins/mobile-plugin-nav-section.test.tsx components/app-sidebar/app-sidebar-footer.test.tsx components/navigation/app-nav-sheet.test.tsx— 6 files, 71 tests passed.
One tooling note, not a code blocker: running pnpm run test -- <files> via
cd web && pnpm run test -- ... (as opposed to pnpm --filter @kandev/web test -- ... from apps/) caused pnpm to forward a literal -- into the
vitest invocation, which made vitest ignore the file filters and run the
entire suite (~15 min before it was killed). Use the pnpm --filter @kandev/web test -- <files> form from apps/ for targeted runs.
Files touched matched Files likely touched exactly. No blockers.