From df055433bb57834dba045306bf26ebd9bb856ea1 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Sun, 25 Oct 2026 20:30:10 -0700 Subject: [PATCH 1/2] fix(context): attach HAR content for a .zip path and tolerate a disposed request context on close Path.endsWith(".zip") compares path elements and never matched; closing a context whose request context the user had disposed threw TargetClosedError. Claude-Session: https://claude.ai/code/session_018p7xPf3r5VjAM7V46nzFTM --- .../com/microsoft/playwright/impl/BrowserContextImpl.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java index 4e018748b..e9a1fa96c 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java @@ -382,7 +382,11 @@ public void close(CloseOptions options) { options = new CloseOptions(); } closeReason = options.reason; - request.dispose(convertType(options, APIRequestContext.DisposeOptions.class)); + try { + request.dispose(convertType(options, APIRequestContext.DisposeOptions.class)); + } catch (TargetClosedError e) { + // The request context was disposed by the user already. + } try { tracing.exportAllHars(); } catch (RuntimeException e) { @@ -934,7 +938,7 @@ protected void initializeHarFromOptions(Browser.NewContextOptions options) { contentPolicy = HarContentPolicy.OMIT; } if (contentPolicy == null) { - contentPolicy = options.recordHarPath.endsWith(".zip") ? HarContentPolicy.ATTACH : HarContentPolicy.EMBED; + contentPolicy = options.recordHarPath.toString().endsWith(".zip") ? HarContentPolicy.ATTACH : HarContentPolicy.EMBED; } RouteFromHAROptions routeFromHAROptions = new RouteFromHAROptions(); From 5094abff5ffd29fbf28eba15254e3a9be58a96cf Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 26 Oct 2026 12:23:03 -0700 Subject: [PATCH 2/2] test(context): check HAR content attachment for a .zip path and closing after request dispose Claude-Session: https://claude.ai/code/session_018p7xPf3r5VjAM7V46nzFTM --- .../playwright/TestBrowserContextFetch.java | 7 +++++++ .../playwright/TestBrowserContextHar.java | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java index 7c874041e..d89b102cc 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextFetch.java @@ -986,4 +986,11 @@ void shouldSupportMultipleHttpCredentials(Browser browser, Server server) { assertEquals(401, response2.status()); } } + + @PlaywrightTest + void shouldCloseContextAfterRequestDispose(Browser browser) { + BrowserContext context = browser.newContext(); + context.request().dispose(); + context.close(); + } } diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextHar.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextHar.java index 2891233c2..678e3c08c 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextHar.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextHar.java @@ -16,6 +16,8 @@ package com.microsoft.playwright; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.microsoft.playwright.fixtures.DisabledOnBrowser; import com.microsoft.playwright.fixtures.PlaywrightTest; import com.microsoft.playwright.options.HarMode; @@ -535,4 +537,22 @@ void shouldNotInterceptAPIRequestContextRequestsByDefault(Browser browser, Serve assertEquals("{\"hello\": \"fresh\"}", replayed.text()); } } + + @PlaywrightTest + void shouldAttachContentWhenRecordingHarZip(Browser browser, Server server, @TempDir Path tmpDir) throws IOException { + Path harPath = tmpDir.resolve("har.zip"); + try (BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setRecordHarPath(harPath) + .setRecordHarMode(HarMode.MINIMAL))) { + Page page = context.newPage(); + page.navigate(server.PREFIX + "/one-style.html"); + } + Path harDir = tmpDir.resolve("har"); + extractZip(harPath, harDir); + String har = new String(Files.readAllBytes(harDir.resolve("har.har")), StandardCharsets.UTF_8); + JsonObject content = JsonParser.parseString(har).getAsJsonObject().getAsJsonObject("log") + .getAsJsonArray("entries").get(0).getAsJsonObject().getAsJsonObject("response").getAsJsonObject("content"); + assertTrue(content.has("_file"), har); + assertTrue(Files.exists(harDir.resolve(content.get("_file").getAsString()))); + } }