Skip to content

Commit 6d6641d

Browse files
authored
fix: suggest hidden:true with getByRole if element is inaccessible (#745)
1 parent 9cbc428 commit 6d6641d

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

src/__tests__/suggestions.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ beforeAll(() => {
88

99
afterEach(() => {
1010
configure({testIdAttribute: 'data-testid'})
11+
console.warn.mockClear()
1112
})
1213

1314
afterAll(() => {
@@ -549,3 +550,31 @@ test('should get the first label with aria-labelledby contains multiple ids', ()
549550
variant: 'get',
550551
})
551552
})
553+
554+
test('should suggest hidden option if element is not in the accessibilty tree', () => {
555+
const {container} = renderIntoDocument(`
556+
<input type="text" aria-hidden=true />
557+
`)
558+
559+
expect(
560+
getSuggestedQuery(container.querySelector('input'), 'get', 'role'),
561+
).toMatchObject({
562+
queryName: 'Role',
563+
queryMethod: 'getByRole',
564+
queryArgs: ['textbox', {hidden: true}],
565+
variant: 'get',
566+
warning: `Element is inaccessible. This means that the element and all its children are invisible to screen readers.
567+
If you are using the aria-hidden prop, make sure this is the right choice for your case.
568+
`,
569+
})
570+
571+
expect(console.warn.mock.calls).toMatchInlineSnapshot(`
572+
Array [
573+
Array [
574+
"Element is inaccessible. This means that the element and all its children are invisible to screen readers.
575+
If you are using the aria-hidden prop, make sure this is the right choice for your case.
576+
",
577+
],
578+
]
579+
`)
580+
})

src/suggestions.js

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {computeAccessibleName} from 'dom-accessibility-api'
22
import {getDefaultNormalizer} from './matches'
33
import {getNodeText} from './get-node-text'
44
import {DEFAULT_IGNORE_TAGS, getConfig} from './config'
5-
import {getImplicitAriaRoles} from './role-helpers'
5+
import {getImplicitAriaRoles, isInaccessible} from './role-helpers'
66

77
const normalize = getDefaultNormalizer()
88

@@ -38,15 +38,28 @@ function getRegExpMatcher(string) {
3838
return new RegExp(escapeRegExp(string.toLowerCase()), 'i')
3939
}
4040

41-
function makeSuggestion(queryName, content, {variant, name}) {
41+
function makeSuggestion(queryName, element, content, {variant, name}) {
42+
let warning = ''
43+
const queryOptions = {}
4244
const queryArgs = [
4345
queryName === 'Role' || queryName === 'TestId'
4446
? content
4547
: getRegExpMatcher(content),
4648
]
4749

4850
if (name) {
49-
queryArgs.push({name: getRegExpMatcher(name)})
51+
queryOptions.name = getRegExpMatcher(name)
52+
}
53+
54+
if (queryName === 'Role' && isInaccessible(element)) {
55+
queryOptions.hidden = true
56+
warning = `Element is inaccessible. This means that the element and all its children are invisible to screen readers.
57+
If you are using the aria-hidden prop, make sure this is the right choice for your case.
58+
`
59+
console.warn(warning)
60+
}
61+
if (Object.keys(queryOptions).length > 0) {
62+
queryArgs.push(queryOptions)
5063
}
5164

5265
const queryMethod = `${variant}By${queryName}`
@@ -56,6 +69,7 @@ function makeSuggestion(queryName, content, {variant, name}) {
5669
queryMethod,
5770
queryArgs,
5871
variant,
72+
warning,
5973
toString() {
6074
let [text, options] = queryArgs
6175

@@ -90,7 +104,7 @@ export function getSuggestedQuery(element, variant = 'get', method) {
90104
const role =
91105
element.getAttribute('role') ?? getImplicitAriaRoles(element)?.[0]
92106
if (role !== 'generic' && canSuggest('Role', method, role)) {
93-
return makeSuggestion('Role', role, {
107+
return makeSuggestion('Role', element, role, {
94108
variant,
95109
name: computeAccessibleName(element, {
96110
computedStyleSupportsPseudoElements: getConfig()
@@ -101,36 +115,40 @@ export function getSuggestedQuery(element, variant = 'get', method) {
101115

102116
const labelText = getLabelTextFor(element)
103117
if (canSuggest('LabelText', method, labelText)) {
104-
return makeSuggestion('LabelText', labelText, {variant})
118+
return makeSuggestion('LabelText', element, labelText, {variant})
105119
}
106120

107121
const placeholderText = element.getAttribute('placeholder')
108122
if (canSuggest('PlaceholderText', method, placeholderText)) {
109-
return makeSuggestion('PlaceholderText', placeholderText, {variant})
123+
return makeSuggestion('PlaceholderText', element, placeholderText, {
124+
variant,
125+
})
110126
}
111127

112128
const textContent = normalize(getNodeText(element))
113129
if (canSuggest('Text', method, textContent)) {
114-
return makeSuggestion('Text', textContent, {variant})
130+
return makeSuggestion('Text', element, textContent, {variant})
115131
}
116132

117133
if (canSuggest('DisplayValue', method, element.value)) {
118-
return makeSuggestion('DisplayValue', normalize(element.value), {variant})
134+
return makeSuggestion('DisplayValue', element, normalize(element.value), {
135+
variant,
136+
})
119137
}
120138

121139
const alt = element.getAttribute('alt')
122140
if (canSuggest('AltText', method, alt)) {
123-
return makeSuggestion('AltText', alt, {variant})
141+
return makeSuggestion('AltText', element, alt, {variant})
124142
}
125143

126144
const title = element.getAttribute('title')
127145
if (canSuggest('Title', method, title)) {
128-
return makeSuggestion('Title', title, {variant})
146+
return makeSuggestion('Title', element, title, {variant})
129147
}
130148

131149
const testId = element.getAttribute(getConfig().testIdAttribute)
132150
if (canSuggest('TestId', method, testId)) {
133-
return makeSuggestion('TestId', testId, {variant})
151+
return makeSuggestion('TestId', element, testId, {variant})
134152
}
135153

136154
return undefined

types/suggestions.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
export interface QueryOptions {
2+
[key: string]: RegExp | boolean
3+
}
4+
5+
export type QueryArgs = [string, QueryOptions?]
6+
17
export interface Suggestion {
28
queryName: string
9+
queryMethod: string
10+
queryArgs: QueryArgs
11+
variant: string
12+
warning?: string
313
toString(): string
414
}
515

0 commit comments

Comments
 (0)