chore: remove bindings and init scripts upon client disconnect (#36064)
infra / docs & lint (push) Waiting to run
Details
infra / Lint snippets (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, macos-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, ubuntu-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, windows-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (20, ubuntu-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (22, ubuntu-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests others / WebView2 (push) Waiting to run
Details
tests others / time library - ${{ matrix.clock }} (frozen) (push) Waiting to run
Details
tests others / time library - ${{ matrix.clock }} (realtime) (push) Waiting to run
Details
tests others / time test runner - ${{ matrix.clock }} (frozen) (push) Waiting to run
Details
tests others / time test runner - ${{ matrix.clock }} (realtime) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 20, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 22, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (firefox, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (webkit, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (chromium tip-of-tree) (ubuntu-22.04) (push) Waiting to run
Details
tests 1 / Test Runner (18, macos-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, macos-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, windows-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, windows-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (20, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (20, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (22, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (22, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Web Components (push) Waiting to run
Details
tests 1 / VSCode Extension (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-15-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-15-xlarge) (push) Waiting to run
Details
tests 2 / Windows (chromium) (push) Waiting to run
Details
tests 2 / Windows (firefox) (push) Waiting to run
Details
tests 2 / Windows (webkit) (push) Waiting to run
Details
tests 2 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (20, ubuntu-latest) (push) Waiting to run
Details
tests 2 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (22, ubuntu-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, windows-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, windows-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, windows-latest) (push) Waiting to run
Details
tests 2 / Transport (driver) (push) Waiting to run
Details
tests 2 / Transport (service) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium, chromium-tip-of-tree) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (firefox) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (webkit) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (, macos-13) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, macos-13) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree headless-shell-${{ matrix.os }} (ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 2 / build-playwright-driver (push) Waiting to run
Details
tests 2 / Test channel=chromium (macos-latest) (push) Waiting to run
Details
tests 2 / Test channel=chromium (ubuntu-latest) (push) Waiting to run
Details
tests 2 / Test channel=chromium (windows-latest) (push) Waiting to run
Details
tests Video / Video Linux (chromium, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests Video / Video Linux (firefox, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests Video / Video Linux (webkit, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (webkit, ubuntu-24.04) (push) Waiting to run
Details
Internal Tests / trigger (push) Waiting to run
Details
infra / docs & lint (push) Waiting to run
Details
infra / Lint snippets (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, macos-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, ubuntu-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (18, windows-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (20, ubuntu-latest) (push) Waiting to run
Details
components / ${{ matrix.os }} - Node.js ${{ matrix.node-version }} (22, ubuntu-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests others / Stress - ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests others / WebView2 (push) Waiting to run
Details
tests others / time library - ${{ matrix.clock }} (frozen) (push) Waiting to run
Details
tests others / time library - ${{ matrix.clock }} (realtime) (push) Waiting to run
Details
tests others / time test runner - ${{ matrix.clock }} (frozen) (push) Waiting to run
Details
tests others / time test runner - ${{ matrix.clock }} (realtime) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests others / Electron - ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 20, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (chromium, 22, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (firefox, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (${{ matrix.browser }} - Node.js ${{ matrix.node-version }}) (webkit, 18, ubuntu-22.04) (push) Waiting to run
Details
tests 1 / ${{ matrix.os }} (chromium tip-of-tree) (ubuntu-22.04) (push) Waiting to run
Details
tests 1 / Test Runner (18, macos-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, macos-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, windows-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (18, windows-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (20, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (20, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Test Runner (22, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (22, ubuntu-latest, 2, 2) (push) Waiting to run
Details
tests 1 / Web Components (push) Waiting to run
Details
tests 1 / VSCode Extension (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (ubuntu-latest) (push) Waiting to run
Details
tests 1 / Installation Test ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (chromium, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (firefox, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-13-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-13-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-14-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-15-large) (push) Waiting to run
Details
tests 2 / ${{ matrix.os }} (${{ matrix.browser }}) (webkit, macos-15-xlarge) (push) Waiting to run
Details
tests 2 / Windows (chromium) (push) Waiting to run
Details
tests 2 / Windows (firefox) (push) Waiting to run
Details
tests 2 / Windows (webkit) (push) Waiting to run
Details
tests 2 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (20, ubuntu-latest) (push) Waiting to run
Details
tests 2 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (22, ubuntu-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (chromium, windows-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (firefox, windows-latest) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, macos-14-xlarge) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, ubuntu-24.04) (push) Waiting to run
Details
tests 2 / headed ${{ matrix.browser }} (${{ matrix.os }}) (webkit, windows-latest) (push) Waiting to run
Details
tests 2 / Transport (driver) (push) Waiting to run
Details
tests 2 / Transport (service) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium, chromium-tip-of-tree) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (firefox) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (webkit) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (chrome-beta, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-beta, windows-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, macos-latest) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Test ${{ matrix.channel }} on ${{ matrix.runs-on }} (msedge-dev, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (, macos-13) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, macos-13) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree ${{ matrix.os }}${{ matrix.headed }} (--headed, windows-latest) (push) Waiting to run
Details
tests 2 / Chromium tip-of-tree headless-shell-${{ matrix.os }} (ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (macos-latest) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Firefox Beta ${{ matrix.os }} (windows-latest) (push) Waiting to run
Details
tests 2 / build-playwright-driver (push) Waiting to run
Details
tests 2 / Test channel=chromium (macos-latest) (push) Waiting to run
Details
tests 2 / Test channel=chromium (ubuntu-latest) (push) Waiting to run
Details
tests 2 / Test channel=chromium (windows-latest) (push) Waiting to run
Details
tests Video / Video Linux (chromium, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (chromium, ubuntu-24.04) (push) Waiting to run
Details
tests Video / Video Linux (firefox, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (firefox, ubuntu-24.04) (push) Waiting to run
Details
tests Video / Video Linux (webkit, ubuntu-22.04) (push) Waiting to run
Details
tests Video / Video Linux (webkit, ubuntu-24.04) (push) Waiting to run
Details
Internal Tests / trigger (push) Waiting to run
Details
This commit is contained in:
parent
926c02735e
commit
d1eb9589f8
|
|
@ -28,6 +28,7 @@ type BindingData = {
|
|||
callbacks: Map<number, { resolve: (value: any) => void, reject: (error: Error) => void }>;
|
||||
lastSeq: number;
|
||||
handles: Map<number, any>;
|
||||
removed: boolean;
|
||||
};
|
||||
|
||||
export class BindingsController {
|
||||
|
|
@ -47,9 +48,12 @@ export class BindingsController {
|
|||
callbacks: new Map(),
|
||||
lastSeq: 0,
|
||||
handles: new Map(),
|
||||
removed: false,
|
||||
};
|
||||
this._bindings.set(bindingName, data);
|
||||
(this._global as any)[bindingName] = (...args: any[]) => {
|
||||
if (data.removed)
|
||||
throw new Error(`binding "${bindingName}" has been removed`);
|
||||
if (needsHandle && args.slice(1).some(arg => arg !== undefined))
|
||||
throw new Error(`exposeBindingHandle supports a single argument, ${args.length} received`);
|
||||
const seq = ++data.lastSeq;
|
||||
|
|
@ -72,6 +76,14 @@ export class BindingsController {
|
|||
};
|
||||
}
|
||||
|
||||
removeBinding(bindingName: string) {
|
||||
const data = this._bindings.get(bindingName);
|
||||
if (data)
|
||||
data.removed = true;
|
||||
this._bindings.delete(bindingName);
|
||||
delete (this._global as any)[bindingName];
|
||||
}
|
||||
|
||||
takeBindingHandle(arg: { name: string, seq: number }) {
|
||||
const handles = this._bindings.get(arg.name)!.handles;
|
||||
const handle = handles.get(arg.seq);
|
||||
|
|
|
|||
|
|
@ -207,7 +207,6 @@ export class BidiBrowser extends Browser {
|
|||
|
||||
export class BidiBrowserContext extends BrowserContext {
|
||||
declare readonly _browser: BidiBrowser;
|
||||
private _initScriptIds: bidi.Script.PreloadScript[] = [];
|
||||
private _originToPermissions = new Map<string, string[]>();
|
||||
private _blockingPageCreations: Set<Promise<unknown>> = new Set();
|
||||
|
||||
|
|
@ -372,14 +371,11 @@ export class BidiBrowserContext extends BrowserContext {
|
|||
functionDeclaration: `() => { return ${initScript.source} }`,
|
||||
userContexts: [this._browserContextId || 'default'],
|
||||
});
|
||||
if (!initScript.internal)
|
||||
this._initScriptIds.push(script);
|
||||
initScript.auxData = script;
|
||||
}
|
||||
|
||||
async doRemoveNonInternalInitScripts() {
|
||||
const promise = Promise.all(this._initScriptIds.map(script => this._browser._browserSession.send('script.removePreloadScript', { script })));
|
||||
this._initScriptIds = [];
|
||||
await promise;
|
||||
async doRemoveInitScripts(initScripts: InitScript[]) {
|
||||
await Promise.all(initScripts.map(script => this._browser._browserSession.send('script.removePreloadScript', { script: script.auxData })));
|
||||
}
|
||||
|
||||
async doUpdateRequestInterception(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ export class BidiPage implements PageDelegate {
|
|||
readonly _browserContext: BidiBrowserContext;
|
||||
readonly _networkManager: BidiNetworkManager;
|
||||
private readonly _pdf: BidiPDF;
|
||||
private _initScriptIds: bidi.Script.PreloadScript[] = [];
|
||||
|
||||
constructor(browserContext: BidiBrowserContext, bidiSession: BidiSession, opener: BidiPage | null) {
|
||||
this._session = bidiSession;
|
||||
|
|
@ -343,14 +342,11 @@ export class BidiPage implements PageDelegate {
|
|||
// TODO: push to iframes?
|
||||
contexts: [this._session.sessionId],
|
||||
});
|
||||
if (!initScript.internal)
|
||||
this._initScriptIds.push(script);
|
||||
initScript.auxData = script;
|
||||
}
|
||||
|
||||
async removeNonInternalInitScripts() {
|
||||
const promises = this._initScriptIds.map(script => this._session.send('script.removePreloadScript', { script }));
|
||||
this._initScriptIds = [];
|
||||
await Promise.all(promises);
|
||||
async removeInitScripts(initScripts: InitScript[]): Promise<void> {
|
||||
await Promise.all(initScripts.map(script => this._session.send('script.removePreloadScript', { script: script.auxData })));
|
||||
}
|
||||
|
||||
async closePage(runBeforeUnload: boolean): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ export abstract class BrowserContext extends SdkObject {
|
|||
}
|
||||
|
||||
async resetForReuse(metadata: CallMetadata, params: channels.BrowserNewContextForReuseParams | null) {
|
||||
this.tracing.resetForReuse();
|
||||
await this.tracing.resetForReuse();
|
||||
|
||||
if (params) {
|
||||
for (const key of paramsThatAllowContextReuse)
|
||||
|
|
@ -218,9 +218,7 @@ export abstract class BrowserContext extends SdkObject {
|
|||
page?.frameManager.setCloseAllOpeningDialogs(false);
|
||||
|
||||
await this._resetStorage();
|
||||
await this._removeExposedBindings();
|
||||
await this._removeInitScripts();
|
||||
this.clock.markAsUninstalled();
|
||||
await this.clock.resetForReuse();
|
||||
// TODO: following can be optimized to not perform noops.
|
||||
if (this._options.permissions)
|
||||
await this.grantPermissions(this._options.permissions);
|
||||
|
|
@ -276,7 +274,7 @@ export abstract class BrowserContext extends SdkObject {
|
|||
protected abstract doClearPermissions(): Promise<void>;
|
||||
protected abstract doSetHTTPCredentials(httpCredentials?: types.Credentials): Promise<void>;
|
||||
protected abstract doAddInitScript(initScript: InitScript): Promise<void>;
|
||||
protected abstract doRemoveNonInternalInitScripts(): Promise<void>;
|
||||
protected abstract doRemoveInitScripts(initScripts: InitScript[]): Promise<void>;
|
||||
protected abstract doUpdateRequestInterception(): Promise<void>;
|
||||
protected abstract doExposePlaywrightBinding(): Promise<void>;
|
||||
protected abstract doClose(reason: string | undefined): Promise<void>;
|
||||
|
|
@ -335,7 +333,7 @@ export abstract class BrowserContext extends SdkObject {
|
|||
return this._playwrightBindingExposed;
|
||||
}
|
||||
|
||||
async exposeBinding(name: string, needsHandle: boolean, playwrightBinding: frames.FunctionWithSource): Promise<void> {
|
||||
async exposeBinding(name: string, needsHandle: boolean, playwrightBinding: frames.FunctionWithSource): Promise<PageBinding> {
|
||||
if (this._pageBindings.has(name))
|
||||
throw new Error(`Function "${name}" has been already registered`);
|
||||
for (const page of this.pages()) {
|
||||
|
|
@ -347,13 +345,16 @@ export abstract class BrowserContext extends SdkObject {
|
|||
this._pageBindings.set(name, binding);
|
||||
await this.doAddInitScript(binding.initScript);
|
||||
await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main');
|
||||
return binding;
|
||||
}
|
||||
|
||||
async _removeExposedBindings() {
|
||||
for (const [key, binding] of this._pageBindings) {
|
||||
if (!binding.internal)
|
||||
this._pageBindings.delete(key);
|
||||
}
|
||||
async removeExposedBindings(bindings: PageBinding[]) {
|
||||
bindings = bindings.filter(binding => this._pageBindings.get(binding.name) === binding);
|
||||
for (const binding of bindings)
|
||||
this._pageBindings.delete(binding.name);
|
||||
await this.doRemoveInitScripts(bindings.map(binding => binding.initScript));
|
||||
const cleanup = bindings.map(binding => `{ ${binding.cleanupScript} };\n`).join('');
|
||||
await this.safeNonStallingEvaluateInAllFrames(cleanup, 'main');
|
||||
}
|
||||
|
||||
async grantPermissions(permissions: string[], origin?: string) {
|
||||
|
|
@ -428,14 +429,16 @@ export abstract class BrowserContext extends SdkObject {
|
|||
}
|
||||
|
||||
async addInitScript(source: string, name?: string) {
|
||||
const initScript = new InitScript(source, false /* internal */, name);
|
||||
const initScript = new InitScript(source, name);
|
||||
this.initScripts.push(initScript);
|
||||
await this.doAddInitScript(initScript);
|
||||
return initScript;
|
||||
}
|
||||
|
||||
async _removeInitScripts(): Promise<void> {
|
||||
this.initScripts = this.initScripts.filter(script => script.internal);
|
||||
await this.doRemoveNonInternalInitScripts();
|
||||
async removeInitScripts(initScripts: InitScript[]) {
|
||||
const set = new Set(initScripts);
|
||||
this.initScripts = this.initScripts.filter(script => !set.has(script));
|
||||
await this.doRemoveInitScripts(initScripts);
|
||||
}
|
||||
|
||||
async setRequestInterceptor(handler: network.RouteHandler | undefined): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -476,9 +476,9 @@ export class CRBrowserContext extends BrowserContext {
|
|||
await (page.delegate as CRPage).addInitScript(initScript);
|
||||
}
|
||||
|
||||
async doRemoveNonInternalInitScripts() {
|
||||
async doRemoveInitScripts(initScripts: InitScript[]) {
|
||||
for (const page of this.pages())
|
||||
await (page.delegate as CRPage).removeNonInternalInitScripts();
|
||||
await (page.delegate as CRPage).removeInitScripts(initScripts);
|
||||
}
|
||||
|
||||
async doUpdateRequestInterception(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ export class CRPage implements PageDelegate {
|
|||
await this._forAllFrameSessions(frame => frame.exposePlaywrightBinding());
|
||||
}
|
||||
|
||||
async removeNonInternalInitScripts() {
|
||||
await this._forAllFrameSessions(frame => frame._removeEvaluatesOnNewDocument());
|
||||
async removeInitScripts(initScripts: InitScript[]): Promise<void> {
|
||||
await this._forAllFrameSessions(frame => frame._removeEvaluatesOnNewDocument(initScripts));
|
||||
}
|
||||
|
||||
async closePage(runBeforeUnload: boolean): Promise<void> {
|
||||
|
|
@ -392,7 +392,6 @@ class FrameSession {
|
|||
private _videoRecorder: VideoRecorder | null = null;
|
||||
private _screencastId: string | null = null;
|
||||
private _screencastClients = new Set<any>();
|
||||
private _evaluateOnNewDocumentIdentifiers: string[] = [];
|
||||
private _metricsOverride: Protocol.Emulation.setDeviceMetricsOverrideParameters | undefined;
|
||||
private _workerSessions = new Map<string, CRSession>();
|
||||
|
||||
|
|
@ -1059,14 +1058,11 @@ class FrameSession {
|
|||
async _evaluateOnNewDocument(initScript: InitScript, world: types.World, runImmediately?: boolean): Promise<void> {
|
||||
const worldName = world === 'utility' ? this._crPage.utilityWorldName : undefined;
|
||||
const { identifier } = await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source: initScript.source, worldName, runImmediately });
|
||||
if (!initScript.internal)
|
||||
this._evaluateOnNewDocumentIdentifiers.push(identifier);
|
||||
initScript.auxData = identifier;
|
||||
}
|
||||
|
||||
async _removeEvaluatesOnNewDocument(): Promise<void> {
|
||||
const identifiers = this._evaluateOnNewDocumentIdentifiers;
|
||||
this._evaluateOnNewDocumentIdentifiers = [];
|
||||
await Promise.all(identifiers.map(identifier => this._client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier })));
|
||||
async _removeEvaluatesOnNewDocument(initScripts: InitScript[]): Promise<void> {
|
||||
await Promise.all(initScripts.map(script => this._client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier: script.auxData }).catch(() => {}))); // target can be closed
|
||||
}
|
||||
|
||||
async exposePlaywrightBinding() {
|
||||
|
|
|
|||
|
|
@ -17,77 +17,78 @@
|
|||
import * as rawClockSource from '../generated/clockSource';
|
||||
|
||||
import type { BrowserContext } from './browserContext';
|
||||
import type { InitScript } from './page';
|
||||
|
||||
export class Clock {
|
||||
private _browserContext: BrowserContext;
|
||||
private _scriptInstalled = false;
|
||||
private _initScripts: InitScript[] = [];
|
||||
|
||||
constructor(browserContext: BrowserContext) {
|
||||
this._browserContext = browserContext;
|
||||
}
|
||||
|
||||
markAsUninstalled() {
|
||||
this._scriptInstalled = false;
|
||||
async resetForReuse() {
|
||||
await this._browserContext.removeInitScripts(this._initScripts);
|
||||
this._initScripts = [];
|
||||
}
|
||||
|
||||
async fastForward(ticks: number | string) {
|
||||
await this._installIfNeeded();
|
||||
const ticksMillis = parseTicks(ticks);
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('fastForward', ${Date.now()}, ${ticksMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('fastForward', ${Date.now()}, ${ticksMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.fastForward(${ticksMillis})`);
|
||||
}
|
||||
|
||||
async install(time: number | string | undefined) {
|
||||
await this._installIfNeeded();
|
||||
const timeMillis = time !== undefined ? parseTime(time) : Date.now();
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('install', ${Date.now()}, ${timeMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('install', ${Date.now()}, ${timeMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.install(${timeMillis})`);
|
||||
}
|
||||
|
||||
async pauseAt(ticks: number | string) {
|
||||
await this._installIfNeeded();
|
||||
const timeMillis = parseTime(ticks);
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('pauseAt', ${Date.now()}, ${timeMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('pauseAt', ${Date.now()}, ${timeMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.pauseAt(${timeMillis})`);
|
||||
}
|
||||
|
||||
async resume() {
|
||||
await this._installIfNeeded();
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('resume', ${Date.now()})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('resume', ${Date.now()})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.resume()`);
|
||||
}
|
||||
|
||||
async setFixedTime(time: string | number) {
|
||||
await this._installIfNeeded();
|
||||
const timeMillis = parseTime(time);
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('setFixedTime', ${Date.now()}, ${timeMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('setFixedTime', ${Date.now()}, ${timeMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.setFixedTime(${timeMillis})`);
|
||||
}
|
||||
|
||||
async setSystemTime(time: string | number) {
|
||||
await this._installIfNeeded();
|
||||
const timeMillis = parseTime(time);
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('setSystemTime', ${Date.now()}, ${timeMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('setSystemTime', ${Date.now()}, ${timeMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.setSystemTime(${timeMillis})`);
|
||||
}
|
||||
|
||||
async runFor(ticks: number | string) {
|
||||
await this._installIfNeeded();
|
||||
const ticksMillis = parseTicks(ticks);
|
||||
await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('runFor', ${Date.now()}, ${ticksMillis})`);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(`globalThis.__pwClock.controller.log('runFor', ${Date.now()}, ${ticksMillis})`));
|
||||
await this._evaluateInFrames(`globalThis.__pwClock.controller.runFor(${ticksMillis})`);
|
||||
}
|
||||
|
||||
private async _installIfNeeded() {
|
||||
if (this._scriptInstalled)
|
||||
if (this._initScripts.length)
|
||||
return;
|
||||
this._scriptInstalled = true;
|
||||
const script = `(() => {
|
||||
const module = {};
|
||||
${rawClockSource.source}
|
||||
globalThis.__pwClock = (module.exports.inject())(globalThis);
|
||||
})();`;
|
||||
await this._browserContext.addInitScript(script);
|
||||
this._initScripts.push(await this._browserContext.addInitScript(script));
|
||||
await this._evaluateInFrames(script);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import type { ConsoleMessage } from '../console';
|
|||
import type { Dialog } from '../dialog';
|
||||
import type { CallMetadata } from '../instrumentation';
|
||||
import type { Request, Response } from '../network';
|
||||
import type { Page } from '../page';
|
||||
import type { InitScript, Page, PageBinding } from '../page';
|
||||
import type { DispatcherScope } from './dispatcher';
|
||||
import type { FrameDispatcher } from './frameDispatcher';
|
||||
import type * as channels from '@protocol/channels';
|
||||
|
|
@ -51,6 +51,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
private _context: BrowserContext;
|
||||
private _subscriptions = new Set<channels.BrowserContextUpdateSubscriptionParams['event']>();
|
||||
_webSocketInterceptionPatterns: channels.BrowserContextSetWebSocketInterceptionPatternsParams['patterns'] = [];
|
||||
private _bindings: PageBinding[] = [];
|
||||
private _initScritps: InitScript[] = [];
|
||||
|
||||
static from(parentScope: DispatcherScope, context: BrowserContext): BrowserContextDispatcher {
|
||||
const result = parentScope.connection.existingDispatcher<BrowserContextDispatcher>(context);
|
||||
|
|
@ -206,7 +208,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
}
|
||||
|
||||
async exposeBinding(params: channels.BrowserContextExposeBindingParams): Promise<void> {
|
||||
await this._context.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
|
||||
const binding = await this._context.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
|
||||
// When reusing the context, we might have some bindings called late enough,
|
||||
// after context and page dispatchers have been disposed.
|
||||
if (this._disposed)
|
||||
|
|
@ -216,6 +218,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
this._dispatchEvent('bindingCall', { binding });
|
||||
return binding.promise();
|
||||
});
|
||||
this._bindings.push(binding);
|
||||
}
|
||||
|
||||
async newPage(params: channels.BrowserContextNewPageParams, metadata: CallMetadata): Promise<channels.BrowserContextNewPageResult> {
|
||||
|
|
@ -266,7 +269,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
}
|
||||
|
||||
async addInitScript(params: channels.BrowserContextAddInitScriptParams): Promise<void> {
|
||||
await this._context.addInitScript(params.source);
|
||||
this._initScritps.push(await this._context.addInitScript(params.source));
|
||||
}
|
||||
|
||||
async setNetworkInterceptionPatterns(params: channels.BrowserContextSetNetworkInterceptionPatternsParams): Promise<void> {
|
||||
|
|
@ -373,7 +376,12 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
|
||||
override _onDispose() {
|
||||
// Avoid protocol calls for the closed context.
|
||||
if (!this._context.isClosingOrClosed())
|
||||
this._context.setRequestInterceptor(undefined).catch(() => {});
|
||||
if (this._context.isClosingOrClosed())
|
||||
return;
|
||||
this._context.setRequestInterceptor(undefined).catch(() => {});
|
||||
this._context.removeExposedBindings(this._bindings).catch(() => {});
|
||||
this._bindings = [];
|
||||
this._context.removeInitScripts(this._initScritps).catch(() => {});
|
||||
this._initScritps = [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import type { CallMetadata } from '../instrumentation';
|
|||
import type { JSHandle } from '../javascript';
|
||||
import type { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||
import type { Frame } from '../frames';
|
||||
import type { InitScript, PageBinding } from '../page';
|
||||
import type * as channels from '@protocol/channels';
|
||||
|
||||
export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, BrowserContextDispatcher> implements channels.PageChannel {
|
||||
|
|
@ -45,6 +46,8 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||
private _page: Page;
|
||||
_subscriptions = new Set<channels.PageUpdateSubscriptionParams['event']>();
|
||||
_webSocketInterceptionPatterns: channels.PageSetWebSocketInterceptionPatternsParams['patterns'] = [];
|
||||
private _bindings: PageBinding[] = [];
|
||||
private _initScripts: InitScript[] = [];
|
||||
|
||||
static from(parentScope: BrowserContextDispatcher, page: Page): PageDispatcher {
|
||||
return PageDispatcher.fromNullable(parentScope, page)!;
|
||||
|
|
@ -107,7 +110,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||
}
|
||||
|
||||
async exposeBinding(params: channels.PageExposeBindingParams, metadata: CallMetadata): Promise<void> {
|
||||
await this._page.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
|
||||
const binding = await this._page.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
|
||||
// When reusing the context, we might have some bindings called late enough,
|
||||
// after context and page dispatchers have been disposed.
|
||||
if (this._disposed)
|
||||
|
|
@ -116,6 +119,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||
this._dispatchEvent('bindingCall', { binding });
|
||||
return binding.promise();
|
||||
});
|
||||
this._bindings.push(binding);
|
||||
}
|
||||
|
||||
async setExtraHTTPHeaders(params: channels.PageSetExtraHTTPHeadersParams, metadata: CallMetadata): Promise<void> {
|
||||
|
|
@ -166,7 +170,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||
}
|
||||
|
||||
async addInitScript(params: channels.PageAddInitScriptParams, metadata: CallMetadata): Promise<void> {
|
||||
await this._page.addInitScript(params.source);
|
||||
this._initScripts.push(await this._page.addInitScript(params.source));
|
||||
}
|
||||
|
||||
async setNetworkInterceptionPatterns(params: channels.PageSetNetworkInterceptionPatternsParams, metadata: CallMetadata): Promise<void> {
|
||||
|
|
@ -326,8 +330,13 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows
|
|||
|
||||
override _onDispose() {
|
||||
// Avoid protocol calls for the closed page.
|
||||
if (!this._page.isClosedOrClosingOrCrashed())
|
||||
this._page.setClientRequestInterceptor(undefined).catch(() => {});
|
||||
if (this._page.isClosedOrClosingOrCrashed())
|
||||
return;
|
||||
this._page.setClientRequestInterceptor(undefined).catch(() => {});
|
||||
this._page.removeExposedBindings(this._bindings).catch(() => {});
|
||||
this._bindings = [];
|
||||
this._page.removeInitScripts(this._initScripts).catch(() => {});
|
||||
this._initScripts = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ export class FFBrowserContext extends BrowserContext {
|
|||
await this._updateInitScripts();
|
||||
}
|
||||
|
||||
async doRemoveNonInternalInitScripts() {
|
||||
async doRemoveInitScripts(initScripts: InitScript[]) {
|
||||
await this._updateInitScripts();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export class FFPage implements PageDelegate {
|
|||
});
|
||||
// Ideally, we somehow ensure that utility world is created before Page.ready arrives, but currently it is racy.
|
||||
// Therefore, we can end up with an initialized page without utility world, although very unlikely.
|
||||
this.addInitScript(new InitScript('', true), UTILITY_WORLD_NAME).catch(e => this._markAsError(e));
|
||||
this.addInitScript(new InitScript(''), UTILITY_WORLD_NAME).catch(e => this._markAsError(e));
|
||||
}
|
||||
|
||||
async _markAsError(error: Error) {
|
||||
|
|
@ -387,11 +387,16 @@ export class FFPage implements PageDelegate {
|
|||
|
||||
async addInitScript(initScript: InitScript, worldName?: string): Promise<void> {
|
||||
this._initScripts.push({ initScript, worldName });
|
||||
await this._session.send('Page.setInitScripts', { scripts: this._initScripts.map(s => ({ script: s.initScript.source, worldName: s.worldName })) });
|
||||
await this._updateInitScripts();
|
||||
}
|
||||
|
||||
async removeNonInternalInitScripts() {
|
||||
this._initScripts = this._initScripts.filter(s => s.initScript.internal);
|
||||
async removeInitScripts(initScripts: InitScript[]): Promise<void> {
|
||||
const set = new Set(initScripts);
|
||||
this._initScripts = this._initScripts.filter(s => !set.has(s.initScript));
|
||||
await this._updateInitScripts();
|
||||
}
|
||||
|
||||
private async _updateInitScripts() {
|
||||
await this._session.send('Page.setInitScripts', { scripts: this._initScripts.map(s => ({ script: s.initScript.source, worldName: s.worldName })) });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export interface PageDelegate {
|
|||
goForward(): Promise<boolean>;
|
||||
requestGC(): Promise<void>;
|
||||
addInitScript(initScript: InitScript): Promise<void>;
|
||||
removeNonInternalInitScripts(): Promise<void>;
|
||||
removeInitScripts(initScripts: InitScript[]): Promise<void>;
|
||||
closePage(runBeforeUnload: boolean): Promise<void>;
|
||||
|
||||
navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>;
|
||||
|
|
@ -258,8 +258,6 @@ export class Page extends SdkObject {
|
|||
async resetForReuse(metadata: CallMetadata) {
|
||||
this._locatorHandlers.clear();
|
||||
|
||||
await this._removeExposedBindings();
|
||||
await this._removeInitScripts();
|
||||
await this.setClientRequestInterceptor(undefined);
|
||||
await this.setServerRequestInterceptor(undefined);
|
||||
await this.setFileChooserIntercepted(false);
|
||||
|
|
@ -328,7 +326,7 @@ export class Page extends SdkObject {
|
|||
return this.frameManager.frames();
|
||||
}
|
||||
|
||||
async exposeBinding(name: string, needsHandle: boolean, playwrightBinding: frames.FunctionWithSource) {
|
||||
async exposeBinding(name: string, needsHandle: boolean, playwrightBinding: frames.FunctionWithSource): Promise<PageBinding> {
|
||||
if (this._pageBindings.has(name))
|
||||
throw new Error(`Function "${name}" has been already registered`);
|
||||
if (this.browserContext._pageBindings.has(name))
|
||||
|
|
@ -338,13 +336,16 @@ export class Page extends SdkObject {
|
|||
this._pageBindings.set(name, binding);
|
||||
await this.delegate.addInitScript(binding.initScript);
|
||||
await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main');
|
||||
return binding;
|
||||
}
|
||||
|
||||
private async _removeExposedBindings() {
|
||||
for (const [key, binding] of this._pageBindings) {
|
||||
if (!binding.internal)
|
||||
this._pageBindings.delete(key);
|
||||
}
|
||||
async removeExposedBindings(bindings: PageBinding[]) {
|
||||
bindings = bindings.filter(binding => this._pageBindings.get(binding.name) === binding);
|
||||
for (const binding of bindings)
|
||||
this._pageBindings.delete(binding.name);
|
||||
await this.delegate.removeInitScripts(bindings.map(binding => binding.initScript));
|
||||
const cleanup = bindings.map(binding => `{ ${binding.cleanupScript} };\n`).join('');
|
||||
await this.safeNonStallingEvaluateInAllFrames(cleanup, 'main');
|
||||
}
|
||||
|
||||
setExtraHTTPHeaders(headers: types.HeadersArray) {
|
||||
|
|
@ -560,14 +561,16 @@ export class Page extends SdkObject {
|
|||
}
|
||||
|
||||
async addInitScript(source: string, name?: string) {
|
||||
const initScript = new InitScript(source, false /* internal */, name);
|
||||
const initScript = new InitScript(source, name);
|
||||
this.initScripts.push(initScript);
|
||||
await this.delegate.addInitScript(initScript);
|
||||
return initScript;
|
||||
}
|
||||
|
||||
private async _removeInitScripts() {
|
||||
this.initScripts = this.initScripts.filter(script => script.internal);
|
||||
await this.delegate.removeNonInternalInitScripts();
|
||||
async removeInitScripts(initScripts: InitScript[]) {
|
||||
const set = new Set(initScripts);
|
||||
this.initScripts = this.initScripts.filter(script => !set.has(script));
|
||||
await this.delegate.removeInitScripts(initScripts);
|
||||
}
|
||||
|
||||
needsRequestInterception(): boolean {
|
||||
|
|
@ -862,21 +865,21 @@ export class PageBinding {
|
|||
if (!globalThis[property])
|
||||
globalThis[property] = new (module.exports.BindingsController())(globalThis, '${PageBinding.kBindingName}');
|
||||
})();
|
||||
`, true /* internal */);
|
||||
`);
|
||||
}
|
||||
|
||||
readonly name: string;
|
||||
readonly playwrightFunction: frames.FunctionWithSource;
|
||||
readonly initScript: InitScript;
|
||||
readonly needsHandle: boolean;
|
||||
readonly internal: boolean;
|
||||
readonly cleanupScript: string;
|
||||
|
||||
constructor(name: string, playwrightFunction: frames.FunctionWithSource, needsHandle: boolean) {
|
||||
this.name = name;
|
||||
this.playwrightFunction = playwrightFunction;
|
||||
this.initScript = new InitScript(`globalThis['${PageBinding.kController}'].addBinding(${JSON.stringify(name)}, ${needsHandle})`, true /* internal */);
|
||||
this.initScript = new InitScript(`globalThis['${PageBinding.kController}'].addBinding(${JSON.stringify(name)}, ${needsHandle})`);
|
||||
this.needsHandle = needsHandle;
|
||||
this.internal = name.startsWith('__pw');
|
||||
this.cleanupScript = `globalThis['${PageBinding.kController}'].removeBinding(${JSON.stringify(name)})`;
|
||||
}
|
||||
|
||||
static async dispatch(page: Page, payload: string, context: dom.FrameExecutionContext) {
|
||||
|
|
@ -905,14 +908,13 @@ export class PageBinding {
|
|||
|
||||
export class InitScript {
|
||||
readonly source: string;
|
||||
readonly internal: boolean;
|
||||
readonly name?: string;
|
||||
auxData: any; // Can be arbitrarily used by a browser-specific implementation.
|
||||
|
||||
constructor(source: string, internal?: boolean, name?: string) {
|
||||
constructor(source: string, name?: string) {
|
||||
this.source = `(() => {
|
||||
${source}
|
||||
})();`;
|
||||
this.internal = !!internal;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { Page } from '../../page';
|
|||
import type { SnapshotData } from './snapshotterInjected';
|
||||
import type { RegisteredListener } from '../../utils/eventsHelper';
|
||||
import type { Frame } from '../../frames';
|
||||
import type { InitScript } from '../../page';
|
||||
import type { FrameSnapshot } from '@trace/snapshot';
|
||||
|
||||
export type SnapshotterBlob = {
|
||||
|
|
@ -43,7 +44,7 @@ export class Snapshotter {
|
|||
private _delegate: SnapshotterDelegate;
|
||||
private _eventListeners: RegisteredListener[] = [];
|
||||
private _snapshotStreamer: string;
|
||||
private _initialized = false;
|
||||
private _initScript: InitScript | undefined;
|
||||
private _started = false;
|
||||
|
||||
constructor(context: BrowserContext, delegate: SnapshotterDelegate) {
|
||||
|
|
@ -59,25 +60,26 @@ export class Snapshotter {
|
|||
|
||||
async start() {
|
||||
this._started = true;
|
||||
if (!this._initialized) {
|
||||
this._initialized = true;
|
||||
if (!this._initScript)
|
||||
await this._initialize();
|
||||
}
|
||||
await this.reset();
|
||||
}
|
||||
|
||||
async reset() {
|
||||
if (this._started)
|
||||
await this._runInAllFrames(`window["${this._snapshotStreamer}"].reset()`);
|
||||
await this._context.safeNonStallingEvaluateInAllFrames(`window["${this._snapshotStreamer}"].reset()`, 'main');
|
||||
}
|
||||
|
||||
async stop() {
|
||||
this._started = false;
|
||||
}
|
||||
|
||||
resetForReuse() {
|
||||
async resetForReuse() {
|
||||
// Next time we start recording, we will call addInitScript again.
|
||||
this._initialized = false;
|
||||
if (this._initScript) {
|
||||
await this._context.removeInitScripts([this._initScript]);
|
||||
this._initScript = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async _initialize() {
|
||||
|
|
@ -88,18 +90,9 @@ export class Snapshotter {
|
|||
];
|
||||
|
||||
const { javaScriptEnabled } = this._context._options;
|
||||
const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === undefined})`;
|
||||
await this._context.addInitScript(initScript);
|
||||
await this._runInAllFrames(initScript);
|
||||
}
|
||||
|
||||
private async _runInAllFrames(expression: string) {
|
||||
const frames = [];
|
||||
for (const page of this._context.pages())
|
||||
frames.push(...page.frames());
|
||||
await Promise.all(frames.map(frame => {
|
||||
return frame.nonStallingRawEvaluateInExistingMainContext(expression).catch(e => debugLogger.log('error', e));
|
||||
}));
|
||||
const initScriptSource = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === undefined})`;
|
||||
this._initScript = await this._context.addInitScript(initScriptSource);
|
||||
await this._context.safeNonStallingEvaluateInAllFrames(initScriptSource, 'main');
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
|
|||
// Discard previous chunk if any and ignore any errors there.
|
||||
await this.stopChunk({ mode: 'discard' }).catch(() => {});
|
||||
await this.stop();
|
||||
this._snapshotter?.resetForReuse();
|
||||
await this._snapshotter?.resetForReuse();
|
||||
}
|
||||
|
||||
async start(options: TracerOptions) {
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ export class WKBrowserContext extends BrowserContext {
|
|||
await (page.delegate as WKPage)._updateBootstrapScript();
|
||||
}
|
||||
|
||||
async doRemoveNonInternalInitScripts() {
|
||||
async doRemoveInitScripts(initScripts: InitScript[]) {
|
||||
for (const page of this.pages())
|
||||
await (page.delegate as WKPage)._updateBootstrapScript();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -768,7 +768,7 @@ export class WKPage implements PageDelegate {
|
|||
await this._updateBootstrapScript();
|
||||
}
|
||||
|
||||
async removeNonInternalInitScripts() {
|
||||
async removeInitScripts(initScripts: InitScript[]): Promise<void> {
|
||||
await this._updateBootstrapScript();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import type { Browser, BrowserContext, BrowserServer, ConnectOptions, Page } fro
|
|||
type ExtraFixtures = {
|
||||
remoteServer: BrowserServer;
|
||||
connect: (wsEndpoint: string, options?: ConnectOptions) => Promise<Browser>,
|
||||
twoPages: { pageA: Page, pageB: Page },
|
||||
};
|
||||
const test = playwrightTest.extend<ExtraFixtures>({
|
||||
remoteServer: async ({ browserType }, use) => {
|
||||
|
|
@ -35,6 +36,17 @@ const test = playwrightTest.extend<ExtraFixtures>({
|
|||
});
|
||||
await browser?.close();
|
||||
},
|
||||
twoPages: async ({ remoteServer, connect }, use) => {
|
||||
const browserA = await connect(remoteServer.wsEndpoint());
|
||||
const contextA = await browserA.newContext();
|
||||
const pageA = await contextA.newPage();
|
||||
|
||||
const browserB = await connect(remoteServer.wsEndpoint());
|
||||
const contextB = browserB.contexts()[0];
|
||||
const pageB = contextB.pages()[0];
|
||||
|
||||
await use({ pageA, pageB });
|
||||
},
|
||||
});
|
||||
|
||||
test.slow(true, 'All connect tests are slow');
|
||||
|
|
@ -65,4 +77,114 @@ test('should connect two clients', async ({ connect, remoteServer, server }) =>
|
|||
const pageB2 = await pageEventPromise;
|
||||
await pageA2.goto('/frames/frame.html');
|
||||
await expect(pageB2).toHaveURL('/frames/frame.html');
|
||||
|
||||
// Both contexts and pages should be still operational after any client disconnects.
|
||||
await browserA.close();
|
||||
await expect(pageB1).toHaveURL(server.EMPTY_PAGE);
|
||||
await expect(pageB2).toHaveURL(server.PREFIX + '/frames/frame.html');
|
||||
});
|
||||
|
||||
test('should have separate default timeouts', async ({ twoPages }) => {
|
||||
const { pageA, pageB } = twoPages;
|
||||
pageA.setDefaultTimeout(500);
|
||||
pageB.setDefaultTimeout(600);
|
||||
|
||||
const [errorA, errorB] = await Promise.all([
|
||||
pageA.click('div').catch(e => e),
|
||||
pageB.click('div').catch(e => e),
|
||||
]);
|
||||
expect(errorA.message).toContain('Timeout 500ms exceeded');
|
||||
expect(errorB.message).toContain('Timeout 600ms exceeded');
|
||||
});
|
||||
|
||||
test('should receive viewport size changes', async ({ twoPages }) => {
|
||||
const { pageA, pageB } = twoPages;
|
||||
|
||||
await pageA.setViewportSize({ width: 567, height: 456 });
|
||||
expect(pageA.viewportSize()).toEqual({ width: 567, height: 456 });
|
||||
await expect.poll(() => pageB.viewportSize()).toEqual({ width: 567, height: 456 });
|
||||
|
||||
await pageB.setViewportSize({ width: 456, height: 567 });
|
||||
expect(pageB.viewportSize()).toEqual({ width: 456, height: 567 });
|
||||
await expect.poll(() => pageA.viewportSize()).toEqual({ width: 456, height: 567 });
|
||||
});
|
||||
|
||||
test('should not allow parallel js coverage', async ({ twoPages, browserName }) => {
|
||||
test.skip(browserName !== 'chromium');
|
||||
const { pageA, pageB } = twoPages;
|
||||
await pageA.coverage.startJSCoverage();
|
||||
const error = await pageB.coverage.startJSCoverage().catch(e => e);
|
||||
expect(error.message).toContain('JSCoverage is already enabled');
|
||||
});
|
||||
|
||||
test('should not allow parallel css coverage', async ({ twoPages, browserName }) => {
|
||||
test.skip(browserName !== 'chromium');
|
||||
const { pageA, pageB } = twoPages;
|
||||
await pageA.coverage.startCSSCoverage();
|
||||
const error = await pageB.coverage.startCSSCoverage().catch(e => e);
|
||||
expect(error.message).toContain('CSSCoverage is already enabled');
|
||||
});
|
||||
|
||||
test('last emulateMedia wins', async ({ twoPages }) => {
|
||||
const { pageA, pageB } = twoPages;
|
||||
await pageA.emulateMedia({ media: 'print' });
|
||||
expect(await pageB.evaluate(() => window.matchMedia('screen').matches)).toBe(false);
|
||||
expect(await pageA.evaluate(() => window.matchMedia('print').matches)).toBe(true);
|
||||
await pageB.emulateMedia({ media: 'screen' });
|
||||
expect(await pageB.evaluate(() => window.matchMedia('screen').matches)).toBe(true);
|
||||
expect(await pageA.evaluate(() => window.matchMedia('print').matches)).toBe(false);
|
||||
});
|
||||
|
||||
test('should remove exposed bindings upon disconnect', async ({ twoPages }) => {
|
||||
const { pageA, pageB } = twoPages;
|
||||
|
||||
await pageA.exposeBinding('pageBindingA', () => 'pageBindingAResult');
|
||||
await pageA.evaluate(() => {
|
||||
(window as any).pageBindingACopy = (window as any).pageBindingA;
|
||||
});
|
||||
expect(await pageB.evaluate(() => (window as any).pageBindingA())).toBe('pageBindingAResult');
|
||||
expect(await pageB.evaluate(() => !!(window as any).pageBindingACopy)).toBe(true);
|
||||
|
||||
await pageA.context().exposeBinding('contextBindingA', () => 'contextBindingAResult');
|
||||
expect(await pageB.evaluate(() => (window as any).contextBindingA())).toBe('contextBindingAResult');
|
||||
|
||||
await pageB.exposeBinding('pageBindingB', () => 'pageBindingBResult');
|
||||
expect(await pageA.evaluate(() => (window as any).pageBindingB())).toBe('pageBindingBResult');
|
||||
await pageB.context().exposeBinding('contextBindingB', () => 'contextBindingBResult');
|
||||
expect(await pageA.evaluate(() => (window as any).contextBindingB())).toBe('contextBindingBResult');
|
||||
|
||||
await pageA.context().browser().close();
|
||||
await new Promise(f => setTimeout(f, 1000)); // Give disconnect some time to cleanup.
|
||||
|
||||
expect(await pageB.evaluate(() => (window as any).pageBindingA)).toBe(undefined);
|
||||
expect(await pageB.evaluate(() => (window as any).contextBindingA)).toBe(undefined);
|
||||
const error = await pageB.evaluate(() => (window as any).pageBindingACopy()).catch(e => e);
|
||||
expect(error.message).toContain('binding "pageBindingA" has been removed');
|
||||
|
||||
expect(await pageB.evaluate(() => (window as any).pageBindingB())).toBe('pageBindingBResult');
|
||||
});
|
||||
|
||||
test('should remove init scripts upon disconnect', async ({ twoPages, server }) => {
|
||||
const { pageA, pageB } = twoPages;
|
||||
|
||||
await pageA.addInitScript(() => (window as any).pageValueA = 'pageValueA');
|
||||
await pageA.context().addInitScript(() => (window as any).contextValueA = 'contextValueA');
|
||||
await pageB.goto(server.EMPTY_PAGE);
|
||||
expect(await pageB.evaluate(() => (window as any).pageValueA)).toBe('pageValueA');
|
||||
expect(await pageB.evaluate(() => (window as any).contextValueA)).toBe('contextValueA');
|
||||
|
||||
await pageB.addInitScript(() => (window as any).pageValueB = 'pageValueB');
|
||||
await pageB.context().addInitScript(() => (window as any).contextValueB = 'contextValueB');
|
||||
await pageA.goto(server.EMPTY_PAGE);
|
||||
expect(await pageA.evaluate(() => (window as any).pageValueB)).toBe('pageValueB');
|
||||
expect(await pageA.evaluate(() => (window as any).contextValueB)).toBe('contextValueB');
|
||||
|
||||
await pageB.context().browser().close();
|
||||
await new Promise(f => setTimeout(f, 1000)); // Give disconnect some time to cleanup.
|
||||
|
||||
await pageA.goto(server.EMPTY_PAGE);
|
||||
expect(await pageA.evaluate(() => (window as any).pageValueB)).toBe(undefined);
|
||||
expect(await pageA.evaluate(() => (window as any).contextValueB)).toBe(undefined);
|
||||
expect(await pageA.evaluate(() => (window as any).pageValueA)).toBe('pageValueA');
|
||||
expect(await pageA.evaluate(() => (window as any).contextValueA)).toBe('contextValueA');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue