Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/src/api/class-browsercontext.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ await context.AddCookiesAsync(new[] { cookie1, cookie2 });

## async method: BrowserContext.addInitScript
* since: v1.8
- returns: <[Disposable]>

Adds a script which would be evaluated in one of the following scenarios:
* Whenever a page is created in the browser context or is navigated.
Expand Down Expand Up @@ -584,6 +585,7 @@ Optional list of URLs.

## async method: BrowserContext.exposeBinding
* since: v1.8
- returns: <[Disposable]>

The method adds a function called [`param: name`] on the `window` object of every frame in every page in the context.
When called, the function executes [`param: callback`] and returns a [Promise] which resolves to the return value of
Expand Down Expand Up @@ -735,6 +737,7 @@ supported. When passing by value, multiple arguments are supported.

## async method: BrowserContext.exposeFunction
* since: v1.8
- returns: <[Disposable]>

The method adds a function called [`param: name`] on the `window` object of every frame in every page in the context.
When called, the function executes [`param: callback`] and returns a [Promise] which resolves to the return value of
Expand Down
12 changes: 12 additions & 0 deletions docs/src/api/class-disposable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# class: Disposable
* since: v1.59
* langs: js

[Disposable] is returned from various methods to allow undoing the corresponding action. For example,
[`method: Page.addInitScript`] returns a [Disposable] that can be used to remove the init script.

## async method: Disposable.dispose
* since: v1.59

Removes the associated resource. For example, removes the init script installed via
[`method: Page.addInitScript`] or [`method: BrowserContext.addInitScript`].
3 changes: 3 additions & 0 deletions docs/src/api/class-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ page.

## async method: Page.addInitScript
* since: v1.8
- returns: <[Disposable]>

Adds a script which would be evaluated in one of the following scenarios:
* Whenever the page is navigated.
Expand Down Expand Up @@ -1717,6 +1718,7 @@ Optional argument to pass to [`param: expression`].

## async method: Page.exposeBinding
* since: v1.8
- returns: <[Disposable]>

The method adds a function called [`param: name`] on the `window` object of every frame in this page. When called, the
function executes [`param: callback`] and returns a [Promise] which resolves to the return value of [`param: callback`].
Expand Down Expand Up @@ -1882,6 +1884,7 @@ supported. When passing by value, multiple arguments are supported.

## async method: Page.exposeFunction
* since: v1.8
- returns: <[Disposable]>

