diff --git a/packages/playwright-core/src/client/harRouter.ts b/packages/playwright-core/src/client/harRouter.ts index a9ab966b2a574..7ac350f6f080a 100644 --- a/packages/playwright-core/src/client/harRouter.ts +++ b/packages/playwright-core/src/client/harRouter.ts @@ -68,9 +68,16 @@ 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 setCookieHeaders = response.headers!.filter(h => h.name.toLowerCase() === 'set-cookie'); + const transformedHeaders = response.headers!.filter(h => h.name.toLowerCase() !== 'set-cookie'); + if (setCookieHeaders.length > 1) + transformedHeaders.push({ name: 'set-cookie', value: setCookieHeaders.map(h => h.value).join('\n') }); + await route.fulfill({ status: response.status, - headers: Object.fromEntries(response.headers!.map(h => [h.name, h.value])), + headers: Object.fromEntries(transformedHeaders.map(h => [h.name, h.value])), body: response.body! }); return; diff --git a/tests/assets/har-fulfill.har b/tests/assets/har-fulfill.har index 5b679098c878a..39261f5ed371a 100644 --- a/tests/assets/har-fulfill.har +++ b/tests/assets/har-fulfill.har @@ -62,6 +62,14 @@ { "name": "content-type", "value": "text/html" + }, + { + "name": "Set-Cookie", + "value": "playwright=works;" + }, + { + "name": "Set-Cookie", + "value": "with=multiple-set-cookie-headers;" } ], "content": { diff --git a/tests/library/browsercontext-har.spec.ts b/tests/library/browsercontext-har.spec.ts index 6e64045902508..5ff1f2c2e6140 100644 --- a/tests/library/browsercontext-har.spec.ts +++ b/tests/library/browsercontext-har.spec.ts @@ -358,6 +358,14 @@ it('should record overridden requests to har', async ({ contextFactory, server } expect(await page2.evaluate(fetchFunction, { path: '/echo', body: '12' })).toBe('12'); }); +it('should replay requests with multiple set-cookie headers properly', async ({ context, asset }) => { + const path = asset('har-fulfill.har'); + await context.routeFromHAR(path); + const page = await context.newPage(); + await page.goto('http://no.playwright/'); + expect(await page.context().cookies()).toEqual([expect.objectContaining({ name: 'playwright', value: 'works' }), expect.objectContaining({ name: 'with', value: 'multiple-set-cookie-headers' })]); +}); + it('should disambiguate by header', async ({ contextFactory, server }, testInfo) => { server.setRoute('/echo', async (req, res) => { res.end(req.headers['baz']);