Repository navigation
test(e2e): cover useFocusTrap's previousFocus cleanup fallback when the trigger unmounts - #1178
Merged
Merged
Conversation
No existing spec closes a lightbox while its trigger is unmounting, so the previousFocus operand at src/components/hooks/useFocusTrap.js:51 is never evaluated in a browser. Both lightboxes are rendered by the card that opens them, so filtering that card out of the member directory unmounts the trigger and the dialog in one commit and the cleanup sees triggerRef.current === null. Asserts the observable consequences of that cleanup -- no pageerror, the body scroll lock released to the value captured before the dialog opened, and focus left in the search field the visitor is typing in -- rather than asserting that a line ran. Closes #1177 Signed-off-by: quality <quality@hive.kubestellar.io>
Contributor
Author
|
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. Non-outreach agents are held at ACMM L3–L5; the Hive will keep the |
This was referenced Oct 8, 2026
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.
Test Improvement
Adds one new end-to-end spec,
tests/e2e/focus-trap-trigger-unmounted.spec.js,for the only close path that nulls a lightbox's trigger ref.
src/components/hooks/useFocusTrap.js:51restores focus with(triggerRef.current || previousFocus)?.focus?.(). Every existing lightbox speccloses the dialog with Escape, the close button or a backdrop click, and in all
three the trigger is still mounted, so the
previousFocusoperand is neverevaluated in a browser.
Both lightboxes are rendered by the card that triggers them
(
src/components/MemberDirectory/MemberCard.js:72-78), and the directory'ssearch field stays live behind the backdrop. A visitor who opens a profile and
keeps typing filters that card out: trigger and dialog unmount in the same
commit, React detaches refs before running passive-effect cleanups, and the
cleanup falls through to
previousFocus.The spec drives exactly that: open a profile, focus
#member-searchthrough theDOM (a click would dismiss via the backdrop while the trigger is still mounted),
type a query no organization matches, then assert
pageerrorfires — written astriggerRef.current.focus()the cleanupthrows a
TypeErrorinto the commit while the visitor is typing,document.body.style.overflowreturns to the value captured before thedialog opened — a cleanup that throws early leaves the page unscrollable with
no dialog on screen,
describe a working page rather than one that stopped responding.
Verification at
03cfcfenpm run build:e2e:coverage, thentest:e2e:coverage): 341 passed, and the gated report(
--check-source 100 --check-source-regions 91 --require-source-files) exits0atsrc files | 100.00 | 91.72 | 2099/2099 lines | 443/483 regions, upfrom 91.63% / 438 of 478 on
main.npm run test:unit: 2025 passed, 0 failed.npm run check:format: clean.This does not retire the region, and that is #1066 / #1079
Stated up front rather than claimed otherwise. A control run of this spec alone
against the real build reports
useFocusTrap's uncovered regions as29 34 35— line 51 absent, i.e. demonstrably executed. The full two-build run puts it
back (
35 51), because the variant build emits the cleanup under coordinatesthe real build's key does not match. That is the region-union attribution
behaviour tracked by #1066 and #1079, and this spec is written as behaviour
rather than as a coverage claim for the same reason
tests/e2e/dialog-non-dismissing.spec.jsalready is.Line 35 (
if (!focusable?.length) return;) is deliberately out of scope: bothlightboxes always render a close button, so the taken arm has no browser path
at all.
Files
One new file, nothing edited:
tests/e2e/focus-trap-trigger-unmounted.spec.jsDisjoint from every open hold-gated PR — not
scripts/audit-gate.mjs(#1161),tests/tools/e2e-coverage-report.mjs(#1163),scripts/lib/svg-active-content.mjs(#1168, #1176),
CONTRIBUTING.md(#1166),tests/architecture-content-mirror.test.mjs(#1165),
tests/tools/e2e-data-fixtures.cjsor themetrics.jsonoverlay(#1171), or
tests/e2e-coverage-run.test.mjs(#1174). No fixture overlay isadded, so the two-build ceiling in #1172 is untouched, and no workflow file is
involved.
Related Issue
Closes #1177
Human review required; this PR carries
holdand must not be merged by automation.— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88