Skip to content

Commit dc2fd95

Browse files
committed
feat(byRole): Add name filter
1 parent 60b65f5 commit dc2fd95

File tree

4 files changed

+93
-6
lines changed

4 files changed

+93
-6
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"@sheerun/mutationobserver-shim": "^0.3.2",
4545
"@types/testing-library__dom": "^6.0.0",
4646
"aria-query": "3.0.0",
47+
"dom-accessibility-api": "^0.2.0",
4748
"pretty-format": "^24.9.0",
4849
"wait-for-expect": "^3.0.0"
4950
},

src/__tests__/role.js

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {configure, getConfig} from '../config'
2-
import {render} from './helpers/test-utils'
2+
import {render, renderIntoDocument} from './helpers/test-utils'
3+
import {getQueriesForElement} from '../get-queries-for-element'
34

45
test('by default logs accessible roles when it fails', () => {
56
const {getByRole} = render(`<h1>Hi</h1>`)
@@ -183,6 +184,73 @@ test('can include inaccessible roles', () => {
183184
expect(getByRole('list', {hidden: true})).not.toBeNull()
184185
})
185186

187+
test('can be filtered by accessible name', () => {
188+
const {getByRole} = renderIntoDocument(
189+
`
190+
<div>
191+
<h1>Order</h1>
192+
<h2>Delivery Adress</h2>
193+
<form aria-label="Delivery Adress">
194+
<label>
195+
<div>Street</div>
196+
<input type="text" />
197+
</label>
198+
<input type="submit" />
199+
</form>
200+
<h2>Invoice Adress</h2>
201+
<form aria-label="Invoice Adress">
202+
<label>
203+
<div>Street</div>
204+
<input type="text" />
205+
</label>
206+
<input type="submit" />
207+
</form>
208+
</div>`,
209+
)
210+
211+
const deliveryForm = getByRole('form', {name: 'Delivery Adress'})
212+
expect(deliveryForm).not.toBeNull()
213+
214+
expect(
215+
// TODO: upstream bug in `aria-query`; should be `button` role
216+
getQueriesForElement(deliveryForm).getByRole('textbox', {name: 'Submit'}),
217+
).not.toBeNull()
218+
219+
const invoiceForm = getByRole('form', {name: 'Delivery Adress'})
220+
expect(invoiceForm).not.toBeNull()
221+
222+
expect(
223+
getQueriesForElement(invoiceForm).getByRole('textbox', {name: 'Street'}),
224+
).not.toBeNull()
225+
})
226+
227+
test('includes accesible names in error message', () => {
228+
const {getByRole} = render(`<h1>Sign <em>up</em></h1>`)
229+
230+
expect(() => getByRole('heading', {name: 'Sign Up'}))
231+
.toThrowErrorMatchingInlineSnapshot(`
232+
"Unable to find an accessible element with the role "heading" and name "Sign Up"
233+
234+
Here are the accessible roles:
235+
236+
heading:
237+
238+
Name "Sign up":
239+
<h1 />
240+
241+
--------------------------------------------------
242+
243+
<div>
244+
<h1>
245+
Sign
246+
<em>
247+
up
248+
</em>
249+
</h1>
250+
</div>"
251+
`)
252+
})
253+
186254
describe('configuration', () => {
187255
let originalConfig
188256
beforeEach(() => {

src/queries/role.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {computeAccessibleName} from 'dom-accessibility-api'
12
import {
23
getImplicitAriaRoles,
34
prettyRoles,
@@ -19,6 +20,7 @@ function queryAllByRole(
1920
exact = true,
2021
collapseWhitespace,
2122
hidden = getConfig().defaultHidden,
23+
name,
2224
trim,
2325
normalizer,
2426
} = {},
@@ -56,6 +58,11 @@ function queryAllByRole(
5658
}) === false
5759
: true
5860
})
61+
.filter(element => {
62+
return typeof name === 'string'
63+
? computeAccessibleName(element) === name
64+
: true
65+
})
5966
}
6067

6168
const getMultipleError = (c, role) =>
@@ -64,9 +71,12 @@ const getMultipleError = (c, role) =>
6471
const getMissingError = (
6572
container,
6673
role,
67-
{hidden = getConfig().defaultHidden} = {},
74+
{hidden = getConfig().defaultHidden, name} = {},
6875
) => {
69-
const roles = prettyRoles(container, {hidden})
76+
const roles = prettyRoles(container, {
77+
hidden,
78+
includeName: typeof name === 'string',
79+
})
7080
let roleMessage
7181

7282
if (roles.length === 0) {
@@ -89,7 +99,9 @@ Here are the ${hidden === false ? 'accessible' : 'available'} roles:
8999
return `
90100
Unable to find an ${
91101
hidden === false ? 'accessible ' : ''
92-
}element with the role "${role}"
102+
}element with the role "${role}"${
103+
typeof name === 'string' ? ` and name "${name}"` : ''
104+
}
93105
94106
${roleMessage}`.trim()
95107
}

src/role-helpers.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {elementRoles} from 'aria-query'
22
import {prettyDOM} from './pretty-dom'
3+
import {computeAccessibleName} from 'dom-accessibility-api'
34

45
const elementRoleList = buildElementRoleList(elementRoles)
56

@@ -138,14 +139,19 @@ function getRoles(container, {hidden = false} = {}) {
138139
}, {})
139140
}
140141

141-
function prettyRoles(dom, {hidden}) {
142+
function prettyRoles(dom, {hidden, includeName = false}) {
142143
const roles = getRoles(dom, {hidden})
143144

144145
return Object.entries(roles)
145146
.map(([role, elements]) => {
146147
const delimiterBar = '-'.repeat(50)
147148
const elementsString = elements
148-
.map(el => prettyDOM(el.cloneNode(false)))
149+
.map(
150+
el =>
151+
`${
152+
includeName === true ? `Name "${computeAccessibleName(el)}":\n` : ''
153+
}${prettyDOM(el.cloneNode(false))}`,
154+
)
149155
.join('\n\n')
150156

151157
return `${role}:\n\n${elementsString}\n\n${delimiterBar}`

0 commit comments

Comments
 (0)