chore: fix BiDi deserializer (#11264)

This commit is contained in:
Nikolay Vitkov 2023-10-30 13:02:04 +01:00 committed by GitHub
parent 22aeff1eac
commit 0d4aab828a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 48 deletions

View File

@ -18,11 +18,6 @@ import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
import {debugError} from '../common/util.js';
/**
* @internal
*/
class UnsupportedTypeError extends Error {}
/**
* @internal
*/
@ -45,43 +40,30 @@ export class BidiDeserializer {
static deserializeLocalValue(result: Bidi.Script.RemoteValue): unknown {
switch (result.type) {
case 'array':
if (result.value) {
return result.value.map(value => {
return BidiDeserializer.deserializeLocalValue(value);
});
}
break;
return result.value?.map(value => {
return BidiDeserializer.deserializeLocalValue(value);
});
case 'set':
if (result.value) {
return result.value.reduce((acc: Set<unknown>, value) => {
return acc.add(BidiDeserializer.deserializeLocalValue(value));
}, new Set());
}
break;
return result.value?.reduce((acc: Set<unknown>, value) => {
return acc.add(BidiDeserializer.deserializeLocalValue(value));
}, new Set());
case 'object':
if (result.value) {
return result.value.reduce((acc: Record<any, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
acc[key as any] = value;
return acc;
}, {});
}
break;
return result.value?.reduce((acc: Record<any, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
acc[key as any] = value;
return acc;
}, {});
case 'map':
if (result.value) {
return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
return acc.set(key, value);
}, new Map());
}
break;
return result.value?.reduce((acc: Map<unknown, unknown>, tuple) => {
const {key, value} = BidiDeserializer.deserializeTuple(tuple);
return acc.set(key, value);
}, new Map());
case 'promise':
return {};
case 'regexp':
return new RegExp(result.value.pattern, result.value.flags);
case 'date':
return new Date(result.value);
case 'undefined':
return undefined;
case 'null':
@ -96,9 +78,8 @@ export class BidiDeserializer {
return result.value;
}
throw new UnsupportedTypeError(
`Deserialization of type ${result.type} not supported.`
);
debugError(`Deserialization of type ${result.type} not supported.`);
return undefined;
}
static deserializeTuple([serializedKey, serializedValue]: [
@ -120,14 +101,6 @@ export class BidiDeserializer {
return undefined;
}
try {
return BidiDeserializer.deserializeLocalValue(result);
} catch (error) {
if (error instanceof UnsupportedTypeError) {
debugError(error.message);
return undefined;
}
throw error;
}
return BidiDeserializer.deserializeLocalValue(result);
}
}

View File

@ -551,6 +551,24 @@
"parameters": ["webDriverBiDi"],
"expectations": ["PASS"]
},
{
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should fail for circular object",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should replace symbols with undefined",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should return properly serialize objects with unknown type fields",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[evaluation.spec] Evaluation specs Page.evaluate should throw if elementHandles are from other frames",
"platforms": ["darwin", "linux", "win32"],

View File

@ -107,14 +107,14 @@ describe('Evaluation specs', function () {
await page.goto(server.PREFIX + '/global-var.html');
expect(await page.evaluate('globalVar')).toBe(123);
});
it('should return undefined for objects with symbols', async () => {
it('should replace symbols with undefined', async () => {
const {page} = await getTestState();
expect(
await page.evaluate(() => {
return [Symbol('foo4')];
return [Symbol('foo4'), 'foo'];
})
).toBe(undefined);
).toEqual([undefined, 'foo']);
});
it('should work with function shorthands', async () => {
const {page} = await getTestState();
@ -455,6 +455,28 @@ describe('Evaluation specs', function () {
});
expect(error.message).toContain('Error in promise');
});
it('should return properly serialize objects with unknown type fields', async () => {
const {page} = await getTestState();
await page.setContent(
"<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='>"
);
const result = await page.evaluate(async () => {
const image = document.querySelector('img')!;
const imageBitmap = await createImageBitmap(image);
return {
a: 'foo',
b: imageBitmap,
};
});
expect(result).toEqual({
a: 'foo',
b: undefined,
});
});
});
describe('Page.evaluateOnNewDocument', function () {