From 058883430740044783125df8ae2e3a3fbe9f7718 Mon Sep 17 00:00:00 2001 From: Kuba Janik Date: Tue, 13 Aug 2024 19:39:56 +0200 Subject: [PATCH] feat: allow `URLSearchParams` and `string` as params in `APIRequestContext` (follow-up) (#32143) Follow-up to https://github.com/microsoft/playwright/pull/32120 I made some changes suggested by @yury-s in the previous PR that make a lot of sense: - added an example to the documentation - improved tests - check params on the client and server end - reverted to non-English characters being used as params --- docs/src/api/class-apirequestcontext.md | 12 ++++ packages/playwright-core/types/types.d.ts | 12 ++++ tests/library/browsercontext-fetch.spec.ts | 69 +++++++++++++++------- 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/docs/src/api/class-apirequestcontext.md b/docs/src/api/class-apirequestcontext.md index 9275fb2d36..a6333d6b0a 100644 --- a/docs/src/api/class-apirequestcontext.md +++ b/docs/src/api/class-apirequestcontext.md @@ -369,12 +369,24 @@ context cookies from the response. The method will automatically follow redirect Request parameters can be configured with `params` option, they will be serialized into the URL search parameters: ```js +// Passing params as object await request.get('https://example.com/api/getText', { params: { 'isbn': '1234', 'page': 23, } }); + +// Passing params as URLSearchParams +const searchParams = new URLSearchParams(); +searchParams.set('isbn', '1234'); +searchParams.append('page', 23); +searchParams.append('page', 24); +await request.get('https://example.com/api/getText', { params: searchParams }); + +// Passing params as string +const queryString = 'isbn=1234&page=23&page=24'; +await request.get('https://example.com/api/getText', { params: queryString }); ``` ```java diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index a2c2f27534..bf4e35a9ca 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -16672,12 +16672,24 @@ export interface APIRequestContext { * Request parameters can be configured with `params` option, they will be serialized into the URL search parameters: * * ```js + * // Passing params as object * await request.get('https://example.com/api/getText', { * params: { * 'isbn': '1234', * 'page': 23, * } * }); + * + * // Passing params as URLSearchParams + * const searchParams = new URLSearchParams(); + * searchParams.set('isbn', '1234'); + * searchParams.append('page', 23); + * searchParams.append('page', 24); + * await request.get('https://example.com/api/getText', { params: searchParams }); + * + * // Passing params as string + * const queryString = 'isbn=1234&page=23&page=24'; + * await request.get('https://example.com/api/getText', { params: queryString }); * ``` * * @param url Target URL. diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index eb8e8da075..51a98dec4a 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -123,39 +123,66 @@ it('should add session cookies to request', async ({ context, server }) => { for (const method of ['fetch', 'delete', 'get', 'head', 'patch', 'post', 'put'] as const) { it(`${method} should support params passed as object`, async ({ context, server }) => { - const params = { - 'first-param': 'value2', - 'second-param': 'value', - }; + const url = new URL(server.EMPTY_PAGE); + url.searchParams.set('param1', 'value1'); + url.searchParams.set('парам2', 'знач2'); - const response = await context.request[method](server.EMPTY_PAGE + '?first-param=value1', { params }); + const [request, response] = await Promise.all([ + server.waitForRequest(url.pathname + url.search), + context.request[method](server.EMPTY_PAGE, { + params: { + 'param1': 'value1', + 'парам2': 'знач2', + } + }), + ]); - const { searchParams } = new URL(response.url()); - expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']); - expect(searchParams.get('second-param')).toBe('value'); + const requestParams = new URLSearchParams(request.url.slice(request.url.indexOf('?'))); + expect(requestParams.get('param1')).toEqual('value1'); + expect(requestParams.get('парам2')).toBe('знач2'); + + const responseParams = new URL(response.url()).searchParams; + expect(responseParams.get('param1')).toEqual('value1'); + expect(responseParams.get('парам2')).toBe('знач2'); }); it(`${method} should support params passed as URLSearchParams`, async ({ context, server }) => { - const params = new URLSearchParams(); - params.append('first-param', 'value1'); - params.append('first-param', 'value2'); - params.append('second-param', 'value'); + const url = new URL(server.EMPTY_PAGE); + const searchParams = new URLSearchParams(); + searchParams.append('param1', 'value1'); + searchParams.append('param1', 'value2'); + searchParams.set('парам2', 'знач2'); - const response = await context.request[method](server.EMPTY_PAGE, { params }); + const [request, response] = await Promise.all([ + server.waitForRequest(url.pathname + '?' + searchParams), + context.request[method](server.EMPTY_PAGE, { params: searchParams }), + ]); - const { searchParams } = new URL(response.url()); - expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']); - expect(searchParams.get('second-param')).toBe('value'); + const requestParams = new URLSearchParams(request.url.slice(request.url.indexOf('?'))); + expect(requestParams.getAll('param1')).toEqual(['value1', 'value2']); + expect(requestParams.get('парам2')).toBe('знач2'); + + const responseParams = new URL(response.url()).searchParams; + expect(responseParams.getAll('param1')).toEqual(['value1', 'value2']); + expect(responseParams.get('парам2')).toBe('знач2'); }); it(`${method} should support params passed as string`, async ({ context, server }) => { - const params = 'first-param=value1&first-param=value2&second-param=value'; + const url = new URL(server.EMPTY_PAGE); + const params = '?param1=value1¶m1=value2&парам2=знач2'; - const response = await context.request[method](server.EMPTY_PAGE, { params }); + const [request, response] = await Promise.all([ + server.waitForRequest(url.pathname + encodeURI(params)), + context.request[method](server.EMPTY_PAGE, { params }), + ]); - const { searchParams } = new URL(response.url()); - expect(searchParams.getAll('first-param')).toEqual(['value1', 'value2']); - expect(searchParams.get('second-param')).toBe('value'); + const requestParams = new URLSearchParams(request.url.slice(request.url.indexOf('?'))); + expect(requestParams.getAll('param1')).toEqual(['value1', 'value2']); + expect(requestParams.get('парам2')).toBe('знач2'); + + const responseParams = new URL(response.url()).searchParams; + expect(responseParams.getAll('param1')).toEqual(['value1', 'value2']); + expect(responseParams.get('парам2')).toBe('знач2'); }); it(`${method} should support failOnStatusCode`, async ({ context, server }) => {