Skip to content

Commit

Permalink
feat(pause): make page.pause public
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Feb 3, 2021
1 parent a8425d3 commit 9bbd432
Show file tree
Hide file tree
Showing 20 changed files with 137 additions and 123 deletions.
13 changes: 13 additions & 0 deletions docs/src/api/class-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,19 @@ The page's main frame. Page is guaranteed to have a main frame which persists du

Returns the opener for popup pages and `null` for others. If the opener has been closed already the returns `null`.

## async method: Page.pause

Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume'
button in the page overlay or to call `playwright.resume()` in the DevTools console.

User can inspect selectors or perform manual steps while paused. Resume will continue running the original script from
the place it was paused.

:::note
This method requires Playwright to be started in a headed mode, with a falsy [`options: headless`] value in
the [`method: BrowserType.launch`].
:::

## async method: Page.pdf
- returns: <[Buffer]>

Expand Down
25 changes: 19 additions & 6 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ program
.command('open [url]')
.description('open page in browser specified via -b, --browser')
.action(function(url, command) {
open(command.parent, url);
open(command.parent, url, language());
}).on('--help', function() {
console.log('');
console.log('Examples:');
Expand All @@ -70,8 +70,9 @@ for (const {alias, name, type} of browsers) {
program
.command(`${alias} [url]`)
.description(`open page in ${name}`)
.option('--target <language>', `language to use, one of javascript, python, python-async, csharp`, language())
.action(function(url, command) {
open({ ...command.parent, browser: type }, url);
open({ ...command.parent, browser: type }, url, command.target);
}).on('--help', function() {
console.log('');
console.log('Examples:');
Expand All @@ -84,7 +85,7 @@ program
.command('codegen [url]')
.description('open page and generate code for user actions')
.option('-o, --output <file name>', 'saves the generated script to a file')
.option('--target <language>', `language to use, one of javascript, python, python-async, csharp`, process.env.PW_CLI_TARGET_LANG || 'javascript')
.option('--target <language>', `language to use, one of javascript, python, python-async, csharp`, language())
.action(function(url, command) {
codegen(command.parent, url, command.target, command.output);
}).on('--help', function() {
Expand Down Expand Up @@ -316,9 +317,16 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi
return page;
}

async function open(options: Options, url: string | undefined) {
const { context } = await launchContext(options, false);
await context._enableConsoleApi();
async function open(options: Options, url: string | undefined, language: string) {
const { context, launchOptions, contextOptions } = await launchContext(options, false);
await context._enableRecorder({
language,
launchOptions,
contextOptions,
device: options.device,
saveStorage: options.saveStorage,
terminal: !!process.stdout.columns,
});
await openPage(context, url);
if (process.env.PWCLI_EXIT_FOR_TEST)
await Promise.all(context.pages().map(p => p.close()));
Expand All @@ -334,6 +342,7 @@ async function codegen(options: Options, url: string | undefined, language: stri
contextOptions,
device: options.device,
saveStorage: options.saveStorage,
startRecording: true,
terminal: !!process.stdout.columns,
outputFile: outputFile ? path.resolve(outputFile) : undefined
});
Expand Down Expand Up @@ -409,3 +418,7 @@ function validateOptions(options: Options) {
process.exit(0);
}
}

function language(): string {
return process.env.PW_CLI_TARGET_LANG || 'javascript';
}
5 changes: 1 addition & 4 deletions src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,16 +276,13 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel,
});
}

async _enableConsoleApi() {
await this._channel.consoleSupplementExpose();
}

async _enableRecorder(params: {
language: string,
launchOptions?: LaunchOptions,
contextOptions?: BrowserContextOptions,
device?: string,
saveStorage?: string,
startRecording?: boolean,
terminal?: boolean,
outputFile?: string
}) {
Expand Down
2 changes: 1 addition & 1 deletion src/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ export class Page extends ChannelOwner<channels.PageChannel, channels.PageInitia
return this;
}

async _pause() {
async pause() {
await this.context()._pause();
}

Expand Down
10 changes: 2 additions & 8 deletions src/dispatchers/browserContextDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
import { CRBrowserContext } from '../server/chromium/crBrowser';
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { RecorderSupplement } from '../server/supplements/recorderSupplement';
import { ConsoleApiSupplement } from '../server/supplements/consoleApiSupplement';

export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channels.BrowserContextInitializer> implements channels.BrowserContextChannel {
private _context: BrowserContext;
Expand Down Expand Up @@ -129,19 +128,14 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
await this._context.close();
}

async consoleSupplementExpose(): Promise<void> {
const consoleApi = new ConsoleApiSupplement(this._context);
await consoleApi.install();
}

async recorderSupplementEnable(params: channels.BrowserContextRecorderSupplementEnableParams): Promise<void> {
await RecorderSupplement.getOrCreate(this._context, 'codegen', params);
await RecorderSupplement.getOrCreate(this._context, params);
}

async pause() {
if (!this._context._browser.options.headful)
return;
const recorder = await RecorderSupplement.getOrCreate(this._context, 'pause', {
const recorder = await RecorderSupplement.getOrCreate(this._context, {
language: 'javascript',
terminal: true
});
Expand Down
6 changes: 2 additions & 4 deletions src/protocol/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,6 @@ export interface BrowserContextChannel extends Channel {
setNetworkInterceptionEnabled(params: BrowserContextSetNetworkInterceptionEnabledParams, metadata?: Metadata): Promise<BrowserContextSetNetworkInterceptionEnabledResult>;
setOffline(params: BrowserContextSetOfflineParams, metadata?: Metadata): Promise<BrowserContextSetOfflineResult>;
storageState(params?: BrowserContextStorageStateParams, metadata?: Metadata): Promise<BrowserContextStorageStateResult>;
consoleSupplementExpose(params?: BrowserContextConsoleSupplementExposeParams, metadata?: Metadata): Promise<BrowserContextConsoleSupplementExposeResult>;
pause(params?: BrowserContextPauseParams, metadata?: Metadata): Promise<BrowserContextPauseResult>;
recorderSupplementEnable(params: BrowserContextRecorderSupplementEnableParams, metadata?: Metadata): Promise<BrowserContextRecorderSupplementEnableResult>;
crNewCDPSession(params: BrowserContextCrNewCDPSessionParams, metadata?: Metadata): Promise<BrowserContextCrNewCDPSessionResult>;
Expand Down Expand Up @@ -709,14 +708,12 @@ export type BrowserContextStorageStateResult = {
cookies: NetworkCookie[],
origins: OriginStorage[],
};
export type BrowserContextConsoleSupplementExposeParams = {};
export type BrowserContextConsoleSupplementExposeOptions = {};
export type BrowserContextConsoleSupplementExposeResult = void;
export type BrowserContextPauseParams = {};
export type BrowserContextPauseOptions = {};
export type BrowserContextPauseResult = void;
export type BrowserContextRecorderSupplementEnableParams = {
language: string,
startRecording?: boolean,
launchOptions?: any,
contextOptions?: any,
device?: string,
Expand All @@ -725,6 +722,7 @@ export type BrowserContextRecorderSupplementEnableParams = {
outputFile?: string,
};
export type BrowserContextRecorderSupplementEnableOptions = {
startRecording?: boolean,
launchOptions?: any,
contextOptions?: any,
device?: string,
Expand Down
4 changes: 1 addition & 3 deletions src/protocol/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -601,16 +601,14 @@ BrowserContext:
type: array
items: OriginStorage

consoleSupplementExpose:
experimental: True

pause:
experimental: True

recorderSupplementEnable:
experimental: True
parameters:
language: string
startRecording: boolean?
launchOptions: json?
contextOptions: json?
device: string?
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,10 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
offline: tBoolean,
});
scheme.BrowserContextStorageStateParams = tOptional(tObject({}));
scheme.BrowserContextConsoleSupplementExposeParams = tOptional(tObject({}));
scheme.BrowserContextPauseParams = tOptional(tObject({}));
scheme.BrowserContextRecorderSupplementEnableParams = tObject({
language: tString,
startRecording: tOptional(tBoolean),
launchOptions: tOptional(tAny),
contextOptions: tOptional(tAny),
device: tOptional(tString),
Expand Down
30 changes: 0 additions & 30 deletions src/server/supplements/consoleApiSupplement.ts

This file was deleted.

29 changes: 24 additions & 5 deletions src/server/supplements/injected/consoleApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,35 @@
import type InjectedScript from '../../injected/injectedScript';
import { generateSelector } from './selectorGenerator';

type ConsoleAPIInterface = {
$: (selector: string) => void;
$$: (selector: string) => void;
inspect: (selector: string) => void;
selector: (element: Element) => void;
resume: () => void;
};

declare global {
interface Window {
playwright?: ConsoleAPIInterface;
inspect: (element: Element | undefined) => void;
_playwrightResume: () => Promise<void>;
}
}

export class ConsoleAPI {
private _injectedScript: InjectedScript;

constructor(injectedScript: InjectedScript) {
this._injectedScript = injectedScript;
if ((window as any).playwright)
if (window.playwright)
return;
(window as any).playwright = {
window.playwright = {
$: (selector: string) => this._querySelector(selector),
$$: (selector: string) => this._querySelectorAll(selector),
inspect: (selector: string) => this._inspect(selector),
selector: (element: Element) => this._selector(element),
resume: () => this._resume(),
};
}

Expand All @@ -47,18 +64,20 @@ export class ConsoleAPI {
}

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));
window.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;
}

private _resume() {
window._playwrightResume().catch(() => {});
}
}

export default ConsoleAPI;

0 comments on commit 9bbd432

Please sign in to comment.