diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js
index a8e00011..056918dd 100644
--- a/src/__tests__/element-queries.js
+++ b/src/__tests__/element-queries.js
@@ -813,6 +813,37 @@ test('queryAllByRole returns semantic html elements', () => {
expect(queryAllByRole('listbox')).toHaveLength(1)
})
+test('getAllByRole matchers with strictVisibility enabled and disabled', () => {
+ const {getAllByRole} = render(`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `)
+
+ const defaultResults = getAllByRole('button')
+ expect(defaultResults).toHaveLength(1)
+
+ const strictResults = getAllByRole('button', {strictVisibility: true})
+ expect(strictResults).toHaveLength(1)
+
+ const looseResults = getAllByRole('button', {strictVisibility: false})
+ expect(looseResults).toHaveLength(1)
+})
+
test('getAll* matchers return an array', () => {
const {
getAllByAltText,
diff --git a/src/queries/role.ts b/src/queries/role.ts
index e4dd395f..caa15a16 100644
--- a/src/queries/role.ts
+++ b/src/queries/role.ts
@@ -24,6 +24,7 @@ import {
prettyRoles,
isInaccessible,
isSubtreeInaccessible,
+ isInaccessibleLoose,
} from '../role-helpers'
import {wrapAllByQueryWithSuggestion} from '../query-helpers'
import {checkContainerType} from '../helpers'
@@ -54,6 +55,7 @@ const queryAllByRole: AllByRole = (
current,
level,
expanded,
+ strictVisibilityCheck = true,
value: {
now: valueNow,
min: valueMin,
@@ -296,11 +298,15 @@ const queryAllByRole: AllByRole = (
)
})
.filter(element => {
- return hidden === false
- ? isInaccessible(element, {
- isSubtreeInaccessible: cachedIsSubtreeInaccessible,
- }) === false
- : true
+ if (strictVisibilityCheck) {
+ return hidden === false
+ ? isInaccessible(element, {
+ isSubtreeInaccessible: cachedIsSubtreeInaccessible,
+ }) === false
+ : true
+ } else {
+ return hidden === false ? isInaccessibleLoose(element) === false : true
+ }
})
}
diff --git a/src/role-helpers.js b/src/role-helpers.js
index 8d7e7cb0..25e4f2d9 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.js
@@ -65,6 +65,26 @@ function isInaccessible(element, options = {}) {
return false
}
+/**
+ * A fast check to see if an element is inaccessible.
+ * @param {Element} element
+ * @returns {boolean} true if exluded, otherwise false
+ */
+function isInaccessibleLoose(element) {
+ const explictlyHidden =
+ element.style.visibility === 'hidden' || element.style.display === 'none'
+ if (explictlyHidden) {
+ return true
+ }
+
+ const ariaHidden = element.getAttribute('aria-hidden') === 'true'
+ if (ariaHidden) {
+ return true
+ }
+
+ return false
+}
+
function getImplicitAriaRoles(currentNode) {
// eslint bug here:
// eslint-disable-next-line no-unused-vars
@@ -382,6 +402,7 @@ export {
isSubtreeInaccessible,
prettyRoles,
isInaccessible,
+ isInaccessibleLoose,
computeAriaSelected,
computeAriaBusy,
computeAriaChecked,
diff --git a/types/queries.d.ts b/types/queries.d.ts
index c6ce9054..549b921e 100644
--- a/types/queries.d.ts
+++ b/types/queries.d.ts
@@ -110,6 +110,17 @@ export interface ByRoleOptions {
* the `aria-level` attribute.
*/
level?: number
+
+ /**
+ * Whether or not to strictly check the visibliity of the element. Doing so
+ * can cause issues with the performance of tests, because it requires the DOM tree
+ * is traversed, and the `getComputedStyle` function is called on each element.
+ *
+ * If you're finding that your tests are slow, you may want to disable this option.
+ * @default true
+ */
+ strictVisibilityCheck?: boolean
+
value?: {
now?: number
min?: number