`)
@@ -10,6 +11,7 @@ Here are the accessible roles:
heading:
+ Name "Hi":
--------------------------------------------------
@@ -32,6 +34,7 @@ Here are the available roles:
heading:
+ Name "Hi":
--------------------------------------------------
@@ -183,6 +186,144 @@ test('can include inaccessible roles', () => {
expect(getByRole('list', {hidden: true})).not.toBeNull()
})
+test('can be filtered by accessible name', () => {
+ const {getByRole} = renderIntoDocument(
+ `
+
+
Order
+
Delivery Adress
+
+
Invoice Adress
+
+
`,
+ )
+
+ const deliveryForm = getByRole('form', {name: 'Delivery Adress'})
+ expect(deliveryForm).not.toBeNull()
+
+ expect(
+ // TODO: upstream bug in `aria-query`; should be `button` role
+ getQueriesForElement(deliveryForm).getByRole('textbox', {name: 'Submit'}),
+ ).not.toBeNull()
+
+ const invoiceForm = getByRole('form', {name: 'Delivery Adress'})
+ expect(invoiceForm).not.toBeNull()
+
+ expect(
+ getQueriesForElement(invoiceForm).getByRole('textbox', {name: 'Street'}),
+ ).not.toBeNull()
+})
+
+test('accessible name comparison is case sensitive', () => {
+ const {getByRole} = render(`
Sign up
`)
+
+ // actual: "Sign up",
+ // queried: "Sign Up"
+ expect(() => getByRole('heading', {name: 'Sign Up'}))
+ .toThrowErrorMatchingInlineSnapshot(`
+"Unable to find an accessible element with the role "heading" and name "Sign Up"
+
+Here are the accessible roles:
+
+ heading:
+
+ Name "Sign up":
+
+
+ --------------------------------------------------
+
+
`)
+
+ expect(() => getByRole('heading', {name: /Login/}))
+ .toThrowErrorMatchingInlineSnapshot(`
+"Unable to find an accessible element with the role "heading" and name \`/Login/\`
+
+Here are the accessible roles:
+
+ heading:
+
+ Name "Sign up":
+
+
+ --------------------------------------------------
+
+
+
+ Sign
+
+ up
+
+
+
"
+`)
+
+ expect(() => getByRole('heading', {name: () => false}))
+ .toThrowErrorMatchingInlineSnapshot(`
+"Unable to find an accessible element with the role "heading" and name \`() => false\`
+
+Here are the accessible roles:
+
+ heading:
+
+ Name "Sign up":
+
+
+ --------------------------------------------------
+
+
+
+ Sign
+
+ up
+
+
+
"
+`)
+})
+
describe('configuration', () => {
let originalConfig
beforeEach(() => {
diff --git a/src/queries/role.js b/src/queries/role.js
index 55e50e10..a442bfd9 100644
--- a/src/queries/role.js
+++ b/src/queries/role.js
@@ -1,3 +1,4 @@
+import {computeAccessibleName} from 'dom-accessibility-api'
import {
getImplicitAriaRoles,
prettyRoles,
@@ -19,6 +20,7 @@ function queryAllByRole(
exact = true,
collapseWhitespace,
hidden = getConfig().defaultHidden,
+ name,
trim,
normalizer,
queryFallbacks = false,
@@ -70,6 +72,19 @@ function queryAllByRole(
}) === false
: true
})
+ .filter(element => {
+ if (name === undefined) {
+ // Don't care
+ return true
+ }
+
+ return matches(
+ computeAccessibleName(element),
+ element,
+ name,
+ text => text,
+ )
+ })
}
const getMultipleError = (c, role) =>
@@ -78,9 +93,12 @@ const getMultipleError = (c, role) =>
const getMissingError = (
container,
role,
- {hidden = getConfig().defaultHidden} = {},
+ {hidden = getConfig().defaultHidden, name} = {},
) => {
- const roles = prettyRoles(container, {hidden})
+ const roles = prettyRoles(container, {
+ hidden,
+ includeName: name !== undefined,
+ })
let roleMessage
if (roles.length === 0) {
@@ -100,10 +118,19 @@ Here are the ${hidden === false ? 'accessible' : 'available'} roles:
`.trim()
}
+ let nameHint = ''
+ if (name === undefined) {
+ nameHint = ''
+ } else if (typeof name === 'string') {
+ nameHint = ` and name "${name}"`
+ } else {
+ nameHint = ` and name \`${name}\``
+ }
+
return `
Unable to find an ${
hidden === false ? 'accessible ' : ''
- }element with the role "${role}"
+ }element with the role "${role}"${nameHint}
${roleMessage}`.trim()
}
diff --git a/src/role-helpers.js b/src/role-helpers.js
index 6218461d..6d3ee309 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.js
@@ -1,4 +1,5 @@
import {elementRoles} from 'aria-query'
+import {computeAccessibleName} from 'dom-accessibility-api'
import {prettyDOM} from './pretty-dom'
const elementRoleList = buildElementRoleList(elementRoles)
@@ -145,7 +146,11 @@ function prettyRoles(dom, {hidden}) {
.map(([role, elements]) => {
const delimiterBar = '-'.repeat(50)
const elementsString = elements
- .map(el => prettyDOM(el.cloneNode(false)))
+ .map(el => {
+ const nameString = `Name "${computeAccessibleName(el)}":\n`
+ const domString = prettyDOM(el.cloneNode(false))
+ return `${nameString}${domString}`
+ })
.join('\n\n')
return `${role}:\n\n${elementsString}\n\n${delimiterBar}`