Skip to content

Commit d05f495

Browse files
shairezcwoolumthejackshelton
committed
added a11y axe tests to select
Co-authored-by: Chris Woolum <[email protected]> Co-authored-by: Jack Shelton <[email protected]>
1 parent 97075c1 commit d05f495

File tree

8 files changed

+65
-26
lines changed

8 files changed

+65
-26
lines changed

apps/component-tests/src/components/showcase-test/component-imports.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ function createMetaGlobComponents() {
1515
},
1616
);
1717

18-
const newThing: Record<string, unknown> = {};
18+
const componentsMap: Record<string, unknown> = {};
1919

2020
for (const key in metaGlobComponents) {
2121
const component = metaGlobComponents[key];
2222

2323
if (component) {
2424
const componentName = key.split('routes/docs/')[1];
2525
if (componentName) {
26-
newThing[componentName] = component;
26+
componentsMap[componentName] = component;
2727
}
2828
}
2929
}
3030

31-
return newThing;
31+
return componentsMap;
3232
}
3333

3434
export const metaGlobComponents = createMetaGlobComponents();

apps/website/src/routes/docs/headless/select/examples/hero.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { component$, useStyles$ } from '@builder.io/qwik';
22
import {
33
Select,
4-
SelectPopover,
54
SelectListbox,
65
SelectOption,
6+
SelectPopover,
77
SelectTrigger,
88
SelectValue,
99
} from '@qwik-ui/headless';
@@ -14,7 +14,7 @@ export default component$(() => {
1414
const users = ['Tim', 'Ryan', 'Jim', 'Jessie', 'Abby'];
1515

1616
return (
17-
<Select class="select">
17+
<Select class="select" aria-label="hero">
1818
<SelectTrigger class="select-trigger">
1919
<SelectValue placeholder="Select an option" />
2020
</SelectTrigger>

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@
3232
"story.headless": "nx storybook headless",
3333
"test.cli": "nx test cli",
3434
"test.headless": "nx component-test headless",
35+
"test.visual.headless": "nx visual-test headless",
3536
"test.pw.headless": "nx e2e headless",
37+
"test.pw.headless.ci": "nx e2e headless",
3638
"test.headless.ci": "nx component-test-ci headless",
3739
"test.utils": "nx test utils"
3840
},
3941
"packageManager": "[email protected]",
4042
"devDependencies": {
43+
"@axe-core/playwright": "4.8.5",
4144
"@builder.io/qwik": "^1.4.0",
4245
"@builder.io/qwik-city": "^1.4.0",
4346
"@builder.io/qwik-react": "0.5.3",
@@ -217,6 +220,5 @@
217220
],
218221
"nx": {
219222
"includedScripts": []
220-
},
221-
"dependencies": {}
223+
}
222224
}

packages/kit-headless/src/components/select/select-trigger.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { component$, type PropsOf, useContext, sync$, $, Slot } from '@builder.io/qwik';
1+
import { $, Slot, component$, sync$, useContext, type PropsOf } from '@builder.io/qwik';
22
import SelectContextId from './select-context';
3-
import { getNextEnabledOptionIndex, getPrevEnabledOptionIndex } from './utils';
43
import { useTypeahead } from './use-select';
4+
import { getNextEnabledOptionIndex, getPrevEnabledOptionIndex } from './utils';
55

