Skip to content

Commit a68d3de

Browse files
committed
feat: Add strictVisibility check option to ByRole queries
1 parent a86c54c commit a68d3de

File tree

4 files changed

+72
-3
lines changed

4 files changed

+72
-3
lines changed

src/__tests__/element-queries.js

+31
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,37 @@ test('queryAllByRole returns semantic html elements', () => {
813813
expect(queryAllByRole('listbox')).toHaveLength(1)
814814
})
815815

816+
test('getAllByRole matchers with strictVisibility enabled and disabled', () => {
817+
const {getAllByRole} = render(`
818+
<div aria-hidden="true">
819+
<button>Aria Hidden Button</button>
820+
</div>
821+
<div style="display: none;">
822+
<button>Display None Button</button>
823+
</div>
824+
<div style="visibility: hidden;">
825+
<button>Visibility Hidden Button</button>
826+
</div>
827+
<div style="visibility: hidden;">
828+
<div>
829+
<button>Deep Visibility Hidden Button</button>
830+
</div>
831+
</div>
832+
<div>
833+
<button>Visible Button</button>
834+
</div>
835+
`)
836+
837+
const defaultResults = getAllByRole('button')
838+
expect(defaultResults).toHaveLength(1)
839+
840+
const strictResults = getAllByRole('button', {strictVisibilityCheck: true})
841+
expect(strictResults).toHaveLength(1)
842+
843+
const looseResults = getAllByRole('button', {strictVisibilityCheck: false})
844+
expect(looseResults).toHaveLength(1)
845+
})
846+
816847
test('getAll* matchers return an array', () => {
817848
const {
818849
getAllByAltText,

src/queries/role.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
prettyRoles,
2525
isInaccessible,
2626
isSubtreeInaccessible,
27+
isInaccessibleLoose,
2728
} from '../role-helpers'
2829
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
2930
import {checkContainerType} from '../helpers'
@@ -54,6 +55,7 @@ const queryAllByRole: AllByRole = (
5455
current,
5556
level,
5657
expanded,
58+
strictVisibilityCheck = true,
5759
value: {
5860
now: valueNow,
5961
min: valueMin,
@@ -297,9 +299,11 @@ const queryAllByRole: AllByRole = (
297299
})
298300
.filter(element => {
299301
return hidden === false
300-
? isInaccessible(element, {
301-
isSubtreeInaccessible: cachedIsSubtreeInaccessible,
302-
}) === false
302+
? strictVisibilityCheck
303+
? isInaccessible(element, {
304+
isSubtreeInaccessible: cachedIsSubtreeInaccessible,
305+
}) === false
306+
: isInaccessibleLoose(element) === false
303307
: true
304308
})
305309
}

src/role-helpers.js

+23
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,28 @@ function isInaccessible(element, options = {}) {
6565
return false
6666
}
6767

68+
/**
69+
* A fast check to see if an element is inaccessible.
70+
* @param {Element} element
71+
* @returns {boolean} true if exluded, otherwise false
72+
*/
73+
function isInaccessibleLoose(element) {
74+
do {
75+
const explictlyHidden =
76+
element.style.visibility === 'hidden' || element.style.display === 'none'
77+
if (explictlyHidden) {
78+
return true
79+
}
80+
81+
const ariaHidden = element.getAttribute('aria-hidden') === 'true'
82+
if (ariaHidden) {
83+
return true
84+
}
85+
} while ((element = element.parentElement))
86+
87+
return false
88+
}
89+
6890
function getImplicitAriaRoles(currentNode) {
6991
// eslint bug here:
7092
// eslint-disable-next-line no-unused-vars
@@ -382,6 +404,7 @@ export {
382404
isSubtreeInaccessible,
383405
prettyRoles,
384406
isInaccessible,
407+
isInaccessibleLoose,
385408
computeAriaSelected,
386409
computeAriaBusy,
387410
computeAriaChecked,

types/queries.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ export interface ByRoleOptions {
110110
* the `aria-level` attribute.
111111
*/
112112
level?: number
113+
114+
/**
115+
* Whether or not to strictly check the visibliity of the element. Doing so
116+
* can cause issues with the performance of tests, because it requires the DOM tree
117+
* is traversed, and the `getComputedStyle` function is called on each element.
118+
*
119+
* If you're finding that your tests are slow, you may want to disable this option.
120+
* @default true
121+
*/
122+
strictVisibilityCheck?: boolean
123+
113124
value?: {
114125
now?: number
115126
min?: number

0 commit comments

Comments
 (0)