From e8d994836ebf66673acd4bda883f97c575d64beb Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 10 May 2023 10:47:40 -0700 Subject: [PATCH] chore: move fetch proxy tests in its own file (#22936) The browser has to be launch with `proxy: 'per-context'` option for the tests to work on Windows. Fixes the following: ``` Error: browser.newContext: Browser needs to be launched with the global proxy. If all contexts override the proxy, global proxy will be never used and can be any string, for example "launch({ proxy: { server: 'http://per-context' } })" at D:\a\playwright\playwright\tests\library\browsercontext-fetch.spec.ts:382:19 ``` --- tests/library/browsercontext-fetch.spec.ts | 97 -------------- tests/library/fetch-proxy.spec.ts | 140 +++++++++++++++++++++ tests/library/global-fetch.spec.ts | 25 ---- 3 files changed, 140 insertions(+), 122 deletions(-) create mode 100644 tests/library/fetch-proxy.spec.ts diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index 1992a2e4a3..fa38270a58 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -325,103 +325,6 @@ it('should return raw headers', async ({ context, page, server }) => { expect(response.headers()['name-b']).toBe('v4'); }); -it('should work with context level proxy', async ({ browserType, contextOptions, server, proxyServer }) => { - server.setRoute('/target.html', async (req, res) => { - res.end('Served by the proxy'); - }); - - const browser = await browserType.launch({ - proxy: { server: 'http://per-context' } - }); - - try { - proxyServer.forwardTo(server.PORT); - const context = await browser.newContext({ - ...contextOptions, - proxy: { server: `localhost:${proxyServer.PORT}` } - }); - - const [request, response] = await Promise.all([ - server.waitForRequest('/target.html'), - context.request.get(`http://non-existent.com/target.html`) - ]); - expect(response.status()).toBe(200); - expect(request.url).toBe('/target.html'); - } finally { - await browser.close(); - } -}); - -it('should pass proxy credentials', async ({ browserType, server, proxyServer }) => { - proxyServer.forwardTo(server.PORT); - let auth; - proxyServer.setAuthHandler(req => { - auth = req.headers['proxy-authorization']; - return !!auth; - }); - const browser = await browserType.launch({ - proxy: { server: `localhost:${proxyServer.PORT}`, username: 'user', password: 'secret' } - }); - const context = await browser.newContext(); - const response = await context.request.get('http://non-existent.com/simple.json'); - expect(proxyServer.connectHosts).toContain('non-existent.com:80'); - expect(auth).toBe('Basic ' + Buffer.from('user:secret').toString('base64')); - expect(await response.json()).toEqual({ foo: 'bar' }); - await browser.close(); -}); - -it(`should support proxy.bypass`, async ({ browser, browserType, browserName, contextOptions, server, proxyServer }) => { - server.setRoute('/target.html', async (req, res) => { - res.end('Served by the proxy'); - }); - // FYI: using long and weird domain names to avoid ATT DNS hijacking - // that resolves everything to some weird search results page. - // - // @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00 - proxyServer.forwardTo(server.PORT); - const context = await browser.newContext({ - ...contextOptions, - proxy: { server: `localhost:${proxyServer.PORT}`, bypass: `1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test` } - }); - - { - const res = await context.request.get(server.CROSS_PROCESS_PREFIX + '/target.html'); - expect(await res.text()).toContain('Served by the proxy'); - expect(proxyServer.connectHosts).toContain(new URL(server.CROSS_PROCESS_PREFIX).host); - proxyServer.connectHosts = []; - } - - { - const res = await context.request.get('http://0.non.existent.domain.for.the.test/target.html'); - expect(await res.text()).toContain('Served by the proxy'); - proxyServer.connectHosts = []; - } - - { - const error = await context.request.get('http://1.non.existent.domain.for.the.test/target.html').catch(e => e); - expect(error.message).toBeTruthy(); - expect(proxyServer.connectHosts).toEqual([]); - } - - { - const error = await context.request.get('http://2.non.existent.domain.for.the.test/target.html').catch(e => e); - expect(error.message).toBeTruthy(); - expect(proxyServer.connectHosts).toEqual([]); - } - - { - const error = await context.request.get('http://foo.is.the.another.test/target.html').catch(e => e); - expect(error.message).toBeTruthy(); - expect(proxyServer.connectHosts).toEqual([]); - } - - { - const res = await context.request.get('http://3.non.existent.domain.for.the.test/target.html'); - expect(await res.text()).toContain('Served by the proxy'); - } -}); - - it('should work with http credentials', async ({ context, server }) => { server.setAuth('/empty.html', 'user', 'pass'); diff --git a/tests/library/fetch-proxy.spec.ts b/tests/library/fetch-proxy.spec.ts new file mode 100644 index 0000000000..9377bbdc06 --- /dev/null +++ b/tests/library/fetch-proxy.spec.ts @@ -0,0 +1,140 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { contextTest as it, expect } from '../config/browserTest'; + +it.use({ + launchOptions: async ({ launchOptions }, use) => { + await use({ + ...launchOptions, + proxy: { server: 'per-context' } + }); + } +}); + +it.skip(({ mode }) => mode !== 'default'); + +it('context request should pick up proxy credentials', async ({ browserType, server, proxyServer }) => { + proxyServer.forwardTo(server.PORT); + let auth; + proxyServer.setAuthHandler(req => { + auth = req.headers['proxy-authorization']; + return !!auth; + }); + const browser = await browserType.launch({ + proxy: { server: `localhost:${proxyServer.PORT}`, username: 'user', password: 'secret' } + }); + const context = await browser.newContext(); + const response = await context.request.get('http://non-existent.com/simple.json'); + expect(proxyServer.connectHosts).toContain('non-existent.com:80'); + expect(auth).toBe('Basic ' + Buffer.from('user:secret').toString('base64')); + expect(await response.json()).toEqual({ foo: 'bar' }); + await browser.close(); +}); + +it('global request should pick up proxy credentials', async ({ playwright, server, proxyServer }) => { + proxyServer.forwardTo(server.PORT); + let auth; + proxyServer.setAuthHandler(req => { + auth = req.headers['proxy-authorization']; + return !!auth; + }); + const request = await playwright.request.newContext({ + proxy: { server: `localhost:${proxyServer.PORT}`, username: 'user', password: 'secret' } + }); + const response = await request.get('http://non-existent.com/simple.json'); + expect(proxyServer.connectHosts).toContain('non-existent.com:80'); + expect(auth).toBe('Basic ' + Buffer.from('user:secret').toString('base64')); + expect(await response.json()).toEqual({ foo: 'bar' }); + await request.dispose(); +}); + +it('should work with context level proxy', async ({ contextFactory, contextOptions, server, proxyServer }) => { + server.setRoute('/target.html', async (req, res) => { + res.end('Served by the proxy'); + }); + + proxyServer.forwardTo(server.PORT); + const context = await contextFactory({ + proxy: { server: `localhost:${proxyServer.PORT}` } + }); + + const [request, response] = await Promise.all([ + server.waitForRequest('/target.html'), + context.request.get(`http://non-existent.com/target.html`) + ]); + expect(response.status()).toBe(200); + expect(request.url).toBe('/target.html'); +}); + +it(`should support proxy.bypass`, async ({ contextFactory, contextOptions, server, proxyServer }) => { + server.setRoute('/target.html', async (req, res) => { + res.end('Served by the proxy'); + }); + // FYI: using long and weird domain names to avoid ATT DNS hijacking + // that resolves everything to some weird search results page. + // + // @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00 + proxyServer.forwardTo(server.PORT); + const context = await contextFactory({ + ...contextOptions, + proxy: { server: `localhost:${proxyServer.PORT}`, bypass: `1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test` } + }); + + { + const res = await context.request.get(server.CROSS_PROCESS_PREFIX + '/target.html'); + expect(await res.text()).toContain('Served by the proxy'); + expect(proxyServer.connectHosts).toContain(new URL(server.CROSS_PROCESS_PREFIX).host); + proxyServer.connectHosts = []; + } + + { + const res = await context.request.get('http://0.non.existent.domain.for.the.test/target.html'); + expect(await res.text()).toContain('Served by the proxy'); + proxyServer.connectHosts = []; + } + + { + const error = await context.request.get('http://1.non.existent.domain.for.the.test/target.html').catch(e => e); + expect(error.message).toBeTruthy(); + expect(proxyServer.connectHosts).toEqual([]); + } + + { + const error = await context.request.get('http://2.non.existent.domain.for.the.test/target.html').catch(e => e); + expect(error.message).toBeTruthy(); + expect(proxyServer.connectHosts).toEqual([]); + } + + { + const error = await context.request.get('http://foo.is.the.another.test/target.html').catch(e => e); + expect(error.message).toBeTruthy(); + expect(proxyServer.connectHosts).toEqual([]); + } + + { + const res = await context.request.get('http://3.non.existent.domain.for.the.test/target.html'); + expect(await res.text()).toContain('Served by the proxy'); + } +}); + +it('should use socks proxy', async ({ playwright, server, socksPort }) => { + const request = await playwright.request.newContext({ proxy: { + server: `socks5://localhost:${socksPort}`, + } }); + const response = await request.get(server.EMPTY_PAGE); + expect(await response.text()).toContain('Served by the SOCKS proxy'); +}); diff --git a/tests/library/global-fetch.spec.ts b/tests/library/global-fetch.spec.ts index d72ce167d6..4642107216 100644 --- a/tests/library/global-fetch.spec.ts +++ b/tests/library/global-fetch.spec.ts @@ -153,31 +153,6 @@ it('should support WWW-Authenticate: Basic', async ({ playwright, server }) => { expect(credentials).toBe('user:pass'); }); -it('should use socks proxy', async ({ playwright, server, socksPort }) => { - const request = await playwright.request.newContext({ proxy: { - server: `socks5://localhost:${socksPort}`, - } }); - const response = await request.get(server.EMPTY_PAGE); - expect(await response.text()).toContain('Served by the SOCKS proxy'); -}); - -it('should pass proxy credentials', async ({ playwright, server, proxyServer }) => { - proxyServer.forwardTo(server.PORT); - let auth; - proxyServer.setAuthHandler(req => { - auth = req.headers['proxy-authorization']; - return !!auth; - }); - const request = await playwright.request.newContext({ - proxy: { server: `localhost:${proxyServer.PORT}`, username: 'user', password: 'secret' } - }); - const response = await request.get('http://non-existent.com/simple.json'); - expect(proxyServer.connectHosts).toContain('non-existent.com:80'); - expect(auth).toBe('Basic ' + Buffer.from('user:secret').toString('base64')); - expect(await response.json()).toEqual({ foo: 'bar' }); - await request.dispose(); -}); - it('should support global ignoreHTTPSErrors option', async ({ playwright, httpsServer }) => { const request = await playwright.request.newContext({ ignoreHTTPSErrors: true }); const response = await request.get(httpsServer.EMPTY_PAGE);