From edb03d695b194a900055be348f7409ac9403c23c Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Wed, 7 Jun 2023 13:54:09 +0200 Subject: [PATCH] chore: add a11y to bidi over bidi+ (#10338) --- .../src/common/Accessibility.ts | 21 ++++++++-------- packages/puppeteer-core/src/common/Page.ts | 11 ++++++++- .../src/common/bidi/BrowsingContext.ts | 14 +++++------ .../puppeteer-core/src/common/bidi/Page.ts | 22 ++++++++++++++++- test/TestExpectations.json | 24 +++++++++++++++++++ 5 files changed, 73 insertions(+), 19 deletions(-) diff --git a/packages/puppeteer-core/src/common/Accessibility.ts b/packages/puppeteer-core/src/common/Accessibility.ts index 1429ecf6072..4f3ddee87ad 100644 --- a/packages/puppeteer-core/src/common/Accessibility.ts +++ b/packages/puppeteer-core/src/common/Accessibility.ts @@ -18,8 +18,6 @@ import {Protocol} from 'devtools-protocol'; import {ElementHandle} from '../api/ElementHandle.js'; -import {CDPSession} from './Connection.js'; - /** * Represents a Node and the properties of it that are relevant to Accessibility. * @public @@ -109,6 +107,11 @@ export interface SnapshotOptions { root?: ElementHandle; } +interface DataProvider { + getFullAXTree(): Promise; + describeNode(id: string): Promise; +} + /** * The Accessibility class provides methods for inspecting the browser's * accessibility tree. The accessibility tree is used by assistive technology @@ -132,13 +135,13 @@ export interface SnapshotOptions { * @public */ export class Accessibility { - #client: CDPSession; + #dataProvider: DataProvider; /** * @internal */ - constructor(client: CDPSession) { - this.#client = client; + constructor(dataProvider: DataProvider) { + this.#dataProvider = dataProvider; } /** @@ -184,12 +187,10 @@ export class Accessibility { options: SnapshotOptions = {} ): Promise { const {interestingOnly = true, root = null} = options; - const {nodes} = await this.#client.send('Accessibility.getFullAXTree'); + const {nodes} = await this.#dataProvider.getFullAXTree(); let backendNodeId: number | undefined; - if (root) { - const {node} = await this.#client.send('DOM.describeNode', { - objectId: root.id, - }); + if (root && root.id) { + const {node} = await this.#dataProvider.describeNode(root.id); backendNodeId = node.backendNodeId; } const defaultRoot = AXNode.createTree(nodes); diff --git a/packages/puppeteer-core/src/common/Page.ts b/packages/puppeteer-core/src/common/Page.ts index cfc25294b66..ad943b852a3 100644 --- a/packages/puppeteer-core/src/common/Page.ts +++ b/packages/puppeteer-core/src/common/Page.ts @@ -167,7 +167,16 @@ export class CDPPage extends Page { this.#keyboard = new Keyboard(client); this.#mouse = new Mouse(client, this.#keyboard); this.#touchscreen = new Touchscreen(client, this.#keyboard); - this.#accessibility = new Accessibility(client); + this.#accessibility = new Accessibility({ + describeNode(id: string) { + return client.send('DOM.describeNode', { + objectId: id, + }); + }, + getFullAXTree() { + return client.send('Accessibility.getFullAXTree'); + }, + }); this.#frameManager = new FrameManager( client, this, diff --git a/packages/puppeteer-core/src/common/bidi/BrowsingContext.ts b/packages/puppeteer-core/src/common/bidi/BrowsingContext.ts index 34c98226213..08b54f67114 100644 --- a/packages/puppeteer-core/src/common/bidi/BrowsingContext.ts +++ b/packages/puppeteer-core/src/common/bidi/BrowsingContext.ts @@ -281,20 +281,20 @@ export class BrowsingContext extends EventEmitter { return await this.evaluate(getPageContent); } - async sendCDPCommand( - method: keyof ProtocolMapping.Commands, - params: object = {} - ): Promise { + async sendCDPCommand( + method: T, + params: ProtocolMapping.Commands[T]['paramsType'][0] = {} + ): Promise { const session = await this.connection.send('cdp.getSession', { context: this.#id, }); - // TODO: remove any once chromium-bidi types are updated. - const sessionId = (session.result as any).cdpSession; - return await this.connection.send('cdp.sendCommand', { + const sessionId = session.result.cdpSession; + const result = await this.connection.send('cdp.sendCommand', { cdpMethod: method, cdpParams: params, cdpSession: sessionId, }); + return result.result; } dispose(): void { diff --git a/packages/puppeteer-core/src/common/bidi/Page.ts b/packages/puppeteer-core/src/common/bidi/Page.ts index 9d9ea13b3df..4f711214fbe 100644 --- a/packages/puppeteer-core/src/common/bidi/Page.ts +++ b/packages/puppeteer-core/src/common/bidi/Page.ts @@ -26,6 +26,7 @@ import { } from '../../api/Page.js'; import {assert} from '../../util/assert.js'; import {Deferred} from '../../util/Deferred.js'; +import {Accessibility} from '../Accessibility.js'; import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js'; import {TargetCloseError} from '../Errors.js'; import {Handler} from '../EventEmitter.js'; @@ -58,6 +59,7 @@ import {BidiSerializer} from './Serializer.js'; * @internal */ export class Page extends PageBase { + #accessibility: Accessibility; #timeoutSettings = new TimeoutSettings(); #browserContext: BrowserContext; #connection: Connection; @@ -135,6 +137,24 @@ export class Page extends PageBase { for (const [event, subscriber] of this.#networkManagerEvents) { this.#networkManager.on(event, subscriber); } + + // TODO: https://github.com/w3c/webdriver-bidi/issues/443 + this.#accessibility = new Accessibility({ + describeNode: (id: string) => { + return this.mainFrame().context().sendCDPCommand('DOM.describeNode', { + objectId: id, + }); + }, + getFullAXTree: () => { + return this.mainFrame() + .context() + .sendCDPCommand('Accessibility.getFullAXTree'); + }, + }); + } + + override get accessibility(): Accessibility { + return this.#accessibility; } override browser(): Browser { @@ -374,7 +394,7 @@ export class Page extends PageBase { const width = viewport.width; const height = viewport.height; const deviceScaleFactor = 1; - const screenOrientation = {angle: 0, type: 'portraitPrimary'}; + const screenOrientation = {angle: 0, type: 'portraitPrimary' as const}; await this.mainFrame() .context() diff --git a/test/TestExpectations.json b/test/TestExpectations.json index a2331053176..c1fc654c998 100644 --- a/test/TestExpectations.json +++ b/test/TestExpectations.json @@ -209,6 +209,12 @@ "parameters": ["cdp", "firefox"], "expectations": ["SKIP", "TIMEOUT"] }, + { + "testIdPattern": "[accessibility.spec] *", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["PASS"] + }, { "testIdPattern": "[ariaqueryhandler.spec] *", "platforms": ["darwin", "linux", "win32"], @@ -2363,6 +2369,24 @@ "parameters": ["cdp", "firefox"], "expectations": ["SKIP"] }, + { + "testIdPattern": "[accessibility.spec] Accessibility get snapshots while the tree is re-calculated", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"] + }, + { + "testIdPattern": "[accessibility.spec] Accessibility should report uninteresting nodes", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"] + }, + { + "testIdPattern": "[accessibility.spec] Accessibility should work", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["FAIL"] + }, { "testIdPattern": "[CDPSession.spec] Target.createCDPSession should send events", "platforms": ["win32"],