From e96135e7a983c08768885e6c12e5757ff8f0f734 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 27 Sep 2021 15:59:12 -0700 Subject: [PATCH 1/3] test: add tests for Cross-Origin-Opener-Policy navigation --- tests/download.spec.ts | 32 ++++++++++ tests/page/page-goto.spec.ts | 77 +++++++++++++++++++++++- tests/page/page-request-continue.spec.ts | 53 ++++++++++++++++ 3 files changed, 160 insertions(+), 2 deletions(-) diff --git a/tests/download.spec.ts b/tests/download.spec.ts index fb338f9c51045..52b975ce3ce7c 100644 --- a/tests/download.spec.ts +++ b/tests/download.spec.ts @@ -39,6 +39,12 @@ it.describe('download event', () => { res.write('foo'); res.uncork(); }); + server.setRoute('/downloadWithCOOP', (req, res) => { + res.setHeader('Content-Type', 'application/octet-stream'); + res.setHeader('Content-Disposition', 'attachment'); + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.end(`Hello world`); + }); }); it('should report download when navigation turns into download', async ({ browser, server, browserName }) => { @@ -67,6 +73,32 @@ it.describe('download event', () => { await page.close(); }); + it('should work with Cross-Origin-Opener-Policy', async ({ browser, server, browserName }) => { + const page = await browser.newPage({ acceptDownloads: true }); + const [ download, responseOrError ] = await Promise.all([ + page.waitForEvent('download'), + page.goto(server.PREFIX + '/downloadWithCOOP').catch(e => e) + ]); + expect(download.page()).toBe(page); + expect(download.url()).toBe(`${server.PREFIX}/downloadWithCOOP`); + const path = await download.path(); + expect(fs.existsSync(path)).toBeTruthy(); + expect(fs.readFileSync(path).toString()).toBe('Hello world'); + if (browserName === 'chromium') { + expect(responseOrError instanceof Error).toBeTruthy(); + expect(responseOrError.message).toContain('net::ERR_ABORTED'); + expect(page.url()).toBe('about:blank'); + } else if (browserName === 'webkit') { + expect(responseOrError instanceof Error).toBeTruthy(); + expect(responseOrError.message).toContain('Download is starting'); + expect(page.url()).toBe('about:blank'); + } else { + expect(responseOrError.status()).toBe(200); + expect(page.url()).toBe(server.PREFIX + '/download'); + } + await page.close(); + }); + it('should report downloads with acceptDownloads: false', async ({ browser, server }) => { const page = await browser.newPage(); await page.setContent(`download`); diff --git a/tests/page/page-goto.spec.ts b/tests/page/page-goto.spec.ts index 7fdfae4f8aef7..e17c194cffaf1 100644 --- a/tests/page/page-goto.spec.ts +++ b/tests/page/page-goto.spec.ts @@ -58,14 +58,87 @@ it('should work cross-process', async ({ page, server }) => { expect(response.url()).toBe(url); }); +it('should work with cross-process that fails before committing', async ({ page, server, browserName }) => { + server.setRoute('/empty.html', (req, res) => { + req.socket.destroy(); + }); + const response1 = await page.goto(server.CROSS_PROCESS_PREFIX + '/title.html'); + await response1.finished(); + const error = await page.goto(server.EMPTY_PAGE).catch(e => e); + if (browserName === 'chromium') + expect(error.message).toContain('net::ERR_EMPTY_RESPONSE'); + if (browserName === 'webkit') + expect(error.message).toContain('Message Corrupt'); + if (browserName === 'firefox') + expect(error.message).toContain('NS_ERROR_NET_RESET'); +}); + it('should work with Cross-Origin-Opener-Policy', async ({ page, server, browserName }) => { - it.fail(browserName === 'webkit', 'Regressed in https://trac.webkit.org/changeset/281516/webkit'); + it.fail(browserName === 'webkit', 'https://github.com/microsoft/playwright/issues/8796'); server.setRoute('/empty.html', (req, res) => { res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); res.end(); }); - await page.goto(server.EMPTY_PAGE); + const requests = new Set(); + const events = []; + page.on('request', r => { + events.push('request'); + requests.add(r); + }); + page.on('requestfailed', r => { + events.push('requestfailed'); + requests.add(r); + }); + page.on('requestfinished', r => { + events.push('requestfinished'); + requests.add(r); + }); + page.on('response', r => { + events.push('response'); + requests.add(r.request()); + }); + const response = await page.goto(server.EMPTY_PAGE); + expect(page.url()).toBe(server.EMPTY_PAGE); + await response.finished(); + expect(events).toEqual(['request', 'response', 'requestfinished']); + expect(requests.size).toBe(1); + expect(response.request().failure()).toBeNull(); +}); + +it('should work with Cross-Origin-Opener-Policy after redirect', async ({ page, server, browserName }) => { + it.fail(browserName === 'webkit', 'https://github.com/microsoft/playwright/issues/8796'); + server.setRedirect('/redirect', '/empty.html'); + server.setRoute('/empty.html', (req, res) => { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.end(); + }); + const requests = new Set(); + const events = []; + page.on('request', r => { + events.push('request'); + requests.add(r); + }); + page.on('requestfailed', r => { + events.push('requestfailed'); + requests.add(r); + }); + page.on('requestfinished', r => { + events.push('requestfinished'); + requests.add(r); + }); + page.on('response', r => { + events.push('response'); + requests.add(r.request()); + }); + const response = await page.goto(server.PREFIX + '/redirect'); expect(page.url()).toBe(server.EMPTY_PAGE); + await response.finished(); + expect(events).toEqual(['request', 'response', 'requestfinished', 'request', 'response', 'requestfinished']); + expect(requests.size).toBe(2); + expect(response.request().failure()).toBeNull(); + const firstRequest = response.request().redirectedFrom(); + expect(firstRequest).toBeTruthy(); + expect(firstRequest.url()).toBe(server.PREFIX + '/redirect'); }); it('should capture iframe navigation request', async ({ page, server }) => { diff --git a/tests/page/page-request-continue.spec.ts b/tests/page/page-request-continue.spec.ts index d1d4c24b2cd7a..3aca7263b2af8 100644 --- a/tests/page/page-request-continue.spec.ts +++ b/tests/page/page-request-continue.spec.ts @@ -167,3 +167,56 @@ it.describe('', () => { expect(arr[i]).toBe(buffer[i]); }); }); + +it('should work with Cross-Origin-Opener-Policy', async ({ page, server, browserName }) => { + it.fail(browserName === 'webkit', 'https://github.com/microsoft/playwright/issues/8796'); + let serverHeaders; + const serverRequests = []; + server.setRoute('/empty.html', (req, res) => { + serverRequests.push(req.url); + serverHeaders ??= req.headers; + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.end(); + }); + + const intercepted = []; + await page.route('**/*', (route, req) => { + intercepted.push(req.url()); + route.continue({ + headers: { + foo: 'bar' + } + }); + }); + const requests = new Set(); + const events = []; + page.on('request', r => { + events.push('request'); + requests.add(r); + }); + page.on('requestfailed', r => { + events.push('requestfailed'); + requests.add(r); + }); + page.on('requestfinished', r => { + events.push('requestfinished'); + requests.add(r); + }); + page.on('response', r => { + events.push('response'); + requests.add(r.request()); + }); + const response = await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual([server.EMPTY_PAGE]); + // There should be only one request to the server. + if (browserName === 'webkit') + expect(serverRequests).toEqual(['/empty.html', '/empty.html']); + else + expect(serverRequests).toEqual(['/empty.html']); + expect(serverHeaders['foo']).toBe('bar'); + expect(page.url()).toBe(server.EMPTY_PAGE); + await response.finished(); + expect(events).toEqual(['request', 'response', 'requestfinished']); + expect(requests.size).toBe(1); + expect(response.request().failure()).toBeNull(); +}); From eb82fac65dc52007cc06491b30a4ff2f439eab97 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Mon, 27 Sep 2021 16:40:14 -0700 Subject: [PATCH 2/3] Update firefox test result --- tests/download.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/download.spec.ts b/tests/download.spec.ts index 52b975ce3ce7c..72c7a8114e5ad 100644 --- a/tests/download.spec.ts +++ b/tests/download.spec.ts @@ -94,7 +94,7 @@ it.describe('download event', () => { expect(page.url()).toBe('about:blank'); } else { expect(responseOrError.status()).toBe(200); - expect(page.url()).toBe(server.PREFIX + '/download'); + expect(page.url()).toBe(server.PREFIX + '/downloadWithCOOP'); } await page.close(); }); From 6fdc97e18b769b1d2d89087e8bdde960ba73b613 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Tue, 28 Sep 2021 08:33:53 -0700 Subject: [PATCH 3/3] Relax test expectation to make it cross-platform --- tests/page/page-goto.spec.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/page/page-goto.spec.ts b/tests/page/page-goto.spec.ts index e17c194cffaf1..40e54e09c7ff6 100644 --- a/tests/page/page-goto.spec.ts +++ b/tests/page/page-goto.spec.ts @@ -58,19 +58,14 @@ it('should work cross-process', async ({ page, server }) => { expect(response.url()).toBe(url); }); -it('should work with cross-process that fails before committing', async ({ page, server, browserName }) => { +it('should work with cross-process that fails before committing', async ({ page, server }) => { server.setRoute('/empty.html', (req, res) => { req.socket.destroy(); }); const response1 = await page.goto(server.CROSS_PROCESS_PREFIX + '/title.html'); await response1.finished(); const error = await page.goto(server.EMPTY_PAGE).catch(e => e); - if (browserName === 'chromium') - expect(error.message).toContain('net::ERR_EMPTY_RESPONSE'); - if (browserName === 'webkit') - expect(error.message).toContain('Message Corrupt'); - if (browserName === 'firefox') - expect(error.message).toContain('NS_ERROR_NET_RESET'); + expect(error instanceof Error).toBeTruthy(); }); it('should work with Cross-Origin-Opener-Policy', async ({ page, server, browserName }) => {