Repository: microsoft/playwright
Pull request #35564: fix: timeout error when downloading browsers
Author: login: yury-s
Labels: name: CQ1
Created: 2025-04-09T22:59:28Z | Merged: 2025-04-10T20:55:49Z

When cdn server returns a redirect, we create a new request to it and continue the download using it. The old request has an open socket that is idling and if the download takes longer than configured timeout, old request will throw a timeout error. The fix is to make sure to close original request when we no longer need it.

Fixes https://github.com/microsoft/playwright/issues/34686


Diff:
diff --git a/packages/playwright-core/src/server/utils/network.ts b/packages/playwright-core/src/server/utils/network.ts
index 8e0357f958122..38fb5ebbb72d8 100644
--- a/packages/playwright-core/src/server/utils/network.ts
+++ b/packages/playwright-core/src/server/utils/network.ts
@@ -70,10 +70,14 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco
 
   const requestCallback = (res: http.IncomingMessage) => {
     const statusCode = res.statusCode || 0;
-    if (statusCode >= 300 && statusCode < 400 && res.headers.location)
+    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {
+      // Close the original socket before following the redirect. Otherwise
+      // it may stay idle and cause a timeout error.
+      request.destroy();
       httpRequest({ ...params, url: new URL(res.headers.location, params.url).toString() }, onResponse, onError);
-    else
+    } else {
       onResponse(res);
+    }
   };
   const request = options.protocol === 'https:' ?
     https.request(options, requestCallback) :
diff --git a/tests/installation/playwright-cdn.spec.ts b/tests/installation/playwright-cdn.spec.ts
index 776aec42ad1ce..1ebb49a01a598 100644
--- a/tests/installation/playwright-cdn.spec.ts
+++ b/tests/installation/playwright-cdn.spec.ts
@@ -72,6 +72,64 @@ test(`playwright cdn should race with a timeout`, async ({ exec }) => {
   }
 });
 
