Skip to content

Commit e1a45a0

Browse files
authored
improvement(ci): run WebKit acceptance in pinned browser containers (#9652)
1 parent 04e6a89 commit e1a45a0

7 files changed

Lines changed: 248 additions & 10 deletions

File tree

‎.github/CI.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Closing a same-repository pull request deletes only its GitHub merge-ref caches
3636

3737
Memory-heavy builds and browser jobs retain appropriately sized Blacksmith runners. Electron uses 4-vCPU Blacksmith: both shards passed within 14 seconds of the 8-vCPU control; the free GitHub rest shard was slower and its lease run stalled.
3838

39+
WebKit acceptance on Blacksmith uses the matching, digest-pinned Playwright browser image for mobile and docs navigation. The app, database fixtures, native modules, and harness stay on the host and retain loopback URLs. Chromium and GitHub fallback keep native browser installation and launch. Update both workspace Playwright dependencies, the image index digest, and the expected client version/revision checks together; verify the installed release's native launch timeout and real WebKit acceptance before changing the pin.
40+
3941
Every HTTP and browser group consumes the same production build in an isolated job/database. Electron also uses that build and skips its development-route warm-up. Local HTTP and Electron development runs retain their dev-server behavior. Build inputs exclude test-only files so a harness edit can reuse an unchanged production build.
4042

4143
Desktop inbox protocol, assistant actions UI, and organization search UI run as three parallel HTTP jobs with isolated databases, apps, and reports. Each harness owns its acceptance task, so an edit selects its own job. The inbox protocol task depends on server and realtime code; the browser tasks also depend on workspace UI. Desktop inbox needs no browser. The UI jobs and browser extension install Chromium while their app starts, waiting for both before executing assertions; browser-install failures still fail the job and preserve the install log. No acceptance assertions are removed by the split.

‎.github/scripts/http-e2e.sh‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,19 @@ JS
318318
export INTERNAL_API_SECRET=mobile-http-ci-local-secret-at-least-32-characters
319319
export NEXT_PUBLIC_SOCKET_URL=http://127.0.0.1:3025 SOCKET_SERVER_URL=http://127.0.0.1:3025
320320
read -ra browsers <<< "${MOBILE_E2E_BROWSER:-chromium webkit}"
321-
start_browser_install mobile --only-shell "${browsers[@]}"
321+
if [ "${PLAYWRIGHT_WEBKIT_WS_ENDPOINT+x}" = x ]; then
322+
if [ "${MOBILE_E2E_BROWSER:-}" != webkit ]; then
323+
echo "::error::A remote endpoint requires explicit WebKit selection." >&2
324+
exit 1
325+
fi
326+
else
327+
start_browser_install mobile --only-shell "${browsers[@]}"
328+
fi
322329
start_app mobile 3024 'mobile browser' record-http-status
323330
start_realtime mobile 3025
324-
wait_for_browsers
331+
if [ "${PLAYWRIGHT_WEBKIT_WS_ENDPOINT+x}" != x ]; then
332+
wait_for_browsers
333+
fi
325334
MOBILE_E2E_BASE_URL="$NEXT_PUBLIC_APP_URL" \
326335
MOBILE_E2E_DATABASE_URL="$DATABASE_URL" \
327336
MOBILE_E2E_AUTH_SECRET="$BETTER_AUTH_SECRET" \
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env bash
2+
# Owns one pinned WebKit server; start prints its loopback endpoint, stop preserves its logs.
3+
set -euo pipefail
4+
umask 077
5+
6+
action=${1:-}
7+
state_argument=${2:-}
8+
if [ "$#" -ne 2 ] || { [ "$action" != start ] && [ "$action" != stop ]; }; then
9+
echo 'Usage: playwright-server.sh <start|stop> <state-directory-under-RUNNER_TEMP>' >&2
10+
exit 2
11+
fi
12+
: "${RUNNER_TEMP:?RUNNER_TEMP must be set}"
13+
: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY must be set}"
14+
: "${GITHUB_RUN_ID:?GITHUB_RUN_ID must be set}"
15+
: "${GITHUB_RUN_ATTEMPT:?GITHUB_RUN_ATTEMPT must be set}"
16+
: "${GITHUB_JOB:?GITHUB_JOB must be set}"
17+
if ! [[ "$GITHUB_RUN_ID" =~ ^[1-9][0-9]*$ && "$GITHUB_RUN_ATTEMPT" =~ ^[1-9][0-9]*$ && "$GITHUB_JOB" =~ ^[a-zA-Z0-9_-]+$ ]]; then
18+
echo 'Invalid GitHub job ownership metadata.' >&2
19+
exit 2
20+
fi
21+
state=$(node - "$RUNNER_TEMP" "$state_argument" <<'JS'
22+
const fs = require('node:fs')
23+
const path = require('node:path')
24+
const root = fs.realpathSync(process.argv[2])
25+
const state = path.resolve(process.argv[3])
26+
if (path.dirname(state) !== root || (fs.existsSync(state) && fs.realpathSync(state) !== state))
27+
throw new Error('State must be a direct, non-symlink child of RUNNER_TEMP')
28+
process.stdout.write(state)
29+
JS
30+
)
31+
state_key=$(node -e 'process.stdout.write(require("node:crypto").createHash("sha256").update(process.argv[1]).digest("hex"))' "$state")
32+
image='mcr.microsoft.com/playwright@sha256:2f05f8a734509a7b3f26a912639488ee08f58a7b292d14d62271bcff9038768f'
33+
starting=false
34+
35+
stop_container() {
36+
local cid inspection remaining status=0
37+
[ -f "$state/cid" ] || return 0
38+
cid=$(< "$state/cid")
39+
if ! [[ "$cid" =~ ^[0-9a-f]{64}$ ]]; then
40+
echo 'Refusing to stop an invalid container ID.' >&2
41+
return 1
42+
fi
43+
if ! inspection=$(docker container inspect "$cid" 2> "$state/inspect-error.log"); then
44+
remaining=$(docker container ls --all --no-trunc --filter "id=$cid" --format '{{.ID}}') || return 1
45+
[ -z "$remaining" ] && return 0
46+
cat "$state/inspect-error.log" >&2
47+
return 1
48+
fi
49+
if ! jq -e --arg repository "$GITHUB_REPOSITORY" --arg run "$GITHUB_RUN_ID" \
50+
--arg attempt "$GITHUB_RUN_ATTEMPT" --arg job "$GITHUB_JOB" --arg state "$state_key" \
51+
'.[0].Config.Labels | .["com.sim.ci.playwright-server"] == "true"
52+
and .["com.sim.ci.repository"] == $repository and .["com.sim.ci.run"] == $run
53+
and .["com.sim.ci.attempt"] == $attempt and .["com.sim.ci.job"] == $job
54+
and .["com.sim.ci.state"] == $state' <<< "$inspection" > /dev/null; then
55+
echo 'Refusing to stop a container owned by another job or state directory.' >&2
56+
return 1
57+
fi
58+
docker stop --timeout 10 "$cid" > "$state/stop.log" 2>&1 || status=1
59+
docker logs "$cid" > "$state/server.log" 2>&1 || status=1
60+
docker rm "$cid" > "$state/remove.log" 2>&1 || status=1
61+
return "$status"
62+
}
63+
64+
trap '
65+
status=$?
66+
trap - EXIT
67+
if [ "$status" -ne 0 ] && [ "$starting" = true ]; then
68+
stop_container || echo "Owned Playwright server cleanup failed; preserve its state and logs." >&2
69+
fi
70+
exit "$status"
71+
' EXIT
72+
trap 'exit 130' INT
73+
trap 'exit 143' TERM
74+
75+
if [ "$action" = stop ]; then
76+
stop_container
77+
exit 0
78+
fi
79+
if [ -e "$state/cid" ]; then
80+
echo 'Refusing to reuse an existing Playwright server state.' >&2
81+
exit 1
82+
fi
83+
mkdir -p -- "$state"
84+
repo_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
85+
driver=$(node - "$repo_root/apps/sim" <<'JS'
86+
const fs = require('node:fs')
87+
const path = require('node:path')
88+
const packagePath = require.resolve('playwright-core/package.json', { paths: [process.argv[2]] })
89+
const root = fs.realpathSync(path.dirname(packagePath))
90+
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'browsers.json'), 'utf8'))
91+
if (JSON.parse(fs.readFileSync(packagePath, 'utf8')).version !== '1.64.1' ||
92+
manifest.browsers.find(browser => browser.name === 'webkit')?.revision !== '2370')
93+
throw new Error('The pinned WebKit image requires Playwright 1.64.1, revision 2370')
94+
process.stdout.write(root)
95+
JS
96+
)
97+
docker pull "$image" > "$state/pull.log" 2>&1
98+
starting=true
99+
docker run --detach --init --cidfile "$state/cid" \
100+
--name "sim-ci-playwright-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT-$GITHUB_JOB-$$" \
101+
--label com.sim.ci.playwright-server=true --label "com.sim.ci.repository=$GITHUB_REPOSITORY" \
102+
--label "com.sim.ci.run=$GITHUB_RUN_ID" --label "com.sim.ci.attempt=$GITHUB_RUN_ATTEMPT" \
103+
--label "com.sim.ci.job=$GITHUB_JOB" --label "com.sim.ci.state=$state_key" \
104+
--network host --cpus 8 --memory 4g --memory-swap 4g --pids-limit 512 --shm-size 256m \
105+
--mount "type=bind,src=$driver,dst=/opt/playwright-core,readonly" \
106+
"$image" node /opt/playwright-core/cli.js run-server --host 127.0.0.1 --port 0 \
107+
> "$state/start.log" 2>&1
108+
cid=$(< "$state/cid")
109+
if ! [[ "$cid" =~ ^[0-9a-f]{64}$ ]]; then
110+
echo 'Docker did not return a complete container ID.' >&2
111+
exit 1
112+
fi
113+
docker container inspect "$cid" > "$state/metadata.json"
114+
deadline=$((SECONDS + 30))
115+
while [ "$SECONDS" -lt "$deadline" ]; do
116+
live=$(docker container inspect --format '{{.State.Running}} {{.State.Pid}}' "$cid")
117+
if ! [[ "$live" =~ ^true\ [1-9][0-9]*$ ]]; then
118+
docker logs "$cid" > "$state/server.log" 2>&1
119+
echo 'Playwright server exited before readiness.' >&2
120+
exit 1
121+
fi
122+
docker logs "$cid" > "$state/server.log" 2>&1
123+
endpoint=$(sed -n 's@^Listening on \(ws://127\.0\.0\.1:[1-9][0-9]*/\)$@\1@p' "$state/server.log")
124+
if [ -n "$endpoint" ]; then
125+
node - "$endpoint" <<'JS'
126+
const endpoint = process.argv[2]
127+
if (!/^ws:\/\/127\.0\.0\.1:[1-9]\d*\/$/.test(endpoint)) throw new Error('Invalid server endpoint')
128+
new URL(endpoint)
129+
process.stdout.write(`${endpoint}\n`)
130+
JS
131+
exit 0
132+
fi
133+
sleep 0.1
134+
done
135+
echo 'Playwright server did not report a live loopback endpoint within 30 seconds.' >&2
136+
exit 1

