From 701a97becaa8b432f409f523dd824253cf4c04dd Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Tue, 5 Oct 2021 13:56:34 -0700 Subject: [PATCH] chore(fetch): unprefix _request and _newRequest (#9325) --- docs/src/api/class-browsercontext.md | 12 +-- docs/src/api/class-page.md | 12 +-- docs/src/api/class-playwright.md | 102 ++++++++++---------- src/client/browserContext.ts | 4 +- src/client/page.ts | 4 +- src/client/playwright.ts | 2 +- tests/browsercontext-fetch.spec.ts | 118 ++++++++++++------------ tests/download.spec.ts | 2 +- tests/global-fetch-cookie.spec.ts | 10 +- tests/global-fetch.spec.ts | 24 ++--- tests/page/page-request-fulfill.spec.ts | 10 +- types/types.d.ts | 42 ++++----- 12 files changed, 171 insertions(+), 171 deletions(-) diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index fc7aea4f4e..9a2adb200c 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -189,12 +189,6 @@ Service workers are only supported on Chromium-based browsers. Emitted when new service worker is created in the context. -## property: BrowserContext._request -* langs: js -- type: <[FetchRequest]> - -API testing helper associated with this context. Requests made with this API will use context cookies. - ## async method: BrowserContext.addCookies Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be @@ -855,6 +849,12 @@ Creates a new page in the browser context. Returns all open pages in the context. +## property: BrowserContext.request +* langs: js +- type: <[FetchRequest]> + +API testing helper associated with this context. Requests made with this API will use context cookies. + ## async method: BrowserContext.route Routing provides the capability to modify network requests that are made by any page in the browser context. Once route diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 577cd6d360..2cef4864a4 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -449,12 +449,6 @@ Emitted when [WebSocket] request is sent. Emitted when a dedicated [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) is spawned by the page. -## property: Page._request -* langs: js -- type: <[FetchRequest]> - -API testing helper associated with this page. Requests made with this API will use page cookies. - ## property: Page.accessibility * langs: csharp, js, python - type: <[Accessibility]> @@ -2420,6 +2414,12 @@ last redirect. ### option: Page.reload.timeout = %%-navigation-timeout-%% +## property: Page.request +* langs: js +- type: <[FetchRequest]> + +API testing helper associated with this page. Requests made with this API will use page cookies. + ## async method: Page.route Routing provides the capability to modify network requests that are made by a page. diff --git a/docs/src/api/class-playwright.md b/docs/src/api/class-playwright.md index 9650b1fea9..b6e293d029 100644 --- a/docs/src/api/class-playwright.md +++ b/docs/src/api/class-playwright.md @@ -83,57 +83,6 @@ class PlaywrightExample } ``` -## async method: Playwright._newRequest -* langs: js -- returns: <[FetchRequest]> - -**experimental** Creates new instances of [FetchRequest]. - -### option: Playwright._newRequest.useragent = %%-context-option-useragent-%% - -### option: Playwright._newRequest.extraHTTPHeaders = %%-context-option-extrahttpheaders-%% - -### option: Playwright._newRequest.httpCredentials = %%-context-option-httpcredentials-%% - -### option: Playwright._newRequest.proxy = %%-browser-option-proxy-%% - -### option: Playwright._newRequest.timeout -- `timeout` <[float]> - -Maximum time in milliseconds to wait for the response. Defaults to -`30000` (30 seconds). Pass `0` to disable timeout. - -### option: Playwright._newRequest.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%% - -### option: Playwright._newRequest.baseURL -- `baseURL` <[string]> - -When using [`method: FetchRequest.get`], [`method: FetchRequest.post`], [`method: FetchRequest.fetch`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. Examples: -* baseURL: `http://localhost:3000` and sending rquest to `/bar.html` results in `http://localhost:3000/bar.html` -* baseURL: `http://localhost:3000/foo/` and sending rquest to `./bar.html` results in `http://localhost:3000/foo/bar.html` - -### option: Playwright._newRequest.storageState -- `storageState` <[path]|[Object]> - - `cookies` <[Array]<[Object]>> - - `name` <[string]> - - `value` <[string]> - - `domain` <[string]> - - `path` <[string]> - - `expires` <[float]> Unix time in seconds. - - `httpOnly` <[boolean]> - - `secure` <[boolean]> - - `sameSite` <[SameSiteAttribute]<"Strict"|"Lax"|"None">> - - `origins` <[Array]<[Object]>> - - `origin` <[string]> - - `localStorage` <[Array]<[Object]>> - - `name` <[string]> - - `value` <[string]> - -Populates context with given storage state. This option can be used to initialize context with logged-in information -obtained via [`method: BrowserContext.storageState`] or [`method: FetchRequest.storageState`]. Either a path to the -file with saved storage, or the value returned by one of [`method: BrowserContext.storageState`] or -[`method: FetchRequest.storageState`] methods. - ## property: Playwright.chromium - type: <[BrowserType]> @@ -265,6 +214,57 @@ except TimeoutError as e: This object can be used to launch or connect to Firefox, returning instances of [Browser]. +## async method: Playwright.newRequest +* langs: js +- returns: <[FetchRequest]> + +**experimental** Creates new instances of [FetchRequest]. + +### option: Playwright.newRequest.useragent = %%-context-option-useragent-%% + +### option: Playwright.newRequest.extraHTTPHeaders = %%-context-option-extrahttpheaders-%% + +### option: Playwright.newRequest.httpCredentials = %%-context-option-httpcredentials-%% + +### option: Playwright.newRequest.proxy = %%-browser-option-proxy-%% + +### option: Playwright.newRequest.timeout +- `timeout` <[float]> + +Maximum time in milliseconds to wait for the response. Defaults to +`30000` (30 seconds). Pass `0` to disable timeout. + +### option: Playwright.newRequest.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%% + +### option: Playwright.newRequest.baseURL +- `baseURL` <[string]> + +When using [`method: FetchRequest.get`], [`method: FetchRequest.post`], [`method: FetchRequest.fetch`] it takes the base URL in consideration by using the [`URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor for building the corresponding URL. Examples: +* baseURL: `http://localhost:3000` and sending rquest to `/bar.html` results in `http://localhost:3000/bar.html` +* baseURL: `http://localhost:3000/foo/` and sending rquest to `./bar.html` results in `http://localhost:3000/foo/bar.html` + +### option: Playwright.newRequest.storageState +- `storageState` <[path]|[Object]> + - `cookies` <[Array]<[Object]>> + - `name` <[string]> + - `value` <[string]> + - `domain` <[string]> + - `path` <[string]> + - `expires` <[float]> Unix time in seconds. + - `httpOnly` <[boolean]> + - `secure` <[boolean]> + - `sameSite` <[SameSiteAttribute]<"Strict"|"Lax"|"None">> + - `origins` <[Array]<[Object]>> + - `origin` <[string]> + - `localStorage` <[Array]<[Object]>> + - `name` <[string]> + - `value` <[string]> + +Populates context with given storage state. This option can be used to initialize context with logged-in information +obtained via [`method: BrowserContext.storageState`] or [`method: FetchRequest.storageState`]. Either a path to the +file with saved storage, or the value returned by one of [`method: BrowserContext.storageState`] or +[`method: FetchRequest.storageState`] methods. + ## property: Playwright.selectors - type: <[Selectors]> diff --git a/src/client/browserContext.ts b/src/client/browserContext.ts index 10322ebf25..e6a44857de 100644 --- a/src/client/browserContext.ts +++ b/src/client/browserContext.ts @@ -49,7 +49,7 @@ export class BrowserContext extends ChannelOwner; _options: channels.BrowserNewContextParams = { }; - readonly _request: FetchRequest; + readonly request: FetchRequest; readonly tracing: Tracing; readonly _backgroundPages = new Set(); readonly _serviceWorkers = new Set(); @@ -69,7 +69,7 @@ export class BrowserContext extends ChannelOwner this._onBinding(BindingCall.from(binding))); this._channel.on('close', () => this._onClose()); diff --git a/src/client/page.ts b/src/client/page.ts index fdedacc84f..e4eb57a079 100644 --- a/src/client/page.ts +++ b/src/client/page.ts @@ -78,7 +78,7 @@ export class Page extends ChannelOwner any>(); @@ -102,7 +102,7 @@ export class Page extends ChannelOwner { + async newRequest(options: NewRequestOptions = {}): Promise { return await this._wrapApiCall(async (channel: channels.PlaywrightChannel) => { const storageState = typeof options.storageState === 'string' ? JSON.parse(await fs.promises.readFile(options.storageState, 'utf8')) : diff --git a/tests/browsercontext-fetch.spec.ts b/tests/browsercontext-fetch.spec.ts index 34b86096c0..e83e27a28f 100644 --- a/tests/browsercontext-fetch.spec.ts +++ b/tests/browsercontext-fetch.spec.ts @@ -43,7 +43,7 @@ it.afterAll(() => { }); it('get should work', async ({ context, server }) => { - const response = await context._request.get(server.PREFIX + '/simple.json'); + const response = await context.request.get(server.PREFIX + '/simple.json'); expect(response.url()).toBe(server.PREFIX + '/simple.json'); expect(response.status()).toBe(200); expect(response.statusText()).toBe('OK'); @@ -55,7 +55,7 @@ it('get should work', async ({ context, server }) => { }); it('fetch should work', async ({ context, server }) => { - const response = await context._request.fetch(server.PREFIX + '/simple.json'); + const response = await context.request.fetch(server.PREFIX + '/simple.json'); expect(response.url()).toBe(server.PREFIX + '/simple.json'); expect(response.status()).toBe(200); expect(response.statusText()).toBe('OK'); @@ -70,7 +70,7 @@ it('should throw on network error', async ({ context, server }) => { server.setRoute('/test', (req, res) => { req.socket.destroy(); }); - const error = await context._request.get(server.PREFIX + '/test').catch(e => e); + const error = await context.request.get(server.PREFIX + '/test').catch(e => e); expect(error.message).toContain('socket hang up'); }); @@ -79,7 +79,7 @@ it('should throw on network error after redirect', async ({ context, server }) = server.setRoute('/test', (req, res) => { req.socket.destroy(); }); - const error = await context._request.get(server.PREFIX + '/redirect').catch(e => e); + const error = await context.request.get(server.PREFIX + '/redirect').catch(e => e); expect(error.message).toContain('socket hang up'); }); @@ -93,7 +93,7 @@ it('should throw on network error when sending body', async ({ context, server } res.uncork(); req.socket.destroy(); }); - const error = await context._request.get(server.PREFIX + '/test').catch(e => e); + const error = await context.request.get(server.PREFIX + '/test').catch(e => e); expect(error.message).toContain('Error: aborted'); }); @@ -108,7 +108,7 @@ it('should throw on network error when sending body after redirect', async ({ co res.uncork(); req.socket.destroy(); }); - const error = await context._request.get(server.PREFIX + '/redirect').catch(e => e); + const error = await context.request.get(server.PREFIX + '/redirect').catch(e => e); expect(error.message).toContain('Error: aborted'); }); @@ -125,7 +125,7 @@ it('should add session cookies to request', async ({ context, server }) => { }]); const [req] = await Promise.all([ server.waitForRequest('/simple.json'), - context._request.get(`http://www.my.playwright.dev:${server.PORT}/simple.json`), + context.request.get(`http://www.my.playwright.dev:${server.PORT}/simple.json`), ]); expect(req.headers.cookie).toEqual('username=John Doe'); }); @@ -140,7 +140,7 @@ for (const method of ['get', 'post', 'fetch']) { request = req; server.serveFile(req, res); }); - await context._request[method](server.EMPTY_PAGE + '?p1=foo', { + await context.request[method](server.EMPTY_PAGE + '?p1=foo', { params: { 'p1': 'v1', 'парам2': 'знач2', @@ -152,14 +152,14 @@ for (const method of ['get', 'post', 'fetch']) { }); it(`${method} should support failOnStatusCode`, async ({ context, server }) => { - const error = await context._request[method](server.PREFIX + '/does-not-exist.html', { + const error = await context.request[method](server.PREFIX + '/does-not-exist.html', { failOnStatusCode: true }).catch(e => e); expect(error.message).toContain('404 Not Found'); }); it(`${method}should support ignoreHTTPSErrors option`, async ({ context, httpsServer }) => { - const response = await context._request[method](httpsServer.EMPTY_PAGE, { ignoreHTTPSErrors: true }); + const response = await context.request[method](httpsServer.EMPTY_PAGE, { ignoreHTTPSErrors: true }); expect(response.status()).toBe(200); }); } @@ -177,7 +177,7 @@ it('should not add context cookie if cookie header passed as a parameter', async }]); const [req] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.get(`http://www.my.playwright.dev:${server.PORT}/empty.html`, { + context.request.get(`http://www.my.playwright.dev:${server.PORT}/empty.html`, { headers: { 'Cookie': 'foo=bar' } @@ -201,7 +201,7 @@ it('should follow redirects', async ({ context, server }) => { }]); const [req, response] = await Promise.all([ server.waitForRequest('/simple.json'), - context._request.get(`http://www.my.playwright.dev:${server.PORT}/redirect1`), + context.request.get(`http://www.my.playwright.dev:${server.PORT}/redirect1`), ]); expect(req.headers.cookie).toEqual('username=John Doe'); expect(response.url()).toBe(`http://www.my.playwright.dev:${server.PORT}/simple.json`); @@ -213,7 +213,7 @@ it('should add cookies from Set-Cookie header', async ({ context, page, server } res.setHeader('Set-Cookie', ['session=value', 'foo=bar; max-age=3600']); res.end(); }); - await context._request.get(server.PREFIX + '/setcookie.html'); + await context.request.get(server.PREFIX + '/setcookie.html'); const cookies = await context.cookies(); expect(new Set(cookies.map(c => ({ name: c.name, value: c.value })))).toEqual(new Set([ { @@ -234,7 +234,7 @@ it('should not lose body while handling Set-Cookie header', async ({ context, se res.setHeader('Set-Cookie', ['session=value', 'foo=bar; max-age=3600']); res.end('text content'); }); - const response = await context._request.get(server.PREFIX + '/setcookie.html'); + const response = await context.request.get(server.PREFIX + '/setcookie.html'); expect(await response.text()).toBe('text content'); }); @@ -254,7 +254,7 @@ it('should handle cookies on redirects', async ({ context, server, browserName, server.waitForRequest('/redirect1'), server.waitForRequest('/a/b/redirect2'), server.waitForRequest('/title.html'), - context._request.get(`${server.PREFIX}/redirect1`), + context.request.get(`${server.PREFIX}/redirect1`), ]); expect(req1.headers.cookie).toBeFalsy(); expect(req2.headers.cookie).toBe('r1=v1'); @@ -265,7 +265,7 @@ it('should handle cookies on redirects', async ({ context, server, browserName, server.waitForRequest('/redirect1'), server.waitForRequest('/a/b/redirect2'), server.waitForRequest('/title.html'), - context._request.get(`${server.PREFIX}/redirect1`), + context.request.get(`${server.PREFIX}/redirect1`), ]); expect(req1.headers.cookie).toBe('r1=v1'); expect(req2.headers.cookie.split(';').map(s => s.trim()).sort()).toEqual(['r1=v1', 'r2=v2']); @@ -310,7 +310,7 @@ it('should return raw headers', async ({ context, page, server }) => { conn.uncork(); conn.end(); }); - const response = await context._request.get(`${server.PREFIX}/headers`); + const response = await context.request.get(`${server.PREFIX}/headers`); expect(response.status()).toBe(200); const headers = response.headersArray().filter(({ name }) => name.toLowerCase().includes('name-')); expect(headers).toEqual([{ name: 'Name-A', value: 'v1' }, { name: 'name-b', value: 'v4' }, { name: 'Name-a', value: 'v2' }, { name: 'name-A', value: 'v3' }]); @@ -338,7 +338,7 @@ it('should work with context level proxy', async ({ browserOptions, browserType, const [request, response] = await Promise.all([ server.waitForRequest('/target.html'), - context._request.get(`http://non-existent.com/target.html`) + context.request.get(`http://non-existent.com/target.html`) ]); expect(response.status()).toBe(200); expect(request.url).toBe('/target.html'); @@ -359,7 +359,7 @@ it('should pass proxy credentials', async ({ browserType, browserOptions, server 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'); + 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' }); @@ -371,7 +371,7 @@ it('should work with http credentials', async ({ context, server }) => { const [request, response] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.get(server.EMPTY_PAGE, { + context.request.get(server.EMPTY_PAGE, { headers: { 'authorization': 'Basic ' + Buffer.from('user:pass').toString('base64') } @@ -383,25 +383,25 @@ it('should work with http credentials', async ({ context, server }) => { it('should work with setHTTPCredentials', async ({ context, server }) => { server.setAuth('/empty.html', 'user', 'pass'); - const response1 = await context._request.get(server.EMPTY_PAGE); + const response1 = await context.request.get(server.EMPTY_PAGE); expect(response1.status()).toBe(401); await context.setHTTPCredentials({ username: 'user', password: 'pass' }); - const response2 = await context._request.get(server.EMPTY_PAGE); + const response2 = await context.request.get(server.EMPTY_PAGE); expect(response2.status()).toBe(200); }); it('should return error with wrong credentials', async ({ context, server }) => { server.setAuth('/empty.html', 'user', 'pass'); await context.setHTTPCredentials({ username: 'user', password: 'wrong' }); - const response2 = await context._request.get(server.EMPTY_PAGE); + const response2 = await context.request.get(server.EMPTY_PAGE); expect(response2.status()).toBe(401); }); it('should support post data', async ({ context, server }) => { const [request, response] = await Promise.all([ server.waitForRequest('/simple.json'), - context._request.post(`${server.PREFIX}/simple.json`, { + context.request.post(`${server.PREFIX}/simple.json`, { data: 'My request' }) ]); @@ -414,7 +414,7 @@ it('should support post data', async ({ context, server }) => { it('should add default headers', async ({ context, server, page }) => { const [request] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.get(server.EMPTY_PAGE) + context.request.get(server.EMPTY_PAGE) ]); expect(request.headers['accept']).toBe('*/*'); const userAgent = await page.evaluate(() => navigator.userAgent); @@ -428,7 +428,7 @@ it('should send content-length', async function({ context, asset, server }) { bytes.push(i); const [request] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.post(server.EMPTY_PAGE, { + context.request.post(server.EMPTY_PAGE, { data: Buffer.from(bytes) }) ]); @@ -440,7 +440,7 @@ it('should add default headers to redirects', async ({ context, server, page }) server.setRedirect('/redirect', '/empty.html'); const [request] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.get(`${server.PREFIX}/redirect`) + context.request.get(`${server.PREFIX}/redirect`) ]); expect(request.headers['accept']).toBe('*/*'); const userAgent = await page.evaluate(() => navigator.userAgent); @@ -451,7 +451,7 @@ it('should add default headers to redirects', async ({ context, server, page }) it('should allow to override default headers', async ({ context, server, page }) => { const [request] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.get(server.EMPTY_PAGE, { + context.request.get(server.EMPTY_PAGE, { headers: { 'User-Agent': 'Playwright', 'Accept': 'text/html', @@ -471,7 +471,7 @@ it('should propagate custom headers with redirects', async ({ context, server }) server.waitForRequest('/a/redirect1'), server.waitForRequest('/b/c/redirect2'), server.waitForRequest('/simple.json'), - context._request.get(`${server.PREFIX}/a/redirect1`, { headers: { 'foo': 'bar' } }), + context.request.get(`${server.PREFIX}/a/redirect1`, { headers: { 'foo': 'bar' } }), ]); expect(req1.headers['foo']).toBe('bar'); expect(req2.headers['foo']).toBe('bar'); @@ -486,7 +486,7 @@ it('should propagate extra http headers with redirects', async ({ context, serve server.waitForRequest('/a/redirect1'), server.waitForRequest('/b/c/redirect2'), server.waitForRequest('/simple.json'), - context._request.get(`${server.PREFIX}/a/redirect1`), + context.request.get(`${server.PREFIX}/a/redirect1`), ]); expect(req1.headers['my-secret']).toBe('Value'); expect(req2.headers['my-secret']).toBe('Value'); @@ -494,7 +494,7 @@ it('should propagate extra http headers with redirects', async ({ context, serve }); it('should throw on invalid header value', async ({ context, server }) => { - const error = await context._request.get(`${server.PREFIX}/a/redirect1`, { + const error = await context.request.get(`${server.PREFIX}/a/redirect1`, { headers: { 'foo': 'недопустимое значение', } @@ -503,9 +503,9 @@ it('should throw on invalid header value', async ({ context, server }) => { }); it('should throw on non-http(s) protocol', async ({ context }) => { - const error1 = await context._request.get(`data:text/plain,test`).catch(e => e); + const error1 = await context.request.get(`data:text/plain,test`).catch(e => e); expect(error1.message).toContain('Protocol "data:" not supported'); - const error2 = await context._request.get(`file:///tmp/foo`).catch(e => e); + const error2 = await context.request.get(`file:///tmp/foo`).catch(e => e); expect(error2.message).toContain('Protocol "file:" not supported'); }); @@ -515,7 +515,7 @@ it('should support https', async ({ context, httpsServer }) => { process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; suppressCertificateWarning(); try { - const response = await context._request.get(httpsServer.EMPTY_PAGE); + const response = await context.request.get(httpsServer.EMPTY_PAGE); expect(response.status()).toBe(200); } finally { process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = oldValue; @@ -524,7 +524,7 @@ it('should support https', async ({ context, httpsServer }) => { it('should inherit ignoreHTTPSErrors from context', async ({ contextFactory, contextOptions, httpsServer }) => { const context = await contextFactory({ ...contextOptions, ignoreHTTPSErrors: true }); - const response = await context._request.get(httpsServer.EMPTY_PAGE); + const response = await context.request.get(httpsServer.EMPTY_PAGE); expect(response.status()).toBe(200); }); @@ -533,7 +533,7 @@ it('should resolve url relative to baseURL', async function({ server, contextFac ...contextOptions, baseURL: server.PREFIX, }); - const response = await context._request.get('/empty.html'); + const response = await context.request.get('/empty.html'); expect(response.url()).toBe(server.EMPTY_PAGE); }); @@ -553,7 +553,7 @@ it('should support gzip compression', async function({ context, server }) { gzip.end(); }); - const response = await context._request.get(server.PREFIX + '/compressed'); + const response = await context.request.get(server.PREFIX + '/compressed'); expect(await response.text()).toBe('Hello, world!'); }); @@ -567,7 +567,7 @@ it('should throw informatibe error on corrupted gzip body', async function({ con res.end(); }); - const error = await context._request.get(server.PREFIX + '/corrupted').catch(e => e); + const error = await context.request.get(server.PREFIX + '/corrupted').catch(e => e); expect(error.message).toContain(`failed to decompress 'gzip' encoding`); }); @@ -587,7 +587,7 @@ it('should support brotli compression', async function({ context, server }) { brotli.end(); }); - const response = await context._request.get(server.PREFIX + '/compressed'); + const response = await context.request.get(server.PREFIX + '/compressed'); expect(await response.text()).toBe('Hello, world!'); }); @@ -601,7 +601,7 @@ it('should throw informatibe error on corrupted brotli body', async function({ c res.end(); }); - const error = await context._request.get(server.PREFIX + '/corrupted').catch(e => e); + const error = await context.request.get(server.PREFIX + '/corrupted').catch(e => e); expect(error.message).toContain(`failed to decompress 'br' encoding`); }); @@ -621,7 +621,7 @@ it('should support deflate compression', async function({ context, server }) { deflate.end(); }); - const response = await context._request.get(server.PREFIX + '/compressed'); + const response = await context.request.get(server.PREFIX + '/compressed'); expect(await response.text()).toBe('Hello, world!'); }); @@ -635,7 +635,7 @@ it('should throw informatibe error on corrupted deflate body', async function({ res.end(); }); - const error = await context._request.get(server.PREFIX + '/corrupted').catch(e => e); + const error = await context.request.get(server.PREFIX + '/corrupted').catch(e => e); expect(error.message).toContain(`failed to decompress 'deflate' encoding`); }); @@ -647,7 +647,7 @@ it('should support timeout option', async function({ context, server }) { }); }); - const error = await context._request.get(server.PREFIX + '/slow', { timeout: 10 }).catch(e => e); + const error = await context.request.get(server.PREFIX + '/slow', { timeout: 10 }).catch(e => e); expect(error.message).toContain(`Request timed out after 10ms`); }); @@ -662,7 +662,7 @@ it('should support a timeout of 0', async function({ context, server }) { }, 50); }); - const response = await context._request.get(server.PREFIX + '/slow', { + const response = await context.request.get(server.PREFIX + '/slow', { timeout: 0, }); expect(await response.text()).toBe('done'); @@ -678,12 +678,12 @@ it('should respect timeout after redirects', async function({ context, server }) }); context.setDefaultTimeout(100); - const error = await context._request.get(server.PREFIX + '/redirect').catch(e => e); + const error = await context.request.get(server.PREFIX + '/redirect').catch(e => e); expect(error.message).toContain(`Request timed out after 100ms`); }); it('should dispose', async function({ context, server }) { - const response = await context._request.get(server.PREFIX + '/simple.json'); + const response = await context.request.get(server.PREFIX + '/simple.json'); expect(await response.json()).toEqual({ foo: 'bar' }); await response.dispose(); const error = await response.body().catch(e => e); @@ -691,7 +691,7 @@ it('should dispose', async function({ context, server }) { }); it('should dispose when context closes', async function({ context, server }) { - const response = await context._request.get(server.PREFIX + '/simple.json'); + const response = await context.request.get(server.PREFIX + '/simple.json'); expect(await response.json()).toEqual({ foo: 'bar' }); await context.close(); const error = await response.body().catch(e => e); @@ -699,7 +699,7 @@ it('should dispose when context closes', async function({ context, server }) { }); it('should throw on invalid first argument', async function({ context }) { - const error = await context._request.get({} as any).catch(e => e); + const error = await context.request.get({} as any).catch(e => e); expect(error.message).toContain('First argument must be either URL string or Request'); }); @@ -710,7 +710,7 @@ it('should override request parameters', async function({ context, page, server ]); const [req] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.post(pageReq, { + context.request.post(pageReq, { headers: { 'foo': 'bar' }, @@ -725,7 +725,7 @@ it('should override request parameters', async function({ context, page, server it('should support application/x-www-form-urlencoded', async function({ context, page, server }) { const [req] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.post(server.EMPTY_PAGE, { + context.request.post(server.EMPTY_PAGE, { form: { firstName: 'John', lastName: 'Doe', @@ -753,7 +753,7 @@ it('should encode to application/json by default', async function({ context, pag }; const [req] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.post(server.EMPTY_PAGE, { data }) + context.request.post(server.EMPTY_PAGE, { data }) ]); expect(req.method).toBe('POST'); expect(req.headers['content-type']).toBe('application/json'); @@ -780,7 +780,7 @@ it('should support multipart/form-data', async function({ context, page, server }; const [{ error, fields, files, serverRequest }, response] = await Promise.all([ formReceived, - context._request.post(server.EMPTY_PAGE, { + context.request.post(server.EMPTY_PAGE, { multipart: { firstName: 'John', lastName: 'Doe', @@ -812,7 +812,7 @@ it('should support multipart/form-data with ReadSream values', async function({ const readStream = fs.createReadStream(asset('simplezip.json')); const [{ error, fields, files, serverRequest }, response] = await Promise.all([ formReceived, - context._request.post(server.EMPTY_PAGE, { + context.request.post(server.EMPTY_PAGE, { multipart: { firstName: 'John', lastName: 'Doe', @@ -839,7 +839,7 @@ it('should serialize data to json regardless of content-type', async function({ }; const [req] = await Promise.all([ server.waitForRequest('/empty.html'), - context._request.post(server.EMPTY_PAGE, { + context.request.post(server.EMPTY_PAGE, { headers: { 'content-type': 'unknown' }, @@ -853,7 +853,7 @@ it('should serialize data to json regardless of content-type', async function({ }); it('should throw nice error on unsupported data type', async function({ context, server }) { - const error = await context._request.post(server.EMPTY_PAGE, { + const error = await context.request.post(server.EMPTY_PAGE, { headers: { 'content-type': 'application/json' }, @@ -863,7 +863,7 @@ it('should throw nice error on unsupported data type', async function({ context, }); it('should throw when data passed for unsupported request', async function({ context, server }) { - const error = await context._request.fetch(server.EMPTY_PAGE, { + const error = await context.request.fetch(server.EMPTY_PAGE, { method: 'GET', data: { foo: 'bar' @@ -877,11 +877,11 @@ it('context request should export same storage state as context', async ({ conte res.setHeader('Set-Cookie', ['a=b', 'c=d']); res.end(); }); - await context._request.get(server.PREFIX + '/setcookie.html'); + await context.request.get(server.PREFIX + '/setcookie.html'); const contextState = await context.storageState(); expect(contextState.cookies.length).toBe(2); - const requestState = await context._request.storageState(); + const requestState = await context.request.storageState(); expect(requestState).toEqual(contextState); - const pageState = await page._request.storageState(); + const pageState = await page.request.storageState(); expect(pageState).toEqual(contextState); }); \ No newline at end of file diff --git a/tests/download.spec.ts b/tests/download.spec.ts index cc4f7be0a2..26bc019694 100644 --- a/tests/download.spec.ts +++ b/tests/download.spec.ts @@ -601,7 +601,7 @@ it('should be able to download a inline PDF file', async ({ browser, server, ass const page = await browser.newPage({ acceptDownloads: true }); await page.goto(server.EMPTY_PAGE); await page.route('**/empty.pdf', async route => { - const response = await page.context()._request.get(route.request()); + const response = await page.context().request.get(route.request()); await route.fulfill({ response, headers: { diff --git a/tests/global-fetch-cookie.spec.ts b/tests/global-fetch-cookie.spec.ts index 409375ee19..841d75345e 100644 --- a/tests/global-fetch-cookie.spec.ts +++ b/tests/global-fetch-cookie.spec.ts @@ -25,7 +25,7 @@ export type GlobalFetchFixtures = { const it = playwrightTest.extend({ request: async ({ playwright }, use) => { - const request = await playwright._newRequest({ ignoreHTTPSErrors: true }); + const request = await playwright.newRequest({ ignoreHTTPSErrors: true }); await use(request); await request.dispose(); }, @@ -235,7 +235,7 @@ it('should preserve local storage on import/export of storage state', async ({ p }, ] }; - const request = await playwright._newRequest({ storageState }); + const request = await playwright.newRequest({ storageState }); await request.get(server.EMPTY_PAGE); const exportedState = await request.storageState(); expect(exportedState).toEqual(storageState); @@ -279,7 +279,7 @@ it('should send cookies from storage state', async ({ playwright, server }) => { ], 'origins': [] }; - const request = await playwright._newRequest({ storageState }); + const request = await playwright.newRequest({ storageState }); const [serverRequest] = await Promise.all([ server.waitForRequest('/first/second/third/not_found.html'), request.get(`http://www.a.b.one.com:${server.PORT}/first/second/third/not_found.html`) @@ -304,7 +304,7 @@ it('storage state should round-trip through file', async ({ playwright, server } 'origins': [] }; - const request1 = await playwright._newRequest({ storageState }); + const request1 = await playwright.newRequest({ storageState }); const path = testInfo.outputPath('storage-state.json'); const state1 = await request1.storageState({ path }); expect(state1).toEqual(storageState); @@ -312,7 +312,7 @@ it('storage state should round-trip through file', async ({ playwright, server } const written = await fs.promises.readFile(path, 'utf8'); expect(JSON.stringify(state1, undefined, 2)).toBe(written); - const request2 = await playwright._newRequest({ storageState: path }); + const request2 = await playwright.newRequest({ storageState: path }); const state2 = await request2.storageState(); expect(state2).toEqual(storageState); }); diff --git a/tests/global-fetch.spec.ts b/tests/global-fetch.spec.ts index 279958e3e0..e53608be4f 100644 --- a/tests/global-fetch.spec.ts +++ b/tests/global-fetch.spec.ts @@ -40,7 +40,7 @@ it.afterAll(() => { for (const method of ['get', 'post', 'fetch']) { it(`${method} should work`, async ({ playwright, server }) => { - const request = await playwright._newRequest(); + const request = await playwright.newRequest(); const response = await request[method](server.PREFIX + '/simple.json'); expect(response.url()).toBe(server.PREFIX + '/simple.json'); expect(response.status()).toBe(200); @@ -53,7 +53,7 @@ for (const method of ['get', 'post', 'fetch']) { }); it(`should dispose global ${method} request`, async function({ playwright, context, server }) { - const request = await playwright._newRequest(); + const request = await playwright.newRequest(); const response = await request.get(server.PREFIX + '/simple.json'); expect(await response.json()).toEqual({ foo: 'bar' }); await request.dispose(); @@ -63,7 +63,7 @@ for (const method of ['get', 'post', 'fetch']) { } it('should support global userAgent option', async ({ playwright, server }) => { - const request = await playwright._newRequest({ userAgent: 'My Agent' }); + const request = await playwright.newRequest({ userAgent: 'My Agent' }); const [serverRequest, response] = await Promise.all([ server.waitForRequest('/empty.html'), request.get(server.EMPTY_PAGE) @@ -74,7 +74,7 @@ it('should support global userAgent option', async ({ playwright, server }) => { }); it('should support global timeout option', async ({ playwright, server }) => { - const request = await playwright._newRequest({ timeout: 1 }); + const request = await playwright.newRequest({ timeout: 1 }); server.setRoute('/empty.html', (req, res) => {}); const error = await request.get(server.EMPTY_PAGE).catch(e => e); expect(error.message).toContain('Request timed out after 1ms'); @@ -83,7 +83,7 @@ it('should support global timeout option', async ({ playwright, server }) => { it('should propagate extra http headers with redirects', async ({ playwright, server }) => { server.setRedirect('/a/redirect1', '/b/c/redirect2'); server.setRedirect('/b/c/redirect2', '/simple.json'); - const request = await playwright._newRequest({ extraHTTPHeaders: { 'My-Secret': 'Value' } }); + const request = await playwright.newRequest({ extraHTTPHeaders: { 'My-Secret': 'Value' } }); const [req1, req2, req3] = await Promise.all([ server.waitForRequest('/a/redirect1'), server.waitForRequest('/b/c/redirect2'), @@ -97,12 +97,12 @@ it('should propagate extra http headers with redirects', async ({ playwright, se it('should support global httpCredentials option', async ({ playwright, server }) => { server.setAuth('/empty.html', 'user', 'pass'); - const request1 = await playwright._newRequest(); + const request1 = await playwright.newRequest(); const response1 = await request1.get(server.EMPTY_PAGE); expect(response1.status()).toBe(401); await request1.dispose(); - const request2 = await playwright._newRequest({ httpCredentials: { username: 'user', password: 'pass' } }); + const request2 = await playwright.newRequest({ httpCredentials: { username: 'user', password: 'pass' } }); const response2 = await request2.get(server.EMPTY_PAGE); expect(response2.status()).toBe(200); await request2.dispose(); @@ -110,7 +110,7 @@ it('should support global httpCredentials option', async ({ playwright, server } it('should return error with wrong credentials', async ({ playwright, server }) => { server.setAuth('/empty.html', 'user', 'pass'); - const request = await playwright._newRequest({ httpCredentials: { username: 'user', password: 'wrong' } }); + const request = await playwright.newRequest({ httpCredentials: { username: 'user', password: 'wrong' } }); const response2 = await request.get(server.EMPTY_PAGE); expect(response2.status()).toBe(401); }); @@ -122,7 +122,7 @@ it('should pass proxy credentials', async ({ playwright, server, proxyServer }) auth = req.headers['proxy-authorization']; return !!auth; }); - const request = await playwright._newRequest({ + const request = await playwright.newRequest({ proxy: { server: `localhost:${proxyServer.PORT}`, username: 'user', password: 'secret' } }); const response = await request.get('http://non-existent.com/simple.json'); @@ -133,19 +133,19 @@ it('should pass proxy credentials', async ({ playwright, server, proxyServer }) }); it('should support global ignoreHTTPSErrors option', async ({ playwright, httpsServer }) => { - const request = await playwright._newRequest({ ignoreHTTPSErrors: true }); + const request = await playwright.newRequest({ ignoreHTTPSErrors: true }); const response = await request.get(httpsServer.EMPTY_PAGE); expect(response.status()).toBe(200); }); it('should resolve url relative to gobal baseURL option', async ({ playwright, server }) => { - const request = await playwright._newRequest({ baseURL: server.PREFIX }); + const request = await playwright.newRequest({ baseURL: server.PREFIX }); const response = await request.get('/empty.html'); expect(response.url()).toBe(server.EMPTY_PAGE); }); it('should set playwright as user-agent', async ({ playwright, server }) => { - const request = await playwright._newRequest(); + const request = await playwright.newRequest(); const [serverRequest] = await Promise.all([ server.waitForRequest('/empty.html'), request.get(server.EMPTY_PAGE) diff --git a/tests/page/page-request-fulfill.spec.ts b/tests/page/page-request-fulfill.spec.ts index 4c6b4a830c..971ddb0f5d 100644 --- a/tests/page/page-request-fulfill.spec.ts +++ b/tests/page/page-request-fulfill.spec.ts @@ -197,7 +197,7 @@ it('should include the origin header', async ({ page, server, isAndroid }) => { it('should fulfill with global fetch result', async ({ playwright, page, server, isElectron }) => { it.fixme(isElectron, 'error: Browser context management is not supported.'); await page.route('**/*', async route => { - const request = await playwright._newRequest(); + const request = await playwright.newRequest(); const response = await request.get(server.PREFIX + '/simple.json'); route.fulfill({ response }); }); @@ -209,7 +209,7 @@ it('should fulfill with global fetch result', async ({ playwright, page, server, it('should fulfill with fetch result', async ({ page, server, isElectron }) => { it.fixme(isElectron, 'error: Browser context management is not supported.'); await page.route('**/*', async route => { - const response = await page._request.get(server.PREFIX + '/simple.json'); + const response = await page.request.get(server.PREFIX + '/simple.json'); route.fulfill({ response }); }); const response = await page.goto(server.EMPTY_PAGE); @@ -220,7 +220,7 @@ it('should fulfill with fetch result', async ({ page, server, isElectron }) => { it('should fulfill with fetch result and overrides', async ({ page, server, isElectron }) => { it.fixme(isElectron, 'error: Browser context management is not supported.'); await page.route('**/*', async route => { - const response = await page._request.get(server.PREFIX + '/simple.json'); + const response = await page.request.get(server.PREFIX + '/simple.json'); route.fulfill({ response, status: 201, @@ -239,7 +239,7 @@ it('should fulfill with fetch result and overrides', async ({ page, server, isEl it('should fetch original request and fulfill', async ({ page, server, isElectron }) => { it.fixme(isElectron, 'error: Browser context management is not supported.'); await page.route('**/*', async route => { - const response = await page._request.get(route.request()); + const response = await page.request.get(route.request()); route.fulfill({ response, }); @@ -276,7 +276,7 @@ it('should fulfill with fetch response that has multiple set-cookie', async ({ p res.end(); }); await page.route('**/empty.html', async route => { - const request = await playwright._newRequest(); + const request = await playwright.newRequest(); const response = await request.fetch(route.request()); route.fulfill({ response }); }); diff --git a/types/types.d.ts b/types/types.d.ts index 0a94d3e821..fbe3daf678 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1416,11 +1416,6 @@ export interface Page { */ off(event: 'worker', listener: (worker: Worker) => void): this; - /** - * API testing helper associated with this page. Requests made with this API will use page cookies. - */ - _request: FetchRequest; - accessibility: Accessibility; /** @@ -2755,6 +2750,11 @@ export interface Page { waitUntil?: "load"|"domcontentloaded"|"networkidle"; }): Promise; + /** + * API testing helper associated with this page. Requests made with this API will use page cookies. + */ + request: FetchRequest; + /** * Routing provides the capability to modify network requests that are made by a page. * @@ -6230,11 +6230,6 @@ export interface BrowserContext { */ off(event: 'serviceworker', listener: (worker: Worker) => void): this; - /** - * API testing helper associated with this context. Requests made with this API will use context cookies. - */ - _request: FetchRequest; - /** * Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be * obtained via @@ -6457,6 +6452,11 @@ export interface BrowserContext { */ pages(): Array; + /** + * API testing helper associated with this context. Requests made with this API will use context cookies. + */ + request: FetchRequest; + /** * Routing provides the capability to modify network requests that are made by any page in the browser context. Once route * is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted. @@ -13371,11 +13371,21 @@ export interface Mouse { wheel(deltaX: number, deltaY: number): Promise; } +/** + * This object can be used to launch or connect to Chromium, returning instances of [Browser]. + */ +export const chromium: BrowserType; + +/** + * This object can be used to launch or connect to Firefox, returning instances of [Browser]. + */ +export const firefox: BrowserType; + /** * **experimental** Creates new instances of [FetchRequest]. * @param options */ -export const _newRequest: (options?: { +export const newRequest: (options?: { /** * When using * [fetchRequest.get(urlOrRequest[, options])](https://playwright.dev/docs/api/class-fetchrequest#fetch-request-get), @@ -13490,16 +13500,6 @@ export const _newRequest: (options?: { userAgent?: string; }) => Promise; -/** - * This object can be used to launch or connect to Chromium, returning instances of [Browser]. - */ -export const chromium: BrowserType; - -/** - * This object can be used to launch or connect to Firefox, returning instances of [Browser]. - */ -export const firefox: BrowserType; - /** * Selectors can be used to install custom selector engines. See [Working with selectors](https://playwright.dev/docs/selectors) for more * information.