Skip to content

Commit 6ecbf77

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

File tree

4 files changed

+74
-5
lines changed

4 files changed

+74
-5
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', {strictVisibility: true})
841+
expect(strictResults).toHaveLength(1)
842+
843+
const looseResults = getAllByRole('button', {strictVisibility: false})
844+
expect(looseResults).toHaveLength(1)
845+
})
846+
816847
test('getAll* matchers return an array', () => {
817848
const {
818849
getAllByAltText,

src/queries/role.ts

+11-5
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,
@@ -296,11 +298,15 @@ const queryAllByRole: AllByRole = (
296298
)
297299
})
298300
.filter(element => {
299-
return hidden === false
300-
? isInaccessible(element, {
301-
isSubtreeInaccessible: cachedIsSubtreeInaccessible,
302-
}) === false
303-
: true
301+
if (strictVisibilityCheck) {
302+
return hidden === false
303+
? isInaccessible(element, {
304+
isSubtreeInaccessible: cachedIsSubtreeInaccessible,
305+
}) === false
306+
: true
307+
} else {
308+
return hidden === false ? isInaccessibleLoose(element) === false : true
309+
}
304310
})
305311
}
306312

src/role-helpers.js

+21
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,26 @@ 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+
const explictlyHidden =
75+
element.style.visibility === 'hidden' || element.style.display === 'none'
76+
if (explictlyHidden) {
77+
return true
78+
}
79+
80+
const ariaHidden = element.getAttribute('aria-hidden') === 'true'
81+
if (ariaHidden) {
82+
return true
83+
}
84+
85+
return false
86+
}
87+
6888
function getImplicitAriaRoles(currentNode) {
6989
// eslint bug here:
7090
// eslint-disable-next-line no-unused-vars
@@ -382,6 +402,7 @@ export {
382402
isSubtreeInaccessible,
383403
prettyRoles,
384404
isInaccessible,
405+
isInaccessibleLoose,
385406
computeAriaSelected,
386407
computeAriaBusy,
387408
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)