mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(fetch): JSON.stringify on client (#27644)
Fixes https://github.com/microsoft/playwright/issues/27602
This commit is contained in:
parent
e8b4c03e54
commit
4e845e7b1d
@ -168,13 +168,13 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
if (options.data !== undefined) {
|
||||
if (isString(options.data)) {
|
||||
if (isJsonContentType(headers))
|
||||
jsonData = options.data;
|
||||
jsonData = isJsonParsable(options.data) ? options.data : JSON.stringify(options.data);
|
||||
else
|
||||
postDataBuffer = Buffer.from(options.data, 'utf8');
|
||||
} else if (Buffer.isBuffer(options.data)) {
|
||||
postDataBuffer = options.data;
|
||||
} else if (typeof options.data === 'object' || typeof options.data === 'number' || typeof options.data === 'boolean') {
|
||||
jsonData = options.data;
|
||||
jsonData = JSON.stringify(options.data);
|
||||
} else {
|
||||
throw new Error(`Unexpected 'data' type`);
|
||||
}
|
||||
@ -230,6 +230,20 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
}
|
||||
}
|
||||
|
||||
function isJsonParsable(value: any) {
|
||||
if (typeof value !== 'string')
|
||||
return false;
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError)
|
||||
return false;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export class APIResponse implements api.APIResponse {
|
||||
private readonly _initializer: channels.APIResponse;
|
||||
private readonly _headers: RawHeaders;
|
||||
|
||||
@ -175,7 +175,7 @@ scheme.APIRequestContextFetchParams = tObject({
|
||||
method: tOptional(tString),
|
||||
headers: tOptional(tArray(tType('NameValue'))),
|
||||
postData: tOptional(tBinary),
|
||||
jsonData: tOptional(tAny),
|
||||
jsonData: tOptional(tString),
|
||||
formData: tOptional(tArray(tType('NameValue'))),
|
||||
multipartData: tOptional(tArray(tType('FormField'))),
|
||||
timeout: tOptional(tNumber),
|
||||
|
||||
@ -671,26 +671,11 @@ function parseCookie(header: string): channels.NetworkCookie | null {
|
||||
return cookie;
|
||||
}
|
||||
|
||||
function isJsonParsable(value: any) {
|
||||
if (typeof value !== 'string')
|
||||
return false;
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError)
|
||||
return false;
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function serializePostData(params: channels.APIRequestContextFetchParams, headers: HeadersObject): Buffer | undefined {
|
||||
assert((params.postData ? 1 : 0) + (params.jsonData ? 1 : 0) + (params.formData ? 1 : 0) + (params.multipartData ? 1 : 0) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
|
||||
if (params.jsonData !== undefined) {
|
||||
const json = isJsonParsable(params.jsonData) ? params.jsonData : JSON.stringify(params.jsonData);
|
||||
setHeader(headers, 'content-type', 'application/json', true);
|
||||
return Buffer.from(json, 'utf8');
|
||||
return Buffer.from(params.jsonData, 'utf8');
|
||||
} else if (params.formData) {
|
||||
const searchParams = new URLSearchParams();
|
||||
for (const { name, value } of params.formData)
|
||||
|
||||
@ -317,7 +317,7 @@ export type APIRequestContextFetchParams = {
|
||||
method?: string,
|
||||
headers?: NameValue[],
|
||||
postData?: Binary,
|
||||
jsonData?: any,
|
||||
jsonData?: string,
|
||||
formData?: NameValue[],
|
||||
multipartData?: FormField[],
|
||||
timeout?: number,
|
||||
@ -330,7 +330,7 @@ export type APIRequestContextFetchOptions = {
|
||||
method?: string,
|
||||
headers?: NameValue[],
|
||||
postData?: Binary,
|
||||
jsonData?: any,
|
||||
jsonData?: string,
|
||||
formData?: NameValue[],
|
||||
multipartData?: FormField[],
|
||||
timeout?: number,
|
||||
|
||||
@ -288,7 +288,7 @@ APIRequestContext:
|
||||
type: array?
|
||||
items: NameValue
|
||||
postData: binary?
|
||||
jsonData: json?
|
||||
jsonData: string?
|
||||
formData:
|
||||
type: array?
|
||||
items: NameValue
|
||||
|
||||
@ -430,3 +430,24 @@ it('should keep headers capitalization', async ({ playwright, server }) => {
|
||||
expect(serverRequest.rawHeaders).toContain('vaLUE');
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
it('should serialize post data on the client', async ({ playwright, server }) => {
|
||||
const request = await playwright.request.newContext();
|
||||
const serverReq = server.waitForRequest('/empty.html');
|
||||
let onStack: boolean = true;
|
||||
const postReq = request.post(server.EMPTY_PAGE, {
|
||||
data: {
|
||||
toJSON() {
|
||||
if (!onStack)
|
||||
throw new Error('Should not be called on the server');
|
||||
return { 'foo': 'bar' };
|
||||
}
|
||||
}
|
||||
});
|
||||
onStack = false;
|
||||
await postReq;
|
||||
const body = await (await serverReq).postBody;
|
||||
expect(body.toString()).toBe('{"foo":"bar"}');
|
||||
// expect(serverRequest.rawHeaders).toContain('vaLUE');
|
||||
await request.dispose();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user