‎.github/workflows/checks.yml‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,43 @@ jobs:
373373
- *extract-e2e-build
374374

375375
- name: Run end-to-end suites
376+
id: acceptance
376377
working-directory: apps/sim
377378
env:
378379
MOBILE_E2E_BROWSER: ${{ matrix.browser }}
379380
MOBILE_E2E_SHARD: ${{ matrix.shard }}
380-
run: bash ../../.github/scripts/http-e2e.sh "${{ matrix.group }}"
381+
run: |
382+
unset PLAYWRIGHT_WEBKIT_WS_ENDPOINT
383+
if [ "${{ matrix.browser == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') }}" = true ]; then
384+
webkit_state="$RUNNER_TEMP/playwright-webkit-server"
385+
trap '
386+
status=$?
387+
trap - EXIT INT TERM
388+
if ! bash ../../.github/scripts/playwright-server.sh stop "$webkit_state"; then
389+
echo "::error::Owned WebKit server cleanup failed." >&2
390+
if [ "$status" -eq 0 ]; then status=1; fi
391+
fi
392+
exit "$status"
393+
' EXIT
394+
trap 'exit 130' INT
395+
trap 'exit 143' TERM
396+
PLAYWRIGHT_WEBKIT_WS_ENDPOINT=$(bash ../../.github/scripts/playwright-server.sh start "$webkit_state")
397+
export PLAYWRIGHT_WEBKIT_WS_ENDPOINT
398+
fi
399+
bash ../../.github/scripts/http-e2e.sh "${{ matrix.group }}"
400+
401+
- name: Stop the owned WebKit server
402+
if: always() && matrix.browser == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && steps.acceptance.outcome != 'skipped'
403+
run: bash .github/scripts/playwright-server.sh stop "$RUNNER_TEMP/playwright-webkit-server"
404+
405+
- name: Upload WebKit server failure logs
406+
if: failure() && matrix.browser == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith')
407+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
408+
with:
409+
name: webkit-server-${{ matrix.artifact }}
410+
path: ${{ runner.temp }}/playwright-webkit-server/
411+
if-no-files-found: ignore
412+
retention-days: 7
381413