+test(`playwright cdn should not timeout on redirect`, {
+  annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/34686' }
+}, async ({ exec }) => {
+  const server = http.createServer(async (req, res) => {
+    if (req.url !== '/foo.zip') {
+      res.writeHead(307, {
+        'Connection': 'keep-alive',
+        'location': `http://127.0.0.1:${(server.address() as AddressInfo).port}/foo.zip`,
+      });
+      res.flushHeaders();
+      // Keep the connection open, the client is expected to close it.
+      return;
+    }
+    const emptyZip = Buffer.from([
+      0x50, 0x4B, 0x05, 0x06, // EOCD
+      0x00, 0x00,             // Disk number
+      0x00, 0x00,             // Central dir start disk
+      0x00, 0x00,             // Central dir records on this disk
+      0x00, 0x00,             // Total central dir records
+      0x00, 0x00, 0x00, 0x00, // Central dir size
+      0x00, 0x00, 0x00, 0x00, // Offset of start of central dir
+      0x00, 0x00              // ZIP comment length
+    ]);
+    res.socket.setNoDelay(true);
+    res.writeHead(200, {
+      'Content-Type': 'application/zip',
+      'Content-Disposition': 'attachment; filename="empty.zip"',
+      'Content-Length': emptyZip.length,
+    });
+    res.flushHeaders();
+    // Send one byte at a time in small intervals (< 1000ms) during 2 seconds
+    // to keep the second connection slow but alive.
+    for (let i = 0; i < emptyZip.length; i ++) {
+      res.write(emptyZip.subarray(i, i + 1));
+      await new Promise(resolve => setTimeout(resolve, 2000 / emptyZip.length));
+    }
+    res.end();
+  });
+  await new Promise<void>(resolve => server.listen(0, resolve));
+
+  try {
+    await exec('npm i playwright');
+    const result = await exec('npx playwright install chromium', {
+      env: {
+        PLAYWRIGHT_DOWNLOAD_HOST: `http://127.0.0.1:${(server.address() as AddressInfo).port}`,
+        DEBUG: 'pw:install',
+        PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT: '1000',
+      },
+      expectToExitWithError: true
+    });
+    // Steps after the extraction will fail, but the download should succeed without timeouts.
+    expect(result).toContain(`pw:install SUCCESS downloading Chromium`);
+    expect(result).not.toContain(`timed out after 1000ms`);
+  } finally {
+    await new Promise(resolve => server.close(resolve));
+  }
+});
+
 test(`npx playwright install should not hang when CDN closes the connection`, async ({ exec }) => {
   let retryCount = 0;
   const server = http.createServer((req, res) => {


Reviews:
user: login: dgozman
body: Nice finding!
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-10T08:35:47Z
user: login: mxschmitt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T11:17:43Z
user: login: mxschmitt
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T16:08:43Z
user: login: dgozman
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-10T19:53:29Z

Review comments:
diff_hunk: @@ -70,10 +70,14 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco
 
   const requestCallback = (res: http.IncomingMessage) => {
     const statusCode = res.statusCode || 0;
-    if (statusCode >= 300 && statusCode < 400 && res.headers.location)
+    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {
+      // Close the original socket before following the redirect. Otherwise
+      // it may stay idle and cause a timeout error.
+      request.destroy();
path: packages/playwright-core/src/server/utils/network.ts
user: login: mxschmitt
body: This would also [destroy the underlying TCP socket](https://github.com/nodejs/node/blob/9bbbe60f6b0001964cb62182ce17e7f3980ccf06/lib/_http_outgoing.js#L319), which means setting `keepAlive: true` would no longer have any effect. As of today we attempt to use [keepAlive: true](https://github.com/microsoft/playwright/blob/c9a1ad4d8d718300b0ed2828daa7311bb1692d01/packages/playwright-core/src/server/utils/happyEyeballs.ts#L54-L56) but it was not working for browser downloads because:

- We have a child process / fork for each download. This makes it impossible to re-use TCP connections and leverage `keep-alive: true`.
- With your PR we'd destroy the sockets. We should call `res.resume()` instead of un-register the event listeners.

Your test also passes without the change to `network.ts` for me which is interesting.

I think we should aim to properly use keepAlive. Whether that's part of this PR or a follow-up can be debated. This would require getting rid of the OOP (out-of-process) downloader, which was already on the agenda.

NOTE: currently we create 5x2 sockets for 5 downloads to 2 hosts. With `keepAlive` we could re-use the sockets and only have 2 of them, since we have two hosts.
created_at: 2025-04-10T11:17:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -70,10 +70,14 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco
 
   const requestCallback = (res: http.IncomingMessage) => {
     const statusCode = res.statusCode || 0;
-    if (statusCode >= 300 && statusCode < 400 && res.headers.location)
+    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {
+      // Close the original socket before following the redirect. Otherwise
+      // it may stay idle and cause a timeout error.
+      request.destroy();
path: packages/playwright-core/src/server/utils/network.ts
user: login: mxschmitt
body: Discussed offline: Let's follow up with keepAlive: true.
created_at: 2025-04-10T16:08:43Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-09T23:49:53Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14368528942-1-c84bb713a6ba1c42e4cbeb7da8f6d4149080e54f/index.html) for "tests 1"
<details>
<summary><b>3 flaky</b></summary>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-ubuntu-22.04-node18 <br/>
:warning: [chromium] › headerView.spec.tsx:46:1 › should toggle filters @web-components-html-reporter <br/>
:warning: [webkit-library] › library/trace-viewer.spec.ts:1306:1 › should pick locator in iframe @webkit-ubuntu-22.04-node18 <br/>

</details>

**39113 passed, 807 skipped**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14369118812).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-10T00:38:49Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14369216023-1-c84bb713a6ba1c42e4cbeb7da8f6d4149080e54f/index.html) for "tests others"
<details>
<summary><b>3 flaky</b></summary>
:warning: [electron-page] › page/page-request-continue.spec.ts:72:3 › should delete header with undefined value @electron-macos-latest <br/>
:warning: [electron-page] › page/page-request-continue.spec.ts:72:3 › should delete header with undefined value @electron-ubuntu-latest <br/>
:warning: [electron-page] › page/page-request-continue.spec.ts:72:3 › should delete header with undefined value @electron-windows-latest <br/>

</details>

**21957 passed, 511 skipped**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14369691864).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-10T00:48:49Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14369211960-1-c84bb713a6ba1c42e4cbeb7da8f6d4149080e54f/index.html) for "tests 1"
<details>
<summary><b>9 flaky</b></summary>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-ubuntu-22.04-node18 <br/>
:warning: [playwright-test] › ui-mode-test-ct.spec.ts:155:5 › should watch test @macos-latest-node18-1 <br/>
:warning: [playwright-test] › ui-mode-test-output.spec.ts:80:5 › should show console messages for test @macos-latest-node18-1 <br/>
:warning: [playwright-test] › ui-mode-test-watch.spec.ts:145:5 › should watch all @ubuntu-latest-node18-1 <br/>
:warning: [webkit-library] › library/screenshot.spec.ts:205:14 › element screenshot › element screenshot should work with a mobile viewport @webkit-ubuntu-22.04-node18 <br/>
:warning: [webkit-library] › library/video.spec.ts:475:5 › screencast › should scale frames down to the requested size  @webkit-ubuntu-22.04-node18 <br/>
:warning: [webkit-page] › page/page-screenshot.spec.ts:345:5 › page screenshot › should work while navigating @webkit-ubuntu-22.04-node18 <br/>
:warning: [webkit-page] › page/page-screenshot.spec.ts:868:5 › page screenshot animations › should wait for fonts to load @webkit-ubuntu-22.04-node18 <br/>
:warning: [playwright-test] › ui-mode-test-watch.spec.ts:145:5 › should watch all @windows-latest-node18-1 <br/>

</details>

**39110 passed, 807 skipped**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14369814177).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-10T00:57:05Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14369216011-1-c84bb713a6ba1c42e4cbeb7da8f6d4149080e54f/index.html) for "tests 2"
**6 failed**
:x: [chromium-library] › library/browsercontext-events.spec.ts:19:5 › console event should work @smoke @driver
:x: [webkit-library] › library/video.spec.ts:475:5 › screencast › should scale frames down to the requested size  @tracing-webkit
:x: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:993:7 › cli codegen › should clear when recording is disabled @webkit-headed-windows-latest
:x: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames fit @webkit-macos-13-xlarge
:x: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames crop @webkit-macos-13-xlarge
:x: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames scale @webkit-macos-13-xlarge

<details>
<summary><b>74 flaky</b></summary>
:warning: [chromium-library] › library/inspector/cli-codegen-aria.spec.ts:76:7 › should update aria snapshot highlight @channel-chromium-windows-latest <br/>
:warning: [chromium-page] › page/workers.spec.ts:240:3 › should support extra http headers @chrome-beta-macos-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:206:1 › should reset mouse position @chromium-headed-ubuntu-24.04 <br/>
:warning: [chromium-library] › library/inspector/cli-codegen-1.spec.ts:268:7 › cli codegen › should fill @chromium-headed-ubuntu-24.04 <br/>
:warning: [chromium-library] › library/trace-viewer.spec.ts:1344:1 › should highlight locator in iframe while typing @chromium-tip-of-tree-windows-latest--headed <br/>
:warning: [chromium-library] › library/inspector/cli-codegen-pick-locator.spec.ts:35:7 › should update locator highlight @chromium-windows-latest <br/>
:warning: [chromium-page] › page/page-request-continue.spec.ts:72:3 › should delete header with undefined value @chromium-windows-latest <br/>
:warning: [firefox-library] › library/video.spec.ts:163:5 › screencast › should work with old options @firefox-beta-macos-latest <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-beta-ubuntu-22.04 <br/>
:warning: [firefox-library] › library/browsercontext-storage-state.spec.ts:361:3 › should support IndexedDB @firefox-beta-windows-latest <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-beta-windows-latest <br/>
:warning: [firefox-library] › library/capabilities.spec.ts:252:3 › requestFullscreen @firefox-headed-macos-14-xlarge <br/>
:warning: [firefox-library] › library/browsercontext-basic.spec.ts:34:3 › should be able to click across browser contexts @firefox-headed-ubuntu-24.04 <br/>
:warning: [firefox-library] › library/inspector/title.spec.ts:35:5 › should update primary page URL when original primary closes @firefox-headed-ubuntu-24.04 <br/>
:warning: [firefox-library] › library/trace-viewer.spec.ts:464:1 › should show snapshot URL @firefox-headed-ubuntu-24.04 <br/>
:warning: [firefox-page] › page/page-click.spec.ts:261:3 › should click on checkbox input and toggle @firefox-headed-ubuntu-24.04 <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-headed-ubuntu-24.04 <br/>
:warning: [firefox-library] › library/browsercontext-cookies.spec.ts:407:3 › should parse cookie with large Max-Age correctly @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/browsercontext-proxy.spec.ts:366:3 › should use socks proxy in second page @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/capabilities.spec.ts:206:3 › webkit should define window.safari @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/client-certificates.spec.ts:280:3 › browser › should keep supporting http @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/emulation-focus.spec.ts:21:3 › should think that it is focused by default @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/har.spec.ts:598:3 › should have connection details @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/inspector/cli-codegen-1.spec.ts:891:7 › cli codegen › should record slider @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/tracing.spec.ts:545:5 › should export trace concurrently to second navigation @firefox-headed-windows-latest <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-headed-windows-latest <br/>
:warning: [firefox-page] › page/page-event-request.spec.ts:182:3 › should return response body when Cross-Origin-Opener-Policy is set @firefox-headed-windows-latest <br/>
:warning: [firefox-library] › library/video.spec.ts:163:5 › screencast › should work with old options @firefox-macos-13-large <br/>
:warning: [firefox-library] › library/video.spec.ts:379:5 › screencast › should capture navigation @firefox-macos-13-large <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-macos-13-large <br/>
:warning: [firefox-library] › library/video.spec.ts:163:5 › screencast › should work with old options @firefox-macos-13-xlarge <br/>
:warning: [firefox-library] › library/video.spec.ts:163:5 › screencast › should work with old options @firefox-macos-14-large <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-macos-14-large <br/>
:warning: [firefox-library] › library/video.spec.ts:163:5 › screencast › should work with old options @firefox-macos-14-xlarge <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-ubuntu-24.04 <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-windows-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-beta-macos-latest <br/>
:warning: [chromium-library] › library/inspector/cli-codegen-2.spec.ts:454:7 › cli codegen › should save assets via SIGINT @msedge-beta-macos-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-beta-ubuntu-22.04 <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-dev-macos-latest <br/>
:warning: [chromium-library] › library/inspector/cli-codegen-2.spec.ts:454:7 › cli codegen › should save assets via SIGINT @msedge-dev-macos-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-dev-ubuntu-22.04 <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-dev-windows-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-macos-latest <br/>
:warning: [chromium-library] › library/browsercontext-reuse.spec.ts:30:1 › should re-add binding after reset @msedge-ubuntu-22.04 <br/>
:warning: [chromium-library] › library/video.spec.ts:379:5 › screencast › should capture navigation @msedge-ubuntu-22.04 <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @tracing-firefox <br/>
:warning: [webkit-library] › library/browsercontext-device.spec.ts:45:5 › device › should scroll to click @tracing-webkit <br/>
:warning: [webkit-library] › library/browsercontext-pages.spec.ts:82:3 › should click the button with offset with page scale @tracing-webkit <br/>
:warning: [webkit-library] › library/browsercontext-pages.spec.ts:105:3 › should return bounding box with page scale @tracing-webkit <br/>
:warning: [webkit-library] › library/screenshot.spec.ts:55:14 › page screenshot › should work with a mobile viewport and clip @tracing-webkit <br/>
:warning: [webkit-library] › library/screenshot.spec.ts:289:14 › element screenshot › should restore viewport after page screenshot and timeout @tracing-webkit <br/>
:warning: [webkit-library] › library/video.spec.ts:411:5 › screencast › should capture css transformation @tracing-webkit <br/>
:warning: [webkit-library] › library/video.spec.ts:441:5 › screencast › should work for popups @tracing-webkit <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:610:7 › cli codegen › should select @webkit-headed-macos-14-xlarge <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:332:7 › cli codegen › should fill textarea @webkit-headed-ubuntu-22.04 <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:55:7 › cli codegen › should double click @webkit-headed-ubuntu-24.04 <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:23:7 › cli codegen › should click @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:483:7 › cli codegen › should emit single keyup on ArrowDown @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:508:7 › cli codegen › should check @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:559:7 › cli codegen › should check with keyboard @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:578:7 › cli codegen › should uncheck @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-1.spec.ts:930:7 › cli codegen › should click button with nested div @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-python.spec.ts:78:5 › should save the codegen output to a file if specified @webkit-headed-windows-latest <br/>
:warning: [webkit-page] › page/page-click.spec.ts:261:3 › should click on checkbox input and toggle @webkit-headed-windows-latest <br/>
:warning: [webkit-library] › library/trace-viewer.spec.ts:1306:1 › should pick locator in iframe @webkit-macos-14-large <br/>
:warning: [webkit-page] › page/page-request-continue.spec.ts:228:5 › post data › should compute content-length from post data @webkit-macos-14-large <br/>
:warning: [webkit-page] › page/wheel.spec.ts:101:3 › should dispatch wheel events after popup was opened @smoke @webkit-macos-14-large <br/>
:warning: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames crop @webkit-macos-14-xlarge <br/>
:warning: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames scale @webkit-macos-14-xlarge <br/>
:warning: [webkit-page] › page/wheel.spec.ts:166:3 › should set the modifiers @webkit-macos-14-xlarge <br/>
:warning: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames crop @webkit-macos-15-xlarge <br/>
:warning: [webkit-library] › library/tracing.spec.ts:432:14 › should produce screencast frames scale @webkit-macos-15-xlarge <br/>
:warning: [webkit-library] › library/inspector/cli-codegen-aria.spec.ts:76:7 › should update aria snapshot highlight @webkit-windows-latest <br/>

</details>

**238018 passed, 9301 skipped**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14369883077).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-10T17:30:11Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14386574822-1-b10f920a152f0bc62296f73848684798f3f317bf/index.html) for "tests 1"
**28 passed**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14386628167).
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-10T18:20:45Z
body: <!-- Generated by Playwright markdown reporter -->
### [Test results](https://mspwblobreport.z1.web.core.windows.net/run-14386621519-1-b10f920a152f0bc62296f73848684798f3f317bf/index.html) for "tests 1"
**1 failed**
:x: [playwright-test] › reporter-html.spec.ts:2838:5 › merged › execSync doesnt produce a second stdout attachment @macos-latest-node18-2

<details>
<summary><b>5 flaky</b></summary>
:warning: [firefox-library] › library/inspector/cli-codegen-pick-locator.spec.ts:35:7 › should update locator highlight @firefox-ubuntu-22.04-node18 <br/>
:warning: [firefox-page] › page/page-evaluate.spec.ts:424:3 › should throw for too deep reference chain @firefox-ubuntu-22.04-node18 <br/>
:warning: [webkit-library] › library/browsercontext-viewport-mobile.spec.ts:97:5 › mobile viewport › should fire orientationchange event @webkit-ubuntu-22.04-node18 <br/>
:warning: [webkit-page] › page/page-screenshot.spec.ts:345:5 › page screenshot › should work while navigating @webkit-ubuntu-22.04-node18 <br/>
:warning: [playwright-test] › ui-mode-test-watch.spec.ts:145:5 › should watch all @windows-latest-node18-1 <br/>

</details>

**39114 passed, 806 skipped**
:heavy_check_mark::heavy_check_mark::heavy_check_mark:


Merge [workflow run](https://github.com/microsoft/playwright/actions/runs/14387519414).
author_association: CONTRIBUTOR