Skip to content

Commit dc780da

Browse files
fix: better accessible values
1 parent 1fb9614 commit dc780da

File tree

6 files changed

+69
-12
lines changed

6 files changed

+69
-12
lines changed

src/Virtual.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,22 @@ export class Virtual implements ScreenReader {
175175
this.#spokenPhraseLog.push(spokenPhrase);
176176
}
177177

178+
async #refreshState() {
179+
await tick();
180+
181+
this.#invalidateTreeCache();
182+
const tree = this.#getAccessibilityTree();
183+
184+
if (!tree.length) {
185+
return;
186+
}
187+
188+
const currentIndex = this.#getCurrentIndexByNode(tree);
189+
const newActiveNode = tree.at(currentIndex);
190+
191+
this.#updateState(newActiveNode);
192+
}
193+
178194
#getCurrentIndex(tree: AccessibilityNode[]) {
179195
return tree.findIndex(
180196
({
@@ -194,6 +210,10 @@ export class Virtual implements ScreenReader {
194210
);
195211
}
196212

213+
#getCurrentIndexByNode(tree: AccessibilityNode[]) {
214+
return tree.findIndex(({ node }) => node === this.#activeNode?.node);
215+
}
216+
197217
/**
198218
* Detect whether the screen reader is supported for the current OS.
199219
*
@@ -396,6 +416,7 @@ export class Virtual implements ScreenReader {
396416

397417
await this.click();
398418
await userEvent.keyboard(keyboardCommand, defaultUserEventOptions);
419+
await this.#refreshState();
399420

400421
return;
401422
}
@@ -422,6 +443,7 @@ export class Virtual implements ScreenReader {
422443

423444
const target = this.#activeNode.node as HTMLElement;
424445
await userEvent.type(target, text, defaultUserEventOptions);
446+
await this.#refreshState();
425447

426448
return;
427449
}
Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
import { isElement } from "../isElement";
22

3+
function getSelectValue(node) {
4+
const selectedOptions = [...node.options].filter((option) => option.selected);
5+
6+
if (node.multiple) {
7+
return [...selectedOptions].map((opt) => opt.value).join("; ");
8+
}
9+
10+
if (selectedOptions.length === 0) {
11+
return "";
12+
}
13+
14+
return selectedOptions[0].value;
15+
}
16+
17+
function getInputValue(node) {
18+
if (["checkbox", "radio"].includes(node.type)) {
19+
return "";
20+
}
21+
22+
return node.value;
23+
}
24+
325
export function getAccessibleValue(node: Node) {
4-
return isElement(node) ? node.getAttribute("value") ?? "" : "";
26+
if (!isElement(node)) {
27+
return "";
28+
}
29+
30+
switch (node.localName) {
31+
case "input": {
32+
return getInputValue(node);
33+
}
34+
case "select": {
35+
return getSelectValue(node);
36+
}
37+
}
38+
39+
return "";
540
}

test/int/press.int.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ describe("press", () => {
2727
await virtual.press("Shift+a+b+c");
2828
// TODO: FAIL: Testing Library user-event doesn't support modification yet, this should be "ABC"
2929
expect(getByRole(container, "textbox")).toHaveValue("abc");
30-
31-
// TODO: FAIL: item text should include the now non-empty value "ABC"
32-
expect(await virtual.itemText()).toEqual("Input Some Text");
30+
expect(await virtual.itemText()).toEqual("Input Some Text, abc");
3331

3432
await virtual.stop();
3533
});

test/int/type.int.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ describe("type", () => {
1414
setupInputPage();
1515
});
1616

17+
afterEach(() => {
18+
document.body.innerHTML = "";
19+
});
20+
1721
it("should type on the active element", async () => {
1822
const container = document.body;
1923

@@ -26,9 +30,7 @@ describe("type", () => {
2630

2731
await virtual.type("Hello World!");
2832
expect(getByRole(container, "textbox")).toHaveValue("Hello World!");
29-
30-
// TODO: FAIL: item text should include the now non-empty value "Hello World!"
31-
expect(await virtual.itemText()).toEqual("Input Some Text");
33+
expect(await virtual.itemText()).toEqual("Input Some Text, Hello World!");
3234

3335
await virtual.stop();
3436
});

test/wpt/html-aam/roles.int.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ describe("HTML-AAM Role Verification Tests", () => {
308308
"checkbox",
309309
"textbox",
310310
"radio",
311-
"slider, orientated horizontally, max value 100, min value 0",
311+
"slider, 50, orientated horizontally, max value 100, min value 0",
312312
"button, x",
313313
"searchbox",
314314
"button, x",
@@ -356,10 +356,10 @@ describe("HTML-AAM Role Verification Tests", () => {
356356
"x",
357357
"end of listitem",
358358
"end of list",
359-
"combobox, not expanded, has popup listbox",
359+
"combobox, x, not expanded, has popup listbox",
360360
"option, x, not selected",
361361
"option, x, not selected",
362-
"end of combobox, not expanded, has popup listbox",
362+
"end of combobox, x, not expanded, has popup listbox",
363363
"status",
364364
"x",
365365
"end of status",

test/wpt/html-aam/table-roles.int.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ describe("HTML-AAM Table Role Verification Tests", () => {
5555
expect(await virtual.spokenPhraseLog()).toEqual([
5656
"document",
5757
"table, caption",
58-
"caption", // TODO: FAIL caption should have role of caption
58+
"caption",
5959
"rowgroup",
60-
"row, a b c", // TODO: Should rows have accessible name of their columns? Likely not?
60+
"row, a b c",
6161
"columnheader, a",
6262
"columnheader, b",
6363
"columnheader, c",

0 commit comments

Comments
 (0)