@guidepup/virtual-screen-reader
Advanced tools
Comparing version 0.11.0 to 0.12.0
import { AccessibilityNode } from "../createAccessibilityTree"; | ||
export declare function getElementNode(accessibilityNode: AccessibilityNode): Node; | ||
export declare function getElementNode(accessibilityNode: AccessibilityNode): Element; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getElementNode = void 0; | ||
const isElement_1 = require("../isElement"); | ||
const getElementFromNode_1 = require("../getElementFromNode"); | ||
function getElementNode(accessibilityNode) { | ||
const { node } = accessibilityNode; | ||
if (node && (0, isElement_1.isElement)(node)) { | ||
return node; | ||
} | ||
return accessibilityNode.parent; | ||
return (0, getElementFromNode_1.getElementFromNode)(node); | ||
} | ||
exports.getElementNode = getElementNode; |
@@ -6,7 +6,8 @@ "use strict"; | ||
const isElement_1 = require("../isElement"); | ||
const sanitizeString_1 = require("../sanitizeString"); | ||
function getAccessibleName(node) { | ||
return (0, isElement_1.isElement)(node) | ||
? (0, dom_accessibility_api_1.computeAccessibleName)(node).trim() | ||
: node.textContent.trim(); | ||
: (0, sanitizeString_1.sanitizeString)(node.textContent); | ||
} | ||
exports.getAccessibleName = getAccessibleName; |
@@ -13,2 +13,11 @@ import { CommandOptions, ScreenReader } from "@guidepup/guidepup"; | ||
/** | ||
* TODO: When a modal element is displayed, assistive technologies SHOULD | ||
* navigate to the element unless focus has explicitly been set elsewhere. Some | ||
* assistive technologies limit navigation to the modal element's contents. If | ||
* focus moves to an element outside the modal element, assistive technologies | ||
* SHOULD NOT limit navigation to the modal element. | ||
* | ||
* REF: https://w3c.github.io/aria/#aria-modal | ||
*/ | ||
/** | ||
* TODO: When an assistive technology reading cursor moves from one article to | ||
@@ -15,0 +24,0 @@ * another, assistive technologies SHOULD set user agent focus on the article |
@@ -8,41 +8,14 @@ "use strict"; | ||
const errors_1 = require("./errors"); | ||
const getElementFromNode_1 = require("./getElementFromNode"); | ||
const getItemText_1 = require("./getItemText"); | ||
const getLiveSpokenPhrase_1 = require("./getLiveSpokenPhrase"); | ||
const getSpokenPhrase_1 = require("./getSpokenPhrase"); | ||
const isElement_1 = require("./isElement"); | ||
const observeDOM_1 = require("./observeDOM"); | ||
const tick_1 = require("./tick"); | ||
const user_event_1 = require("@testing-library/user-event"); | ||
const defaultUserEventOptions = { | ||
delay: null, | ||
delay: 0, | ||
skipHover: true, | ||
}; | ||
/** | ||
* TODO: handle live region roles: | ||
* | ||
* - alert | ||
* - log | ||
* - marquee | ||
* - status | ||
* - timer | ||
* - alertdialog | ||
* | ||
* And handle live region attributes: | ||
* | ||
* - aria-atomic | ||
* - aria-busy | ||
* - aria-live | ||
* - aria-relevant | ||
* | ||
* When live regions are marked as polite, assistive technologies SHOULD | ||
* announce updates at the next graceful opportunity, such as at the end of | ||
* speaking the current sentence or when the user pauses typing. When live | ||
* regions are marked as assertive, assistive technologies SHOULD notify the | ||
* user immediately. | ||
* | ||
* REF: | ||
* | ||
* - https://w3c.github.io/aria/#live_region_roles | ||
* - https://w3c.github.io/aria/#window_roles | ||
* - https://w3c.github.io/aria/#attrs_liveregions | ||
* - https://w3c.github.io/aria/#aria-live | ||
*/ | ||
/** | ||
* TODO: When a modal element is displayed, assistive technologies SHOULD | ||
@@ -56,28 +29,2 @@ * navigate to the element unless focus has explicitly been set elsewhere. Some | ||
*/ | ||
const observeDOM = (function () { | ||
const MutationObserver = window.MutationObserver; | ||
return function observeDOM(node, onChange) { | ||
if (!(0, isElement_1.isElement)(node)) { | ||
return; | ||
} | ||
if (MutationObserver) { | ||
const mutationObserver = new MutationObserver(onChange); | ||
mutationObserver.observe(node, { | ||
attributes: true, | ||
childList: true, | ||
subtree: true, | ||
}); | ||
return () => { | ||
mutationObserver.disconnect(); | ||
}; | ||
} | ||
return () => { | ||
// gracefully fallback to not supporting Accessibility Tree refreshes if | ||
// the DOM changes. | ||
}; | ||
}; | ||
})(); | ||
async function tick() { | ||
return await new Promise((resolve) => setTimeout(() => resolve())); | ||
} | ||
/** | ||
@@ -126,3 +73,3 @@ * TODO: When an assistive technology reading cursor moves from one article to | ||
async #handleFocusChange({ target }) { | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
this.#invalidateTreeCache(); | ||
@@ -135,7 +82,18 @@ const tree = this.#getAccessibilityTree(); | ||
#focusActiveElement() { | ||
if (!this.#activeNode || !(0, isElement_1.isElement)(this.#activeNode.node)) { | ||
return; | ||
} | ||
this.#activeNode.node.focus(); | ||
const target = (0, getElementFromNode_1.getElementFromNode)(this.#activeNode.node); | ||
target?.focus(); | ||
} | ||
async #announceLiveRegions(mutations) { | ||
await (0, tick_1.tick)(); | ||
const container = this.#container; | ||
mutations | ||
.map((mutation) => (0, getLiveSpokenPhrase_1.getLiveSpokenPhrase)({ | ||
container, | ||
mutation, | ||
})) | ||
.filter(Boolean) | ||
.forEach((spokenPhrase) => { | ||
this.#spokenPhraseLog.push(spokenPhrase); | ||
}); | ||
} | ||
#updateState(accessibilityNode, ignoreIfNoChange = false) { | ||
@@ -154,3 +112,3 @@ const spokenPhrase = (0, getSpokenPhrase_1.getSpokenPhrase)(accessibilityNode); | ||
async #refreshState(ignoreIfNoChange) { | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
this.#invalidateTreeCache(); | ||
@@ -210,3 +168,6 @@ const tree = this.#getAccessibilityTree(); | ||
this.#container = container; | ||
this.#disconnectDOMObserver = observeDOM(container, this.#invalidateTreeCache.bind(this)); | ||
this.#disconnectDOMObserver = (0, observeDOM_1.observeDOM)(container, (mutations) => { | ||
this.#invalidateTreeCache(); | ||
this.#announceLiveRegions(mutations); | ||
}); | ||
const tree = this.#getAccessibilityTree(); | ||
@@ -236,3 +197,3 @@ if (!tree.length) { | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
const tree = this.#getAccessibilityTree(); | ||
@@ -253,3 +214,3 @@ if (!tree.length) { | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
const tree = this.#getAccessibilityTree(); | ||
@@ -272,7 +233,7 @@ if (!tree.length) { | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
if (!this.#activeNode) { | ||
return; | ||
} | ||
const target = this.#activeNode.node; | ||
const target = (0, getElementFromNode_1.getElementFromNode)(this.#activeNode.node); | ||
// TODO: verify that is appropriate for all default actions | ||
@@ -324,3 +285,3 @@ await user_event_1.default.click(target, defaultUserEventOptions); | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
if (!this.#activeNode) { | ||
@@ -365,7 +326,7 @@ return; | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
if (!this.#activeNode) { | ||
return; | ||
} | ||
const target = this.#activeNode.node; | ||
const target = (0, getElementFromNode_1.getElementFromNode)(this.#activeNode.node); | ||
await user_event_1.default.type(target, text, defaultUserEventOptions); | ||
@@ -383,3 +344,3 @@ await this.#refreshState(true); | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
const tree = this.#getAccessibilityTree(); | ||
@@ -410,3 +371,3 @@ if (!tree.length) { | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
if (!this.#activeNode) { | ||
@@ -417,3 +378,3 @@ return; | ||
const keys = key.repeat(clickCount); | ||
const target = this.#activeNode.node; | ||
const target = (0, getElementFromNode_1.getElementFromNode)(this.#activeNode.node); | ||
await user_event_1.default.pointer([{ target }, { keys, target }], defaultUserEventOptions); | ||
@@ -429,3 +390,3 @@ return; | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
return this.#spokenPhraseLog.at(-1) ?? ""; | ||
@@ -440,3 +401,3 @@ } | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
return this.#itemTextLog.at(-1) ?? ""; | ||
@@ -451,3 +412,3 @@ } | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
return this.#spokenPhraseLog; | ||
@@ -462,3 +423,3 @@ } | ||
this.#checkContainer(); | ||
await tick(); | ||
await (0, tick_1.tick)(); | ||
return this.#itemTextLog; | ||
@@ -465,0 +426,0 @@ } |
{ | ||
"name": "@guidepup/virtual-screen-reader", | ||
"version": "0.11.0", | ||
"version": "0.12.0", | ||
"description": "Virtual screen reader driver for unit test automation.", | ||
@@ -32,24 +32,24 @@ "main": "lib/index.js", | ||
}, | ||
"dependencies": { | ||
"@guidepup/guidepup": "^0.19.0", | ||
"@testing-library/dom": "^9.3.3", | ||
"@testing-library/user-event": "^14.5.1", | ||
"aria-query": "^5.3.0", | ||
"dom-accessibility-api": "^0.6.3" | ||
}, | ||
"devDependencies": { | ||
"@testing-library/jest-dom": "^5.16.5", | ||
"@types/jest": "^29.4.0", | ||
"@types/node": "^18.11.18", | ||
"@typescript-eslint/eslint-plugin": "^5.49.0", | ||
"@typescript-eslint/parser": "^5.49.0", | ||
"eslint": "^8.32.0", | ||
"eslint-config-prettier": "^8.6.0", | ||
"jest": "^29.4.0", | ||
"jest-environment-jsdom": "^29.5.0", | ||
"rimraf": "^4.1.2", | ||
"ts-jest": "^29.0.5", | ||
"@testing-library/jest-dom": "^6.1.4", | ||
"@types/jest": "^29.5.7", | ||
"@types/node": "^20.8.10", | ||
"@typescript-eslint/eslint-plugin": "^6.9.1", | ||
"@typescript-eslint/parser": "^6.9.1", | ||
"eslint": "^8.53.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"rimraf": "^5.0.5", | ||
"ts-jest": "^29.1.1", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.9.4" | ||
}, | ||
"dependencies": { | ||
"@guidepup/guidepup": "^0.17.1", | ||
"@testing-library/dom": "^9.3.0", | ||
"@testing-library/user-event": "^14.4.3", | ||
"aria-query": "^5.1.3", | ||
"dom-accessibility-api": "^0.6.1" | ||
"typescript": "^5.2.2" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
<h1 align="center">Guidepup Virtual Screen Reader</h1> | ||
<h1 align="center">Virtual Screen Reader</h1> | ||
<p align="center"> | ||
@@ -6,6 +6,6 @@ <i>Virtual screen reader driver for unit test automation.</i> | ||
<p align="center"> | ||
<a href="https://www.npmjs.com/package/@guidepup/virtual-screen-reader"><img alt="Guidepup Virtual Screen Reader available on NPM" src="https://img.shields.io/npm/v/@guidepup/virtual-screen-reader" /></a> | ||
<a href="https://www.npmjs.com/package/@guidepup/virtual-screen-reader"><img alt="Guidepup Virtual Screen Reader available on NPM" src="https://img.shields.io/npm/dt/@guidepup/virtual-screen-reader"></a> | ||
<a href="https://github.com/guidepup/virtual-screen-reader/actions/workflows/test.yml"><img alt="Guidepup Virtual Screen Reader test workflows" src="https://github.com/guidepup/virtual-screen-reader/workflows/Test/badge.svg" /></a> | ||
<a href="https://github.com/guidepup/virtual-screen-reader/blob/main/LICENSE"><img alt="Guidepup Virtual Screen Reader uses the MIT license" src="https://img.shields.io/github/license/guidepup/virtual-screen-reader" /></a> | ||
<a href="https://www.npmjs.com/package/@guidepup/virtual-screen-reader"><img alt="Virtual Screen Reader available on NPM" src="https://img.shields.io/npm/v/@guidepup/virtual-screen-reader" /></a> | ||
<a href="https://www.npmjs.com/package/@guidepup/virtual-screen-reader"><img alt="Virtual Screen Reader available on NPM" src="https://img.shields.io/npm/dt/@guidepup/virtual-screen-reader"></a> | ||
<a href="https://github.com/guidepup/virtual-screen-reader/actions/workflows/test.yml"><img alt="Virtual Screen Reader test workflows" src="https://github.com/guidepup/virtual-screen-reader/workflows/Test/badge.svg" /></a> | ||
<a href="https://github.com/guidepup/virtual-screen-reader/blob/main/LICENSE"><img alt="Virtual Screen Reader uses the MIT license" src="https://img.shields.io/github/license/guidepup/virtual-screen-reader" /></a> | ||
</p> | ||
@@ -20,3 +20,3 @@ <p align="center"> | ||
With Guidepup Virtual Screen Reader you can automate your screen reader unit test workflows the same you as would for mouse or keyboard based scenarios, no sweat! | ||
With Virtual Screen Reader you can automate your screen reader unit test workflows the same you as would for mouse or keyboard based scenarios, no sweat! | ||
@@ -32,3 +32,3 @@ ## Features | ||
Install Guidepup to your project: | ||
Install Virtual Screen Reader to your project: | ||
@@ -119,2 +119,2 @@ ```bash | ||
[MIT](https://github.com/guidepup/guidepup/blob/main/LICENSE) | ||
[MIT](https://github.com/guidepup/virtual-screen-reader/blob/main/LICENSE) |
106780
77
2567
+ Added@derhuerst/http-basic@8.2.4(transitive)
+ Added@guidepup/guidepup@0.19.1(transitive)
+ Added@types/node@10.17.60(transitive)
+ Addedagent-base@6.0.2(transitive)
+ Addedbuffer-from@1.1.2(transitive)
+ Addedcaseless@0.12.0(transitive)
+ Addedconcat-stream@2.0.0(transitive)
+ Addedenv-paths@2.2.1(transitive)
+ Addedffmpeg-static@5.2.0(transitive)
+ Addedhttp-response-object@3.0.2(transitive)
+ Addedhttps-proxy-agent@5.0.1(transitive)
+ Addedparse-cache-control@1.0.1(transitive)
+ Addedprogress@2.0.3(transitive)
+ Addedreadable-stream@3.6.2(transitive)
+ Addedregedit@5.1.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedstring_decoder@1.3.0(transitive)
+ Addedtypedarray@0.0.6(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
- Removed@guidepup/guidepup@0.17.1(transitive)
- Removedregedit@5.0.1(transitive)
Updated@guidepup/guidepup@^0.19.0
Updated@testing-library/dom@^9.3.3
Updatedaria-query@^5.3.0
Updateddom-accessibility-api@^0.6.3