66
type SelectTriggerProps = PropsOf<'button'>;
77
export const SelectTrigger = component$<SelectTriggerProps>((props) => {

packages/kit-headless/src/components/select/select.test.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import AxeBuilder from '@axe-core/playwright';
12
import { expect, test, type Page } from '@playwright/test';
23
import { createTestDriver } from './select.driver';
4+
35
async function setup(page: Page, exampleName: string) {
46
await page.goto(`/headless/select/${exampleName}`);
57

@@ -123,7 +125,7 @@ test.describe('Mouse Behavior', () => {
123125
// });
124126

125127
test(`GIVEN an open hero select
126-
WHEN clikcking on the group label
128+
WHEN clicking on the group label
127129
THEN the listbox should remain open`, async ({ page }) => {
128130
const { getRoot, openListbox, getListbox } = await setup(page, 'group');
129131

@@ -229,7 +231,7 @@ test.describe('Keyboard Behavior', () => {
229231
test.describe('data-highlighted navigation', () => {
230232
test(`GIVEN a hero select
231233
WHEN pressing the down arrow key
232-
THEN open up the listbox
234+
THEN the listbox should be opened
233235
AND the first option should have data-highlighted`, async ({ page }) => {
234236
const { getTrigger, getListbox, getOptionAt } = await setup(page, 'hero');
235237

@@ -366,10 +368,9 @@ test.describe('Keyboard Behavior', () => {
366368
});
367369

368370
test.describe('selecting options', () => {
369-
test(`GIVEN an open hero select
370-
WHEN an option has data-highlighted
371-
AND the Enter key is pressed
372-
THEN the listbox should be closed and aria-expanded false`, async ({
371+
test(`GIVEN an opened hero select with the first option highlighted
372+
WHEN the Enter key is pressed
373+
THEN the listbox should be closed and aria-expanded should be false`, async ({
373374
page,
374375
}) => {
375376
const { getTrigger, getListbox, getOptionAt, openListbox } = await setup(
@@ -491,13 +492,14 @@ test.describe('Keyboard Behavior', () => {
491492
);
492493

493494
// get initial selected value
494-
const firstItemValue = await getHiddenOptionAt(0).textContent();
495+
// const firstItemValue = await getHiddenOptionAt(0).textContent();
495496
await getTrigger().focus();
496497
await getTrigger().press('ArrowRight');
498+
await expect(getValueElement()).toHaveText('Tim');
497499
await getTrigger().press('ArrowRight');
498500

499501
await getTrigger().press('ArrowLeft');
500-
expect(await getValueElement()).toHaveText(firstItemValue!);
502+
await expect(getValueElement()).toHaveText('Tim');
501503
await expect(getHiddenOptionAt(0)).toHaveAttribute('aria-selected', 'true');
502504
await expect(getHiddenOptionAt(0)).toHaveAttribute('data-highlighted');
503505
});
@@ -1002,7 +1004,26 @@ test.describe('Props', () => {
10021004
});
10031005
});
10041006

1007+
/** TODO: add docs telling people how to add an aria-label to the root component. (accessible name) */
10051008
test.describe('A11y', () => {
1009+
test('Axe Validation Test', async ({ page }) => {
1010+
const { openListbox } = await setup(page, 'hero');
1011+
1012+
const initialResults = await new AxeBuilder({ page })
1013+
.include('[role="combobox"]')
1014+
.analyze();
1015+
1016+
expect(initialResults.violations).toEqual([]);
1017+
1018+
await openListbox('click');
1019+
1020+
const afterClickResults = await new AxeBuilder({ page })
1021+
.include('[role="combobox"]')
1022+
.analyze();
1023+
1024+
expect(afterClickResults.violations).toEqual([]);
1025+
});
1026+
10061027
test(`GIVEN a select with a group
10071028
WHEN the user adds a new group
10081029
THEN the group should have an aria-labelledby attribute

packages/kit-headless/src/components/select/select.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
import {
2-
component$,
2+
PropsOf,
3+
Signal,
34
Slot,
4-
useSignal,
5+
component$,
6+
useComputed$,
57
useContextProvider,
8+
useId,
9+
useSignal,
610
useTask$,
7-
useComputed$,
811
type QRL,
9-
useId,
10-
PropsOf,
11-
Signal,
1212
} from '@builder.io/qwik';
13-
import { type SelectContext } from './select-context';
14-
import SelectContextId from './select-context';
15-
import { Opt } from './select-inline';
1613
import { isBrowser } from '@builder.io/qwik/build';
14+
import SelectContextId, { type SelectContext } from './select-context';
15+
import { Opt } from './select-inline';
1716
import { getActiveDescendant } from './utils';
1817

1918
export type InternalSelectProps = {

pnpm-lock.yaml

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)