382414
- name: Upload end-to-end reports and server logs
383415
if: failure()

‎.github/workflows/docs-negotiation.yml‎

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ on:
1919
- '.github/actions/cache/**'
2020
- '.github/actions/setup/**'
2121
- '.github/scripts/stop-session.sh'
22+
- '.github/scripts/playwright-server.sh'
2223
push:
2324
branches: [staging]
2425
paths:
@@ -38,6 +39,7 @@ on:
3839
- '.github/actions/cache/**'
3940
- '.github/actions/setup/**'
4041
- '.github/scripts/stop-session.sh'
42+
- '.github/scripts/playwright-server.sh'
4143
workflow_dispatch:
4244
inputs:
4345
benchmark:
@@ -370,14 +372,17 @@ jobs:
370372
go-version: '1.25.x'
371373
cache: false
372374
- name: Install the selected navigation browser
373-
if: matrix.group == 'chromium' || matrix.group == 'webkit'
375+
if: matrix.group == 'chromium' || (matrix.group == 'webkit' && vars.CI_PROVIDER != '' && vars.CI_PROVIDER != 'blacksmith')
374376
env:
375377
BROWSER: ${{ matrix.group }}
376378
run: bunx --no-install playwright install --with-deps --only-shell "$BROWSER"
377379
- name: Verify production documentation
380+
id: acceptance
378381
env:
379382
DOCS_ACCEPTANCE_GROUP: ${{ matrix.group }}
380383
run: |
384+
unset PLAYWRIGHT_WEBKIT_WS_ENDPOINT
385+
webkit_state=''
381386
mkdir -p apps/docs/test-results
382387
FEEDBACK_TLS_DIR=$(mktemp -d)
383388
export DOCS_FEEDBACK_TEST_CERT="$FEEDBACK_TLS_DIR/cert.pem"
@@ -392,16 +397,27 @@ jobs:
392397
DOCS_SERVER_PID=$!
393398
finish() {
394399
local status=$1
395-
trap - EXIT
400+
trap - EXIT INT TERM
396401
if bash .github/scripts/stop-session.sh "$DOCS_SERVER_PID" "$APP_TAG"; then
397402
wait "$DOCS_SERVER_PID" 2>/dev/null || true
398403
else
399-
status=1
404+
if [ "$status" -eq 0 ]; then status=1; fi
405+
fi
406+
if [ -n "$webkit_state" ] && ! bash .github/scripts/playwright-server.sh stop "$webkit_state"; then
407+
echo '::error::Owned WebKit server cleanup failed.' >&2
408+
if [ "$status" -eq 0 ]; then status=1; fi
400409
fi
401410
rm -rf "$FEEDBACK_TLS_DIR"
402411
exit "$status"
403412
}
404413
trap 'finish "$?"' EXIT
414+
trap 'exit 130' INT
415+
trap 'exit 143' TERM
416+
if [ "${{ matrix.group == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') }}" = true ]; then
417+
webkit_state="$RUNNER_TEMP/playwright-webkit-server"
418+
PLAYWRIGHT_WEBKIT_WS_ENDPOINT=$(bash .github/scripts/playwright-server.sh start "$webkit_state")
419+
export PLAYWRIGHT_WEBKIT_WS_ENDPOINT
420+
fi
405421
for attempt in $(seq 1 60); do
406422
if ! kill -0 "$DOCS_SERVER_PID" 2>/dev/null; then
407423
echo '::error::Documentation server exited before becoming ready.'
@@ -431,6 +447,17 @@ jobs:
431447
*) echo "::error::Unknown documentation acceptance group: $DOCS_ACCEPTANCE_GROUP"; STATUS=1 ;;
432448
esac
433449
finish "$STATUS"
450+
- name: Stop the owned WebKit server
451+
if: always() && matrix.group == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && steps.acceptance.outcome != 'skipped'
452+
run: bash .github/scripts/playwright-server.sh stop "$RUNNER_TEMP/playwright-webkit-server"
453+
- name: Upload WebKit server failure logs
454+
if: failure() && matrix.group == 'webkit' && (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith')
455+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
456+
with:
457+
name: webkit-server-docs
458+
path: ${{ runner.temp }}/playwright-webkit-server/
459+
if-no-files-found: ignore
460+
retention-days: 14
434461
- name: Upload acceptance regression reports
435462
if: always()
436463
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2

‎apps/docs/scripts/test-navigation-e2e.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { mkdir, readFile, writeFile } from 'node:fs/promises'
2+
import { createRequire } from 'node:module'
23
import { dirname, join } from 'node:path'
34
import {
45
type Browser,
@@ -30,6 +31,16 @@ const canonicalOrigin = new URL(process.env.NEXT_PUBLIC_DOCS_URL ?? 'https://doc
3031
const engine = process.env.DOCS_NAVIGATION_BROWSER ?? 'chromium'
3132
if (engine !== 'chromium' && engine !== 'webkit')
3233
throw new Error('DOCS_NAVIGATION_BROWSER must be chromium or webkit')
34+
const webkitEndpoint = process.env.PLAYWRIGHT_WEBKIT_WS_ENDPOINT
35+
if (webkitEndpoint !== undefined) {
36+
if (engine !== 'webkit' || !/^ws:\/\/127\.0\.0\.1:[1-9]\d*\/$/.test(webkitEndpoint))
37+
throw new Error('A remote endpoint requires explicit WebKit selection and a loopback URL')
38+
new URL(webkitEndpoint)
39+
if (
40+
toRecord(createRequire(import.meta.url)('@playwright/test/package.json')).version !== '1.64.1'
41+
)
42+
throw new Error('The remote WebKit image requires Playwright 1.64.1')
43+
}
3344
const results: Array<{
3445
name: string
3546
status: 'passed' | 'failed' | 'unavailable'
@@ -162,7 +173,10 @@ async function verifyClipboard(
162173

163174
let browser: Browser | undefined
164175
try {
165-
browser = await (engine === 'webkit' ? webkit : chromium).launch()
176+
browser =
177+
webkitEndpoint === undefined
178+
? await (engine === 'webkit' ? webkit : chromium).launch()
179+
: await webkit.connect(webkitEndpoint, { timeout: 180_000 })
166180
const feedbackBrowser = browser
167181
await check('Feedback forwards votes and preserves unchanged retry identity', async () => {
168182
const cert = process.env.DOCS_FEEDBACK_TEST_CERT

‎apps/sim/scripts/test-mobile-e2e.ts‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert from 'node:assert/strict'
22
import { mkdir, writeFile } from 'node:fs/promises'
3+
import { createRequire } from 'node:module'
34
import { dirname, resolve } from 'node:path'
45
import {
56
type Browser,
@@ -13,13 +14,15 @@ import {
1314
import { createLogger } from '@sim/logger'
1415
import { getErrorMessage } from '@sim/utils/errors'
1516
import { generateId, generateShortId } from '@sim/utils/id'
17+
import { toRecord } from '@sim/utils/object'
1618
import { makeSignature } from 'better-auth/crypto'
1719
import postgres from 'postgres'
1820

1921
/**
2022
* Real browser coverage against a running local app and disposable PostgreSQL.
2123
* Requires MOBILE_E2E_BASE_URL, MOBILE_E2E_DATABASE_URL, MOBILE_E2E_AUTH_SECRET,
22-
* and MOBILE_E2E_REPORT_PATH. Install Chromium and WebKit with Playwright first.
24+
* and MOBILE_E2E_REPORT_PATH. Native launches require installed Playwright browsers.
25+
* PLAYWRIGHT_WEBKIT_WS_ENDPOINT uses the pinned loopback WebKit server instead.
2326
* MOBILE_E2E_BROWSER and MOBILE_E2E_VIEWPORT narrow a diagnostic rerun.
2427
* MOBILE_E2E_SHARD (index/count, one-based) partitions all viewports across CI jobs.
2528
*/
@@ -32,6 +35,19 @@ function requiredEnvironment(name: string): string {
3235
return value
3336
}
3437

38+
const selectedBrowser = process.env.MOBILE_E2E_BROWSER
39+
const webkitEndpoint = process.env.PLAYWRIGHT_WEBKIT_WS_ENDPOINT
40+
if (webkitEndpoint !== undefined) {
41+
assert.equal(selectedBrowser, 'webkit', 'A remote endpoint requires explicit WebKit selection')
42+
assert(/^ws:\/\/127\.0\.0\.1:[1-9]\d*\/$/.test(webkitEndpoint), 'Invalid WebKit endpoint')
43+
new URL(webkitEndpoint)
44+
assert.equal(
45+
toRecord(createRequire(import.meta.url)('@playwright/test/package.json')).version,
46+
'1.64.1',
47+
'The remote WebKit image requires Playwright 1.64.1'
48+
)
49+
}
50+
3551
const baseUrl = new URL(requiredEnvironment('MOBILE_E2E_BASE_URL'))
3652
const databaseUrl = new URL(requiredEnvironment('MOBILE_E2E_DATABASE_URL'))
3753
const authSecret = requiredEnvironment('MOBILE_E2E_AUTH_SECRET')
@@ -98,7 +114,6 @@ const viewports = [
98114
{ name: 'wide-desktop', width: 1920, height: 1080, touch: false },
99115
] as const
100116
const routes = ['home', 'files', 'tables', 'knowledge', 'logs', 'integrations', 'settings/general']
101-
const selectedBrowser = process.env.MOBILE_E2E_BROWSER
102117
const selectedViewport = process.env.MOBILE_E2E_VIEWPORT
103118
assert(!selectedBrowser || ['chromium', 'webkit'].includes(selectedBrowser), 'Unknown browser')
104119
assert(
@@ -1281,7 +1296,10 @@ try {
12811296
if (selectedBrowser && selectedBrowser !== browserName) continue
12821297
let browser: Browser | undefined
12831298
await check(`${browserName}/browser starts`, undefined, async () => {
1284-
browser = await browserType.launch()
1299+
browser =
1300+
webkitEndpoint === undefined
1301+
? await browserType.launch()
1302+
: await browserType.connect(webkitEndpoint, { timeout: 180_000 })
12851303
})
12861304
if (!browser) continue
12871305
try {

0 commit comments

Comments
 (0)