From fb3322aefd948243c82ffce8838dfd178e1938d7 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 4 Feb 2020 22:46:35 +0100 Subject: [PATCH 1/5] test: add select-combobox test --- src/__tests__/element-queries.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js index f673b918..9bb438a0 100644 --- a/src/__tests__/element-queries.js +++ b/src/__tests__/element-queries.js @@ -414,6 +414,11 @@ test('queryAllByRole returns semantic html elements', () => {
+ + `) @@ -437,6 +442,8 @@ test('queryAllByRole returns semantic html elements', () => { expect(queryAllByRole('meter')).toHaveLength(1) expect(queryAllByRole('progressbar')).toHaveLength(0) expect(queryAllByRole('progressbar', {queryFallbacks: true})).toHaveLength(1) + expect(queryAllByRole('combobox')).toHaveLength(2) + expect(queryAllByRole('listbox')).toHaveLength(2) }) test('getAll* matchers return an array', () => { From 6577f03c5dc90e5846a140ee617c18136a6b3022 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 4 Feb 2020 21:37:05 +0100 Subject: [PATCH 2/5] fix: Various implicit roles in ByRole --- package.json | 2 +- .../__snapshots__/role-helpers.js.snap | 18 +--------------- src/__tests__/element-queries.js | 12 ++++++----- src/__tests__/role-helpers.js | 21 ++++++++----------- src/role-helpers.js | 13 +++++++++--- 5 files changed, 28 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index 5cadd2b5..35cafab6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@babel/runtime": "^7.6.2", "@sheerun/mutationobserver-shim": "^0.3.2", "@types/testing-library__dom": "^6.0.0", - "aria-query": "3.0.0", + "aria-query": "^4.0.1", "dom-accessibility-api": "^0.3.0", "pretty-format": "^24.9.0", "wait-for-expect": "^3.0.0" diff --git a/src/__tests__/__snapshots__/role-helpers.js.snap b/src/__tests__/__snapshots__/role-helpers.js.snap index 2e5ce3d7..bf8f9a7f 100644 --- a/src/__tests__/__snapshots__/role-helpers.js.snap +++ b/src/__tests__/__snapshots__/role-helpers.js.snap @@ -1,15 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`logRoles calls console.log with output from prettyRoles 1`] = ` -"region: - -Name "": -
- --------------------------------------------------- -link: +"link: Name "link": --------------------------------------------------- -form: - -Name "": -
- -------------------------------------------------- radio: diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js index 9bb438a0..f85974e1 100644 --- a/src/__tests__/element-queries.js +++ b/src/__tests__/element-queries.js @@ -427,23 +427,25 @@ 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: fix upstream in `aria-query` + 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: fix upstream in `aria-query` + 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(2) - expect(queryAllByRole('listbox')).toHaveLength(2) + 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..f5d25c07 100644 --- a/src/__tests__/role-helpers.js +++ b/src/__tests__/role-helpers.js @@ -67,7 +67,7 @@ function setup() { `) return { - section: getByTestId('a-section'), + unnamedSection: getByTestId('a-section'), anchor: getByTestId('a-link'), h1: getByTestId('a-h1'), h2: getByTestId('a-h2'), @@ -88,7 +88,7 @@ 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'), radio: getByTestId('a-radio-1'), radio2: getByTestId('a-radio-2'), input: getByTestId('a-input-1'), @@ -99,7 +99,7 @@ function setup() { test('getRoles returns expected roles for various dom nodes', () => { const { - section, + unnamedSection, anchor, h1, h2, @@ -120,7 +120,6 @@ test('getRoles returns expected roles for various dom nodes', () => { td1, td2, td3, - form, radio, radio2, input, @@ -128,9 +127,8 @@ test('getRoles returns expected roles for various dom nodes', () => { textarea, } = setup() - expect(getRoles(section)).toEqual({ + expect(getRoles(unnamedSection)).toEqual({ link: [anchor], - region: [section], heading: [h1, h2, h3], navigation: [nav], radio: [radio, radio2], @@ -140,7 +138,6 @@ 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], @@ -149,18 +146,18 @@ test('getRoles returns expected roles for various dom nodes', () => { }) test('logRoles calls console.log with output from prettyRoles', () => { - const {section} = setup() - logRoles(section) + const {unnamedSection} = setup() + logRoles(unnamedSection) 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 {unnamedSection, h1, unnamedForm, radio, input} = setup() - expect(getImplicitAriaRoles(section)).toEqual(['region']) + expect(getImplicitAriaRoles(unnamedSection)).toEqual([]) 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/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('')}` } From 8e0ad83e0d7200e20d67febab89d0d8837f4ddeb Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Tue, 4 Feb 2020 23:25:36 +0100 Subject: [PATCH 3/5] test: add note about aria-query fix --- src/__tests__/element-queries.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/__tests__/element-queries.js b/src/__tests__/element-queries.js index f85974e1..82b2ee2b 100644 --- a/src/__tests__/element-queries.js +++ b/src/__tests__/element-queries.js @@ -432,13 +432,15 @@ test('queryAllByRole returns semantic html elements', () => { expect(queryAllByRole(/heading/i)).toHaveLength(6) expect(queryAllByRole('list')).toHaveLength(2) expect(queryAllByRole(/listitem/i)).toHaveLength(3) - // TODO: fix upstream in `aria-query` + // 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) - // TODO: fix upstream in `aria-query` + // 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) From 29d9b47dd0f5a723a1418ba564a73396208527a2 Mon Sep 17 00:00:00 2001 From: "Kent C. Dodds" Date: Wed, 4 Mar 2020 09:28:55 -0700 Subject: [PATCH 4/5] simplify some tests --- src/__tests__/role.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) 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: From 3d38d1b39275129624508703d7acb96284c2f3d7 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Wed, 4 Mar 2020 17:48:59 +0100 Subject: [PATCH 5/5] test: document how to name elements --- .../__snapshots__/role-helpers.js.snap | 20 +++++++++++++++- src/__tests__/role-helpers.js | 24 ++++++++++++------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/__tests__/__snapshots__/role-helpers.js.snap b/src/__tests__/__snapshots__/role-helpers.js.snap index bf8f9a7f..89f55ec9 100644 --- a/src/__tests__/__snapshots__/role-helpers.js.snap +++ b/src/__tests__/__snapshots__/role-helpers.js.snap @@ -1,7 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`logRoles calls console.log with output from prettyRoles 1`] = ` -"link: +"region: + +Name "a region": +
+ +-------------------------------------------------- +link: Name "link": +-------------------------------------------------- +form: + +Name "a form": + + -------------------------------------------------- radio: diff --git a/src/__tests__/role-helpers.js b/src/__tests__/role-helpers.js index f5d25c07..47a58e9b 100644 --- a/src/__tests__/role-helpers.js +++ b/src/__tests__/role-helpers.js @@ -16,7 +16,7 @@ afterEach(() => { function setup() { const {getByTestId} = render(` -
+
link invalid link @@ -50,7 +50,7 @@ function setup() { - + @@ -62,12 +62,16 @@ function setup() {
  • Item 1
  • Item 2
  • + + +
    `) return { unnamedSection: getByTestId('a-section'), + namedSection: getByTestId('named-section'), anchor: getByTestId('a-link'), h1: getByTestId('a-h1'), h2: getByTestId('a-h2'), @@ -89,6 +93,7 @@ function setup() { td2: getByTestId('a-cell-2'), td3: getByTestId('a-cell-3'), 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 { - unnamedSection, anchor, h1, h2, @@ -125,9 +129,11 @@ test('getRoles returns expected roles for various dom nodes', () => { input, input2, textarea, + namedSection, + namedForm, } = setup() - expect(getRoles(unnamedSection)).toEqual({ + expect(getRoles(namedSection)).toEqual({ link: [anchor], heading: [h1, h2, h3], navigation: [nav], @@ -142,20 +148,22 @@ test('getRoles returns expected roles for various dom nodes', () => { rowgroup: [tbody], command: [menuItem, menuItem2], menuitem: [menuItem, menuItem2], + form: [namedForm], + region: [namedSection], }) }) test('logRoles calls console.log with output from prettyRoles', () => { - const {unnamedSection} = setup() - logRoles(unnamedSection) + 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 {unnamedSection, h1, unnamedForm, radio, input} = setup() + const {namedSection, h1, unnamedForm, radio, input} = setup() - expect(getImplicitAriaRoles(unnamedSection)).toEqual([]) + expect(getImplicitAriaRoles(namedSection)).toEqual(['region']) expect(getImplicitAriaRoles(h1)).toEqual(['heading']) expect(getImplicitAriaRoles(unnamedForm)).toEqual([]) expect(getImplicitAriaRoles(radio)).toEqual(['radio'])