+
+
`)
@@ -422,21 +427,27 @@ test('queryAllByRole returns semantic html elements', () => {
expect(queryAllByRole(/columnheader/i)).toHaveLength(1)
expect(queryAllByRole(/rowheader/i)).toHaveLength(1)
expect(queryAllByRole(/grid/i)).toHaveLength(1)
- expect(queryAllByRole(/form/i)).toHaveLength(1)
+ expect(queryAllByRole(/form/i)).toHaveLength(0)
expect(queryAllByRole(/button/i)).toHaveLength(1)
expect(queryAllByRole(/heading/i)).toHaveLength(6)
expect(queryAllByRole('list')).toHaveLength(2)
expect(queryAllByRole(/listitem/i)).toHaveLength(3)
- expect(queryAllByRole(/textbox/i)).toHaveLength(2)
+ // TODO: with https://github.com/A11yance/aria-query/pull/42
+ // the actual value will match `toHaveLength(2)`
+ expect(queryAllByRole(/textbox/i)).toHaveLength(1)
expect(queryAllByRole(/checkbox/i)).toHaveLength(1)
expect(queryAllByRole(/radio/i)).toHaveLength(1)
expect(queryAllByRole('row')).toHaveLength(3)
expect(queryAllByRole(/rowgroup/i)).toHaveLength(2)
- expect(queryAllByRole(/(table)|(textbox)/i)).toHaveLength(3)
+ // TODO: with https://github.com/A11yance/aria-query/pull/42
+ // the actual value will match `toHaveLength(3)`
+ expect(queryAllByRole(/(table)|(textbox)/i)).toHaveLength(2)
expect(queryAllByRole(/img/i)).toHaveLength(1)
expect(queryAllByRole('meter')).toHaveLength(1)
expect(queryAllByRole('progressbar')).toHaveLength(0)
expect(queryAllByRole('progressbar', {queryFallbacks: true})).toHaveLength(1)
+ expect(queryAllByRole('combobox')).toHaveLength(1)
+ expect(queryAllByRole('listbox')).toHaveLength(1)
})
test('getAll* matchers return an array', () => {
diff --git a/src/__tests__/role-helpers.js b/src/__tests__/role-helpers.js
index 9563b66c..47a58e9b 100644
--- a/src/__tests__/role-helpers.js
+++ b/src/__tests__/role-helpers.js
@@ -16,7 +16,7 @@ afterEach(() => {
function setup() {
const {getByTestId} = render(`
-
+linkinvalid link
@@ -50,7 +50,7 @@ function setup() {
-
+
`)
return {
- section: getByTestId('a-section'),
+ unnamedSection: getByTestId('a-section'),
+ namedSection: getByTestId('named-section'),
anchor: getByTestId('a-link'),
h1: getByTestId('a-h1'),
h2: getByTestId('a-h2'),
@@ -88,7 +92,8 @@ function setup() {
td1: getByTestId('a-cell-1'),
td2: getByTestId('a-cell-2'),
td3: getByTestId('a-cell-3'),
- form: getByTestId('a-form'),
+ unnamedForm: getByTestId('a-form'),
+ namedForm: getByTestId('named-form'),
radio: getByTestId('a-radio-1'),
radio2: getByTestId('a-radio-2'),
input: getByTestId('a-input-1'),
@@ -99,7 +104,6 @@ function setup() {
test('getRoles returns expected roles for various dom nodes', () => {
const {
- section,
anchor,
h1,
h2,
@@ -120,17 +124,17 @@ test('getRoles returns expected roles for various dom nodes', () => {
td1,
td2,
td3,
- form,
radio,
radio2,
input,
input2,
textarea,
+ namedSection,
+ namedForm,
} = setup()
- expect(getRoles(section)).toEqual({
+ expect(getRoles(namedSection)).toEqual({
link: [anchor],
- region: [section],
heading: [h1, h2, h3],
navigation: [nav],
radio: [radio, radio2],
@@ -140,27 +144,28 @@ test('getRoles returns expected roles for various dom nodes', () => {
table: [table],
row: [tr],
cell: [td1, td2, td3],
- form: [form],
textbox: [input, input2, textarea],
rowgroup: [tbody],
command: [menuItem, menuItem2],
menuitem: [menuItem, menuItem2],
+ form: [namedForm],
+ region: [namedSection],
})
})
test('logRoles calls console.log with output from prettyRoles', () => {
- const {section} = setup()
- logRoles(section)
+ const {namedSection} = setup()
+ logRoles(namedSection)
expect(console.log).toHaveBeenCalledTimes(1)
expect(console.log.mock.calls[0][0]).toMatchSnapshot()
})
test('getImplicitAriaRoles returns expected roles for various dom nodes', () => {
- const {section, h1, form, radio, input} = setup()
+ const {namedSection, h1, unnamedForm, radio, input} = setup()
- expect(getImplicitAriaRoles(section)).toEqual(['region'])
+ expect(getImplicitAriaRoles(namedSection)).toEqual(['region'])
expect(getImplicitAriaRoles(h1)).toEqual(['heading'])
- expect(getImplicitAriaRoles(form)).toEqual(['form'])
+ expect(getImplicitAriaRoles(unnamedForm)).toEqual([])
expect(getImplicitAriaRoles(radio)).toEqual(['radio'])
expect(getImplicitAriaRoles(input)).toEqual(['textbox'])
})
diff --git a/src/__tests__/role.js b/src/__tests__/role.js
index b68410fe..ec9beff7 100644
--- a/src/__tests__/role.js
+++ b/src/__tests__/role.js
@@ -214,8 +214,7 @@ test('can be filtered by accessible name', () => {
expect(deliveryForm).not.toBeNull()
expect(
- // TODO: upstream bug in `aria-query`; should be `button` role
- getQueriesForElement(deliveryForm).getByRole('textbox', {name: 'Submit'}),
+ getQueriesForElement(deliveryForm).getByRole('button', {name: 'Submit'}),
).not.toBeNull()
const invoiceForm = getByRole('form', {name: 'Delivery Adress'})
@@ -229,11 +228,9 @@ test('can be filtered by accessible name', () => {
test('accessible name comparison is case sensitive', () => {
const {getByRole} = render(`
Sign up
`)
- // actual: "Sign up",
- // queried: "Sign Up"
- expect(() => getByRole('heading', {name: 'Sign Up'}))
+ expect(() => getByRole('heading', {name: 'something that does not match'}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "heading" and name "Sign Up"
+"Unable to find an accessible element with the role "heading" and name "something that does not match"
Here are the accessible roles:
@@ -277,9 +274,9 @@ test('accessible name filter implements TextMatch', () => {
test('TextMatch serialization in error message', () => {
const {getByRole} = render(`
Sign up
`)
- expect(() => getByRole('heading', {name: /Login/}))
+ expect(() => getByRole('heading', {name: /something that does not match/}))
.toThrowErrorMatchingInlineSnapshot(`
-"Unable to find an accessible element with the role "heading" and name \`/Login/\`
+"Unable to find an accessible element with the role "heading" and name \`/something that does not match/\`
Here are the accessible roles:
diff --git a/src/role-helpers.js b/src/role-helpers.js
index 6d3ee309..5027ec31 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.js
@@ -76,9 +76,16 @@ function getImplicitAriaRoles(currentNode) {
function buildElementRoleList(elementRolesMap) {
function makeElementSelector({name, attributes = []}) {
return `${name}${attributes
- .map(({name: attributeName, value}) =>
- value ? `[${attributeName}=${value}]` : `[${attributeName}]`,
- )
+ .map(({name: attributeName, value, constraints = []}) => {
+ const shouldNotExist = constraints.indexOf('undefined') !== -1
+ if (shouldNotExist) {
+ return `:not([${attributeName}])`
+ } else if (value) {
+ return `[${attributeName}="${value}"]`
+ } else {
+ return `[${attributeName}]`
+ }
+ })
.join('')}`
}