Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): bring selector generator into playwright #4795

Merged
merged 1 commit into from Dec 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions docs-src/api-body.md
Expand Up @@ -4639,12 +4639,6 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk
(async () => {
// Must be a function that evaluates to a selector engine instance.
const createTagNameEngine = () => ({
// Creates a selector that matches given target when queried at the root.
dgozman marked this conversation as resolved.
Show resolved Hide resolved
// Can return undefined if unable to create one.
create(root, target) {
return root.querySelector(target.tagName) === target ? target.tagName : undefined;
},

// Returns the first element matching given selector in the root's subtree.
query(root, selector) {
return root.querySelector(selector);
Expand Down
6 changes: 0 additions & 6 deletions docs/api.md
Expand Up @@ -4224,12 +4224,6 @@ const { selectors, firefox } = require('playwright'); // Or 'chromium' or 'webk
(async () => {
// Must be a function that evaluates to a selector engine instance.
const createTagNameEngine = () => ({
// Creates a selector that matches given target when queried at the root.
// Can return undefined if unable to create one.
create(root, target) {
return root.querySelector(target.tagName) === target ? target.tagName : undefined;
},

// Returns the first element matching given selector in the root's subtree.
query(root, selector) {
return root.querySelector(selector);
Expand Down
6 changes: 0 additions & 6 deletions docs/extensibility.md
Expand Up @@ -20,12 +20,6 @@ An example of registering selector engine that queries elements based on a tag n
```js
// Must be a function that evaluates to a selector engine instance.
const createTagNameEngine = () => ({
// Creates a selector that matches given target when queried at the root.
// Can return undefined if unable to create one.
create(root, target) {
return root.querySelector(target.tagName) === target ? target.tagName : undefined;
},

// Returns the first element matching given selector in the root's subtree.
query(root, selector) {
return root.querySelector(selector);
Expand Down
5 changes: 0 additions & 5 deletions src/client/types.ts
Expand Up @@ -100,11 +100,6 @@ export type LaunchServerOptions = {
} & FirefoxUserPrefs;

export type SelectorEngine = {
/**
* Creates a selector that matches given target when queried at the root.
* Can return undefined if unable to create one.
*/
create(root: HTMLElement, target: HTMLElement): string | undefined;
/**
* Returns the first element matching given selector in the root's subtree.
*/
Expand Down
34 changes: 19 additions & 15 deletions src/debug/debugController.ts
Expand Up @@ -25,23 +25,27 @@ export function installDebugController() {
}

class DebugController implements ContextListener {
private async ensureInstalledInFrame(frame: frames.Frame) {
try {
await frame.extendInjectedScript(debugScriptSource.source);
} catch (e) {
}
}

async onContextCreated(context: BrowserContext): Promise<void> {
if (!isDebugMode())
return;
context.on(BrowserContext.Events.Page, (page: Page) => {
for (const frame of page.frames())
this.ensureInstalledInFrame(frame);
page.on(Page.Events.FrameNavigated, frame => this.ensureInstalledInFrame(frame));
});
if (isDebugMode())
installDebugControllerInContext(context);
}

async onContextWillDestroy(context: BrowserContext): Promise<void> {}
async onContextDidDestroy(context: BrowserContext): Promise<void> {}
}

async function ensureInstalledInFrame(frame: frames.Frame) {
try {
await frame.extendInjectedScript(debugScriptSource.source);
} catch (e) {
}
}

async function installInPage(page: Page) {
page.on(Page.Events.FrameNavigated, ensureInstalledInFrame);
dgozman marked this conversation as resolved.
Show resolved Hide resolved
await Promise.all(page.frames().map(ensureInstalledInFrame));
}

export async function installDebugControllerInContext(context: BrowserContext) {
context.on(BrowserContext.Events.Page, installInPage);
await Promise.all(context.pages().map(installInPage));
}
14 changes: 11 additions & 3 deletions src/debug/injected/consoleApi.ts
Expand Up @@ -15,6 +15,7 @@
*/

import type InjectedScript from '../../server/injected/injectedScript';
import { generateSelector } from './selectorGenerator';

export class ConsoleAPI {
private _injectedScript: InjectedScript;
Expand All @@ -25,28 +26,35 @@ export class ConsoleAPI {
$: (selector: string) => this._querySelector(selector),
$$: (selector: string) => this._querySelectorAll(selector),
inspect: (selector: string) => this._inspect(selector),
selector: (element: Element) => this._selector(element),
};
}

_querySelector(selector: string): (Element | undefined) {
private _querySelector(selector: string): (Element | undefined) {
if (typeof selector !== 'string')
throw new Error(`Usage: playwright.query('Playwright >> selector').`);
const parsed = this._injectedScript.parseSelector(selector);
return this._injectedScript.querySelector(parsed, document);
}

_querySelectorAll(selector: string): Element[] {
private _querySelectorAll(selector: string): Element[] {
if (typeof selector !== 'string')
throw new Error(`Usage: playwright.$$('Playwright >> selector').`);
const parsed = this._injectedScript.parseSelector(selector);
return this._injectedScript.querySelectorAll(parsed, document);
}

_inspect(selector: string) {
private _inspect(selector: string) {
if (typeof (window as any).inspect !== 'function')
return;
if (typeof selector !== 'string')
throw new Error(`Usage: playwright.inspect('Playwright >> selector').`);
(window as any).inspect(this._querySelector(selector));
}

private _selector(element: Element) {
if (!(element instanceof Element))
throw new Error(`Usage: playwright.selector(element).`);
return generateSelector(this._injectedScript, element).selector;
}
}