The method adds a function called [`param: name`] on the `window` object of every frame in the page. When called, the
function executes [`param: callback`] and returns a [Promise] which resolves to the return value of [`param: callback`].
Expand Down
33 changes: 25 additions & 8 deletions packages/playwright-client/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ export interface Page {
* [`script`](https://playwright.dev/docs/api/class-page#page-add-init-script-option-script) (only supported when
* passing a function).
*/
addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<void>;
addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<Disposable>;

/**
* **NOTE** Use locator-based [page.locator(selector[, options])](https://playwright.dev/docs/api/class-page#page-locator)
Expand Down Expand Up @@ -920,7 +920,7 @@ export interface Page {
* @param callback Callback function that will be called in the Playwright's context.
* @param options
*/
exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise<void>;
exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise<Disposable>;
/**
* The method adds a function called
* [`name`](https://playwright.dev/docs/api/class-page#page-expose-binding-option-name) on the `window` object of
Expand Down Expand Up @@ -972,7 +972,7 @@ export interface Page {
* @param callback Callback function that will be called in the Playwright's context.
* @param options
*/
exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise<void>;
exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise<Disposable>;

/**
* Removes all the listeners of the given type (or all registered listeners if no type given). Allows to wait for
Expand Down Expand Up @@ -2758,7 +2758,7 @@ export interface Page {
* @param name Name of the function on the window object
* @param callback Callback function which will be called in Playwright's context.
*/
exposeFunction(name: string, callback: Function): Promise<void>;
exposeFunction(name: string, callback: Function): Promise<Disposable>;

/**
* **NOTE** Use locator-based [locator.fill(value[, options])](https://playwright.dev/docs/api/class-locator#locator-fill)
Expand Down Expand Up @@ -8471,7 +8471,7 @@ export interface BrowserContext {
* @param callback Callback function that will be called in the Playwright's context.
* @param options
*/
exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise<void>;
exposeBinding(name: string, playwrightBinding: (source: BindingSource, arg: JSHandle) => any, options: { handle: true }): Promise<Disposable>;
/**
* The method adds a function called
* [`name`](https://playwright.dev/docs/api/class-browsercontext#browser-context-expose-binding-option-name) on the
Expand Down Expand Up @@ -8519,7 +8519,7 @@ export interface BrowserContext {
* @param callback Callback function that will be called in the Playwright's context.
* @param options
*/
exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise<void>;
exposeBinding(name: string, playwrightBinding: (source: BindingSource, ...args: any[]) => any, options?: { handle?: boolean }): Promise<Disposable>;

/**
* Adds a script which would be evaluated in one of the following scenarios:
Expand Down Expand Up @@ -8556,7 +8556,7 @@ export interface BrowserContext {
* [`script`](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script-option-script)
* (only supported when passing a function).
*/
addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<void>;
addInitScript<Arg>(script: PageFunction<Arg, any> | { path?: string, content?: string }, arg?: Arg): Promise<Disposable>;

/**
* Removes all the listeners of the given type (or all registered listeners if no type given). Allows to wait for
Expand Down Expand Up @@ -9345,7 +9345,7 @@ export interface BrowserContext {
* @param name Name of the function on the window object.
* @param callback Callback function that will be called in the Playwright's context.
*/
exposeFunction(name: string, callback: Function): Promise<void>;
exposeFunction(name: string, callback: Function): Promise<Disposable>;

/**
* Grants specified permissions to the browser context. Only grants corresponding permissions to the given origin if
Expand Down Expand Up @@ -19531,6 +19531,23 @@ export interface Dialog {
type(): string;
}

/**
* [Disposable](https://playwright.dev/docs/api/class-disposable) is returned from various methods to allow undoing
* the corresponding action. For example,
* [page.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-page#page-add-init-script) returns a
* [Disposable](https://playwright.dev/docs/api/class-disposable) that can be used to remove the init script.
*/
export interface Disposable {
/**
* Removes the associated resource. For example, removes the init script installed via
* [page.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-page#page-add-init-script) or
* [browserContext.addInitScript(script[, arg])](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script).
*/
dispose(): Promise<void>;

[Symbol.asyncDispose](): Promise<void>;
}

/**
* [Download](https://playwright.dev/docs/api/class-download) objects are dispatched by page via the
* [page.on('download')](https://playwright.dev/docs/api/class-page#page-event-download) event.
Expand Down
1 change: 1 addition & 0 deletions packages/playwright-core/src/client/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { Clock } from './clock';
export { ConsoleMessage } from './consoleMessage';
export { Coverage } from './coverage';
export { Dialog } from './dialog';
export { Disposable } from './disposable';
export { Download } from './download';
export { Electron, ElectronApplication } from './electron';
export { FrameLocator, Locator } from './locator';
Expand Down
15 changes: 9 additions & 6 deletions packages/playwright-core/src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { evaluationScript } from './clientHelper';
import { Clock } from './clock';
import { ConsoleMessage } from './consoleMessage';
import { Dialog } from './dialog';
import { Disposable } from './disposable';
import { TargetClosedError, parseError } from './errors';
import { Events } from './events';
import { APIRequestContext } from './fetch';
Expand Down Expand Up @@ -349,20 +350,22 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
}

async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any): Promise<void> {
async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await evaluationScript(this._platform, script, arg);
await this._channel.addInitScript({ source });
return Disposable.from((await this._channel.addInitScript({ source })).disposable);
}

async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the signature in the .md?

await this._channel.exposeBinding({ name, needsHandle: options.handle });
async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}): Promise<Disposable> {
const result = await this._channel.exposeBinding({ name, needsHandle: options.handle });
this._bindings.set(name, callback);
return Disposable.from(result.disposable);
}

async exposeFunction(name: string, callback: Function): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

await this._channel.exposeBinding({ name });
async exposeFunction(name: string, callback: Function): Promise<Disposable> {
const result = await this._channel.exposeBinding({ name });
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
this._bindings.set(name, binding);
return Disposable.from(result.disposable);
}

async route(url: URLMatch, handler: network.RouteHandlerCallback, options: { times?: number } = {}): Promise<void> {
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright-core/src/client/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { CDPSession } from './cdpSession';
import { ChannelOwner } from './channelOwner';
import { createInstrumentation } from './clientInstrumentation';
import { Dialog } from './dialog';
import { Disposable } from './disposable';
import { Electron, ElectronApplication } from './electron';
import { ElementHandle } from './elementHandle';
import { TargetClosedError, parseError } from './errors';
Expand Down Expand Up @@ -270,6 +271,9 @@ export class Connection extends EventEmitter {
case 'Dialog':
result = new Dialog(parent, type, guid, initializer);
break;
case 'Disposable':
result = new Disposable(parent, type, guid, initializer);
break;
case 'Electron':
result = new Electron(parent, type, guid, initializer);
break;
Expand Down
40 changes: 40 additions & 0 deletions packages/playwright-core/src/client/disposable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ChannelOwner } from './channelOwner';
import { isTargetClosedError } from './errors';

import type * as channels from '@protocol/channels';

export class Disposable<T extends channels.DisposableChannel = channels.DisposableChannel> extends ChannelOwner<T> {
static from(channel: channels.DisposableChannel): Disposable {
return (channel as any)._object;
}

async [Symbol.asyncDispose]() {
await this.dispose();
}

async dispose() {
try {
await this._channel.dispose();
} catch (e) {
if (isTargetClosedError(e))
return;
throw e;
}
}
}
9 changes: 6 additions & 3 deletions packages/playwright-core/src/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Artifact } from './artifact';
import { ChannelOwner } from './channelOwner';
import { evaluationScript } from './clientHelper';
import { Coverage } from './coverage';
import { Disposable } from './disposable';
import { Download } from './download';
import { ElementHandle, determineScreenshotType } from './elementHandle';
import { TargetClosedError, isTargetClosedError, parseError, serializeError } from './errors';
Expand Down Expand Up @@ -332,14 +333,16 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
}

async exposeFunction(name: string, callback: Function) {
await this._channel.exposeBinding({ name });
const result = await this._channel.exposeBinding({ name });
const binding = (source: structs.BindingSource, ...args: any[]) => callback(...args);
this._bindings.set(name, binding);
return Disposable.from(result.disposable);
}

async exposeBinding(name: string, callback: (source: structs.BindingSource, ...args: any[]) => any, options: { handle?: boolean } = {}) {
await this._channel.exposeBinding({ name, needsHandle: options.handle });
const result = await this._channel.exposeBinding({ name, needsHandle: options.handle });
this._bindings.set(name, callback);
return Disposable.from(result.disposable);
}

async setExtraHTTPHeaders(headers: Headers) {
Expand Down Expand Up @@ -507,7 +510,7 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page

async addInitScript(script: Function | string | { path?: string, content?: string }, arg?: any) {
const source = await evaluationScript(this._platform, script, arg);
await this._channel.addInitScript({ source });
return Disposable.from((await this._channel.addInitScript({ source })).disposable);
}

async route(url: URLMatch, handler: RouteHandlerCallback, options: { times?: number } = {}): Promise<void> {
Expand Down
19 changes: 15 additions & 4 deletions packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,9 @@ scheme.BrowserContextAddCookiesResult = tOptional(tObject({}));
scheme.BrowserContextAddInitScriptParams = tObject({
source: tString,
});
scheme.BrowserContextAddInitScriptResult = tOptional(tObject({}));
scheme.BrowserContextAddInitScriptResult = tObject({
disposable: tChannel(['Disposable']),
});
scheme.BrowserContextClearCookiesParams = tObject({
name: tOptional(tString),
nameRegexSource: tOptional(tString),
Expand Down Expand Up @@ -1016,7 +1018,9 @@ scheme.BrowserContextExposeBindingParams = tObject({
name: tString,
needsHandle: tOptional(tBoolean),
});
scheme.BrowserContextExposeBindingResult = tOptional(tObject({}));
scheme.BrowserContextExposeBindingResult = tObject({
disposable: tChannel(['Disposable']),
});
scheme.BrowserContextGrantPermissionsParams = tObject({
permissions: tArray(tString),
origin: tOptional(tString),
Expand Down Expand Up @@ -1242,7 +1246,9 @@ scheme.PageWorkerEvent = tObject({
scheme.PageAddInitScriptParams = tObject({
source: tString,
});
scheme.PageAddInitScriptResult = tOptional(tObject({}));
scheme.PageAddInitScriptResult = tObject({
disposable: tChannel(['Disposable']),
});
scheme.PageCloseParams = tObject({
runBeforeUnload: tOptional(tBoolean),
reason: tOptional(tString),
Expand Down Expand Up @@ -1276,7 +1282,9 @@ scheme.PageExposeBindingParams = tObject({
name: tString,
needsHandle: tOptional(tBoolean),
});
scheme.PageExposeBindingResult = tOptional(tObject({}));
scheme.PageExposeBindingResult = tObject({
disposable: tChannel(['Disposable']),
});
scheme.PageGoBackParams = tObject({
timeout: tFloat,
waitUntil: tOptional(tType('LifecycleEvent')),
Expand Down Expand Up @@ -2028,6 +2036,9 @@ scheme.WorkerUpdateSubscriptionParams = tObject({
enabled: tBoolean,
});
scheme.WorkerUpdateSubscriptionResult = tOptional(tObject({}));
scheme.DisposableInitializer = tOptional(tObject({}));
scheme.DisposableDisposeParams = tOptional(tObject({}));
scheme.DisposableDisposeResult = tOptional(tObject({}));
scheme.JSHandleInitializer = tObject({
preview: tString,
});
Expand Down
Loading
Loading