chore(codegen): move action update into the recorder app (#36523)
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 / legacy progress timeouts (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 }}) (chromium, 24, 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 / Test Runner (24, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (24, 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 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (24, 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, chromium-tip-of-tree, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (firefox, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (webkit, ubuntu-24.04) (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 / legacy progress timeouts (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 }}) (chromium, 24, 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 / Test Runner (24, ubuntu-latest, 1, 2) (push) Waiting to run
Details
tests 1 / Test Runner (24, 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 / Installation Test ${{ matrix.os }} (${{ matrix.node_version }}) (24, 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, chromium-tip-of-tree, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (chromium, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (firefox, ubuntu-22.04) (push) Waiting to run
Details
tests 2 / Tracing ${{ matrix.browser }} ${{ matrix.channel }} (webkit, ubuntu-24.04) (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
04d1c083b1
commit
fc0b770d0c
|
@ -71,7 +71,14 @@ commandWithOpenOptions('codegen [url]', 'open page and generate code for user ac
|
||||||
['--target <language>', `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()],
|
['--target <language>', `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()],
|
||||||
['--test-id-attribute <attributeName>', 'use the specified attribute to generate data test ID selectors'],
|
['--test-id-attribute <attributeName>', 'use the specified attribute to generate data test ID selectors'],
|
||||||
]).action(function(url, options) {
|
]).action(function(url, options) {
|
||||||
codegen(options, url).catch(logErrorAndExit);
|
codegen(options, url).catch(error => {
|
||||||
|
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
|
||||||
|
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
|
||||||
|
// in a stray navigation aborted error. We should ignore it.
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
}).addHelpText('afterAll', `
|
}).addHelpText('afterAll', `
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -480,8 +487,12 @@ async function launchContext(options: Options, extraOptions: LaunchOptions): Pro
|
||||||
process.stdout.write(text);
|
process.stdout.write(text);
|
||||||
process.stdout.write('\n-------------8<-------------\n');
|
process.stdout.write('\n-------------8<-------------\n');
|
||||||
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
|
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
|
||||||
if (autoExitCondition && text.includes(autoExitCondition))
|
if (autoExitCondition && text.includes(autoExitCondition)) {
|
||||||
closeBrowser();
|
// Firefox needs a break here
|
||||||
|
setTimeout(() => {
|
||||||
|
closeBrowser();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Make sure we exit abnormally when browser crashes.
|
// Make sure we exit abnormally when browser crashes.
|
||||||
const logs: string[] = [];
|
const logs: string[] = [];
|
||||||
|
@ -615,14 +626,7 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi
|
||||||
url = 'file://' + path.resolve(url);
|
url = 'file://' + path.resolve(url);
|
||||||
else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:'))
|
else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:'))
|
||||||
url = 'http://' + url;
|
url = 'http://' + url;
|
||||||
await page.goto(url).catch(error => {
|
await page.goto(url);
|
||||||
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
|
|
||||||
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
|
|
||||||
// in a stray navigation aborted error. We should ignore it.
|
|
||||||
} else {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
../utilsBundle.ts
|
../utilsBundle.ts
|
||||||
../zipBundle.ts
|
../zipBundle.ts
|
||||||
./
|
./
|
||||||
./codegen/language.ts
|
./codegen/
|
||||||
./codegen/languages.ts
|
|
||||||
./isomorphic/
|
./isomorphic/
|
||||||
./har/
|
./har/
|
||||||
./recorder/
|
./recorder/
|
||||||
|
|
|
@ -31,7 +31,6 @@ import { SdkObject } from './instrumentation';
|
||||||
import * as network from './network';
|
import * as network from './network';
|
||||||
import { InitScript } from './page';
|
import { InitScript } from './page';
|
||||||
import { Page, PageBinding } from './page';
|
import { Page, PageBinding } from './page';
|
||||||
import { Recorder } from './recorder';
|
|
||||||
import { RecorderApp } from './recorder/recorderApp';
|
import { RecorderApp } from './recorder/recorderApp';
|
||||||
import { Selectors } from './selectors';
|
import { Selectors } from './selectors';
|
||||||
import { Tracing } from './trace/recorder/tracing';
|
import { Tracing } from './trace/recorder/tracing';
|
||||||
|
@ -129,15 +128,15 @@ export abstract class BrowserContext extends SdkObject {
|
||||||
|
|
||||||
// When PWDEBUG=1, show inspector for each context.
|
// When PWDEBUG=1, show inspector for each context.
|
||||||
if (debugMode() === 'inspector')
|
if (debugMode() === 'inspector')
|
||||||
await Recorder.show(this, RecorderApp.factory(this), { pauseOnNextStatement: true });
|
await RecorderApp.show(this, { pauseOnNextStatement: true });
|
||||||
|
|
||||||
// When paused, show inspector.
|
// When paused, show inspector.
|
||||||
if (this._debugger.isPaused())
|
if (this._debugger.isPaused())
|
||||||
Recorder.showInspectorNoReply(this, RecorderApp.factory(this));
|
await RecorderApp.showInspectorNoReply(this);
|
||||||
|
|
||||||
this._debugger.on(Debugger.Events.PausedStateChanged, () => {
|
this._debugger.on(Debugger.Events.PausedStateChanged, () => {
|
||||||
if (this._debugger.isPaused())
|
if (this._debugger.isPaused())
|
||||||
Recorder.showInspectorNoReply(this, RecorderApp.factory(this));
|
RecorderApp.showInspectorNoReply(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (debugMode() === 'console')
|
if (debugMode() === 'console')
|
||||||
|
|
|
@ -22,16 +22,16 @@ import { PythonLanguageGenerator } from './python';
|
||||||
|
|
||||||
export function languageSet() {
|
export function languageSet() {
|
||||||
return new Set([
|
return new Set([
|
||||||
new JavaLanguageGenerator('junit'),
|
|
||||||
new JavaLanguageGenerator('library'),
|
|
||||||
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
|
|
||||||
new JavaScriptLanguageGenerator(/* isPlaywrightTest */true),
|
new JavaScriptLanguageGenerator(/* isPlaywrightTest */true),
|
||||||
|
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
|
||||||
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */true),
|
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */true),
|
||||||
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */false),
|
new PythonLanguageGenerator(/* isAsync */false, /* isPytest */false),
|
||||||
new PythonLanguageGenerator(/* isAsync */true, /* isPytest */false),
|
new PythonLanguageGenerator(/* isAsync */true, /* isPytest */false),
|
||||||
new CSharpLanguageGenerator('mstest'),
|
new CSharpLanguageGenerator('mstest'),
|
||||||
new CSharpLanguageGenerator('nunit'),
|
new CSharpLanguageGenerator('nunit'),
|
||||||
new CSharpLanguageGenerator('library'),
|
new CSharpLanguageGenerator('library'),
|
||||||
|
new JavaLanguageGenerator('junit'),
|
||||||
|
new JavaLanguageGenerator('library'),
|
||||||
new JsonlLanguageGenerator(),
|
new JsonlLanguageGenerator(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,18 @@ import { parseAriaSnapshotUnsafe } from '../utils/isomorphic/ariaSnapshot';
|
||||||
import { yaml } from '../utilsBundle';
|
import { yaml } from '../utilsBundle';
|
||||||
import { EmptyRecorderApp } from './recorder/recorderApp';
|
import { EmptyRecorderApp } from './recorder/recorderApp';
|
||||||
import { unsafeLocatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser';
|
import { unsafeLocatorOrSelectorAsSelector } from '../utils/isomorphic/locatorParser';
|
||||||
|
import { generateCode } from './codegen/language';
|
||||||
|
import { collapseActions } from './recorder/recorderUtils';
|
||||||
|
import { JavaScriptLanguageGenerator } from './codegen/javascript';
|
||||||
|
|
||||||
import type { Language } from '../utils';
|
import type { Language } from '../utils';
|
||||||
import type { Browser } from './browser';
|
import type { Browser } from './browser';
|
||||||
import type { BrowserContext } from './browserContext';
|
import type { BrowserContext } from './browserContext';
|
||||||
import type { InstrumentationListener } from './instrumentation';
|
import type { InstrumentationListener } from './instrumentation';
|
||||||
import type { Playwright } from './playwright';
|
import type { Playwright } from './playwright';
|
||||||
import type { ElementInfo, Mode, Source } from '@recorder/recorderTypes';
|
import type { ElementInfo, Mode } from '@recorder/recorderTypes';
|
||||||
import type { Progress } from '@protocol/progress';
|
import type { Progress } from '@protocol/progress';
|
||||||
|
import type * as actions from '@recorder/actions';
|
||||||
|
|
||||||
export class DebugController extends SdkObject {
|
export class DebugController extends SdkObject {
|
||||||
static Events = {
|
static Events = {
|
||||||
|
@ -43,7 +47,6 @@ export class DebugController extends SdkObject {
|
||||||
private _trackHierarchyListener: InstrumentationListener | undefined;
|
private _trackHierarchyListener: InstrumentationListener | undefined;
|
||||||
private _playwright: Playwright;
|
private _playwright: Playwright;
|
||||||
_sdkLanguage: Language = 'javascript';
|
_sdkLanguage: Language = 'javascript';
|
||||||
_codegenId: string = 'playwright-test';
|
|
||||||
|
|
||||||
constructor(playwright: Playwright) {
|
constructor(playwright: Playwright) {
|
||||||
super({ attribution: { isInternalPlaywright: true }, instrumentation: createInstrumentation() } as any, undefined, 'DebugController');
|
super({ attribution: { isInternalPlaywright: true }, instrumentation: createInstrumentation() } as any, undefined, 'DebugController');
|
||||||
|
@ -51,7 +54,6 @@ export class DebugController extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(codegenId: string, sdkLanguage: Language) {
|
initialize(codegenId: string, sdkLanguage: Language) {
|
||||||
this._codegenId = codegenId;
|
|
||||||
this._sdkLanguage = sdkLanguage;
|
this._sdkLanguage = sdkLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +88,7 @@ export class DebugController extends SdkObject {
|
||||||
await p.mainFrame().goto(progress, url);
|
await p.mainFrame().goto(progress, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRecorderMode(progress: Progress, params: { mode: Mode, file?: string, testIdAttributeName?: string }) {
|
async setRecorderMode(progress: Progress, params: { mode: Mode, testIdAttributeName?: string }) {
|
||||||
// TODO: |file| is only used in the legacy mode.
|
|
||||||
await progress.race(this._closeBrowsersWithoutPages());
|
await progress.race(this._closeBrowsersWithoutPages());
|
||||||
|
|
||||||
if (params.mode === 'none') {
|
if (params.mode === 'none') {
|
||||||
|
@ -115,8 +116,6 @@ export class DebugController extends SdkObject {
|
||||||
// Toggle the mode.
|
// Toggle the mode.
|
||||||
for (const recorder of await progress.race(this._allRecorders())) {
|
for (const recorder of await progress.race(this._allRecorders())) {
|
||||||
recorder.hideHighlightedSelector();
|
recorder.hideHighlightedSelector();
|
||||||
if (params.mode !== 'inspecting')
|
|
||||||
recorder.setOutput(this._codegenId, params.file);
|
|
||||||
recorder.setMode(params.mode);
|
recorder.setMode(params.mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,10 +187,13 @@ export class DebugController extends SdkObject {
|
||||||
|
|
||||||
class InspectingRecorderApp extends EmptyRecorderApp {
|
class InspectingRecorderApp extends EmptyRecorderApp {
|
||||||
private _debugController: DebugController;
|
private _debugController: DebugController;
|
||||||
|
private _actions: actions.ActionInContext[] = [];
|
||||||
|
private _languageGenerator: JavaScriptLanguageGenerator;
|
||||||
|
|
||||||
constructor(debugController: DebugController) {
|
constructor(debugController: DebugController) {
|
||||||
super();
|
super();
|
||||||
this._debugController = debugController;
|
this._debugController = debugController;
|
||||||
|
this._languageGenerator = new JavaScriptLanguageGenerator(/* isPlaywrightTest */true);
|
||||||
}
|
}
|
||||||
|
|
||||||
override async elementPicked(elementInfo: ElementInfo): Promise<void> {
|
override async elementPicked(elementInfo: ElementInfo): Promise<void> {
|
||||||
|
@ -199,12 +201,6 @@ class InspectingRecorderApp extends EmptyRecorderApp {
|
||||||
this._debugController.emit(DebugController.Events.InspectRequested, { selector: elementInfo.selector, locator, ariaSnapshot: elementInfo.ariaSnapshot });
|
this._debugController.emit(DebugController.Events.InspectRequested, { selector: elementInfo.selector, locator, ariaSnapshot: elementInfo.ariaSnapshot });
|
||||||
}
|
}
|
||||||
|
|
||||||
override async setSources(sources: Source[]): Promise<void> {
|
|
||||||
const source = sources.find(s => s.id === this._debugController._codegenId);
|
|
||||||
const { text, header, footer, actions } = source || { text: '' };
|
|
||||||
this._debugController.emit(DebugController.Events.SourceChanged, { text, header, footer, actions });
|
|
||||||
}
|
|
||||||
|
|
||||||
override async setPaused(paused: boolean) {
|
override async setPaused(paused: boolean) {
|
||||||
this._debugController.emit(DebugController.Events.Paused, { paused });
|
this._debugController.emit(DebugController.Events.Paused, { paused });
|
||||||
}
|
}
|
||||||
|
@ -212,4 +208,26 @@ class InspectingRecorderApp extends EmptyRecorderApp {
|
||||||
override async setMode(mode: Mode) {
|
override async setMode(mode: Mode) {
|
||||||
this._debugController.emit(DebugController.Events.SetModeRequested, { mode });
|
this._debugController.emit(DebugController.Events.SetModeRequested, { mode });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override async actionAdded(action: actions.ActionInContext): Promise<void> {
|
||||||
|
this._actions.push(action);
|
||||||
|
this._actionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
override async signalAdded(signal: actions.Signal): Promise<void> {
|
||||||
|
const lastAction = this._actions[this._actions.length - 1];
|
||||||
|
if (lastAction)
|
||||||
|
lastAction.action.signals.push(signal);
|
||||||
|
this._actionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _actionsChanged() {
|
||||||
|
const actions = collapseActions(this._actions);
|
||||||
|
const { header, footer, text, actionTexts } = generateCode(actions, this._languageGenerator, {
|
||||||
|
browserName: 'chromium',
|
||||||
|
launchOptions: {},
|
||||||
|
contextOptions: {},
|
||||||
|
});
|
||||||
|
this._debugController.emit(DebugController.Events.SourceChanged, { text, header, footer, actions: actionTexts });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import { APIRequestContextDispatcher, RequestDispatcher, ResponseDispatcher, Rou
|
||||||
import { BindingCallDispatcher, PageDispatcher, WorkerDispatcher } from './pageDispatcher';
|
import { BindingCallDispatcher, PageDispatcher, WorkerDispatcher } from './pageDispatcher';
|
||||||
import { CRBrowserContext } from '../chromium/crBrowser';
|
import { CRBrowserContext } from '../chromium/crBrowser';
|
||||||
import { serializeError } from '../errors';
|
import { serializeError } from '../errors';
|
||||||
import { Recorder } from '../recorder';
|
|
||||||
import { TracingDispatcher } from './tracingDispatcher';
|
import { TracingDispatcher } from './tracingDispatcher';
|
||||||
import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher';
|
import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher';
|
||||||
import { WritableStreamDispatcher } from './writableStreamDispatcher';
|
import { WritableStreamDispatcher } from './writableStreamDispatcher';
|
||||||
|
@ -332,7 +331,7 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
||||||
}
|
}
|
||||||
|
|
||||||
async enableRecorder(params: channels.BrowserContextEnableRecorderParams, progress: Progress): Promise<void> {
|
async enableRecorder(params: channels.BrowserContextEnableRecorderParams, progress: Progress): Promise<void> {
|
||||||
await Recorder.show(this._context, RecorderApp.factory(this._context), params);
|
await RecorderApp.show(this._context, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async pause(params: channels.BrowserContextPauseParams, progress: Progress) {
|
async pause(params: channels.BrowserContextPauseParams, progress: Progress) {
|
||||||
|
|
|
@ -27,16 +27,12 @@ import { serverSideCallMetadata } from './instrumentation';
|
||||||
import { RecorderSignalProcessor } from './recorder/recorderSignalProcessor';
|
import { RecorderSignalProcessor } from './recorder/recorderSignalProcessor';
|
||||||
import * as rawRecorderSource from './../generated/pollingRecorderSource';
|
import * as rawRecorderSource from './../generated/pollingRecorderSource';
|
||||||
import { eventsHelper, monotonicTime } from './../utils';
|
import { eventsHelper, monotonicTime } from './../utils';
|
||||||
import { languageSet } from './codegen/languages';
|
|
||||||
import { Frame } from './frames';
|
import { Frame } from './frames';
|
||||||
import { Page } from './page';
|
import { Page } from './page';
|
||||||
import { ThrottledFile } from './recorder/throttledFile';
|
|
||||||
import { generateCode } from './codegen/language';
|
|
||||||
import { performAction } from './recorder/recorderRunner';
|
import { performAction } from './recorder/recorderRunner';
|
||||||
import { collapseActions } from './recorder/recorderUtils';
|
|
||||||
|
|
||||||
|
|
||||||
import type { Language, LanguageGenerator, LanguageGeneratorOptions } from './codegen/types';
|
import type { Language } from './codegen/types';
|
||||||
import type { CallMetadata, InstrumentationListener, SdkObject } from './instrumentation';
|
import type { CallMetadata, InstrumentationListener, SdkObject } from './instrumentation';
|
||||||
import type { IRecorder, IRecorderApp, IRecorderAppFactory } from './recorder/recorderFrontend';
|
import type { IRecorder, IRecorderApp, IRecorderAppFactory } from './recorder/recorderFrontend';
|
||||||
import type { Point } from '../utils/isomorphic/types';
|
import type { Point } from '../utils/isomorphic/types';
|
||||||
|
@ -60,11 +56,10 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
private _overlayState: OverlayState = { offsetX: 0 };
|
private _overlayState: OverlayState = { offsetX: 0 };
|
||||||
private _recorderApp: IRecorderApp | null = null;
|
private _recorderApp: IRecorderApp | null = null;
|
||||||
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
||||||
private _recorderSources: Source[] = [];
|
|
||||||
private _userSources = new Map<string, Source>();
|
private _userSources = new Map<string, Source>();
|
||||||
private _debugger: Debugger;
|
private _debugger: Debugger;
|
||||||
private _omitCallTracking = false;
|
private _omitCallTracking = false;
|
||||||
private _currentLanguage: Language;
|
private _currentLanguage: Language = 'javascript';
|
||||||
private _recorderMode: 'record' | 'perform';
|
private _recorderMode: 'record' | 'perform';
|
||||||
|
|
||||||
private _signalProcessor: RecorderSignalProcessor;
|
private _signalProcessor: RecorderSignalProcessor;
|
||||||
|
@ -72,23 +67,13 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
private _lastPopupOrdinal = 0;
|
private _lastPopupOrdinal = 0;
|
||||||
private _lastDialogOrdinal = -1;
|
private _lastDialogOrdinal = -1;
|
||||||
private _lastDownloadOrdinal = -1;
|
private _lastDownloadOrdinal = -1;
|
||||||
private _throttledOutputFile: ThrottledFile | null = null;
|
|
||||||
private _orderedLanguages: LanguageGenerator[] = [];
|
|
||||||
private _listeners: RegisteredListener[] = [];
|
private _listeners: RegisteredListener[] = [];
|
||||||
private _actions: actions.ActionInContext[] = [];
|
|
||||||
private _languageGeneratorOptions: LanguageGeneratorOptions;
|
|
||||||
private _enabled: boolean = false;
|
private _enabled: boolean = false;
|
||||||
|
|
||||||
static async showInspector(context: BrowserContext, params: channels.BrowserContextEnableRecorderParams, recorderAppFactory: IRecorderAppFactory) {
|
static async showInspector(context: BrowserContext, params: channels.BrowserContextEnableRecorderParams, recorderAppFactory: IRecorderAppFactory) {
|
||||||
if (isUnderTest())
|
|
||||||
params.language = process.env.TEST_INSPECTOR_LANGUAGE;
|
|
||||||
return await Recorder.show(context, recorderAppFactory, params);
|
return await Recorder.show(context, recorderAppFactory, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static showInspectorNoReply(context: BrowserContext, recorderAppFactory: IRecorderAppFactory) {
|
|
||||||
Recorder.showInspector(context, {}, recorderAppFactory).catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static show(context: BrowserContext, recorderAppFactory: IRecorderAppFactory, params: channels.BrowserContextEnableRecorderParams): Promise<Recorder> {
|
static show(context: BrowserContext, recorderAppFactory: IRecorderAppFactory, params: channels.BrowserContextEnableRecorderParams): Promise<Recorder> {
|
||||||
let recorderPromise = (context as any)[recorderSymbol] as Promise<Recorder>;
|
let recorderPromise = (context as any)[recorderSymbol] as Promise<Recorder>;
|
||||||
if (!recorderPromise) {
|
if (!recorderPromise) {
|
||||||
|
@ -102,6 +87,7 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
const recorder = new Recorder(context, params);
|
const recorder = new Recorder(context, params);
|
||||||
const recorderApp = await recorderAppFactory(recorder);
|
const recorderApp = await recorderAppFactory(recorder);
|
||||||
await recorder._install(recorderApp);
|
await recorder._install(recorderApp);
|
||||||
|
recorderApp.start();
|
||||||
return recorder;
|
return recorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,46 +98,28 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
this._recorderMode = params.recorderMode ?? 'perform';
|
this._recorderMode = params.recorderMode ?? 'perform';
|
||||||
this.handleSIGINT = params.handleSIGINT;
|
this.handleSIGINT = params.handleSIGINT;
|
||||||
|
|
||||||
// Make a copy of options to modify them later.
|
|
||||||
this._languageGeneratorOptions = {
|
|
||||||
browserName: context._browser.options.name,
|
|
||||||
launchOptions: { headless: false, ...params.launchOptions, tracesDir: undefined },
|
|
||||||
contextOptions: { ...params.contextOptions },
|
|
||||||
deviceName: params.device,
|
|
||||||
saveStorage: params.saveStorage,
|
|
||||||
};
|
|
||||||
|
|
||||||
this._signalProcessor = new RecorderSignalProcessor();
|
this._signalProcessor = new RecorderSignalProcessor();
|
||||||
this._signalProcessor.on('action', (actionInContext: actions.ActionInContext) => {
|
this._signalProcessor.on('action', (actionInContext: actions.ActionInContext) => {
|
||||||
if (!this._enabled)
|
if (this._enabled)
|
||||||
return;
|
this._recorderApp?.actionAdded(actionInContext);
|
||||||
this._actions.push(actionInContext);
|
|
||||||
this._updateActions();
|
|
||||||
});
|
});
|
||||||
this._signalProcessor.on('signal', (signal: Signal) => {
|
this._signalProcessor.on('signal', (signal: Signal) => {
|
||||||
if (!this._enabled)
|
if (this._enabled)
|
||||||
return;
|
this._recorderApp?.signalAdded(signal);
|
||||||
const lastAction = this._actions[this._actions.length - 1];
|
|
||||||
if (lastAction)
|
|
||||||
lastAction.action.signals.push(signal);
|
|
||||||
this._updateActions();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context.on(BrowserContext.Events.BeforeClose, () => {
|
context.on(BrowserContext.Events.BeforeClose, () => {
|
||||||
this._throttledOutputFile?.flush();
|
this._recorderApp?.flushOutput().catch(() => {});
|
||||||
});
|
});
|
||||||
this._listeners.push(eventsHelper.addEventListener(process, 'exit', () => {
|
this._listeners.push(eventsHelper.addEventListener(process, 'exit', () => {
|
||||||
this._throttledOutputFile?.flush();
|
this._recorderApp?.flushOutput().catch(() => {});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const language = params.language || context._browser.sdkLanguage();
|
|
||||||
this._innerSetOutput(language, params.outputFile);
|
|
||||||
this._setEnabled(params.mode === 'recording');
|
this._setEnabled(params.mode === 'recording');
|
||||||
|
|
||||||
this._omitCallTracking = !!params.omitCallTracking;
|
this._omitCallTracking = !!params.omitCallTracking;
|
||||||
this._debugger = context.debugger();
|
this._debugger = context.debugger();
|
||||||
context.instrumentation.addListener(this, context);
|
context.instrumentation.addListener(this, context);
|
||||||
this._currentLanguage = this._languageName();
|
|
||||||
|
|
||||||
if (isUnderTest()) {
|
if (isUnderTest()) {
|
||||||
// Most of our tests put elements at the top left, so get out of the way.
|
// Most of our tests put elements at the top left, so get out of the way.
|
||||||
|
@ -181,8 +149,8 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
this._debugger.resume(true);
|
this._debugger.resume(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.event === 'fileChanged') {
|
if (data.event === 'languageChanged') {
|
||||||
this._currentLanguage = this._languageName(data.params.file);
|
this._currentLanguage = data.params.language;
|
||||||
this._refreshOverlay();
|
this._refreshOverlay();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -203,7 +171,7 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
recorderApp.setMode(this._mode),
|
recorderApp.setMode(this._mode),
|
||||||
recorderApp.setPaused(this._debugger.isPaused()),
|
recorderApp.setPaused(this._debugger.isPaused()),
|
||||||
this._pushAllSources()
|
this._pushUserSources()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this._context.once(BrowserContext.Events.Close, () => {
|
this._context.once(BrowserContext.Events.Close, () => {
|
||||||
|
@ -361,21 +329,6 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOutput(codegenId: string, outputFile: string | undefined) {
|
|
||||||
this._innerSetOutput(codegenId, outputFile);
|
|
||||||
this._resetActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _innerSetOutput(codegenId: string, outputFile: string | undefined) {
|
|
||||||
const languages = languageSet();
|
|
||||||
const primaryLanguage = [...languages].find(l => l.id === codegenId);
|
|
||||||
if (!primaryLanguage)
|
|
||||||
throw new Error(`\n===============================\nUnsupported language: '${codegenId}'\n===============================\n`);
|
|
||||||
languages.delete(primaryLanguage);
|
|
||||||
this._orderedLanguages = [primaryLanguage, ...languages];
|
|
||||||
this._throttledOutputFile = outputFile ? new ThrottledFile(outputFile) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _refreshOverlay() {
|
private _refreshOverlay() {
|
||||||
for (const page of this._context.pages()) {
|
for (const page of this._context.pages()) {
|
||||||
for (const frame of page.frames())
|
for (const frame of page.frames())
|
||||||
|
@ -406,37 +359,33 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
|
|
||||||
private _updateUserSources() {
|
private _updateUserSources() {
|
||||||
// Remove old decorations.
|
// Remove old decorations.
|
||||||
|
const timestamp = monotonicTime();
|
||||||
for (const source of this._userSources.values()) {
|
for (const source of this._userSources.values()) {
|
||||||
source.highlight = [];
|
source.highlight = [];
|
||||||
source.revealLine = undefined;
|
source.revealLine = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply new decorations.
|
// Apply new decorations.
|
||||||
let fileToSelect = undefined;
|
|
||||||
for (const metadata of this._currentCallsMetadata.keys()) {
|
for (const metadata of this._currentCallsMetadata.keys()) {
|
||||||
if (!metadata.location)
|
if (!metadata.location)
|
||||||
continue;
|
continue;
|
||||||
const { file, line } = metadata.location;
|
const { file, line } = metadata.location;
|
||||||
let source = this._userSources.get(file);
|
let source = this._userSources.get(file);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
source = { isRecorded: false, label: file, id: file, text: this._readSource(file), highlight: [], language: languageForFile(file) };
|
source = { isPrimary: false, isRecorded: false, label: file, id: file, text: this._readSource(file), highlight: [], language: languageForFile(file), timestamp };
|
||||||
this._userSources.set(file, source);
|
this._userSources.set(file, source);
|
||||||
}
|
}
|
||||||
if (line) {
|
if (line) {
|
||||||
const paused = this._debugger.isPaused(metadata);
|
const paused = this._debugger.isPaused(metadata);
|
||||||
source.highlight.push({ line, type: metadata.error ? 'error' : (paused ? 'paused' : 'running') });
|
source.highlight.push({ line, type: metadata.error ? 'error' : (paused ? 'paused' : 'running') });
|
||||||
source.revealLine = line;
|
source.revealLine = line;
|
||||||
fileToSelect = source.id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._pushAllSources();
|
this._pushUserSources();
|
||||||
if (fileToSelect)
|
|
||||||
this._recorderApp?.setRunningFile(fileToSelect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _pushAllSources() {
|
private _pushUserSources() {
|
||||||
const primaryPage: Page | undefined = this._context.pages()[0];
|
this._recorderApp?.userSourcesChanged([...this._userSources.values()]);
|
||||||
this._recorderApp?.setSources([...this._recorderSources, ...this._userSources.values()], primaryPage?.mainFrame().url());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) {
|
async onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) {
|
||||||
|
@ -475,48 +424,6 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resetActions() {
|
|
||||||
this._actions = [];
|
|
||||||
this._updateActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateActions() {
|
|
||||||
const actions = collapseActions(this._actions);
|
|
||||||
const recorderSources = [];
|
|
||||||
for (const languageGenerator of this._orderedLanguages) {
|
|
||||||
const { header, footer, actionTexts, text } = generateCode(actions, languageGenerator, this._languageGeneratorOptions);
|
|
||||||
const source: Source = {
|
|
||||||
isRecorded: true,
|
|
||||||
label: languageGenerator.name,
|
|
||||||
group: languageGenerator.groupName,
|
|
||||||
id: languageGenerator.id,
|
|
||||||
text,
|
|
||||||
header,
|
|
||||||
footer,
|
|
||||||
actions: actionTexts,
|
|
||||||
language: languageGenerator.highlighter,
|
|
||||||
highlight: []
|
|
||||||
};
|
|
||||||
source.revealLine = text.split('\n').length - 1;
|
|
||||||
recorderSources.push(source);
|
|
||||||
if (languageGenerator === this._orderedLanguages[0])
|
|
||||||
this._throttledOutputFile?.setContent(source.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._recorderSources = recorderSources;
|
|
||||||
this._recorderApp?.setActions(actions, recorderSources);
|
|
||||||
this._recorderApp?.setRunningFile(undefined);
|
|
||||||
this._pushAllSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _languageName(id?: string): Language {
|
|
||||||
for (const lang of this._orderedLanguages) {
|
|
||||||
if (!id || lang.id === id)
|
|
||||||
return lang.highlighter;
|
|
||||||
}
|
|
||||||
return 'javascript';
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setEnabled(enabled: boolean) {
|
private _setEnabled(enabled: boolean) {
|
||||||
this._enabled = enabled;
|
this._enabled = enabled;
|
||||||
}
|
}
|
||||||
|
@ -534,10 +441,13 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
startTime: monotonicTime()
|
startTime: monotonicTime()
|
||||||
});
|
});
|
||||||
this._pageAliases.delete(page);
|
this._pageAliases.delete(page);
|
||||||
|
this._filePrimaryURLChanged();
|
||||||
});
|
});
|
||||||
frame.on(Frame.Events.InternalNavigation, event => {
|
frame.on(Frame.Events.InternalNavigation, event => {
|
||||||
if (event.isPublic)
|
if (event.isPublic) {
|
||||||
this._onFrameNavigated(frame, page);
|
this._onFrameNavigated(frame, page);
|
||||||
|
this._filePrimaryURLChanged();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
page.on(Page.Events.Download, () => this._onDownload(page));
|
page.on(Page.Events.Download, () => this._onDownload(page));
|
||||||
const suffix = this._pageAliases.size ? String(++this._lastPopupOrdinal) : '';
|
const suffix = this._pageAliases.size ? String(++this._lastPopupOrdinal) : '';
|
||||||
|
@ -557,10 +467,15 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
startTime: monotonicTime()
|
startTime: monotonicTime()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this._filePrimaryURLChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filePrimaryURLChanged() {
|
||||||
|
const page = this._context.pages()[0];
|
||||||
|
this._recorderApp?.pageNavigated(page?.mainFrame().url());
|
||||||
}
|
}
|
||||||
|
|
||||||
private _clearScript(): void {
|
private _clearScript(): void {
|
||||||
this._resetActions();
|
|
||||||
if (this._params.mode === 'recording') {
|
if (this._params.mode === 'recording') {
|
||||||
for (const page of this._context.pages())
|
for (const page of this._context.pages())
|
||||||
this._onFrameNavigated(page.mainFrame(), page);
|
this._onFrameNavigated(page.mainFrame(), page);
|
||||||
|
|
|
@ -24,40 +24,63 @@ import { serverSideCallMetadata } from '../instrumentation';
|
||||||
import { syncLocalStorageWithSettings } from '../launchApp';
|
import { syncLocalStorageWithSettings } from '../launchApp';
|
||||||
import { launchApp } from '../launchApp';
|
import { launchApp } from '../launchApp';
|
||||||
import { ProgressController } from '../progress';
|
import { ProgressController } from '../progress';
|
||||||
|
import { ThrottledFile } from './throttledFile';
|
||||||
|
import { languageSet } from '../codegen/languages';
|
||||||
|
import { collapseActions } from './recorderUtils';
|
||||||
|
import { generateCode } from '../codegen/language';
|
||||||
|
import { Recorder } from '../recorder';
|
||||||
|
import { monotonicTime } from '../../utils/isomorphic/time';
|
||||||
|
|
||||||
import type { BrowserContext } from '../browserContext';
|
import type { BrowserContext } from '../browserContext';
|
||||||
import type { Page } from '../page';
|
import type { Page } from '../page';
|
||||||
import type { IRecorder, IRecorderApp, IRecorderAppFactory } from './recorderFrontend';
|
import type { IRecorder, IRecorderApp, IRecorderAppFactory, RecorderAppParams } from './recorderFrontend';
|
||||||
import type * as actions from '@recorder/actions';
|
import type * as actions from '@recorder/actions';
|
||||||
import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes';
|
import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes';
|
||||||
|
import type { LanguageGeneratorOptions } from '../codegen/types';
|
||||||
|
import type * as channels from '@protocol/channels';
|
||||||
|
|
||||||
export class EmptyRecorderApp extends EventEmitter implements IRecorderApp {
|
export class EmptyRecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
wsEndpointForTest: undefined;
|
wsEndpointForTest: undefined;
|
||||||
async close(): Promise<void> {}
|
async close(): Promise<void> {}
|
||||||
async setPaused(paused: boolean): Promise<void> {}
|
async setPaused(paused: boolean): Promise<void> {}
|
||||||
async setMode(mode: Mode): Promise<void> {}
|
async setMode(mode: Mode): Promise<void> {}
|
||||||
async setRunningFile(file: string | undefined): Promise<void> {}
|
|
||||||
async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void> {}
|
async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void> {}
|
||||||
async updateCallLogs(callLogs: CallLog[]): Promise<void> {}
|
async updateCallLogs(callLogs: CallLog[]): Promise<void> {}
|
||||||
async setSources(sources: Source[], primaryPageURL: string | undefined): Promise<void> {}
|
async userSourcesChanged(sources: Source[]): Promise<void> {}
|
||||||
async setActions(actions: actions.ActionInContext[], sources: Source[]): Promise<void> {}
|
async start() {}
|
||||||
|
async actionAdded(action: actions.ActionInContext): Promise<void> {}
|
||||||
|
async signalAdded(signal: actions.Signal): Promise<void> {}
|
||||||
|
async pageNavigated(url: string): Promise<void> {}
|
||||||
|
async flushOutput(): Promise<void> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecorderApp extends EventEmitter implements IRecorderApp {
|
export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
private _page: Page;
|
private _page: Page;
|
||||||
readonly wsEndpointForTest: string | undefined;
|
readonly wsEndpointForTest: string | undefined;
|
||||||
private _recorder: IRecorder;
|
private _languageGeneratorOptions: LanguageGeneratorOptions;
|
||||||
|
private _throttledOutputFile: ThrottledFile | null = null;
|
||||||
|
private _actions: actions.ActionInContext[] = [];
|
||||||
|
private _userSources: Source[] = [];
|
||||||
|
private _recorderSources: Source[] = [];
|
||||||
|
private _primaryLanguage: string;
|
||||||
|
|
||||||
constructor(recorder: IRecorder, page: Page, wsEndpoint: string | undefined) {
|
constructor(params: RecorderAppParams, page: Page, wsEndpointForTest: string | undefined) {
|
||||||
super();
|
super();
|
||||||
this.setMaxListeners(0);
|
this.setMaxListeners(0);
|
||||||
this._recorder = recorder;
|
|
||||||
this._page = page;
|
this._page = page;
|
||||||
this.wsEndpointForTest = wsEndpoint;
|
this.wsEndpointForTest = wsEndpointForTest;
|
||||||
}
|
|
||||||
|
|
||||||
async close() {
|
// Make a copy of options to modify them later.
|
||||||
await this._page.browserContext.close({ reason: 'Recorder window closed' });
|
this._languageGeneratorOptions = {
|
||||||
|
browserName: params.browserName,
|
||||||
|
launchOptions: { headless: false, ...params.launchOptions, tracesDir: undefined },
|
||||||
|
contextOptions: { ...params.contextOptions },
|
||||||
|
deviceName: params.device,
|
||||||
|
saveStorage: params.saveStorage,
|
||||||
|
};
|
||||||
|
|
||||||
|
this._throttledOutputFile = params.outputFile ? new ThrottledFile(params.outputFile) : null;
|
||||||
|
this._primaryLanguage = process.env.TEST_INSPECTOR_LANGUAGE || params.language || params.sdkLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _init() {
|
private async _init() {
|
||||||
|
@ -85,7 +108,7 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await this._page.exposeBinding(progress, 'dispatch', false, (_, data: any) => this.emit('event', data));
|
await this._page.exposeBinding(progress, 'dispatch', false, (_, data: any) => this._handleUIEvent(data));
|
||||||
|
|
||||||
this._page.once('close', () => {
|
this._page.once('close', () => {
|
||||||
this.emit('close');
|
this.emit('close');
|
||||||
|
@ -96,15 +119,78 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static factory(context: BrowserContext): IRecorderAppFactory {
|
start() {
|
||||||
|
this._updateActions(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async actionAdded(action: actions.ActionInContext): Promise<void> {
|
||||||
|
this._actions.push(action);
|
||||||
|
this._updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
async signalAdded(signal: actions.Signal): Promise<void> {
|
||||||
|
const lastAction = this._actions[this._actions.length - 1];
|
||||||
|
if (lastAction)
|
||||||
|
lastAction.action.signals.push(signal);
|
||||||
|
this._updateActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
async pageNavigated(url: string): Promise<void> {
|
||||||
|
await this._page.mainFrame().evaluateExpression((({ url }: { url: string }) => {
|
||||||
|
window.playwrightSetPageURL(url);
|
||||||
|
}).toString(), { isFunction: true }, { url }).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectedFileChanged(fileId: string) {
|
||||||
|
const source = [...this._recorderSources, ...this._userSources].find(s => s.id === fileId);
|
||||||
|
if (source)
|
||||||
|
this.emit('event', { event: 'languageChanged', params: { language: source.language } });
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
await this._page.browserContext.close({ reason: 'Recorder window closed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleUIEvent(data: any) {
|
||||||
|
if (data.event === 'clear') {
|
||||||
|
this._actions = [];
|
||||||
|
this._updateActions();
|
||||||
|
this.emit('clear');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data.event === 'fileChanged') {
|
||||||
|
this._selectedFileChanged(data.params.fileId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass through events.
|
||||||
|
this.emit('event', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async show(context: BrowserContext, params: channels.BrowserContextEnableRecorderParams) {
|
||||||
|
const factory = RecorderApp._factory(context, params);
|
||||||
|
await Recorder.show(context, factory, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static showInspectorNoReply(context: BrowserContext) {
|
||||||
|
Recorder.showInspector(context, {}, RecorderApp._factory(context, {})).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static _factory(context: BrowserContext, params: channels.BrowserContextEnableRecorderParams): IRecorderAppFactory {
|
||||||
|
const appParams = {
|
||||||
|
browserName: context._browser.options.name,
|
||||||
|
sdkLanguage: context._browser.sdkLanguage(),
|
||||||
|
wsEndpointForTest: context._browser.options.wsEndpoint,
|
||||||
|
...params,
|
||||||
|
};
|
||||||
return async recorder => {
|
return async recorder => {
|
||||||
if (process.env.PW_CODEGEN_NO_INSPECTOR)
|
if (process.env.PW_CODEGEN_NO_INSPECTOR)
|
||||||
return new EmptyRecorderApp();
|
return new EmptyRecorderApp();
|
||||||
return await RecorderApp._open(recorder, context);
|
return await RecorderApp._open(appParams, recorder, context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async _open(recorder: IRecorder, inspectedContext: BrowserContext): Promise<IRecorderApp> {
|
private static async _open(params: RecorderAppParams, recorder: IRecorder, inspectedContext: BrowserContext): Promise<IRecorderApp> {
|
||||||
const sdkLanguage = inspectedContext._browser.sdkLanguage();
|
const sdkLanguage = inspectedContext._browser.sdkLanguage();
|
||||||
const headed = !!inspectedContext._browser.options.headful;
|
const headed = !!inspectedContext._browser.options.headful;
|
||||||
const recorderPlaywright = (require('../playwright').createPlaywright as typeof import('../playwright').createPlaywright)({ sdkLanguage: 'javascript', isInternalPlaywright: true });
|
const recorderPlaywright = (require('../playwright').createPlaywright as typeof import('../playwright').createPlaywright)({ sdkLanguage: 'javascript', isInternalPlaywright: true });
|
||||||
|
@ -116,7 +202,7 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
noDefaultViewport: true,
|
noDefaultViewport: true,
|
||||||
headless: !!process.env.PWTEST_CLI_HEADLESS || (isUnderTest() && !headed),
|
headless: !!process.env.PWTEST_CLI_HEADLESS || (isUnderTest() && !headed),
|
||||||
cdpPort: isUnderTest() ? 0 : undefined,
|
cdpPort: isUnderTest() ? 0 : undefined,
|
||||||
handleSIGINT: recorder.handleSIGINT,
|
handleSIGINT: params.handleSIGINT,
|
||||||
executablePath: inspectedContext._browser.options.isChromium ? inspectedContext._browser.options.customExecutablePath : undefined,
|
executablePath: inspectedContext._browser.options.isChromium ? inspectedContext._browser.options.customExecutablePath : undefined,
|
||||||
// Use the same channel as the inspected context to guarantee that the browser is installed.
|
// Use the same channel as the inspected context to guarantee that the browser is installed.
|
||||||
channel: inspectedContext._browser.options.isChromium ? inspectedContext._browser.options.channel : undefined,
|
channel: inspectedContext._browser.options.isChromium ? inspectedContext._browser.options.channel : undefined,
|
||||||
|
@ -127,7 +213,7 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
await context._browser._defaultContext!._loadDefaultContextAsIs(progress);
|
await context._browser._defaultContext!._loadDefaultContextAsIs(progress);
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = new RecorderApp(recorder, page, context._browser.options.wsEndpoint);
|
const result = new RecorderApp(params, page, context._browser.options.wsEndpoint);
|
||||||
await result._init();
|
await result._init();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -138,33 +224,33 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
}).toString(), { isFunction: true }, mode).catch(() => {});
|
}).toString(), { isFunction: true }, mode).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRunningFile(file: string | undefined): Promise<void> {
|
|
||||||
await this._page.mainFrame().evaluateExpression(((file: string) => {
|
|
||||||
window.playwrightSetRunningFile(file);
|
|
||||||
}).toString(), { isFunction: true }, file).catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
async setPaused(paused: boolean): Promise<void> {
|
async setPaused(paused: boolean): Promise<void> {
|
||||||
await this._page.mainFrame().evaluateExpression(((paused: boolean) => {
|
await this._page.mainFrame().evaluateExpression(((paused: boolean) => {
|
||||||
window.playwrightSetPaused(paused);
|
window.playwrightSetPaused(paused);
|
||||||
}).toString(), { isFunction: true }, paused).catch(() => {});
|
}).toString(), { isFunction: true }, paused).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
async setSources(sources: Source[], primaryPageURL: string | undefined): Promise<void> {
|
async userSourcesChanged(sources: Source[]): Promise<void> {
|
||||||
await this._page.mainFrame().evaluateExpression((({ sources, primaryPageURL }: { sources: Source[], primaryPageURL: string | undefined }) => {
|
if (!sources.length && !this._userSources.length)
|
||||||
window.playwrightSetSources(sources, primaryPageURL);
|
return;
|
||||||
}).toString(), { isFunction: true }, { sources, primaryPageURL }).catch(() => {});
|
this._userSources = sources;
|
||||||
|
this._pushAllSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _pushAllSources() {
|
||||||
|
const sources = [...this._userSources, ...this._recorderSources];
|
||||||
|
this._page.mainFrame().evaluateExpression((({ sources }: { sources: Source[] }) => {
|
||||||
|
window.playwrightSetSources(sources);
|
||||||
|
}).toString(), { isFunction: true }, { sources }).catch(() => {});
|
||||||
|
|
||||||
// Testing harness for runCLI mode.
|
// Testing harness for runCLI mode.
|
||||||
if (process.env.PWTEST_CLI_IS_UNDER_TEST && sources.length) {
|
if (process.env.PWTEST_CLI_IS_UNDER_TEST && sources.length) {
|
||||||
if ((process as any)._didSetSourcesForTest(sources[0].text))
|
const primarySource = sources.find(s => s.isPrimary);
|
||||||
|
if ((process as any)._didSetSourcesForTest(primarySource?.text ?? ''))
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setActions(actions: actions.ActionInContext[], sources: Source[]): Promise<void> {
|
|
||||||
}
|
|
||||||
|
|
||||||
async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void> {
|
async elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void> {
|
||||||
if (userGesture)
|
if (userGesture)
|
||||||
this._page.bringToFront();
|
this._page.bringToFront();
|
||||||
|
@ -178,4 +264,39 @@ export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
window.playwrightUpdateLogs(callLogs);
|
window.playwrightUpdateLogs(callLogs);
|
||||||
}).toString(), { isFunction: true }, callLogs).catch(() => {});
|
}).toString(), { isFunction: true }, callLogs).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async flushOutput(): Promise<void> {
|
||||||
|
this._throttledOutputFile?.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateActions(initial: boolean = false) {
|
||||||
|
const timestamp = initial ? 0 : monotonicTime();
|
||||||
|
const recorderSources = [];
|
||||||
|
const actions = collapseActions(this._actions);
|
||||||
|
|
||||||
|
for (const languageGenerator of languageSet()) {
|
||||||
|
const { header, footer, actionTexts, text } = generateCode(actions, languageGenerator, this._languageGeneratorOptions);
|
||||||
|
const source: Source = {
|
||||||
|
isPrimary: languageGenerator.id === this._primaryLanguage,
|
||||||
|
timestamp,
|
||||||
|
isRecorded: true,
|
||||||
|
label: languageGenerator.name,
|
||||||
|
group: languageGenerator.groupName,
|
||||||
|
id: languageGenerator.id,
|
||||||
|
text,
|
||||||
|
header,
|
||||||
|
footer,
|
||||||
|
actions: actionTexts,
|
||||||
|
language: languageGenerator.highlighter,
|
||||||
|
highlight: []
|
||||||
|
};
|
||||||
|
source.revealLine = text.split('\n').length - 1;
|
||||||
|
recorderSources.push(source);
|
||||||
|
if (languageGenerator.id === this._primaryLanguage)
|
||||||
|
this._throttledOutputFile?.setContent(source.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._recorderSources = recorderSources;
|
||||||
|
this._pushAllSources();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@
|
||||||
import type * as actions from '@recorder/actions';
|
import type * as actions from '@recorder/actions';
|
||||||
import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes';
|
import type { CallLog, ElementInfo, Mode, Source } from '@recorder/recorderTypes';
|
||||||
import type { EventEmitter } from 'events';
|
import type { EventEmitter } from 'events';
|
||||||
|
import type * as channels from '@protocol/channels';
|
||||||
|
import type { Language } from '../codegen/types';
|
||||||
|
|
||||||
export interface IRecorder {
|
export interface IRecorder {
|
||||||
setMode(mode: Mode): void;
|
setMode(mode: Mode): void;
|
||||||
mode(): Mode;
|
mode(): Mode;
|
||||||
readonly handleSIGINT: boolean | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRecorderApp extends EventEmitter {
|
export interface IRecorderApp extends EventEmitter {
|
||||||
|
@ -29,11 +30,19 @@ export interface IRecorderApp extends EventEmitter {
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
setPaused(paused: boolean): Promise<void>;
|
setPaused(paused: boolean): Promise<void>;
|
||||||
setMode(mode: Mode): Promise<void>;
|
setMode(mode: Mode): Promise<void>;
|
||||||
setRunningFile(file: string | undefined): Promise<void>;
|
|
||||||
elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void>;
|
elementPicked(elementInfo: ElementInfo, userGesture?: boolean): Promise<void>;
|
||||||
updateCallLogs(callLogs: CallLog[]): Promise<void>;
|
updateCallLogs(callLogs: CallLog[]): Promise<void>;
|
||||||
setSources(sources: Source[], primaryPageURL: string | undefined): Promise<void>;
|
userSourcesChanged(sources: Source[]): Promise<void>;
|
||||||
setActions(actions: actions.ActionInContext[], sources: Source[]): Promise<void>;
|
start(): void;
|
||||||
|
actionAdded(action: actions.ActionInContext): Promise<void>;
|
||||||
|
signalAdded(signal: actions.Signal): Promise<void>;
|
||||||
|
pageNavigated(url: string): Promise<void>;
|
||||||
|
flushOutput(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type RecorderAppParams = channels.BrowserContextEnableRecorderParams & {
|
||||||
|
browserName: string;
|
||||||
|
sdkLanguage: Language;
|
||||||
|
};
|
||||||
|
|
||||||
export type IRecorderAppFactory = (recorder: IRecorder) => Promise<IRecorderApp>;
|
export type IRecorderAppFactory = (recorder: IRecorder) => Promise<IRecorderApp>;
|
||||||
|
|
|
@ -27,11 +27,13 @@ export const Main: React.FC = ({}) => {
|
||||||
|
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
window.playwrightSetMode = setMode;
|
window.playwrightSetMode = setMode;
|
||||||
window.playwrightSetSources = (sources, primaryPageURL) => {
|
window.playwrightSetSources = sources => {
|
||||||
setSources(sources);
|
setSources(sources);
|
||||||
window.playwrightSourcesEchoForTest = sources;
|
window.playwrightSourcesEchoForTest = sources;
|
||||||
document.title = primaryPageURL
|
};
|
||||||
? `Playwright Inspector - ${primaryPageURL}`
|
window.playwrightSetPageURL = url => {
|
||||||
|
document.title = url
|
||||||
|
? `Playwright Inspector - ${url}`
|
||||||
: `Playwright Inspector`;
|
: `Playwright Inspector`;
|
||||||
};
|
};
|
||||||
window.playwrightSetPaused = setPaused;
|
window.playwrightSetPaused = setPaused;
|
||||||
|
|
|
@ -45,21 +45,30 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
mode,
|
mode,
|
||||||
}) => {
|
}) => {
|
||||||
const [selectedFileId, setSelectedFileId] = React.useState<string | undefined>();
|
const [selectedFileId, setSelectedFileId] = React.useState<string | undefined>();
|
||||||
const [runningFileId, setRunningFileId] = React.useState<string | undefined>();
|
|
||||||
const [selectedTab, setSelectedTab] = useSetting<string>('recorderPropertiesTab', 'log');
|
const [selectedTab, setSelectedTab] = useSetting<string>('recorderPropertiesTab', 'log');
|
||||||
const [ariaSnapshot, setAriaSnapshot] = React.useState<string | undefined>();
|
const [ariaSnapshot, setAriaSnapshot] = React.useState<string | undefined>();
|
||||||
const [ariaSnapshotErrors, setAriaSnapshotErrors] = React.useState<SourceHighlight[]>();
|
const [ariaSnapshotErrors, setAriaSnapshotErrors] = React.useState<SourceHighlight[]>();
|
||||||
|
|
||||||
const fileId = selectedFileId || runningFileId || sources[0]?.id;
|
React.useEffect(() => {
|
||||||
|
if (!sources.length)
|
||||||
|
return;
|
||||||
|
const selectedSource = sources.find(s => s.id === selectedFileId);
|
||||||
|
const newestSource = sources.sort((a, b) => b.timestamp - a.timestamp)[0];
|
||||||
|
if (!selectedSource || newestSource.isRecorded !== selectedSource.isRecorded) {
|
||||||
|
// Debugger kicked in, or recording resumed. Switch selection to the newest source.
|
||||||
|
setSelectedFileId(newestSource.id);
|
||||||
|
}
|
||||||
|
}, [sources, selectedFileId]);
|
||||||
|
|
||||||
const source = React.useMemo(() => {
|
const source = React.useMemo(() => {
|
||||||
if (fileId) {
|
const source = sources.find(s => s.id === selectedFileId);
|
||||||
const source = sources.find(s => s.id === fileId);
|
if (source)
|
||||||
if (source)
|
return source;
|
||||||
return source;
|
const primarySource = sources.find(s => s.isPrimary);
|
||||||
}
|
if (primarySource)
|
||||||
|
return primarySource;
|
||||||
return emptySource();
|
return emptySource();
|
||||||
}, [sources, fileId]);
|
}, [sources, selectedFileId]);
|
||||||
|
|
||||||
const [locator, setLocator] = React.useState('');
|
const [locator, setLocator] = React.useState('');
|
||||||
window.playwrightElementPicked = (elementInfo: ElementInfo, userGesture?: boolean) => {
|
window.playwrightElementPicked = (elementInfo: ElementInfo, userGesture?: boolean) => {
|
||||||
|
@ -77,8 +86,6 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.playwrightSetRunningFile = setRunningFileId;
|
|
||||||
|
|
||||||
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||||
|
@ -179,9 +186,9 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
}}></ToolbarButton>
|
}}></ToolbarButton>
|
||||||
<div style={{ flex: 'auto' }}></div>
|
<div style={{ flex: 'auto' }}></div>
|
||||||
<div>Target:</div>
|
<div>Target:</div>
|
||||||
<SourceChooser fileId={fileId} sources={sources} setFileId={fileId => {
|
<SourceChooser fileId={source.id} sources={sources} setFileId={fileId => {
|
||||||
setSelectedFileId(fileId);
|
setSelectedFileId(fileId);
|
||||||
window.dispatch({ event: 'fileChanged', params: { file: fileId } });
|
window.dispatch({ event: 'fileChanged', params: { fileId } });
|
||||||
}} />
|
}} />
|
||||||
<ToolbarButton icon='clear-all' title='Clear' disabled={!source || !source.text} onClick={() => {
|
<ToolbarButton icon='clear-all' title='Clear' disabled={!source || !source.text} onClick={() => {
|
||||||
window.dispatch({ event: 'clear' });
|
window.dispatch({ event: 'clear' });
|
||||||
|
|
|
@ -43,7 +43,7 @@ export type EventData = {
|
||||||
| 'pause'
|
| 'pause'
|
||||||
| 'setMode'
|
| 'setMode'
|
||||||
| 'highlightRequested'
|
| 'highlightRequested'
|
||||||
| 'fileChanged';
|
| 'languageChanged';
|
||||||
params: any;
|
params: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,12 +84,14 @@ export type SourceHighlight = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Source = {
|
export type Source = {
|
||||||
|
isPrimary: boolean;
|
||||||
isRecorded: boolean;
|
isRecorded: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
text: string;
|
text: string;
|
||||||
language: Language;
|
language: Language;
|
||||||
highlight: SourceHighlight[];
|
highlight: SourceHighlight[];
|
||||||
|
timestamp: number;
|
||||||
revealLine?: number;
|
revealLine?: number;
|
||||||
// used to group the language generators
|
// used to group the language generators
|
||||||
group?: string;
|
group?: string;
|
||||||
|
@ -102,10 +104,10 @@ declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
playwrightSetMode: (mode: Mode) => void;
|
playwrightSetMode: (mode: Mode) => void;
|
||||||
playwrightSetPaused: (paused: boolean) => void;
|
playwrightSetPaused: (paused: boolean) => void;
|
||||||
playwrightSetSources: (sources: Source[], primaryPageURL: string | undefined) => void;
|
playwrightSetSources: (sources: Source[]) => void;
|
||||||
|
playwrightSetPageURL: (url: string | undefined) => void;
|
||||||
playwrightSetOverlayVisible: (visible: boolean) => void;
|
playwrightSetOverlayVisible: (visible: boolean) => void;
|
||||||
playwrightUpdateLogs: (callLogs: CallLog[]) => void;
|
playwrightUpdateLogs: (callLogs: CallLog[]) => void;
|
||||||
playwrightSetRunningFile: (file: string | undefined) => void;
|
|
||||||
playwrightElementPicked: (elementInfo: ElementInfo, userGesture?: boolean) => void;
|
playwrightElementPicked: (elementInfo: ElementInfo, userGesture?: boolean) => void;
|
||||||
playwrightSourcesEchoForTest: Source[];
|
playwrightSourcesEchoForTest: Source[];
|
||||||
dispatch(data: any): Promise<void>;
|
dispatch(data: any): Promise<void>;
|
||||||
|
|
|
@ -53,6 +53,8 @@ function renderSourceOptions(sources: Source[]): React.ReactNode {
|
||||||
export function emptySource(): Source {
|
export function emptySource(): Source {
|
||||||
return {
|
return {
|
||||||
id: 'default',
|
id: 'default',
|
||||||
|
timestamp: 0,
|
||||||
|
isPrimary: false,
|
||||||
isRecorded: false,
|
isRecorded: false,
|
||||||
text: '',
|
text: '',
|
||||||
language: 'javascript',
|
language: 'javascript',
|
||||||
|
|
|
@ -462,6 +462,9 @@ await page1.GotoAsync("about:blank?foo");`);
|
||||||
const harFileName = testInfo.outputPath('har.har');
|
const harFileName = testInfo.outputPath('har.har');
|
||||||
const cli = runCLI([`--save-storage=${storageFileName}`, `--save-har=${harFileName}`]);
|
const cli = runCLI([`--save-storage=${storageFileName}`, `--save-har=${harFileName}`]);
|
||||||
await cli.waitFor(`import { test, expect } from '@playwright/test'`);
|
await cli.waitFor(`import { test, expect } from '@playwright/test'`);
|
||||||
|
// Since our interrupt is non-graceful, we need to wait for the process to settle.
|
||||||
|
// This test should be fixed.
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
await cli.process.kill('SIGINT');
|
await cli.process.kill('SIGINT');
|
||||||
const { exitCode, signal } = await cli.process.exited;
|
const { exitCode, signal } = await cli.process.exited;
|
||||||
if (exitCode !== null) {
|
if (exitCode !== null) {
|
||||||
|
|
|
@ -447,6 +447,7 @@ it.describe('pause', () => {
|
||||||
})();
|
})();
|
||||||
const recorderPage = await recorderPageGetter();
|
const recorderPage = await recorderPageGetter();
|
||||||
|
|
||||||
|
await recorderPage.getByRole('combobox', { name: 'Source chooser' }).selectOption('csharp');
|
||||||
const box1Promise = waitForTestLog<BoundingBox>(page, 'Highlight box for test: ');
|
const box1Promise = waitForTestLog<BoundingBox>(page, 'Highlight box for test: ');
|
||||||
await recorderPage.getByText('Locator', { exact: true }).click();
|
await recorderPage.getByText('Locator', { exact: true }).click();
|
||||||
await recorderPage.locator('.tabbed-pane .CodeMirror').click();
|
await recorderPage.locator('.tabbed-pane .CodeMirror').click();
|
||||||
|
@ -541,7 +542,7 @@ it.describe('pause', () => {
|
||||||
await recorder.hoverOverElement('body', { omitTooltip: true });
|
await recorder.hoverOverElement('body', { omitTooltip: true });
|
||||||
await recorder.trustedClick();
|
await recorder.trustedClick();
|
||||||
|
|
||||||
await expect(recorderPage.getByRole('combobox', { name: 'Source chooser' })).toHaveValue('javascript');
|
await expect(recorderPage.getByRole('combobox', { name: 'Source chooser' })).toHaveValue('playwright-test');
|
||||||
await expect(recorderPage.locator('.cm-wrapper')).toContainText(`await page.locator('body').click();`);
|
await expect(recorderPage.locator('.cm-wrapper')).toContainText(`await page.locator('body').click();`);
|
||||||
await recorderPage.getByRole('button', { name: 'Resume' }).click();
|
await recorderPage.getByRole('button', { name: 'Resume' }).click();
|
||||||
await scriptPromise;
|
await scriptPromise;
|
||||||
|
|
|
@ -70,15 +70,11 @@ test('should update primary page URL when original primary closes', async ({
|
||||||
);
|
);
|
||||||
|
|
||||||
await recorder.page.close();
|
await recorder.page.close();
|
||||||
// URL will not update without performing some action
|
|
||||||
await page3.getByRole('checkbox').click();
|
|
||||||
await expect(recorder.recorderPage).toHaveTitle(
|
await expect(recorder.recorderPage).toHaveTitle(
|
||||||
`Playwright Inspector - ${server.PREFIX}/dom.html`,
|
`Playwright Inspector - ${server.PREFIX}/dom.html`,
|
||||||
);
|
);
|
||||||
|
|
||||||
await page3.close();
|
await page3.close();
|
||||||
// URL will not update without performing some action
|
|
||||||
await page4.locator('div').first().click();
|
|
||||||
await expect(recorder.recorderPage).toHaveTitle(
|
await expect(recorder.recorderPage).toHaveTitle(
|
||||||
`Playwright Inspector - ${server.PREFIX}/grid.html`,
|
`Playwright Inspector - ${server.PREFIX}/grid.html`,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue