New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@guidepup/virtual-screen-reader

Package Overview
Dependencies
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@guidepup/virtual-screen-reader - npm Package Compare versions

Comparing version 0.9.1 to 0.10.0

lib/commands/getElementNode.d.ts

2

lib/createAccessibilityTree.d.ts

@@ -7,4 +7,6 @@ export interface AccessibilityNode {

allowedAccessibilityChildRoles: string[][];
alternateReadingOrderParents: Node[];
childrenPresentational: boolean;
node: Node;
parent: Node | null;
role: string;

@@ -11,0 +13,0 @@ spokenRole: string;

82

lib/createAccessibilityTree.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAccessibilityTree = void 0;
const getIdRefsByAttribute_1 = require("./getIdRefsByAttribute");
const getNodeAccessibilityData_1 = require("./getNodeAccessibilityData");
const getNodeByIdRef_1 = require("./getNodeByIdRef");
const isElement_1 = require("./isElement");
const dom_accessibility_api_1 = require("dom-accessibility-api");
function addOwnedNodes(owningNode, ownedNodes) {
const ownedNodesIdRefs = (owningNode.getAttribute("aria-owns") ?? "")
.trim()
.split(" ");
ownedNodesIdRefs.filter(Boolean).forEach((id) => {
const ownedNode = document.querySelector(`#${id}`);
function addAlternateReadingOrderNodes(node, alternateReadingOrderMap, container) {
const idRefs = (0, getIdRefsByAttribute_1.getIdRefsByAttribute)({
attributeName: "aria-flowto",
node,
});
idRefs.forEach((idRef) => {
const childNode = (0, getNodeByIdRef_1.getNodeByIdRef)({ container, idRef });
if (!childNode) {
return;
}
const currentParentNodes = alternateReadingOrderMap.get(childNode) ?? new Set();
currentParentNodes.add(node);
alternateReadingOrderMap.set(childNode, currentParentNodes);
});
}
function mapAlternateReadingOrder(node) {
const alternateReadingOrderMap = new Map();
if (!(0, isElement_1.isElement)(node)) {
return alternateReadingOrderMap;
}
node
.querySelectorAll("[aria-flowto]")
.forEach((parentNode) => addAlternateReadingOrderNodes(parentNode, alternateReadingOrderMap, node));
return alternateReadingOrderMap;
}
function addOwnedNodes(node, ownedNodes, container) {
const idRefs = (0, getIdRefsByAttribute_1.getIdRefsByAttribute)({
attributeName: "aria-owns",
node,
});
idRefs.forEach((idRef) => {
const ownedNode = (0, getNodeByIdRef_1.getNodeByIdRef)({ container, idRef });
if (!!ownedNode && !ownedNodes.has(ownedNode)) {

@@ -25,11 +53,11 @@ ownedNodes.add(ownedNode);

.querySelectorAll("[aria-owns]")
.forEach((owningNode) => addOwnedNodes(owningNode, ownedNodes));
.forEach((owningNode) => addOwnedNodes(owningNode, ownedNodes, node));
return ownedNodes;
}
function getOwnedNodes(node) {
function getOwnedNodes(node, container) {
const ownedNodes = new Set();
if (!(0, isElement_1.isElement)(node)) {
if (!(0, isElement_1.isElement)(node) || !(0, isElement_1.isElement)(container)) {
return ownedNodes;
}
addOwnedNodes(node, ownedNodes);
addOwnedNodes(node, ownedNodes, container);
return ownedNodes;

@@ -61,5 +89,6 @@ }

const { children, ...treeNode } = tree;
const isAnnounced = treeNode.accessibleName ||
treeNode.accessibleDescription ||
treeNode.spokenRole;
const isAnnounced = !!treeNode.accessibleName ||
!!treeNode.accessibleDescription ||
treeNode.accessibleAttributeLabels.length > 0 ||
!!treeNode.spokenRole;
const ignoreChildren = shouldIgnoreChildren(tree);

@@ -80,4 +109,6 @@ const flattenedTree = ignoreChildren

allowedAccessibilityChildRoles: treeNode.allowedAccessibilityChildRoles,
alternateReadingOrderParents: treeNode.alternateReadingOrderParents,
childrenPresentational: treeNode.childrenPresentational,
node: treeNode.node,
parent: treeNode.parent,
role: treeNode.role,

@@ -89,3 +120,3 @@ spokenRole: `end of ${treeNode.spokenRole}`,

}
function growTree(node, tree, { container, ownedNodes, visitedNodes }) {
function growTree(node, tree, { alternateReadingOrderMap, container, ownedNodes, visitedNodes, }) {
/**

@@ -110,4 +141,8 @@ * Authors MUST NOT create circular references with aria-owns. In the case of

}
const alternateReadingOrderParents = alternateReadingOrderMap.has(childNode)
? Array.from(alternateReadingOrderMap.get(childNode))
: [];
const { accessibleAttributeLabels, accessibleDescription, accessibleName, accessibleValue, allowedAccessibilityChildRoles, childrenPresentational, role, spokenRole, } = (0, getNodeAccessibilityData_1.getNodeAccessibilityData)({
allowedAccessibilityRoles: tree.allowedAccessibilityChildRoles,
alternateReadingOrderParents,
container,

@@ -123,8 +158,10 @@ node: childNode,

allowedAccessibilityChildRoles,
alternateReadingOrderParents,
children: [],
childrenPresentational,
node: childNode,
parent: node,
role,
spokenRole,
}, { container, ownedNodes, visitedNodes }));
}, { alternateReadingOrderMap, container, ownedNodes, visitedNodes }));
});

@@ -142,3 +179,3 @@ /**

*/
const ownedChildNodes = getOwnedNodes(node);
const ownedChildNodes = getOwnedNodes(node, container);
ownedChildNodes.forEach((childNode) => {

@@ -148,4 +185,8 @@ if (isHiddenFromAccessibilityTree(childNode)) {

}
const alternateReadingOrderParents = alternateReadingOrderMap.has(childNode)
? Array.from(alternateReadingOrderMap.get(childNode))
: [];
const { accessibleAttributeLabels, accessibleDescription, accessibleName, accessibleValue, allowedAccessibilityChildRoles, childrenPresentational, role, spokenRole, } = (0, getNodeAccessibilityData_1.getNodeAccessibilityData)({
allowedAccessibilityRoles: tree.allowedAccessibilityChildRoles,
alternateReadingOrderParents,
container,

@@ -161,8 +202,10 @@ node: childNode,

allowedAccessibilityChildRoles,
alternateReadingOrderParents,
children: [],
childrenPresentational,
node: childNode,
parent: node,
role,
spokenRole,
}, { container, ownedNodes, visitedNodes }));
}, { alternateReadingOrderMap, container, ownedNodes, visitedNodes }));
});

@@ -175,2 +218,3 @@ return tree;

}
const alternateReadingOrderMap = mapAlternateReadingOrder(node);
const ownedNodes = getAllOwnedNodes(node);

@@ -180,2 +224,3 @@ const visitedNodes = new Set();

allowedAccessibilityRoles: [],
alternateReadingOrderParents: [],
container: node,

@@ -191,8 +236,11 @@ node,

allowedAccessibilityChildRoles,
alternateReadingOrderParents: [],
children: [],
childrenPresentational,
node,
parent: null,
role,
spokenRole,
}, {
alternateReadingOrderMap,
container: node,

@@ -199,0 +247,0 @@ ownedNodes,

@@ -1,3 +0,4 @@

export declare const getAccessibleAttributeLabels: ({ accessibleValue, container, node, role, }: {
export declare const getAccessibleAttributeLabels: ({ accessibleValue, alternateReadingOrderParents, container, node, role, }: {
accessibleValue: string;
alternateReadingOrderParents: Node[];
container: Node;

@@ -4,0 +5,0 @@ node: Node;

@@ -11,3 +11,3 @@ "use strict";

const postProcessLabels_1 = require("./postProcessLabels");
const getAccessibleAttributeLabels = ({ accessibleValue, container, node, role, }) => {
const getAccessibleAttributeLabels = ({ accessibleValue, alternateReadingOrderParents, container, node, role, }) => {
if (!(0, isElement_1.isElement)(node)) {

@@ -68,4 +68,19 @@ return [];

});
return (0, postProcessLabels_1.postProcessLabels)({ labels, role });
const processedLabels = (0, postProcessLabels_1.postProcessLabels)({ labels, role }).filter(Boolean);
/**
* aria-flowto MUST requirements:
*
* The reading order goes both directions, and a user needs to be aware of the
* alternate reading order so that they can invoke the functionality.
*
* The reading order goes both directions, and a user needs to be able to
* travel backwards through their chosen reading order.
*
* REF: https://a11ysupport.io/tech/aria/aria-flowto_attribute
*/
if (alternateReadingOrderParents.length > 0) {
processedLabels.push(`${alternateReadingOrderParents.length} previous alternate reading ${alternateReadingOrderParents.length === 1 ? "order" : "orders"}`);
}
return processedLabels;
};
exports.getAccessibleAttributeLabels = getAccessibleAttributeLabels;

@@ -7,3 +7,3 @@ "use strict";

const getItemText_1 = require("../../getItemText");
const isElement_1 = require("../../isElement");
const getNodeByIdRef_1 = require("../../getNodeByIdRef");
var State;

@@ -28,3 +28,3 @@ (function (State) {

const ariaPropertyToVirtualLabelMap = {
"aria-activedescendant": idref("active descendant"),
"aria-activedescendant": idRef("active descendant"),
"aria-atomic": null,

@@ -45,3 +45,3 @@ "aria-autocomplete": token({

"aria-colspan": integer("column span"),
"aria-controls": null,
"aria-controls": idRefs("control", "controls"),
"aria-current": token({

@@ -63,3 +63,3 @@ page: "current page",

"aria-expanded": state(State.EXPANDED),
"aria-flowto": null,
"aria-flowto": idRefs("alternate reading order", "alternate reading orders"),
"aria-grabbed": null,

@@ -132,8 +132,19 @@ "aria-haspopup": token({

}
function idref(propertyName) {
return function mapper({ attributeValue: idref, container }) {
if (!(0, isElement_1.isElement)(container) || !idref) {
function idRefs(propertyDescriptionSuffixSingular, propertyDescriptionSuffixPlural) {
return function mapper({ attributeValue, container }) {
const idRefsCount = attributeValue
.trim()
.split(" ")
.filter((idRef) => !!(0, getNodeByIdRef_1.getNodeByIdRef)({ container, idRef })).length;
if (idRefsCount === 0) {
return "";
}
const node = container.querySelector(`#${idref}`);
return `${idRefsCount} ${idRefsCount === 1
? propertyDescriptionSuffixSingular
: propertyDescriptionSuffixPlural}`;
};
}
function idRef(propertyName) {
return function mapper({ attributeValue: idRef, container }) {
const node = (0, getNodeByIdRef_1.getNodeByIdRef)({ container, idRef });
if (!node) {

@@ -140,0 +151,0 @@ return "";

@@ -1,3 +0,4 @@

export declare function getNodeAccessibilityData({ allowedAccessibilityRoles, container, inheritedImplicitPresentational, node, }: {
export declare function getNodeAccessibilityData({ allowedAccessibilityRoles, alternateReadingOrderParents, container, inheritedImplicitPresentational, node, }: {
allowedAccessibilityRoles: string[][];
alternateReadingOrderParents: Node[];
container: Node;

@@ -4,0 +5,0 @@ inheritedImplicitPresentational: boolean;

@@ -38,3 +38,3 @@ "use strict";

};
function getNodeAccessibilityData({ allowedAccessibilityRoles, container, inheritedImplicitPresentational, node, }) {
function getNodeAccessibilityData({ allowedAccessibilityRoles, alternateReadingOrderParents, container, inheritedImplicitPresentational, node, }) {
const accessibleDescription = (0, getAccessibleDescription_1.getAccessibleDescription)(node);

@@ -51,2 +51,3 @@ const accessibleName = (0, getAccessibleName_1.getAccessibleName)(node);

accessibleValue,
alternateReadingOrderParents,
container,

@@ -60,3 +61,8 @@ node,

const isGeneric = role === "generic";
const spokenRole = getSpokenRole({ isGeneric, isPresentational, node, role });
const spokenRole = getSpokenRole({
isGeneric,
isPresentational,
node,
role,
});
const { requiredOwnedElements: allowedAccessibilityChildRoles } = aria_query_1.roles.get(role) ?? { requiredOwnedElements: [] };

@@ -63,0 +69,0 @@ const { requiredOwnedElements: implicitAllowedAccessibilityChildRoles } = aria_query_1.roles.get(implicitRole) ?? { requiredOwnedElements: [] };

import { CommandOptions, ScreenReader } from "@guidepup/guidepup";
import { VirtualCommandKey, VirtualCommands } from "./commands";
import { VirtualCommandArgs } from "./commands/types";
export interface StartOptions extends CommandOptions {

@@ -8,3 +10,3 @@ /**

*/
container: HTMLElement;
container: Node;
}

@@ -23,2 +25,12 @@ /**

/**
* Getter for screen reader commands.
*
* Use with `await virtual.perform(command)`.
*/
get commands(): {
jumpToControlledElement: "jumpToControlledElement";
moveToNextAlternateReadingOrderElement: "moveToNextAlternateReadingOrderElement";
moveToPreviousAlternateReadingOrderElement: "moveToPreviousAlternateReadingOrderElement";
};
/**
* Detect whether the screen reader is supported for the current OS.

@@ -108,5 +120,8 @@ *

*
* Currently not implemented.
* @param {string} command Screen reader command.
* @param {object} [options] Command options.
*/
perform(): Promise<void>;
perform<T extends VirtualCommandKey, K extends Omit<Parameters<VirtualCommands[T]>[0], keyof VirtualCommandArgs>>(command: T, options?: {
[L in keyof K]: K[L];
} & CommandOptions): Promise<void>;
/**

@@ -113,0 +128,0 @@ * Click the mouse.

@@ -6,2 +6,3 @@ "use strict";

const guidepup_1 = require("@guidepup/guidepup");
const commands_1 = require("./commands");
const errors_1 = require("./errors");

@@ -11,3 +12,2 @@ const getItemText_1 = require("./getItemText");

const isElement_1 = require("./isElement");
const notImplemented_1 = require("./notImplemented");
const user_event_1 = require("@testing-library/user-event");

@@ -171,2 +171,13 @@ const defaultUserEventOptions = {

/**
* Getter for screen reader commands.
*
* Use with `await virtual.perform(command)`.
*/
get commands() {
return Object.fromEntries(Object.keys(commands_1.commands).map((command) => [
command,
command,
]));
}
/**
* Detect whether the screen reader is supported for the current OS.

@@ -359,81 +370,25 @@ *

*
* Currently not implemented.
* @param {string} command Screen reader command.
* @param {object} [options] Command options.
*/
async perform() {
async perform(command, options) {
this.#checkContainer();
await tick();
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role banner.
*
* REF: https://w3c.github.io/aria/#banner
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role complementary.
*
* REF: https://w3c.github.io/aria/#complementary
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role contentinfo.
*
* REF: https://w3c.github.io/aria/#contentinfo
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* figures.
*
* REF: https://w3c.github.io/aria/#figure
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role form.
*
* REF: https://w3c.github.io/aria/#form
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* landmark regions.
*
* REF: https://w3c.github.io/aria/#landmark
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role main.
*
* REF: https://w3c.github.io/aria/#main
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role navigation.
*
* REF: https://w3c.github.io/aria/#navigation
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role region.
*
* REF: https://w3c.github.io/aria/#region
*/
/**
* TODO: Assistive technologies SHOULD enable users to quickly navigate to
* elements with role search.
*
* REF: https://w3c.github.io/aria/#search
*/
/**
* TODO: However, when aria-flowto is provided with multiple ID
* references, assistive technologies SHOULD present the referenced
* elements as path choices.
*
* In the case of one or more ID references, user agents or assistive
* technologies SHOULD give the user the option of navigating to any of the
* targeted elements. The name of the path can be determined by the name of
* the target element of the aria-flowto attribute. Accessibility APIs can
* provide named path relationships.
*
* REF: https://w3c.github.io/aria/#aria-flowto
*/
(0, notImplemented_1.notImplemented)();
const tree = this.#getAccessibilityTree();
if (!tree.length) {
return;
}
const currentIndex = this.#getCurrentIndex(tree);
const nextIndex = commands_1.commands[command]?.({
...options,
container: this.#container,
currentIndex,
tree,
});
if (typeof nextIndex !== "number") {
return;
}
const newActiveNode = tree.at(nextIndex);
this.#updateState(newActiveNode);
return;
}

@@ -440,0 +395,0 @@ /**

{
"name": "@guidepup/virtual-screen-reader",
"version": "0.9.1",
"version": "0.10.0",
"description": "Virtual screen reader driver for unit test automation.",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc