@progress/kendo-e2e
Version:
Kendo UI end-to-end test utilities.
191 lines (190 loc) • 7.74 kB
TypeScript
export type A11yAttribute = {
/** Attribute name, e.g. "aria-hidden", "role" */
name: string;
/** Attribute value, e.g. "true", "button" */
value: string;
};
export type A11yNodeDiff = {
/** CSS class selector identifying this node (e.g. ".k-button.k-button-md") */
classSelector: string;
/** Depth level in the tree */
depth: number;
/** Attributes matched in both actual and expected (name + value) */
matchedAttributes: A11yAttribute[];
/** Attributes in expected but not in actual */
missingAttributes: A11yAttribute[];
/** Attributes in actual but not in expected */
extraAttributes: A11yAttribute[];
/** Attributes present in both but with different values */
differentAttributes: {
name: string;
actualValue: string;
expectedValue: string;
}[];
/** Attributes inherited from classless ancestor elements — orange warning */
carriedAttributes?: A11yAttribute[];
/** Node comparison status */
status: 'matched' | 'missing' | 'extra' | 'different';
/** Child node diffs */
children: A11yNodeDiff[];
};
export type A11yResult = {
/** Nodes where all a11y attributes matched */
passed: {
selector: string;
attributes: A11yAttribute[];
}[];
/** Attributes in expected but missing in actual */
missing: {
selector: string;
attribute: A11yAttribute;
}[];
/** Attributes in actual but not in expected */
extra: {
selector: string;
attribute: A11yAttribute;
}[];
/** Attributes present in both but with different values */
different: {
selector: string;
name: string;
actualValue: string;
expectedValue: string;
}[];
/** Attributes carried from classless ancestor elements — may be misattributed */
carried: {
selector: string;
attribute: A11yAttribute;
}[];
/** Classless entries removed by `ignoreClasslessNodes` (for reporting) */
ignoredClassless?: {
missing: {
selector: string;
attribute: A11yAttribute;
}[];
extra: {
selector: string;
attribute: A11yAttribute;
}[];
};
/** Tree-based diff showing per-node a11y attribute differences */
treeDiff?: A11yNodeDiff[];
};
type A11yDomNode = {
classes: string[];
classSelector: string;
a11yAttributes: A11yAttribute[];
children: A11yDomNode[];
/** Names of a11y attributes on this node that were inherited from a classless ancestor */
carriedAttrNames?: Set<string>;
};
/**
* Build a DOM tree that preserves both class selectors and a11y attributes.
* Nodes without classes are "transparent" – their children are promoted,
* but their a11y attributes are carried to the first class-bearing ancestor.
*
* When `collapseClasses` is provided, nodes whose classes are **entirely**
* covered by one of these selectors are also treated as transparent wrappers
* (children promoted, a11y attributes carried down). This automatically
* collapses framework-specific wrappers like `.k-icon-wrapper-host`.
*/
export declare function buildA11yDomTree(element: Element, collapseClasses?: Set<string>): A11yDomNode[];
/** Sanitize Angular-specific selectors from a11y DOM tree */
export declare function sanitizeA11yDomTreeNG(nodes: A11yDomNode[]): A11yDomNode[];
/**
* Diff two a11y DOM trees, matching nodes by class similarity
* and comparing their a11y attributes.
*/
export declare function diffA11yTrees(actual: A11yDomNode[], expected: A11yDomNode[], depth?: number, presenceOnlyAttrs?: Set<string>): A11yNodeDiff[];
/** Per-node a11y allow entry: maps a class selector to attribute names,
* e.g. `{ ".k-slider": ["aria-label"] }` */
export type A11yAllowEntry = Record<string, string[]>;
export type A11yCompareOptions = {
sanitizeNGSelectors?: boolean;
/**
* A11y attributes to ignore when missing from actual, scoped per node.
* Each entry maps a CSS class selector to an array of attribute names.
* A selector key matches a node when **every class** in the key appears in the node's classSelector.
* @example [{ ".k-slider": ["aria-label"] }, { ".k-radio": ["aria-label", "role"] }]
*/
allowMissing?: A11yAllowEntry[];
/**
* A11y attributes to ignore when extra in actual, scoped per node.
* Same matching semantics as `allowMissing`.
* @example [{ ".k-button": ["aria-expanded"] }]
*/
allowExtra?: A11yAllowEntry[];
/**
* Attributes to compare by presence only (ignore exact value).
* Defaults to: `["aria-label", "title", "aria-controls", "aria-labelledby", "aria-owns", "aria-describedby"]`.
* Set to `[]` to disable and compare all values exactly.
* Add extra attribute names to extend the default list.
*/
ignoreValueAttributes?: string[];
/**
* CSS class selectors to collapse in the a11y tree (treat as transparent wrappers).
* Nodes whose classes are **entirely** covered by these entries are collapsed:
* their children are promoted and their a11y attributes are carried down.
*
* This is populated automatically from the CSS `allowExtra` option in `compareHtml`,
* so framework-specific wrappers like `.k-icon-wrapper-host` are collapsed when
* they appear in `allowExtra`.
*
* @example ['.k-icon-wrapper-host', '.k-button-text']
*/
collapseExtraClasses?: string[];
/**
* CSS class selectors to collapse in the **expected** a11y tree.
* Nodes whose classes are entirely covered by these entries are collapsed.
*
* This is populated automatically from the CSS `allowMissing` option in `compareHtml`,
* so wrappers present in expected but absent in actual are collapsed.
*
* @example ['.k-button-text']
*/
collapseMissingClasses?: string[];
/**
* When true, classless nodes (e.g. `<svg>`, `<path>`) are excluded from the
* a11y comparison entirely. Useful when specs include `aria-hidden` on SVG
* elements but the actual framework output doesn't.
*
* Defaults to `false`.
*/
ignoreClasslessNodes?: boolean;
};
/**
* Default attributes that are compared by presence only (value ignored).
* These attributes typically contain dynamic IDs or locale-specific text
* that differ between actual and expected HTML.
*/
export declare const DEFAULT_PRESENCE_ONLY_ATTRIBUTES: string[];
/**
* Compare a11y attributes (aria-* and role) between two HTML documents.
*
* Nodes are matched by their CSS class hierarchy. For each matched node pair,
* `aria-*` and `role` attributes are compared between actual and expected.
*
* @example
* const result = compareA11yAttributes(
* '<button class="k-button" aria-disabled="true" role="button">OK</button>',
* '<button class="k-button" aria-disabled="false" role="button" aria-label="Confirm">OK</button>'
* );
* // result.missing → aria-label on .k-button
* // result.different → aria-disabled has different values
*
* @param actualHtml The actual HTML markup.
* @param expectedHtml The expected HTML markup.
* @param options Comparison options.
*/
export declare function compareA11yAttributes(actualHtml: string, expectedHtml: string, options?: A11yCompareOptions): A11yResult;
/**
* Format an a11y comparison result as a human-readable diff.
*
* @param result The a11y comparison result.
* @param options Formatting options.
*/
export declare function formatA11yDiff(result: A11yResult, options?: {
useColors?: boolean;
}): string;
export declare function renderA11yHtmlDiffTree(nodes: A11yNodeDiff[], ignoreClasslessNodes?: boolean): string;
export {};