From 1857a3fb5653acde8bebd032d32c82d6b433b5d7 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 21 Sep 2023 13:31:28 -0700 Subject: [PATCH] fix(evaluate): make sure to try/catch `toJSON` access (#27238) --- .../isomorphic/utilityScriptSerializers.ts | 12 +++++++++--- tests/page/page-evaluate.spec.ts | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts b/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts index 6ba427eb2b..01092e0ed8 100644 --- a/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts +++ b/packages/playwright-core/src/server/isomorphic/utilityScriptSerializers.ts @@ -208,9 +208,15 @@ export function source() { o.push({ k: name, v: serialize(item, handleSerializer, visitorInfo) }); } - // If Object.keys().length === 0 we fall back to toJSON if it exists - if (o.length === 0 && value.toJSON && typeof value.toJSON === 'function') - return innerSerialize(value.toJSON(), handleSerializer, visitorInfo); + let jsonWrapper; + try { + // If Object.keys().length === 0 we fall back to toJSON if it exists + if (o.length === 0 && value.toJSON && typeof value.toJSON === 'function') + jsonWrapper = { value: value.toJSON() }; + } catch (e) { + } + if (jsonWrapper) + return innerSerialize(jsonWrapper.value, handleSerializer, visitorInfo); return { o, id }; } diff --git a/tests/page/page-evaluate.spec.ts b/tests/page/page-evaluate.spec.ts index db1120d6fe..699e3e7302 100644 --- a/tests/page/page-evaluate.spec.ts +++ b/tests/page/page-evaluate.spec.ts @@ -654,6 +654,23 @@ it('should not use toJSON in jsonValue', async ({ page }) => { expect(await resultHandle.jsonValue()).toEqual({ data: 'data', toJSON: {} }); }); +it('should ignore buggy toJSON', async ({ page }) => { + const result = await page.evaluate(() => { + class Foo { + toJSON() { + throw new Error('Bad'); + } + } + class Bar { + get toJSON() { + throw new Error('Also bad'); + } + } + return { foo: new Foo(), bar: new Bar() }; + }); + expect(result).toEqual({ foo: {}, bar: {} }); +}); + it('should not expose the injected script export', async ({ page }) => { expect(await page.evaluate('typeof pwExport === "undefined"')).toBe(true); });