Repository navigation
test: pin FilterToolbar's object-option labels against the value/label ternary - #1675
Conversation
…l ternary
src/components/shared/FilterToolbar.js accepts select options as either a
bare string, where value and visible label are the same token, or a
{ value, label } pair, where they deliberately differ. Only MemberDirectory
passes the pair shape (MEMBERSHIP_FILTERS, e.g. value 'unknown' shown as
'Membership not specified').
Every existing assertion over a rendered <select> reads option values or
drives onChange directly, so collapsing
const optionLabel = typeof option === 'string' ? option : option.label;
to the value arm leaves the entire unit suite green while the membership
dropdown silently renders raw values. Line and region coverage of src/ is
already 100%, so no coverage gate catches it either.
Add tests/filter-toolbar-options.test.mjs, which owns the shared component's
option contract directly: both option shapes, a mixed list, per-value keying
so two options may share a label, the onSearchChange/onChange/onClear
wiring, and the activeCount gate on 'Clear filters'. Under the mutation
above it is the only failing file in the suite.
Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
✅ Deploy Preview for endusers ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an Hive will keep the |
There was a problem hiding this comment.
Read the component and ran the suite locally — this looks correct to me.
Verified at head 0b3bc54, node v26.10.0:
- The six assertions in
tests/filter-toolbar-options.test.mjsmatchsrc/components/shared/FilterToolbar.jsexactly: the value/label ternary (FilterToolbar.js:82-85),key={optionValue}(FilterToolbar.js:87),onChange(event.target.value)for both the search input and selects (FilterToolbar.js:63, 77), and theactiveCount > 0guard on "Clear filters" (FilterToolbar.js:105). - The
MEMBERSHIP_FILTERSexpectations matchsrc/components/MemberDirectory/hooks.js:3-10verbatim. - All 6 tests pass. Mutation check confirms the PR's claim: collapsing the label arm of the ternary to
option.valuefails 2 of these tests, so the gap this file pins is real.
Test-only change, one new file, no production edits, CI green. No findings.
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.88
Test Improvement
Adds
tests/filter-toolbar-options.test.mjs, a contract for theselects[].optionshandling ofsrc/components/shared/FilterToolbar.js. No production file changes.FilterToolbar(landed in #1659) accepts two option shapes: a bare string, where value and visible label are the same token, and a{ value, label }pair, where they deliberately differ. OnlyMemberDirectorypasses the pair shape —MEMBERSHIP_FILTERSinsrc/components/MemberDirectory/hooks.js:3, where valueunknownis displayed as "Membership not specified".Why the existing suite does not cover this. Collapsing
to the value arm leaves the entire unit suite green at
maina621619 on node v26.10.0 —TZ=UTC node --testreports zero failures, includingtests/member-directory.test.mjs,tests/member-directory-membership-vocabulary.test.mjs,tests/case-studies.test.mjsandtests/architecture-filters-ui.test.mjs(83 tests, 83 pass). Every assertion over a rendered<select>reads option values (optionValues(),tests/member-directory.test.mjs:157) or drivesonChangedirectly; none reads an option's visible text. The coverage gates do not catch it either:npm run test:unit:coveragealready reportssrc files | 100.00 | 100.00 | 9967/9967 lines | 2904/2904 regions, so both arms execute. The gap is behavioural, not a counter gap.With this file applied, that same mutation makes
tests/filter-toolbar-options.test.mjsthe only failing file in the suite.What it pins, calling the component as a plain function the way its callers do (no hook dispatcher needed):
{ value, label }options render the label, not the value — asserted against the realMEMBERSHIP_FILTERSselectsentry may mix both shapes<option>keys off its value, so two options may share a labelonSearchChange/onChange/onClearreceive the changed value, not the eventactiveCount > 0, withtype="button"Verification at this branch head, node v26.10.0:
TZ=UTC node --test— green.npm run test:unit:coverage:check(the CI gate thresholds) — exit 0; the new file reports100.00 | 100.00,src filesandharness filesunchanged at their floors.npx prettier --checkon the new file — clean.node scripts/check-duplication.mjs—ok, 264 clones against a ceiling of 264 (unchanged).Scope / overlap. Touches exactly one new file under
tests/. Disjoint from every open hold-gated PR: #1673 (MDX active-content link definitions), #1664 (CONTRIBUTING data model), #1666 (CI exemption file references), #1668 (open-automation-prpolicy), #1671 (activeSchemescheme boundary). It adds no assertion totests/member-directory.test.mjsor any other existing file, so it cannot conflict with work in those.Related Issue
Fixes #1674
Filed by quality agent (hold-gated mode). Human review required.
— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88