chore: implement ARIA queries in BiDi (#11999)

This commit is contained in:
jrandolf 2024-02-26 14:09:37 +01:00 committed by GitHub
parent 53cf9ce5d7
commit 414f43388b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 75 additions and 73 deletions

View File

@ -36,6 +36,10 @@ export interface Commands extends BidiCommands {
params: Bidi.Cdp.GetSessionParameters; params: Bidi.Cdp.GetSessionParameters;
returnType: Bidi.Cdp.GetSessionResult; returnType: Bidi.Cdp.GetSessionResult;
}; };
'cdp.resolveRealm': {
params: Bidi.Cdp.ResolveRealmParameters;
returnType: Bidi.Cdp.ResolveRealmResult;
};
} }
/** /**

View File

@ -428,7 +428,7 @@ export class BidiFrame extends Frame {
selector: Selector, selector: Selector,
options?: WaitForSelectorOptions options?: WaitForSelectorOptions
): Promise<ElementHandle<NodeFor<Selector>> | null> { ): Promise<ElementHandle<NodeFor<Selector>> | null> {
if (selector.startsWith('aria')) { if (selector.startsWith('aria') && !this.page().browser().cdpSupported) {
throw new UnsupportedOperation( throw new UnsupportedOperation(
'ARIA selector is not supported for BiDi!' 'ARIA selector is not supported for BiDi!'
); );

View File

@ -7,6 +7,7 @@ import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import type {JSHandle} from '../api/JSHandle.js'; import type {JSHandle} from '../api/JSHandle.js';
import {Realm} from '../api/Realm.js'; import {Realm} from '../api/Realm.js';
import {ARIAQueryHandler} from '../cdp/AriaQueryHandler.js';
import {LazyArg} from '../common/LazyArg.js'; import {LazyArg} from '../common/LazyArg.js';
import {scriptInjector} from '../common/ScriptInjector.js'; import {scriptInjector} from '../common/ScriptInjector.js';
import type {TimeoutSettings} from '../common/TimeoutSettings.js'; import type {TimeoutSettings} from '../common/TimeoutSettings.js';
@ -20,6 +21,7 @@ import {
SOURCE_URL_REGEX, SOURCE_URL_REGEX,
} from '../common/util.js'; } from '../common/util.js';
import type PuppeteerUtil from '../injected/injected.js'; import type PuppeteerUtil from '../injected/injected.js';
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
import {stringifyFunction} from '../util/Function.js'; import {stringifyFunction} from '../util/Function.js';
import type { import type {
@ -30,6 +32,7 @@ import type {
import type {WindowRealm} from './core/Realm.js'; import type {WindowRealm} from './core/Realm.js';
import {BidiDeserializer} from './Deserializer.js'; import {BidiDeserializer} from './Deserializer.js';
import {BidiElementHandle} from './ElementHandle.js'; import {BidiElementHandle} from './ElementHandle.js';
import {ExposeableFunction} from './ExposedFunction.js';
import type {BidiFrame} from './Frame.js'; import type {BidiFrame} from './Frame.js';
import {BidiJSHandle} from './JSHandle.js'; import {BidiJSHandle} from './JSHandle.js';
import {BidiSerializer} from './Serializer.js'; import {BidiSerializer} from './Serializer.js';
@ -277,12 +280,49 @@ export class BidiFrameRealm extends BidiRealm {
} }
#initialize() { #initialize() {
super.initialize();
// This should run first. // This should run first.
this.realm.on('updated', () => { this.realm.on('updated', () => {
this.environment.clearDocumentHandle(); this.environment.clearDocumentHandle();
this.#bindingsInstalled = false;
}); });
}
super.initialize(); #bindingsInstalled = false;
override get puppeteerUtil(): Promise<BidiJSHandle<PuppeteerUtil>> {
let promise = Promise.resolve() as Promise<unknown>;
if (!this.#bindingsInstalled) {
promise = Promise.all([
ExposeableFunction.from(
this.environment as BidiFrame,
'__ariaQuerySelector',
ARIAQueryHandler.queryOne,
!!this.sandbox
),
ExposeableFunction.from(
this.environment as BidiFrame,
'__ariaQuerySelectorAll',
async (
element: BidiElementHandle<Node>,
selector: string
): Promise<JSHandle<Node[]>> => {
const results = ARIAQueryHandler.queryAll(element, selector);
return await element.realm.evaluateHandle(
(...elements) => {
return elements;
},
...(await AsyncIterableUtil.collect(results))
);
},
!!this.sandbox
),
]);
this.#bindingsInstalled = true;
}
return promise.then(() => {
return super.puppeteerUtil;
});
} }
get sandbox(): string | undefined { get sandbox(): string | undefined {
@ -298,14 +338,19 @@ export class BidiFrameRealm extends BidiRealm {
): Promise<JSHandle<Node>> { ): Promise<JSHandle<Node>> {
const {object} = await this.#frame.client.send('DOM.resolveNode', { const {object} = await this.#frame.client.send('DOM.resolveNode', {
backendNodeId, backendNodeId,
executionContextId: await this.realm.resolveExecutionContextId(),
}); });
return BidiElementHandle.from( using handle = BidiElementHandle.from(
{ {
handle: object.objectId, handle: object.objectId,
type: 'node', type: 'node',
}, },
this this
); );
// We need the sharedId, so we perform the following to obtain it.
return await handle.evaluateHandle(element => {
return element;
});
} }
} }

View File

@ -9,6 +9,7 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import {EventEmitter} from '../../common/EventEmitter.js'; import {EventEmitter} from '../../common/EventEmitter.js';
import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js'; import {inertIfDisposed, throwIfDisposed} from '../../util/decorators.js';
import {DisposableStack, disposeSymbol} from '../../util/disposable.js'; import {DisposableStack, disposeSymbol} from '../../util/disposable.js';
import type {BidiConnection} from '../Connection.js';
import type {Browser} from './Browser.js'; import type {Browser} from './Browser.js';
import type {BrowsingContext} from './BrowsingContext.js'; import type {BrowsingContext} from './BrowsingContext.js';
@ -121,6 +122,18 @@ export abstract class Realm extends EventEmitter<{
return result; return result;
} }
@throwIfDisposed<Realm>(realm => {
// SAFETY: Disposal implies this exists.
return realm.#reason!;
})
async resolveExecutionContextId(): Promise<number> {
const {result} = await (this.session.connection as BidiConnection).send(
'cdp.resolveRealm',
{realm: this.id}
);
return result.executionContextId;
}
[disposeSymbol](): void { [disposeSymbol](): void {
this.#reason ??= this.#reason ??=
'Realm already destroyed, probably because all associated browsing contexts closed.'; 'Realm already destroyed, probably because all associated browsing contexts closed.';

View File

@ -1,8 +1,8 @@
[ [
{ {
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) *", "testIdPattern": "[ariaqueryhandler.spec] *",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["firefox"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{ {
@ -180,37 +180,13 @@
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{ {
"testIdPattern": "[ariaqueryhandler.spec] *", "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"button\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[ariaqueryhandler.spec] *",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have an error message specifically for awaiting an element to be hidden",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["webDriverBiDi"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{ {
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should have correct stack trace for timeout", "testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"heading\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should respect timeout",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler waitForSelector (aria) should throw when frame is detached",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["webDriverBiDi"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
@ -725,25 +701,25 @@
{ {
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors", "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["firefox"],
"expectations": ["FAIL"] "expectations": ["SKIP"]
}, },
{ {
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role", "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["firefox"],
"expectations": ["FAIL"] "expectations": ["SKIP"]
}, },
{ {
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role", "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["firefox"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{ {
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds", "testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"], "parameters": ["firefox"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{ {
@ -844,18 +820,6 @@
"parameters": ["chrome", "webDriverBiDi"], "parameters": ["chrome", "webDriverBiDi"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"button\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[ariaqueryhandler.spec] AriaQueryHandler queryOne (Chromium web test) should find by role \"heading\"",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{ {
"testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker", "testIdPattern": "[bfcache.spec] BFCache can navigate to a BFCached page containing an OOPIF and a worker",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],
@ -3003,30 +2967,6 @@
"parameters": ["firefox", "webDriverBiDi"], "parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"] "expectations": ["FAIL"]
}, },
{
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with name and role",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work ARIA selectors with role",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[queryhandler.spec] Query handler tests P selectors should work for ARIA selectors in multiple isolated worlds",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["SKIP"]
},
{ {
"testIdPattern": "[queryObjects.spec] page.queryObjects should fail for disposed handles", "testIdPattern": "[queryObjects.spec] page.queryObjects should fail for disposed handles",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],