From f4cbaa6a68ea769b64a302d93a875d5fa39bc972 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Fri, 13 Feb 2026 16:15:05 -0800 Subject: [PATCH 1/5] chore: use published extension id (#39265) --- packages/playwright/src/mcp/extension/cdpRelay.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playwright/src/mcp/extension/cdpRelay.ts b/packages/playwright/src/mcp/extension/cdpRelay.ts index 4b489bf890373..0041965f4a87e 100644 --- a/packages/playwright/src/mcp/extension/cdpRelay.ts +++ b/packages/playwright/src/mcp/extension/cdpRelay.ts @@ -118,7 +118,7 @@ export class CDPRelayServer { private _connectBrowser(clientInfo: ClientInfo, forceNewTab: boolean) { const mcpRelayEndpoint = `${this._wsHost}${this._extensionPath}`; // Need to specify "key" in the manifest.json to make the id stable when loading from file. - const url = new URL('chrome-extension://jakfalbnbhgkpmoaakfflhflbfpkailf/connect.html'); + const url = new URL('chrome-extension://mmlmfjhmonkocbjadbfplnigmagldckm/connect.html'); url.searchParams.set('mcpRelayUrl', mcpRelayEndpoint); const client = { name: clientInfo.name, From c69930103a7d1013ad92aa19b929e9cf0fef2265 Mon Sep 17 00:00:00 2001 From: Victor Lin <125177+yepitschunked@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:25:51 -0800 Subject: [PATCH 2/5] fix(routeFromHAR, take 2): hack harRouter to merge set-cookie headers (#38487) --- .../playwright-core/src/client/harRouter.ts | 21 +++++++- tests/library/browsercontext-har.spec.ts | 53 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/playwright-core/src/client/harRouter.ts b/packages/playwright-core/src/client/harRouter.ts index a9ab966b2a574..f3f11f852e37a 100644 --- a/packages/playwright-core/src/client/harRouter.ts +++ b/packages/playwright-core/src/client/harRouter.ts @@ -68,9 +68,28 @@ export class HarRouter { // test when HAR was recorded but we'd abort it immediately. if (response.status === -1) return; + + + // route.fulfill does not support multiple set-cookie headers. We need to merge them into one. + const transformedHeaders = response.headers!.reduce((headersMap, { name, value }) => { + if (name.toLowerCase() !== 'set-cookie') { + // non-set-cookie header gets set as-is + headersMap[name] = value; + } else { + // first set-cookie header gets included as-is + if (!headersMap['set-cookie']) + headersMap['set-cookie'] = value; + else + // subsequent set-cookie headers get appended to existing header + headersMap['set-cookie'] += `\n${value}`; + + } + return headersMap; + }, {} as Record); + await route.fulfill({ status: response.status, - headers: Object.fromEntries(response.headers!.map(h => [h.name, h.value])), + headers: transformedHeaders, body: response.body! }); return; diff --git a/tests/library/browsercontext-har.spec.ts b/tests/library/browsercontext-har.spec.ts index 6e64045902508..f82bd30e87e43 100644 --- a/tests/library/browsercontext-har.spec.ts +++ b/tests/library/browsercontext-har.spec.ts @@ -452,6 +452,59 @@ it('should ignore boundary when matching multipart/form-data body', { await expect(page2.locator('div')).toHaveText('done'); }); +it('should record single set-cookie headers', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/31495' } +}, async ({ contextFactory, server }, testInfo) => { + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Content-Type', 'text/html'); + res.setHeader('set-cookie', ['first=foo']); + res.end(); + }); + + const harPath = testInfo.outputPath('har.zip'); + const context1 = await contextFactory(); + await context1.routeFromHAR(harPath, { update: true }); + const page1 = await context1.newPage(); + await page1.goto(server.EMPTY_PAGE); + const cookie1 = await page1.evaluate(() => document.cookie); + expect(cookie1).toBe('first=foo'); + await context1.close(); + + const context2 = await contextFactory(); + await context2.routeFromHAR(harPath, { notFound: 'abort' }); + const page2 = await context2.newPage(); + await page2.goto(server.EMPTY_PAGE); + const cookie2 = await page2.evaluate(() => document.cookie); + expect(cookie2).toBe('first=foo'); +}); + +it('should record multiple set-cookie headers', { + annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/31495' } +}, async ({ contextFactory, server }, testInfo) => { + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Content-Type', 'text/html'); + res.setHeader('set-cookie', ['first=foo', 'second=bar']); + res.end(); + }); + + const harPath = testInfo.outputPath('har.zip'); + const context1 = await contextFactory(); + await context1.routeFromHAR(harPath, { update: true }); + const page1 = await context1.newPage(); + await page1.goto(server.EMPTY_PAGE); + const cookie1 = await page1.evaluate(() => document.cookie); + expect(cookie1.split('; ').sort().join('; ')).toBe('first=foo; second=bar'); + await context1.close(); + + const context2 = await contextFactory(); + await context2.routeFromHAR(harPath, { notFound: 'abort' }); + const page2 = await context2.newPage(); + await page2.goto(server.EMPTY_PAGE); + const cookie2 = await page2.evaluate(() => document.cookie); + expect(cookie2.split('; ').sort().join('; ')).toBe('first=foo; second=bar'); +}); + + it('should update har.zip for page', async ({ contextFactory, server }, testInfo) => { const harPath = testInfo.outputPath('har.zip'); const context1 = await contextFactory(); From 0ffb1d066349f6a6ff90cefac80acfd39eaab74c Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Fri, 13 Feb 2026 17:10:47 -0800 Subject: [PATCH 3/5] chore: minor grid versioning fixes (#39266) --- packages/devtools/src/devtools.tsx | 5 ++-- packages/devtools/src/devtoolsChannel.ts | 1 + packages/devtools/src/grid.css | 3 +- packages/devtools/src/grid.tsx | 21 ++++++++------ packages/devtools/src/index.tsx | 7 +++-- packages/devtools/src/sessionModel.ts | 6 ++-- packages/devtools/src/transport.ts | 5 ++++ .../src/server/devtoolsController.ts | 29 +++++-------------- .../playwright/src/cli/client/devtoolsApp.ts | 2 -- packages/playwright/src/cli/client/program.ts | 4 +++ 10 files changed, 43 insertions(+), 40 deletions(-) diff --git a/packages/devtools/src/devtools.tsx b/packages/devtools/src/devtools.tsx index 5d886e16f3f05..520f7577dba7f 100644 --- a/packages/devtools/src/devtools.tsx +++ b/packages/devtools/src/devtools.tsx @@ -351,7 +351,7 @@ export const DevTools: React.FC<{ wsUrl?: string }> = ({ wsUrl }) => { onKeyDown={onOmniboxKeyDown} onFocus={e => e.target.select()} /> - - {selectedTab?.inspectorUrl && ( + } + {false && selectedTab?.inspectorUrl && (