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.14.0 to 0.15.0

100

lib/getNodeAccessibilityData/getAccessibleAttributeLabels/getLabelFromHtmlEquivalentAttribute.js

@@ -5,17 +5,83 @@ "use strict";

const mapAttributeNameAndValueToLabel_1 = require("./mapAttributeNameAndValueToLabel");
// REF: https://www.w3.org/TR/html-aria/#docconformance-attr
const isNotMatchingElement = ({ elements, node }) => elements.length && !elements.includes(node.localName);
const isNotMatchingProperties = ({ node, properties }) => properties.length &&
!properties.some(({ key, value }) => node.getAttribute(key) === value);
// REFs:
// - https://www.w3.org/TR/html-aria/#docconformance-attr
// - https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
const ariaToHTMLAttributeMapping = {
"aria-checked": [{ name: "checked" }],
"aria-disabled": [{ name: "disabled" }],
"aria-autocomplete": [
{ elements: ["form"], name: "autocomplete" },
{ elements: ["input", "select", "textarea"], name: "autocomplete" },
],
"aria-checked": [
{
elements: ["input"],
implicitMissingValue: "false",
name: "checked",
properties: [
{ key: "type", value: "checkbox" },
{ key: "type", value: "radio" },
],
},
{
value: "mixed",
name: "indeterminate",
},
],
"aria-colspan": [{ elements: ["td", "th"], name: "colspan" }],
"aria-controls": [
{
elements: ["input"],
name: "list",
},
],
"aria-disabled": [
{
elements: ["button", "input", "optgroup", "option", "select", "textarea"],
name: "disabled",
},
{
// TODO: Form controls within a valid legend child element of a fieldset
// with a disabled attribute do not become disabled.
elements: ["fieldset"],
name: "disabled",
},
],
// TODO: Set properties on the summary element.
// REF: https://www.w3.org/TR/html-aam-1.0/#att-open-details
// "aria-expanded": [{ elements: ["details"], name: "open" }],
// Not announced, indeed it will be hidden from the accessibility tree.
// "aria-hidden": [{ name: "hidden" }],
"aria-placeholder": [{ name: "placeholder" }],
"aria-valuemax": [{ name: "max" }],
"aria-valuemin": [{ name: "min" }],
"aria-invalid": [
// TODO: If the value doesn't match the pattern: aria-invalid="true";
// Otherwise, aria-invalid="false"
// REF: https://www.w3.org/TR/html-aam-1.0/#att-pattern
// { elements: ["input"], name: "pattern" },
// TODO: aria-invalid="spelling" or grammar
// REF: https://www.w3.org/TR/html-aam-1.0/#att-spellcheck
// { elements: ["input"], name: "spellcheck" },
],
"aria-multiselectable": [{ elements: ["select"], name: "multiple" }],
"aria-placeholder": [
{ elements: ["input", "textarea"], name: "placeholder" },
],
"aria-valuemax": [
{ elements: ["input"], name: "max" },
{ elements: ["meter", "progress"], name: "max" },
],
"aria-valuemin": [
{ elements: ["input"], name: "min" },
{ elements: ["meter", "progress"], name: "min" },
],
"aria-valuenow": [{ elements: ["meter", "progress"], name: "value" }],
"aria-readonly": [
{ name: "readonly" },
{ elements: ["input", "textarea"], name: "readonly" },
{ name: "contenteditable", negative: true },
],
"aria-required": [{ name: "required" }],
"aria-colspan": [{ name: "colspan" }],
"aria-rowspan": [{ name: "rowspan" }],
"aria-required": [
{ elements: ["input", "select", "textarea"], name: "required" },
],
"aria-rowspan": [{ elements: ["td", "th"], name: "rowspan" }],
"aria-selected": [{ elements: ["option"], name: "selected" }],
};

@@ -27,4 +93,14 @@ const getLabelFromHtmlEquivalentAttribute = ({ attributeName, container, node, }) => {

}
for (const { name, negative = false } of htmlAttribute) {
const attributeValue = node.getAttribute(name);
for (const { elements = [], implicitMissingValue, name, negative = false, properties = [], value, } of htmlAttribute) {
if (isNotMatchingElement({ elements, node })) {
continue;
}
if (isNotMatchingProperties({ node, properties })) {
continue;
}
const attributeValue = node.hasAttribute(name)
? value ?? node.getAttribute(name)
: node.hasAttribute(attributeName)
? undefined
: implicitMissingValue;
const label = (0, mapAttributeNameAndValueToLabel_1.mapAttributeNameAndValueToLabel)({

@@ -31,0 +107,0 @@ attributeName,

14

lib/test/int/accessibleValue.int.test.js

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

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Label");
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Label, not checked");
await __1.virtual.stop();

@@ -62,3 +62,3 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("radio, Label");
expect(await __1.virtual.lastSpokenPhrase()).toBe("radio, Label, not checked");
await __1.virtual.stop();

@@ -74,3 +74,3 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("radio, Label");
expect(await __1.virtual.lastSpokenPhrase()).toBe("radio, Label, not checked");
await __1.virtual.stop();

@@ -101,3 +101,3 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("listbox, second; third, orientated vertically");
expect(await __1.virtual.lastSpokenPhrase()).toBe("listbox, second; third, multi-selectable, orientated vertically");
await __1.virtual.stop();

@@ -127,6 +127,6 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("progressbar, Loading:, 23, max value 100");
expect(await __1.virtual.lastSpokenPhrase()).toBe("progressbar, Loading:, 23, max value 100, current value 23%");
await __1.virtual.stop();
});
it("should not announce the value for a progress element which has an aria-valuenow", async () => {
it("should announce the value in place of aria-valuenow for a progress element", async () => {
document.body.innerHTML = `

@@ -139,3 +139,3 @@ <label for="element1">Loading:</label>

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("progressbar, Loading:, max value 100, current value 24%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("progressbar, Loading:, max value 100, current value 23%");
await __1.virtual.stop();

@@ -142,0 +142,0 @@ });

@@ -61,8 +61,4 @@ "use strict";

<span id="element1">Label</span>
<span role="progressbar" aria-labelledby="element1" aria-valuenow="1" min="1">
<svg width="300" height="10">
<rect height="10" width="100" stroke="black" fill="red" />
<rect height="10" width="200" fill="white" />
</svg>
</span>
<progress aria-labelledby="element1" aria-valuenow="1" min="1">
</progress>
`;

@@ -78,8 +74,4 @@ await __1.virtual.start({ container: document.body });

<span id="element1">Label</span>
<span role="progressbar" aria-labelledby="element1" aria-valuenow="1" max="3">
<svg width="300" height="10">
<rect height="10" width="100" stroke="black" fill="red" />
<rect height="10" width="200" fill="white" />
</svg>
</span>
<progress aria-labelledby="element1" aria-valuenow="1" max="3">
</progress>
`;

@@ -161,3 +153,3 @@ await __1.virtual.start({ container: document.body });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="1">
<svg width="300" height="10">

@@ -168,2 +160,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -173,3 +166,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 100, min value 0, current value 1%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 100, min value 0, 1 control, current value 1%");
await __1.virtual.stop();

@@ -180,3 +173,3 @@ });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1" aria-valuemin="1">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="1" aria-valuemin="1">
<svg width="300" height="10">

@@ -187,2 +180,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -192,3 +186,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 100, min value 1, current value 0%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 100, min value 1, 1 control, current value 0%");
await __1.virtual.stop();

@@ -199,3 +193,3 @@ });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1" aria-valuemax="3">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="1" aria-valuemax="3">
<svg width="300" height="10">

@@ -206,2 +200,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -211,41 +206,9 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 0, current value 33.33%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 0, 1 control, current value 33.33%");
await __1.virtual.stop();
});
it("should announce aria-valuenow on scrollbar roles as a percentage when only min is provided", async () => {
document.body.innerHTML = `
<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1" min="1">
<svg width="300" height="10">
<rect height="10" width="100" stroke="black" fill="red" />
<rect height="10" width="200" fill="white" />
</svg>
</span>
`;
await __1.virtual.start({ container: document.body });
await __1.virtual.next();
await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 100, min value 1, current value 0%");
await __1.virtual.stop();
});
it("should announce aria-valuenow on scrollbar roles as a percentage when only max is provided", async () => {
document.body.innerHTML = `
<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1" max="3">
<svg width="300" height="10">
<rect height="10" width="100" stroke="black" fill="red" />
<rect height="10" width="200" fill="white" />
</svg>
</span>
`;
await __1.virtual.start({ container: document.body });
await __1.virtual.next();
await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 0, current value 33.33%");
await __1.virtual.stop();
});
it("should announce aria-valuenow on scrollbar roles as a zero percentage of a positive aria-valuemin - aria-valuemax range", async () => {
document.body.innerHTML = `
<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="1" aria-valuemin="1" aria-valuemax="3">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="1" aria-valuemin="1" aria-valuemax="3">
<svg width="300" height="10">

@@ -256,2 +219,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -261,3 +225,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 1, current value 0%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 1, 1 control, current value 0%");
await __1.virtual.stop();

@@ -268,3 +232,3 @@ });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="1" aria-valuemax="3">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="1" aria-valuemax="3">
<svg width="300" height="10">

@@ -275,2 +239,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -280,3 +245,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 1, current value 50%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 1, 1 control, current value 50%");
await __1.virtual.stop();

@@ -287,3 +252,3 @@ });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="0" aria-valuemax="3">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="0" aria-valuemax="3">
<svg width="300" height="10">

@@ -294,2 +259,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -299,3 +265,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 0, current value 66.67%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value 0, 1 control, current value 66.67%");
await __1.virtual.stop();

@@ -306,3 +272,3 @@ });

<span id="element1">Label</span>
<span role="scrollbar" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="-2" aria-valuemax="3">
<span role="scrollbar" aria-controls="scrollable-target" aria-labelledby="element1" aria-valuenow="2" aria-valuemin="-2" aria-valuemax="3">
<svg width="300" height="10">

@@ -313,2 +279,3 @@ <rect height="10" width="100" stroke="black" fill="red" />

</span>
<span id="scrollable-target">Scrollable Region</span>
`;

@@ -318,3 +285,3 @@ await __1.virtual.start({ container: document.body });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value -2, current value 80%");
expect(await __1.virtual.lastSpokenPhrase()).toBe("scrollbar, Label, orientated vertically, max value 3, min value -2, 1 control, current value 80%");
await __1.virtual.stop();

@@ -321,0 +288,0 @@ });

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

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns");
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns, not checked");
await __1.virtual.stop();

@@ -59,3 +59,3 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns");
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns, not checked");
await __1.virtual.stop();

@@ -109,3 +109,3 @@ });

await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns");
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Horns, not checked");
await __1.virtual.stop();

@@ -187,2 +187,11 @@ });

});
it("should ignore an invalid 'checked' property on an element + properties combination that doesn't support it", async () => {
document.body.innerHTML = `
<input role="checkbox" type="text" value="Some text" checked />
`;
await __1.virtual.start({ container: document.body });
await __1.virtual.next();
expect(await __1.virtual.lastSpokenPhrase()).toBe("checkbox, Some text");
await __1.virtual.stop();
});
});

@@ -303,5 +303,5 @@ "use strict";

"button, x",
"checkbox",
"checkbox, not checked",
"textbox",
"radio",
"radio, not checked",
"slider, 50, orientated horizontally, max value 100, min value 0",

@@ -308,0 +308,0 @@ "button, x",

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

@@ -41,6 +41,6 @@ "main": "lib/index.js",

"@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",
"@types/jest": "^29.5.8",
"@types/node": "^20.9.0",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"eslint": "^8.53.0",

@@ -47,0 +47,0 @@ "eslint-config-prettier": "^9.0.0",

@@ -132,2 +132,3 @@ <h1 align="center">Virtual Screen Reader</h1>

- [`@guidepup/playwright`](https://github.com/guidepup/guidepup-playwright/) - seamless integration of Guidepup with Playwright.
- [`@guidepup/jest`](https://github.com/guidepup/jest/) - jest matchers for reliable unit testing of your screen reader a11y workflows.

@@ -134,0 +135,0 @@ ## Similar

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