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 }>; |   callbacks: Map<number, { resolve: (value: any) => void, reject: (error: Error) => void }>; | ||||||
|   lastSeq: number; |   lastSeq: number; | ||||||
|   handles: Map<number, any>; |   handles: Map<number, any>; | ||||||
|  |   removed: boolean; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export class BindingsController { | export class BindingsController { | ||||||
|  | @ -47,9 +48,12 @@ export class BindingsController { | ||||||
|       callbacks: new Map(), |       callbacks: new Map(), | ||||||
|       lastSeq: 0, |       lastSeq: 0, | ||||||
|       handles: new Map(), |       handles: new Map(), | ||||||
|  |       removed: false, | ||||||
|     }; |     }; | ||||||
|     this._bindings.set(bindingName, data); |     this._bindings.set(bindingName, data); | ||||||
|     (this._global as any)[bindingName] = (...args: any[]) => { |     (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)) |       if (needsHandle && args.slice(1).some(arg => arg !== undefined)) | ||||||
|         throw new Error(`exposeBindingHandle supports a single argument, ${args.length} received`); |         throw new Error(`exposeBindingHandle supports a single argument, ${args.length} received`); | ||||||
|       const seq = ++data.lastSeq; |       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 }) { |   takeBindingHandle(arg: { name: string, seq: number }) { | ||||||
|     const handles = this._bindings.get(arg.name)!.handles; |     const handles = this._bindings.get(arg.name)!.handles; | ||||||
|     const handle = handles.get(arg.seq); |     const handle = handles.get(arg.seq); | ||||||
|  |  | ||||||
|  | @ -207,7 +207,6 @@ export class BidiBrowser extends Browser { | ||||||
| 
 | 
 | ||||||
| export class BidiBrowserContext extends BrowserContext { | export class BidiBrowserContext extends BrowserContext { | ||||||
|   declare readonly _browser: BidiBrowser; |   declare readonly _browser: BidiBrowser; | ||||||
|   private _initScriptIds: bidi.Script.PreloadScript[] = []; |  | ||||||
|   private _originToPermissions = new Map<string, string[]>(); |   private _originToPermissions = new Map<string, string[]>(); | ||||||
|   private _blockingPageCreations: Set<Promise<unknown>> = new Set(); |   private _blockingPageCreations: Set<Promise<unknown>> = new Set(); | ||||||
| 
 | 
 | ||||||
|  | @ -372,14 +371,11 @@ export class BidiBrowserContext extends BrowserContext { | ||||||
|       functionDeclaration: `() => { return ${initScript.source} }`, |       functionDeclaration: `() => { return ${initScript.source} }`, | ||||||
|       userContexts: [this._browserContextId || 'default'], |       userContexts: [this._browserContextId || 'default'], | ||||||
|     }); |     }); | ||||||
|     if (!initScript.internal) |     initScript.auxData = script; | ||||||
|       this._initScriptIds.push(script); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doRemoveNonInternalInitScripts() { |   async doRemoveInitScripts(initScripts: InitScript[]) { | ||||||
|     const promise = Promise.all(this._initScriptIds.map(script => this._browser._browserSession.send('script.removePreloadScript', { script }))); |     await Promise.all(initScripts.map(script => this._browser._browserSession.send('script.removePreloadScript', { script: script.auxData }))); | ||||||
|     this._initScriptIds = []; |  | ||||||
|     await promise; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doUpdateRequestInterception(): Promise<void> { |   async doUpdateRequestInterception(): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -51,7 +51,6 @@ export class BidiPage implements PageDelegate { | ||||||
|   readonly _browserContext: BidiBrowserContext; |   readonly _browserContext: BidiBrowserContext; | ||||||
|   readonly _networkManager: BidiNetworkManager; |   readonly _networkManager: BidiNetworkManager; | ||||||
|   private readonly _pdf: BidiPDF; |   private readonly _pdf: BidiPDF; | ||||||
|   private _initScriptIds: bidi.Script.PreloadScript[] = []; |  | ||||||
| 
 | 
 | ||||||
|   constructor(browserContext: BidiBrowserContext, bidiSession: BidiSession, opener: BidiPage | null) { |   constructor(browserContext: BidiBrowserContext, bidiSession: BidiSession, opener: BidiPage | null) { | ||||||
|     this._session = bidiSession; |     this._session = bidiSession; | ||||||
|  | @ -343,14 +342,11 @@ export class BidiPage implements PageDelegate { | ||||||
|       // TODO: push to iframes?
 |       // TODO: push to iframes?
 | ||||||
|       contexts: [this._session.sessionId], |       contexts: [this._session.sessionId], | ||||||
|     }); |     }); | ||||||
|     if (!initScript.internal) |     initScript.auxData = script; | ||||||
|       this._initScriptIds.push(script); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async removeNonInternalInitScripts() { |   async removeInitScripts(initScripts: InitScript[]): Promise<void> { | ||||||
|     const promises = this._initScriptIds.map(script => this._session.send('script.removePreloadScript', { script })); |     await Promise.all(initScripts.map(script => this._session.send('script.removePreloadScript', { script: script.auxData }))); | ||||||
|     this._initScriptIds = []; |  | ||||||
|     await Promise.all(promises); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async closePage(runBeforeUnload: boolean): Promise<void> { |   async closePage(runBeforeUnload: boolean): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -189,7 +189,7 @@ export abstract class BrowserContext extends SdkObject { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async resetForReuse(metadata: CallMetadata, params: channels.BrowserNewContextForReuseParams | null) { |   async resetForReuse(metadata: CallMetadata, params: channels.BrowserNewContextForReuseParams | null) { | ||||||
|     this.tracing.resetForReuse(); |     await this.tracing.resetForReuse(); | ||||||
| 
 | 
 | ||||||
|     if (params) { |     if (params) { | ||||||
|       for (const key of paramsThatAllowContextReuse) |       for (const key of paramsThatAllowContextReuse) | ||||||
|  | @ -218,9 +218,7 @@ export abstract class BrowserContext extends SdkObject { | ||||||
|     page?.frameManager.setCloseAllOpeningDialogs(false); |     page?.frameManager.setCloseAllOpeningDialogs(false); | ||||||
| 
 | 
 | ||||||
|     await this._resetStorage(); |     await this._resetStorage(); | ||||||
|     await this._removeExposedBindings(); |     await this.clock.resetForReuse(); | ||||||
|     await this._removeInitScripts(); |  | ||||||
|     this.clock.markAsUninstalled(); |  | ||||||
|     // TODO: following can be optimized to not perform noops.
 |     // TODO: following can be optimized to not perform noops.
 | ||||||
|     if (this._options.permissions) |     if (this._options.permissions) | ||||||
|       await this.grantPermissions(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 doClearPermissions(): Promise<void>; | ||||||
|   protected abstract doSetHTTPCredentials(httpCredentials?: types.Credentials): Promise<void>; |   protected abstract doSetHTTPCredentials(httpCredentials?: types.Credentials): Promise<void>; | ||||||
|   protected abstract doAddInitScript(initScript: InitScript): 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 doUpdateRequestInterception(): Promise<void>; | ||||||
|   protected abstract doExposePlaywrightBinding(): Promise<void>; |   protected abstract doExposePlaywrightBinding(): Promise<void>; | ||||||
|   protected abstract doClose(reason: string | undefined): Promise<void>; |   protected abstract doClose(reason: string | undefined): Promise<void>; | ||||||
|  | @ -335,7 +333,7 @@ export abstract class BrowserContext extends SdkObject { | ||||||
|     return this._playwrightBindingExposed; |     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)) |     if (this._pageBindings.has(name)) | ||||||
|       throw new Error(`Function "${name}" has been already registered`); |       throw new Error(`Function "${name}" has been already registered`); | ||||||
|     for (const page of this.pages()) { |     for (const page of this.pages()) { | ||||||
|  | @ -347,13 +345,16 @@ export abstract class BrowserContext extends SdkObject { | ||||||
|     this._pageBindings.set(name, binding); |     this._pageBindings.set(name, binding); | ||||||
|     await this.doAddInitScript(binding.initScript); |     await this.doAddInitScript(binding.initScript); | ||||||
|     await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main'); |     await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main'); | ||||||
|  |     return binding; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async _removeExposedBindings() { |   async removeExposedBindings(bindings: PageBinding[]) { | ||||||
|     for (const [key, binding] of this._pageBindings) { |     bindings = bindings.filter(binding => this._pageBindings.get(binding.name) === binding); | ||||||
|       if (!binding.internal) |     for (const binding of bindings) | ||||||
|         this._pageBindings.delete(key); |       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) { |   async grantPermissions(permissions: string[], origin?: string) { | ||||||
|  | @ -428,14 +429,16 @@ export abstract class BrowserContext extends SdkObject { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async addInitScript(source: string, name?: string) { |   async addInitScript(source: string, name?: string) { | ||||||
|     const initScript = new InitScript(source, false /* internal */, name); |     const initScript = new InitScript(source, name); | ||||||
|     this.initScripts.push(initScript); |     this.initScripts.push(initScript); | ||||||
|     await this.doAddInitScript(initScript); |     await this.doAddInitScript(initScript); | ||||||
|  |     return initScript; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async _removeInitScripts(): Promise<void> { |   async removeInitScripts(initScripts: InitScript[]) { | ||||||
|     this.initScripts = this.initScripts.filter(script => script.internal); |     const set = new Set(initScripts); | ||||||
|     await this.doRemoveNonInternalInitScripts(); |     this.initScripts = this.initScripts.filter(script => !set.has(script)); | ||||||
|  |     await this.doRemoveInitScripts(initScripts); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async setRequestInterceptor(handler: network.RouteHandler | undefined): Promise<void> { |   async setRequestInterceptor(handler: network.RouteHandler | undefined): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -476,9 +476,9 @@ export class CRBrowserContext extends BrowserContext { | ||||||
|       await (page.delegate as CRPage).addInitScript(initScript); |       await (page.delegate as CRPage).addInitScript(initScript); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doRemoveNonInternalInitScripts() { |   async doRemoveInitScripts(initScripts: InitScript[]) { | ||||||
|     for (const page of this.pages()) |     for (const page of this.pages()) | ||||||
|       await (page.delegate as CRPage).removeNonInternalInitScripts(); |       await (page.delegate as CRPage).removeInitScripts(initScripts); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doUpdateRequestInterception(): Promise<void> { |   async doUpdateRequestInterception(): Promise<void> { | ||||||
|  |  | ||||||
|  | @ -240,8 +240,8 @@ export class CRPage implements PageDelegate { | ||||||
|     await this._forAllFrameSessions(frame => frame.exposePlaywrightBinding()); |     await this._forAllFrameSessions(frame => frame.exposePlaywrightBinding()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async removeNonInternalInitScripts() { |   async removeInitScripts(initScripts: InitScript[]): Promise<void> { | ||||||
|     await this._forAllFrameSessions(frame => frame._removeEvaluatesOnNewDocument()); |     await this._forAllFrameSessions(frame => frame._removeEvaluatesOnNewDocument(initScripts)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async closePage(runBeforeUnload: boolean): Promise<void> { |   async closePage(runBeforeUnload: boolean): Promise<void> { | ||||||
|  | @ -392,7 +392,6 @@ class FrameSession { | ||||||
|   private _videoRecorder: VideoRecorder | null = null; |   private _videoRecorder: VideoRecorder | null = null; | ||||||
|   private _screencastId: string | null = null; |   private _screencastId: string | null = null; | ||||||
|   private _screencastClients = new Set<any>(); |   private _screencastClients = new Set<any>(); | ||||||
|   private _evaluateOnNewDocumentIdentifiers: string[] = []; |  | ||||||
|   private _metricsOverride: Protocol.Emulation.setDeviceMetricsOverrideParameters | undefined; |   private _metricsOverride: Protocol.Emulation.setDeviceMetricsOverrideParameters | undefined; | ||||||
|   private _workerSessions = new Map<string, CRSession>(); |   private _workerSessions = new Map<string, CRSession>(); | ||||||
| 
 | 
 | ||||||
|  | @ -1059,14 +1058,11 @@ class FrameSession { | ||||||
|   async _evaluateOnNewDocument(initScript: InitScript, world: types.World, runImmediately?: boolean): Promise<void> { |   async _evaluateOnNewDocument(initScript: InitScript, world: types.World, runImmediately?: boolean): Promise<void> { | ||||||
|     const worldName = world === 'utility' ? this._crPage.utilityWorldName : undefined; |     const worldName = world === 'utility' ? this._crPage.utilityWorldName : undefined; | ||||||
|     const { identifier } = await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source: initScript.source, worldName, runImmediately }); |     const { identifier } = await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source: initScript.source, worldName, runImmediately }); | ||||||
|     if (!initScript.internal) |     initScript.auxData = identifier; | ||||||
|       this._evaluateOnNewDocumentIdentifiers.push(identifier); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async _removeEvaluatesOnNewDocument(): Promise<void> { |   async _removeEvaluatesOnNewDocument(initScripts: InitScript[]): Promise<void> { | ||||||
|     const identifiers = this._evaluateOnNewDocumentIdentifiers; |     await Promise.all(initScripts.map(script => this._client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier: script.auxData }).catch(() => {}))); // target can be closed
 | ||||||
|     this._evaluateOnNewDocumentIdentifiers = []; |  | ||||||
|     await Promise.all(identifiers.map(identifier => this._client.send('Page.removeScriptToEvaluateOnNewDocument', { identifier }))); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async exposePlaywrightBinding() { |   async exposePlaywrightBinding() { | ||||||
|  |  | ||||||
|  | @ -17,77 +17,78 @@ | ||||||
| import * as rawClockSource from '../generated/clockSource'; | import * as rawClockSource from '../generated/clockSource'; | ||||||
| 
 | 
 | ||||||
| import type { BrowserContext } from './browserContext'; | import type { BrowserContext } from './browserContext'; | ||||||
|  | import type { InitScript } from './page'; | ||||||
| 
 | 
 | ||||||
| export class Clock { | export class Clock { | ||||||
|   private _browserContext: BrowserContext; |   private _browserContext: BrowserContext; | ||||||
|   private _scriptInstalled = false; |   private _initScripts: InitScript[] = []; | ||||||
| 
 | 
 | ||||||
|   constructor(browserContext: BrowserContext) { |   constructor(browserContext: BrowserContext) { | ||||||
|     this._browserContext = browserContext; |     this._browserContext = browserContext; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   markAsUninstalled() { |   async resetForReuse() { | ||||||
|     this._scriptInstalled = false; |     await this._browserContext.removeInitScripts(this._initScripts); | ||||||
|  |     this._initScripts = []; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async fastForward(ticks: number | string) { |   async fastForward(ticks: number | string) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const ticksMillis = parseTicks(ticks); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.fastForward(${ticksMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async install(time: number | string | undefined) { |   async install(time: number | string | undefined) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const timeMillis = time !== undefined ? parseTime(time) : Date.now(); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.install(${timeMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async pauseAt(ticks: number | string) { |   async pauseAt(ticks: number | string) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const timeMillis = parseTime(ticks); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.pauseAt(${timeMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async resume() { |   async resume() { | ||||||
|     await this._installIfNeeded(); |     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()`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.resume()`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async setFixedTime(time: string | number) { |   async setFixedTime(time: string | number) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const timeMillis = parseTime(time); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.setFixedTime(${timeMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async setSystemTime(time: string | number) { |   async setSystemTime(time: string | number) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const timeMillis = parseTime(time); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.setSystemTime(${timeMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async runFor(ticks: number | string) { |   async runFor(ticks: number | string) { | ||||||
|     await this._installIfNeeded(); |     await this._installIfNeeded(); | ||||||
|     const ticksMillis = parseTicks(ticks); |     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})`); |     await this._evaluateInFrames(`globalThis.__pwClock.controller.runFor(${ticksMillis})`); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async _installIfNeeded() { |   private async _installIfNeeded() { | ||||||
|     if (this._scriptInstalled) |     if (this._initScripts.length) | ||||||
|       return; |       return; | ||||||
|     this._scriptInstalled = true; |  | ||||||
|     const script = `(() => {
 |     const script = `(() => {
 | ||||||
|       const module = {}; |       const module = {}; | ||||||
|       ${rawClockSource.source} |       ${rawClockSource.source} | ||||||
|       globalThis.__pwClock = (module.exports.inject())(globalThis); |       globalThis.__pwClock = (module.exports.inject())(globalThis); | ||||||
|     })();`;
 |     })();`;
 | ||||||
|     await this._browserContext.addInitScript(script); |     this._initScripts.push(await this._browserContext.addInitScript(script)); | ||||||
|     await this._evaluateInFrames(script); |     await this._evaluateInFrames(script); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ import type { ConsoleMessage } from '../console'; | ||||||
| import type { Dialog } from '../dialog'; | import type { Dialog } from '../dialog'; | ||||||
| import type { CallMetadata } from '../instrumentation'; | import type { CallMetadata } from '../instrumentation'; | ||||||
| import type { Request, Response } from '../network'; | 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 { DispatcherScope } from './dispatcher'; | ||||||
| import type { FrameDispatcher } from './frameDispatcher'; | import type { FrameDispatcher } from './frameDispatcher'; | ||||||
| import type * as channels from '@protocol/channels'; | import type * as channels from '@protocol/channels'; | ||||||
|  | @ -51,6 +51,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel | ||||||
|   private _context: BrowserContext; |   private _context: BrowserContext; | ||||||
|   private _subscriptions = new Set<channels.BrowserContextUpdateSubscriptionParams['event']>(); |   private _subscriptions = new Set<channels.BrowserContextUpdateSubscriptionParams['event']>(); | ||||||
|   _webSocketInterceptionPatterns: channels.BrowserContextSetWebSocketInterceptionPatternsParams['patterns'] = []; |   _webSocketInterceptionPatterns: channels.BrowserContextSetWebSocketInterceptionPatternsParams['patterns'] = []; | ||||||
|  |   private _bindings: PageBinding[] = []; | ||||||
|  |   private _initScritps: InitScript[] = []; | ||||||
| 
 | 
 | ||||||
|   static from(parentScope: DispatcherScope, context: BrowserContext): BrowserContextDispatcher { |   static from(parentScope: DispatcherScope, context: BrowserContext): BrowserContextDispatcher { | ||||||
|     const result = parentScope.connection.existingDispatcher<BrowserContextDispatcher>(context); |     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> { |   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,
 |       // When reusing the context, we might have some bindings called late enough,
 | ||||||
|       // after context and page dispatchers have been disposed.
 |       // after context and page dispatchers have been disposed.
 | ||||||
|       if (this._disposed) |       if (this._disposed) | ||||||
|  | @ -216,6 +218,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel | ||||||
|       this._dispatchEvent('bindingCall', { binding }); |       this._dispatchEvent('bindingCall', { binding }); | ||||||
|       return binding.promise(); |       return binding.promise(); | ||||||
|     }); |     }); | ||||||
|  |     this._bindings.push(binding); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async newPage(params: channels.BrowserContextNewPageParams, metadata: CallMetadata): Promise<channels.BrowserContextNewPageResult> { |   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> { |   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> { |   async setNetworkInterceptionPatterns(params: channels.BrowserContextSetNetworkInterceptionPatternsParams): Promise<void> { | ||||||
|  | @ -373,7 +376,12 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel | ||||||
| 
 | 
 | ||||||
|   override _onDispose() { |   override _onDispose() { | ||||||
|     // Avoid protocol calls for the closed context.
 |     // Avoid protocol calls for the closed context.
 | ||||||
|     if (!this._context.isClosingOrClosed()) |     if (this._context.isClosingOrClosed()) | ||||||
|       this._context.setRequestInterceptor(undefined).catch(() => {}); |       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 { JSHandle } from '../javascript'; | ||||||
| import type { BrowserContextDispatcher } from './browserContextDispatcher'; | import type { BrowserContextDispatcher } from './browserContextDispatcher'; | ||||||
| import type { Frame } from '../frames'; | import type { Frame } from '../frames'; | ||||||
|  | import type { InitScript, PageBinding } from '../page'; | ||||||
| import type * as channels from '@protocol/channels'; | import type * as channels from '@protocol/channels'; | ||||||
| 
 | 
 | ||||||
| export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, BrowserContextDispatcher> implements channels.PageChannel { | 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; |   private _page: Page; | ||||||
|   _subscriptions = new Set<channels.PageUpdateSubscriptionParams['event']>(); |   _subscriptions = new Set<channels.PageUpdateSubscriptionParams['event']>(); | ||||||
|   _webSocketInterceptionPatterns: channels.PageSetWebSocketInterceptionPatternsParams['patterns'] = []; |   _webSocketInterceptionPatterns: channels.PageSetWebSocketInterceptionPatternsParams['patterns'] = []; | ||||||
|  |   private _bindings: PageBinding[] = []; | ||||||
|  |   private _initScripts: InitScript[] = []; | ||||||
| 
 | 
 | ||||||
|   static from(parentScope: BrowserContextDispatcher, page: Page): PageDispatcher { |   static from(parentScope: BrowserContextDispatcher, page: Page): PageDispatcher { | ||||||
|     return PageDispatcher.fromNullable(parentScope, page)!; |     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> { |   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,
 |       // When reusing the context, we might have some bindings called late enough,
 | ||||||
|       // after context and page dispatchers have been disposed.
 |       // after context and page dispatchers have been disposed.
 | ||||||
|       if (this._disposed) |       if (this._disposed) | ||||||
|  | @ -116,6 +119,7 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows | ||||||
|       this._dispatchEvent('bindingCall', { binding }); |       this._dispatchEvent('bindingCall', { binding }); | ||||||
|       return binding.promise(); |       return binding.promise(); | ||||||
|     }); |     }); | ||||||
|  |     this._bindings.push(binding); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async setExtraHTTPHeaders(params: channels.PageSetExtraHTTPHeadersParams, metadata: CallMetadata): Promise<void> { |   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> { |   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> { |   async setNetworkInterceptionPatterns(params: channels.PageSetNetworkInterceptionPatternsParams, metadata: CallMetadata): Promise<void> { | ||||||
|  | @ -326,8 +330,13 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageChannel, Brows | ||||||
| 
 | 
 | ||||||
|   override _onDispose() { |   override _onDispose() { | ||||||
|     // Avoid protocol calls for the closed page.
 |     // Avoid protocol calls for the closed page.
 | ||||||
|     if (!this._page.isClosedOrClosingOrCrashed()) |     if (this._page.isClosedOrClosingOrCrashed()) | ||||||
|       this._page.setClientRequestInterceptor(undefined).catch(() => {}); |       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(); |     await this._updateInitScripts(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doRemoveNonInternalInitScripts() { |   async doRemoveInitScripts(initScripts: InitScript[]) { | ||||||
|     await this._updateInitScripts(); |     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.
 |     // 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.
 |     // 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) { |   async _markAsError(error: Error) { | ||||||
|  | @ -387,11 +387,16 @@ export class FFPage implements PageDelegate { | ||||||
| 
 | 
 | ||||||
|   async addInitScript(initScript: InitScript, worldName?: string): Promise<void> { |   async addInitScript(initScript: InitScript, worldName?: string): Promise<void> { | ||||||
|     this._initScripts.push({ initScript, worldName }); |     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() { |   async removeInitScripts(initScripts: InitScript[]): Promise<void> { | ||||||
|     this._initScripts = this._initScripts.filter(s => s.initScript.internal); |     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 })) }); |     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>; |   goForward(): Promise<boolean>; | ||||||
|   requestGC(): Promise<void>; |   requestGC(): Promise<void>; | ||||||
|   addInitScript(initScript: InitScript): Promise<void>; |   addInitScript(initScript: InitScript): Promise<void>; | ||||||
|   removeNonInternalInitScripts(): Promise<void>; |   removeInitScripts(initScripts: InitScript[]): Promise<void>; | ||||||
|   closePage(runBeforeUnload: boolean): Promise<void>; |   closePage(runBeforeUnload: boolean): Promise<void>; | ||||||
| 
 | 
 | ||||||
|   navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>; |   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) { |   async resetForReuse(metadata: CallMetadata) { | ||||||
|     this._locatorHandlers.clear(); |     this._locatorHandlers.clear(); | ||||||
| 
 | 
 | ||||||
|     await this._removeExposedBindings(); |  | ||||||
|     await this._removeInitScripts(); |  | ||||||
|     await this.setClientRequestInterceptor(undefined); |     await this.setClientRequestInterceptor(undefined); | ||||||
|     await this.setServerRequestInterceptor(undefined); |     await this.setServerRequestInterceptor(undefined); | ||||||
|     await this.setFileChooserIntercepted(false); |     await this.setFileChooserIntercepted(false); | ||||||
|  | @ -328,7 +326,7 @@ export class Page extends SdkObject { | ||||||
|     return this.frameManager.frames(); |     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)) |     if (this._pageBindings.has(name)) | ||||||
|       throw new Error(`Function "${name}" has been already registered`); |       throw new Error(`Function "${name}" has been already registered`); | ||||||
|     if (this.browserContext._pageBindings.has(name)) |     if (this.browserContext._pageBindings.has(name)) | ||||||
|  | @ -338,13 +336,16 @@ export class Page extends SdkObject { | ||||||
|     this._pageBindings.set(name, binding); |     this._pageBindings.set(name, binding); | ||||||
|     await this.delegate.addInitScript(binding.initScript); |     await this.delegate.addInitScript(binding.initScript); | ||||||
|     await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main'); |     await this.safeNonStallingEvaluateInAllFrames(binding.initScript.source, 'main'); | ||||||
|  |     return binding; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async _removeExposedBindings() { |   async removeExposedBindings(bindings: PageBinding[]) { | ||||||
|     for (const [key, binding] of this._pageBindings) { |     bindings = bindings.filter(binding => this._pageBindings.get(binding.name) === binding); | ||||||
|       if (!binding.internal) |     for (const binding of bindings) | ||||||
|         this._pageBindings.delete(key); |       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) { |   setExtraHTTPHeaders(headers: types.HeadersArray) { | ||||||
|  | @ -560,14 +561,16 @@ export class Page extends SdkObject { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async addInitScript(source: string, name?: string) { |   async addInitScript(source: string, name?: string) { | ||||||
|     const initScript = new InitScript(source, false /* internal */, name); |     const initScript = new InitScript(source, name); | ||||||
|     this.initScripts.push(initScript); |     this.initScripts.push(initScript); | ||||||
|     await this.delegate.addInitScript(initScript); |     await this.delegate.addInitScript(initScript); | ||||||
|  |     return initScript; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async _removeInitScripts() { |   async removeInitScripts(initScripts: InitScript[]) { | ||||||
|     this.initScripts = this.initScripts.filter(script => script.internal); |     const set = new Set(initScripts); | ||||||
|     await this.delegate.removeNonInternalInitScripts(); |     this.initScripts = this.initScripts.filter(script => !set.has(script)); | ||||||
|  |     await this.delegate.removeInitScripts(initScripts); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   needsRequestInterception(): boolean { |   needsRequestInterception(): boolean { | ||||||
|  | @ -862,21 +865,21 @@ export class PageBinding { | ||||||
|         if (!globalThis[property]) |         if (!globalThis[property]) | ||||||
|           globalThis[property] = new (module.exports.BindingsController())(globalThis, '${PageBinding.kBindingName}'); |           globalThis[property] = new (module.exports.BindingsController())(globalThis, '${PageBinding.kBindingName}'); | ||||||
|       })(); |       })(); | ||||||
|     `, true /* internal */);
 |     `);
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   readonly name: string; |   readonly name: string; | ||||||
|   readonly playwrightFunction: frames.FunctionWithSource; |   readonly playwrightFunction: frames.FunctionWithSource; | ||||||
|   readonly initScript: InitScript; |   readonly initScript: InitScript; | ||||||
|   readonly needsHandle: boolean; |   readonly needsHandle: boolean; | ||||||
|   readonly internal: boolean; |   readonly cleanupScript: string; | ||||||
| 
 | 
 | ||||||
|   constructor(name: string, playwrightFunction: frames.FunctionWithSource, needsHandle: boolean) { |   constructor(name: string, playwrightFunction: frames.FunctionWithSource, needsHandle: boolean) { | ||||||
|     this.name = name; |     this.name = name; | ||||||
|     this.playwrightFunction = playwrightFunction; |     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.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) { |   static async dispatch(page: Page, payload: string, context: dom.FrameExecutionContext) { | ||||||
|  | @ -905,14 +908,13 @@ export class PageBinding { | ||||||
| 
 | 
 | ||||||
| export class InitScript { | export class InitScript { | ||||||
|   readonly source: string; |   readonly source: string; | ||||||
|   readonly internal: boolean; |  | ||||||
|   readonly name?: string; |   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 = `(() => {
 |     this.source = `(() => {
 | ||||||
|       ${source} |       ${source} | ||||||
|     })();`;
 |     })();`;
 | ||||||
|     this.internal = !!internal; |  | ||||||
|     this.name = name; |     this.name = name; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ import { Page } from '../../page'; | ||||||
| import type { SnapshotData } from './snapshotterInjected'; | import type { SnapshotData } from './snapshotterInjected'; | ||||||
| import type { RegisteredListener } from '../../utils/eventsHelper'; | import type { RegisteredListener } from '../../utils/eventsHelper'; | ||||||
| import type { Frame } from '../../frames'; | import type { Frame } from '../../frames'; | ||||||
|  | import type { InitScript } from '../../page'; | ||||||
| import type { FrameSnapshot } from '@trace/snapshot'; | import type { FrameSnapshot } from '@trace/snapshot'; | ||||||
| 
 | 
 | ||||||
| export type SnapshotterBlob = { | export type SnapshotterBlob = { | ||||||
|  | @ -43,7 +44,7 @@ export class Snapshotter { | ||||||
|   private _delegate: SnapshotterDelegate; |   private _delegate: SnapshotterDelegate; | ||||||
|   private _eventListeners: RegisteredListener[] = []; |   private _eventListeners: RegisteredListener[] = []; | ||||||
|   private _snapshotStreamer: string; |   private _snapshotStreamer: string; | ||||||
|   private _initialized = false; |   private _initScript: InitScript | undefined; | ||||||
|   private _started = false; |   private _started = false; | ||||||
| 
 | 
 | ||||||
|   constructor(context: BrowserContext, delegate: SnapshotterDelegate) { |   constructor(context: BrowserContext, delegate: SnapshotterDelegate) { | ||||||
|  | @ -59,25 +60,26 @@ export class Snapshotter { | ||||||
| 
 | 
 | ||||||
|   async start() { |   async start() { | ||||||
|     this._started = true; |     this._started = true; | ||||||
|     if (!this._initialized) { |     if (!this._initScript) | ||||||
|       this._initialized = true; |  | ||||||
|       await this._initialize(); |       await this._initialize(); | ||||||
|     } |  | ||||||
|     await this.reset(); |     await this.reset(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async reset() { |   async reset() { | ||||||
|     if (this._started) |     if (this._started) | ||||||
|       await this._runInAllFrames(`window["${this._snapshotStreamer}"].reset()`); |       await this._context.safeNonStallingEvaluateInAllFrames(`window["${this._snapshotStreamer}"].reset()`, 'main'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async stop() { |   async stop() { | ||||||
|     this._started = false; |     this._started = false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   resetForReuse() { |   async resetForReuse() { | ||||||
|     // Next time we start recording, we will call addInitScript again.
 |     // 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() { |   async _initialize() { | ||||||
|  | @ -88,18 +90,9 @@ export class Snapshotter { | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     const { javaScriptEnabled } = this._context._options; |     const { javaScriptEnabled } = this._context._options; | ||||||
|     const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === undefined})`; |     const initScriptSource = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === undefined})`; | ||||||
|     await this._context.addInitScript(initScript); |     this._initScript = await this._context.addInitScript(initScriptSource); | ||||||
|     await this._runInAllFrames(initScript); |     await this._context.safeNonStallingEvaluateInAllFrames(initScriptSource, 'main'); | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   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)); |  | ||||||
|     })); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   dispose() { |   dispose() { | ||||||
|  |  | ||||||
|  | @ -126,7 +126,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps | ||||||
|     // Discard previous chunk if any and ignore any errors there.
 |     // Discard previous chunk if any and ignore any errors there.
 | ||||||
|     await this.stopChunk({ mode: 'discard' }).catch(() => {}); |     await this.stopChunk({ mode: 'discard' }).catch(() => {}); | ||||||
|     await this.stop(); |     await this.stop(); | ||||||
|     this._snapshotter?.resetForReuse(); |     await this._snapshotter?.resetForReuse(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async start(options: TracerOptions) { |   async start(options: TracerOptions) { | ||||||
|  |  | ||||||
|  | @ -319,7 +319,7 @@ export class WKBrowserContext extends BrowserContext { | ||||||
|       await (page.delegate as WKPage)._updateBootstrapScript(); |       await (page.delegate as WKPage)._updateBootstrapScript(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async doRemoveNonInternalInitScripts() { |   async doRemoveInitScripts(initScripts: InitScript[]) { | ||||||
|     for (const page of this.pages()) |     for (const page of this.pages()) | ||||||
|       await (page.delegate as WKPage)._updateBootstrapScript(); |       await (page.delegate as WKPage)._updateBootstrapScript(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -768,7 +768,7 @@ export class WKPage implements PageDelegate { | ||||||
|     await this._updateBootstrapScript(); |     await this._updateBootstrapScript(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async removeNonInternalInitScripts() { |   async removeInitScripts(initScripts: InitScript[]): Promise<void> { | ||||||
|     await this._updateBootstrapScript(); |     await this._updateBootstrapScript(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ import type { Browser, BrowserContext, BrowserServer, ConnectOptions, Page } fro | ||||||
| type ExtraFixtures = { | type ExtraFixtures = { | ||||||
|   remoteServer: BrowserServer; |   remoteServer: BrowserServer; | ||||||
|   connect: (wsEndpoint: string, options?: ConnectOptions) => Promise<Browser>, |   connect: (wsEndpoint: string, options?: ConnectOptions) => Promise<Browser>, | ||||||
|  |   twoPages: { pageA: Page, pageB: Page }, | ||||||
| }; | }; | ||||||
| const test = playwrightTest.extend<ExtraFixtures>({ | const test = playwrightTest.extend<ExtraFixtures>({ | ||||||
|   remoteServer: async ({ browserType }, use) => { |   remoteServer: async ({ browserType }, use) => { | ||||||
|  | @ -35,6 +36,17 @@ const test = playwrightTest.extend<ExtraFixtures>({ | ||||||
|     }); |     }); | ||||||
|     await browser?.close(); |     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'); | 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; |   const pageB2 = await pageEventPromise; | ||||||
|   await pageA2.goto('/frames/frame.html'); |   await pageA2.goto('/frames/frame.html'); | ||||||
|   await expect(pageB2).toHaveURL('/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