Skip to content

[Test Improver] Add unit tests for getFirstFocusableElement in focusTrap composable - #73

Draft
github-actions[bot] wants to merge 1 commit into
masterfrom
test-assist/focus-trap-util-d11a6d3b3c697655
Draft

[Test Improver] Add unit tests for getFirstFocusableElement in focusTrap composable#73
github-actions[bot] wants to merge 1 commit into
masterfrom
test-assist/focus-trap-util-d11a6d3b3c697655

Conversation

@github-actions

Copy link
Copy Markdown

🤖 This PR was created by Test Improver, an automated AI assistant focused on improving test coverage.

Goal and Rationale

Add unit tests for getFirstFocusableElement in shell/composables/focusTrap.ts. This function is responsible for finding the first keyboard-focusable element within a container — it is used by useBasicSetupFocusTrap and useWatcherBasedSetupFocusTrapWithDestroyIncluded to anchor the focus trap. It had zero test coverage despite containing non-trivial logic:

  • A multi-type CSS selector covering 7 element categories
  • Explicit exclusion of tabindex="-1" elements
  • Filtering out disabled elements from the result set
  • Fallback to document.body when no candidates remain

Approach

  • Tested getFirstFocusableElement in isolation — it is a pure function with no Vue lifecycle hooks or Vuex dependencies, so no component mount is required.
  • Used JSDOM's document.createElement to build controlled containers for each case.
  • Used it.each with named-object entries (desc field) for the element-type cases to avoid repetition.
  • Covered both the happy path (each focusable type found) and the unhappy paths (all disabled, tabindex=-1, empty container).

Coverage Impact

getFirstFocusableElement goes from 0% to 100% statement/branch/function coverage.

Metric Before After
getFirstFocusableElement statements 0% 100%
getFirstFocusableElement branches 0% 100%

Test Cases (16 total)

  • returns document.body when the container has no focusable elements
  • returns document.body when no element argument is provided and document has no focusable elements
  • returns the button element (via it.each over all 8 focusable types)
  • skips a disabled button and returns the next non-disabled focusable element
  • skips a disabled input and returns the next non-disabled focusable element
  • returns document.body when every focusable element is disabled
  • does not return an element with tabindex="-1"
  • returns the first of multiple focusable elements
  • returns the first non-disabled element when leading elements are all disabled

Trade-offs

  • Tests use JSDOM DOM APIs (document.createElement, innerHTML) — low maintenance burden.
  • useBasicSetupFocusTrap and useWatcherBasedSetupFocusTrapWithDestroyIncluded are not tested here; they rely on the focus-trap library and Vue lifecycle hooks and are best tested via component integration tests.

Reproducibility

NODE_OPTIONS=--max_old_space_size=8192 yarn test:ci --testPathPattern=shell/composables/focusTrap

Test Status

✅ All 16 new tests pass
✅ All 42 existing composable tests continue to pass
✅ ESLint: no warnings or errors

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • download.cypress.io

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "download.cypress.io"

See Network Configuration for more information.

Generated by Daily Test Improver · ● 3.6M ·

…able

Add 16 unit tests covering getFirstFocusableElement from
shell/composables/focusTrap.ts:

- Returns document.body when no focusable elements exist (including
  default document parameter)
- Identifies all focusable element types: button, anchor, input,
  textarea, select, details, tabindex >=0
- Excludes elements with tabindex="-1"
- Skips disabled elements (button and input)
- Returns document.body when all elements are disabled
- Returns the first of multiple eligible elements
- Returns first non-disabled element when leading elements are disabled

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants