Commit 5746d6cf authored by David Sveningsson's avatar David Sveningsson Committed by David Sveningsson
Browse files

feat(rules): implement caching in some helper methods

parent 13d99e49
......@@ -73,5 +73,17 @@ describe("a17y helpers", () => {
const p = root.querySelector("p");
expect(inAccessibilityTree(p)).toBeFalsy();
});
it("should cache result", () => {
expect.assertions(4);
const root = parse("<p></p>");
const p = root.querySelector("p");
const spy = jest.spyOn(p, "getAttribute");
expect(inAccessibilityTree(p)).toBeTruthy();
expect(spy).toHaveBeenCalledTimes(2);
spy.mockClear();
expect(inAccessibilityTree(p)).toBeTruthy();
expect(spy).toHaveBeenCalledTimes(0);
});
});
});
import { HtmlElement } from "../../dom";
declare module "../../dom/cache" {
export interface DOMNodeCache {
[CACHE_KEY]: boolean;
}
}
const CACHE_KEY = Symbol(inAccessibilityTree.name);
/**
* Tests if this element is present in the accessibility tree.
*
......@@ -8,23 +16,28 @@ import { HtmlElement } from "../../dom";
* visible since the element might be in the visibility tree sometimes.
*/
export function inAccessibilityTree(node: HtmlElement): boolean {
if (node.cacheExists(CACHE_KEY)) {
return node.cacheGet(CACHE_KEY);
}
let cur: HtmlElement = node;
do {
const role = node.getAttribute("role");
const ariaHidden = node.getAttribute("aria-hidden");
const role = cur.getAttribute("role");
const ariaHidden = cur.getAttribute("aria-hidden");
/* role="presentation" */
if (role && role.value === "presentation") {
return false;
return cur.cacheSet(CACHE_KEY, false);
}
/* aria-hidden="true" */
if (ariaHidden && ariaHidden.value === "true") {
return false;
return cur.cacheSet(CACHE_KEY, false);
}
/* check parents */
node = node.parent;
} while (!node.isRootElement());
cur = cur.parent;
} while (!cur.isRootElement());
return true;
return node.cacheSet(CACHE_KEY, true);
}
......@@ -43,4 +43,12 @@ describe("classifyNodeText()", () => {
node.querySelector("b").appendText(new DynamicValue(""));
expect(classifyNodeText(node)).toEqual(TextClassification.DYNAMIC_TEXT);
});
it("should cache result", () => {
expect.assertions(2);
const node = parser.parseHtml("<p>foo</p>").querySelector("p");
expect(classifyNodeText(node)).toEqual(TextClassification.STATIC_TEXT);
node.childNodes.length = 0; /* hack to remove all text content */
expect(classifyNodeText(node)).toEqual(TextClassification.STATIC_TEXT);
});
});
import { HtmlElement, NodeType, TextNode } from "../../dom";
const CACHE_KEY = Symbol(classifyNodeText.name);
export enum TextClassification {
EMPTY_TEXT,
DYNAMIC_TEXT,
STATIC_TEXT,
}
declare module "../../dom/cache" {
export interface DOMNodeCache {
[CACHE_KEY]: TextClassification;
}
}
/**
* Checks text content of an element.
*
......@@ -15,20 +23,24 @@ export enum TextClassification {
* If any text is dynamic `TextClassification.DYNAMIC_TEXT` is returned.
*/
export function classifyNodeText(node: HtmlElement): TextClassification {
if (node.cacheExists(CACHE_KEY)) {
return node.cacheGet(CACHE_KEY);
}
const text = findTextNodes(node);
/* if any text is dynamic classify as dynamic */
if (text.some((cur) => cur.isDynamic)) {
return TextClassification.DYNAMIC_TEXT;
return node.cacheSet(CACHE_KEY, TextClassification.DYNAMIC_TEXT);
}
/* if any text has non-whitespace character classify as static */
if (text.some((cur) => cur.textContent.match(/\S/) !== null)) {
return TextClassification.STATIC_TEXT;
return node.cacheSet(CACHE_KEY, TextClassification.STATIC_TEXT);
}
/* default to empty */
return TextClassification.EMPTY_TEXT;
return node.cacheSet(CACHE_KEY, TextClassification.EMPTY_TEXT);
}
function findTextNodes(node: HtmlElement): TextNode[] {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment