basic root accessibility stuff
This commit is contained in:
parent
92bd854d8f
commit
f2d3ac68ae
|
|
@ -55,13 +55,12 @@ export interface AXNode {
|
||||||
isLeafNode(): boolean;
|
isLeafNode(): boolean;
|
||||||
isControl(): boolean;
|
isControl(): boolean;
|
||||||
serialize(): SerializedAXNode;
|
serialize(): SerializedAXNode;
|
||||||
findElement(element: dom.ElementHandle): Promise<AXNode|null>;
|
|
||||||
children(): Iterable<AXNode>;
|
children(): Iterable<AXNode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Accessibility {
|
export class Accessibility {
|
||||||
private _getAXTree: () => Promise<AXNode>;
|
private _getAXTree: (needle?: dom.ElementHandle) => Promise<{tree: AXNode, needle?: AXNode}>;
|
||||||
constructor(getAXTree: () => Promise<AXNode>) {
|
constructor(getAXTree: (needle?: dom.ElementHandle) => Promise<{tree: AXNode, needle?: AXNode}>) {
|
||||||
this._getAXTree = getAXTree;
|
this._getAXTree = getAXTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,18 +72,12 @@ export class Accessibility {
|
||||||
interestingOnly = true,
|
interestingOnly = true,
|
||||||
root = null,
|
root = null,
|
||||||
} = options;
|
} = options;
|
||||||
const defaultRoot = await this._getAXTree();
|
const {tree, needle} = await this._getAXTree(root);
|
||||||
let needle: AXNode | null = defaultRoot;
|
|
||||||
if (root) {
|
|
||||||
needle = await defaultRoot.findElement(root);
|
|
||||||
if (!needle)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!interestingOnly)
|
if (!interestingOnly)
|
||||||
return serializeTree(needle)[0];
|
return serializeTree(needle)[0];
|
||||||
|
|
||||||
const interestingNodes: Set<AXNode> = new Set();
|
const interestingNodes: Set<AXNode> = new Set();
|
||||||
collectInterestingNodes(interestingNodes, defaultRoot, false);
|
collectInterestingNodes(interestingNodes, tree, false);
|
||||||
if (root && !interestingNodes.has(needle))
|
if (root && !interestingNodes.has(needle))
|
||||||
return null;
|
return null;
|
||||||
return serializeTree(needle, interestingNodes)[0];
|
return serializeTree(needle, interestingNodes)[0];
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,13 @@ import { Protocol } from './protocol';
|
||||||
import * as dom from '../dom';
|
import * as dom from '../dom';
|
||||||
import * as accessibility from '../accessibility';
|
import * as accessibility from '../accessibility';
|
||||||
|
|
||||||
export async function getAccessibilityTree(client: CRSession) : Promise<accessibility.AXNode> {
|
export async function getAccessibilityTree(client: CRSession, needle?: dom.ElementHandle) : Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}> {
|
||||||
const {nodes} = await client.send('Accessibility.getFullAXTree');
|
const {nodes} = await client.send('Accessibility.getFullAXTree');
|
||||||
return CRAXNode.createTree(client, nodes);
|
const tree = CRAXNode.createTree(client, nodes);
|
||||||
|
return {
|
||||||
|
tree,
|
||||||
|
needle: needle && await tree._findElement(needle)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class CRAXNode implements accessibility.AXNode {
|
class CRAXNode implements accessibility.AXNode {
|
||||||
|
|
@ -90,7 +94,7 @@ class CRAXNode implements accessibility.AXNode {
|
||||||
return this._children;
|
return this._children;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findElement(element: dom.ElementHandle): Promise<CRAXNode | null> {
|
async _findElement(element: dom.ElementHandle): Promise<CRAXNode | null> {
|
||||||
const remoteObject = element._remoteObject as Protocol.Runtime.RemoteObject;
|
const remoteObject = element._remoteObject as Protocol.Runtime.RemoteObject;
|
||||||
const {node: {backendNodeId}} = await this._client.send('DOM.describeNode', {objectId: remoteObject.objectId});
|
const {node: {backendNodeId}} = await this._client.send('DOM.describeNode', {objectId: remoteObject.objectId});
|
||||||
const needle = this.find(node => node._payload.backendDOMNodeId === backendNodeId);
|
const needle = this.find(node => node._payload.backendDOMNodeId === backendNodeId);
|
||||||
|
|
|
||||||
|
|
@ -480,8 +480,8 @@ export class CRPage implements PageDelegate {
|
||||||
return to._createHandle(result.object).asElement()!;
|
return to._createHandle(result.object).asElement()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccessibilityTree(): Promise<accessibility.AXNode> {
|
async getAccessibilityTree(needle?: dom.ElementHandle) {
|
||||||
return getAccessibilityTree(this._client);
|
return getAccessibilityTree(this._client, needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
async pdf(options?: types.PDFOptions): Promise<platform.BufferType> {
|
async pdf(options?: types.PDFOptions): Promise<platform.BufferType> {
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,21 @@
|
||||||
import * as accessibility from '../accessibility';
|
import * as accessibility from '../accessibility';
|
||||||
import { FFSession } from './ffConnection';
|
import { FFSession } from './ffConnection';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
|
import * as dom from '../dom';
|
||||||
|
|
||||||
export async function getAccessibilityTree(session: FFSession) : Promise<accessibility.AXNode> {
|
export async function getAccessibilityTree(session: FFSession, needle: dom.ElementHandle) : Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}> {
|
||||||
const { tree } = await session.send('Accessibility.getFullAXTree');
|
const objectId = needle ? needle._remoteObject.objectId : undefined;
|
||||||
return new FFAXNode(tree);
|
const { tree } = await session.send('Accessibility.getFullAXTree', { objectId });
|
||||||
|
const axNode = new FFAXNode(tree);
|
||||||
|
return {
|
||||||
|
tree: axNode,
|
||||||
|
needle: needle && axNode._findNeedle()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class FFAXNode implements accessibility.AXNode {
|
class FFAXNode implements accessibility.AXNode {
|
||||||
_children: FFAXNode[];
|
_children: FFAXNode[];
|
||||||
private _payload: any;
|
private _payload: Protocol.AXTree;
|
||||||
private _editable: boolean;
|
private _editable: boolean;
|
||||||
private _richlyEditable: boolean;
|
private _richlyEditable: boolean;
|
||||||
private _focusable: boolean;
|
private _focusable: boolean;
|
||||||
|
|
@ -77,8 +83,15 @@ class FFAXNode implements accessibility.AXNode {
|
||||||
return this._children;
|
return this._children;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findElement(): Promise<FFAXNode | null> {
|
_findNeedle(): FFAXNode | null {
|
||||||
throw new Error('Not implimented');
|
if (this._payload.foundObject)
|
||||||
|
return this;
|
||||||
|
for (const child of this._children) {
|
||||||
|
const found = child._findNeedle();
|
||||||
|
if (found)
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isLeafNode(): boolean {
|
isLeafNode(): boolean {
|
||||||
|
|
|
||||||
|
|
@ -355,8 +355,8 @@ export class FFPage implements PageDelegate {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccessibilityTree() : Promise<accessibility.AXNode> {
|
async getAccessibilityTree(needle?: dom.ElementHandle) {
|
||||||
return getAccessibilityTree(this._session);
|
return getAccessibilityTree(this._session, needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
coverage(): Coverage | undefined {
|
coverage(): Coverage | undefined {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export interface PageDelegate {
|
||||||
setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void>;
|
setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void>;
|
||||||
getBoundingBox(handle: dom.ElementHandle): Promise<types.Rect | null>;
|
getBoundingBox(handle: dom.ElementHandle): Promise<types.Rect | null>;
|
||||||
|
|
||||||
getAccessibilityTree(): Promise<accessibility.AXNode>;
|
getAccessibilityTree(needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}>;
|
||||||
pdf?: (options?: types.PDFOptions) => Promise<platform.BufferType>;
|
pdf?: (options?: types.PDFOptions) => Promise<platform.BufferType>;
|
||||||
coverage(): Coverage | undefined;
|
coverage(): Coverage | undefined;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,16 @@
|
||||||
import * as accessibility from '../accessibility';
|
import * as accessibility from '../accessibility';
|
||||||
import { WKSession } from './wkConnection';
|
import { WKSession } from './wkConnection';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
|
import * as dom from '../dom';
|
||||||
|
|
||||||
export async function getAccessibilityTree(session: WKSession) {
|
export async function getAccessibilityTree(session: WKSession, needle?: dom.ElementHandle) {
|
||||||
const {axNode} = await session.send('Page.accessibilitySnapshot');
|
const objectId = needle ? needle._remoteObject.objectId : undefined;
|
||||||
return new WKAXNode(axNode);
|
const {axNode} = await session.send('Page.accessibilitySnapshot', { objectId });
|
||||||
|
const tree = new WKAXNode(axNode);
|
||||||
|
return {
|
||||||
|
tree,
|
||||||
|
needle: needle && tree._findNeedle()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class WKAXNode implements accessibility.AXNode {
|
class WKAXNode implements accessibility.AXNode {
|
||||||
|
|
@ -38,7 +44,14 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
return this._children;
|
return this._children;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findElement() {
|
_findNeedle() : WKAXNode {
|
||||||
|
if (this._payload.found)
|
||||||
|
return this;
|
||||||
|
for (const child of this._children) {
|
||||||
|
const found = child._findNeedle()
|
||||||
|
if (found)
|
||||||
|
return found;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -497,8 +497,8 @@ export class WKPage implements PageDelegate {
|
||||||
return to._createHandle(result.object) as dom.ElementHandle<T>;
|
return to._createHandle(result.object) as dom.ElementHandle<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccessibilityTree() : Promise<accessibility.AXNode> {
|
async getAccessibilityTree(needle?: dom.ElementHandle) : Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}> {
|
||||||
return getAccessibilityTree(this._session);
|
return getAccessibilityTree(this._session, needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
coverage(): Coverage | undefined {
|
coverage(): Coverage | undefined {
|
||||||
|
|
|
||||||
|
|
@ -363,8 +363,8 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||||
expect(snapshot.children[0]).toEqual(golden);
|
expect(snapshot.children[0]).toEqual(golden);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.skip(FFOX || WEBKIT)('root option', function() {
|
describe('root option', function() {
|
||||||
it('should work a button', async({page}) => {
|
fit('should work a button', async({page}) => {
|
||||||
await page.setContent(`<button>My Button</button>`);
|
await page.setContent(`<button>My Button</button>`);
|
||||||
|
|
||||||
const button = await page.$('button');
|
const button = await page.$('button');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue