basic root accessibility stuff

This commit is contained in:
Joel Einbinder 2020-01-10 13:15:03 -08:00 committed by Joel Einbinder
parent 92bd854d8f
commit f2d3ac68ae
9 changed files with 56 additions and 33 deletions

View file

@ -55,13 +55,12 @@ export interface AXNode {
isLeafNode(): boolean;
isControl(): boolean;
serialize(): SerializedAXNode;
findElement(element: dom.ElementHandle): Promise<AXNode|null>;
children(): Iterable<AXNode>;
}
export class Accessibility {
private _getAXTree: () => Promise<AXNode>;
constructor(getAXTree: () => Promise<AXNode>) {
private _getAXTree: (needle?: dom.ElementHandle) => Promise<{tree: AXNode, needle?: AXNode}>;
constructor(getAXTree: (needle?: dom.ElementHandle) => Promise<{tree: AXNode, needle?: AXNode}>) {
this._getAXTree = getAXTree;
}
@ -73,18 +72,12 @@ export class Accessibility {
interestingOnly = true,
root = null,
} = options;
const defaultRoot = await this._getAXTree();
let needle: AXNode | null = defaultRoot;
if (root) {
needle = await defaultRoot.findElement(root);
if (!needle)
return null;
}
const {tree, needle} = await this._getAXTree(root);
if (!interestingOnly)
return serializeTree(needle)[0];
const interestingNodes: Set<AXNode> = new Set();
collectInterestingNodes(interestingNodes, defaultRoot, false);
collectInterestingNodes(interestingNodes, tree, false);
if (root && !interestingNodes.has(needle))
return null;
return serializeTree(needle, interestingNodes)[0];

View file

@ -20,9 +20,13 @@ import { Protocol } from './protocol';
import * as dom from '../dom';
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');
return CRAXNode.createTree(client, nodes);
const tree = CRAXNode.createTree(client, nodes);
return {
tree,
needle: needle && await tree._findElement(needle)
};
}
class CRAXNode implements accessibility.AXNode {
@ -90,7 +94,7 @@ class CRAXNode implements accessibility.AXNode {
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 {node: {backendNodeId}} = await this._client.send('DOM.describeNode', {objectId: remoteObject.objectId});
const needle = this.find(node => node._payload.backendDOMNodeId === backendNodeId);

View file

@ -480,8 +480,8 @@ export class CRPage implements PageDelegate {
return to._createHandle(result.object).asElement()!;
}
async getAccessibilityTree(): Promise<accessibility.AXNode> {
return getAccessibilityTree(this._client);
async getAccessibilityTree(needle?: dom.ElementHandle) {
return getAccessibilityTree(this._client, needle);
}
async pdf(options?: types.PDFOptions): Promise<platform.BufferType> {

View file

@ -18,15 +18,21 @@
import * as accessibility from '../accessibility';
import { FFSession } from './ffConnection';
import { Protocol } from './protocol';
import * as dom from '../dom';
export async function getAccessibilityTree(session: FFSession) : Promise<accessibility.AXNode> {
const { tree } = await session.send('Accessibility.getFullAXTree');
return new FFAXNode(tree);
export async function getAccessibilityTree(session: FFSession, needle: dom.ElementHandle) : Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}> {
const objectId = needle ? needle._remoteObject.objectId : undefined;
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 {
_children: FFAXNode[];
private _payload: any;
private _payload: Protocol.AXTree;
private _editable: boolean;
private _richlyEditable: boolean;
private _focusable: boolean;
@ -77,8 +83,15 @@ class FFAXNode implements accessibility.AXNode {
return this._children;
}
async findElement(): Promise<FFAXNode | null> {
throw new Error('Not implimented');
_findNeedle(): FFAXNode | null {
if (this._payload.foundObject)
return this;
for (const child of this._children) {
const found = child._findNeedle();
if (found)
return found;
}
return null;
}
isLeafNode(): boolean {

View file

@ -355,8 +355,8 @@ export class FFPage implements PageDelegate {
return handle;
}
async getAccessibilityTree() : Promise<accessibility.AXNode> {
return getAccessibilityTree(this._session);
async getAccessibilityTree(needle?: dom.ElementHandle) {
return getAccessibilityTree(this._session, needle);
}
coverage(): Coverage | undefined {

View file

@ -68,7 +68,7 @@ export interface PageDelegate {
setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void>;
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>;
coverage(): Coverage | undefined;
}

View file

@ -16,10 +16,16 @@
import * as accessibility from '../accessibility';
import { WKSession } from './wkConnection';
import { Protocol } from './protocol';
import * as dom from '../dom';
export async function getAccessibilityTree(session: WKSession) {
const {axNode} = await session.send('Page.accessibilitySnapshot');
return new WKAXNode(axNode);
export async function getAccessibilityTree(session: WKSession, needle?: dom.ElementHandle) {
const objectId = needle ? needle._remoteObject.objectId : undefined;
const {axNode} = await session.send('Page.accessibilitySnapshot', { objectId });
const tree = new WKAXNode(axNode);
return {
tree,
needle: needle && tree._findNeedle()
};
}
class WKAXNode implements accessibility.AXNode {
@ -38,7 +44,14 @@ class WKAXNode implements accessibility.AXNode {
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;
}

View file

@ -497,8 +497,8 @@ export class WKPage implements PageDelegate {
return to._createHandle(result.object) as dom.ElementHandle<T>;
}
async getAccessibilityTree() : Promise<accessibility.AXNode> {
return getAccessibilityTree(this._session);
async getAccessibilityTree(needle?: dom.ElementHandle) : Promise<{tree: accessibility.AXNode, needle?: accessibility.AXNode}> {
return getAccessibilityTree(this._session, needle);
}
coverage(): Coverage | undefined {

View file

@ -363,8 +363,8 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
expect(snapshot.children[0]).toEqual(golden);
});
describe.skip(FFOX || WEBKIT)('root option', function() {
it('should work a button', async({page}) => {
describe('root option', function() {
fit('should work a button', async({page}) => {
await page.setContent(`<button>My Button</button>`);
const button = await page.$('button');