From 27027658dc208a5202944313a310f9571a51e5ac Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 28 Feb 2023 12:45:14 -0800 Subject: [PATCH] chore: fix all Proxy() to account for symbol properties (#21272) Fixes #20940. --- packages/playwright-core/src/client/channelOwner.ts | 2 +- .../playwright-core/src/client/clientInstrumentation.ts | 4 +++- packages/playwright-core/src/server/instrumentation.ts | 4 +++- packages/playwright-core/src/server/socksInterceptor.ts | 2 +- packages/playwright-test/src/matchers/expect.ts | 8 +++++--- tests/page/page-basic.spec.ts | 8 ++++++++ 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/playwright-core/src/client/channelOwner.ts b/packages/playwright-core/src/client/channelOwner.ts index af85d90fe7..6a2118cf75 100644 --- a/packages/playwright-core/src/client/channelOwner.ts +++ b/packages/playwright-core/src/client/channelOwner.ts @@ -132,7 +132,7 @@ export abstract class ChannelOwner { + get: (obj: any, prop: string | symbol) => { if (typeof prop === 'string') { const validator = maybeFindValidator(this._type, prop, 'Params'); if (validator) { diff --git a/packages/playwright-core/src/client/clientInstrumentation.ts b/packages/playwright-core/src/client/clientInstrumentation.ts index bda55dca49..a90f2964ad 100644 --- a/packages/playwright-core/src/client/clientInstrumentation.ts +++ b/packages/playwright-core/src/client/clientInstrumentation.ts @@ -31,7 +31,9 @@ export interface ClientInstrumentationListener { export function createInstrumentation(): ClientInstrumentation { const listeners: ClientInstrumentationListener[] = []; return new Proxy({}, { - get: (obj: any, prop: string) => { + get: (obj: any, prop: string | symbol) => { + if (typeof prop !== 'string') + return obj[prop]; if (prop === 'addListener') return (listener: ClientInstrumentationListener) => listeners.push(listener); if (prop === 'removeListener') diff --git a/packages/playwright-core/src/server/instrumentation.ts b/packages/playwright-core/src/server/instrumentation.ts index 8f06a7afcd..d58ed444ea 100644 --- a/packages/playwright-core/src/server/instrumentation.ts +++ b/packages/playwright-core/src/server/instrumentation.ts @@ -84,7 +84,9 @@ export interface InstrumentationListener { export function createInstrumentation(): Instrumentation { const listeners = new Map(); return new Proxy({}, { - get: (obj: any, prop: string) => { + get: (obj: any, prop: string | symbol) => { + if (typeof prop !== 'string') + return obj[prop]; if (prop === 'addListener') return (listener: InstrumentationListener, context: BrowserContext | APIRequestContext | null) => listeners.set(listener, context); if (prop === 'removeListener') diff --git a/packages/playwright-core/src/server/socksInterceptor.ts b/packages/playwright-core/src/server/socksInterceptor.ts index 0fd31645e5..498e8bfe73 100644 --- a/packages/playwright-core/src/server/socksInterceptor.ts +++ b/packages/playwright-core/src/server/socksInterceptor.ts @@ -32,7 +32,7 @@ export class SocksInterceptor { let lastId = -1; this._channel = new Proxy(new EventEmitter(), { - get: (obj: any, prop) => { + get: (obj: any, prop: string | symbol) => { if ((prop in obj) || obj[prop] !== undefined || typeof prop !== 'string') return obj[prop]; return (params: any) => { diff --git a/packages/playwright-test/src/matchers/expect.ts b/packages/playwright-test/src/matchers/expect.ts index f6a3707101..af94aa5312 100644 --- a/packages/playwright-test/src/matchers/expect.ts +++ b/packages/playwright-test/src/matchers/expect.ts @@ -101,7 +101,7 @@ export const printReceivedStringContainExpectedResult = ( type ExpectMessageOrOptions = undefined | string | { message?: string, timeout?: number, intervals?: number[] }; -function createExpect(actual: unknown, messageOrOptions: ExpectMessageOrOptions, isSoft: boolean, isPoll: boolean, generator?: Generator) { +function createExpect(actual: unknown, messageOrOptions: ExpectMessageOrOptions, isSoft: boolean, isPoll: boolean, generator?: Generator): any { return new Proxy(expectLibrary(actual), new ExpectMetaInfoProxyHandler(messageOrOptions, isSoft, isPoll, generator)); } @@ -164,7 +164,7 @@ type ExpectMetaInfo = { generator?: Generator; }; -class ExpectMetaInfoProxyHandler { +class ExpectMetaInfoProxyHandler implements ProxyHandler { private _info: ExpectMetaInfo; constructor(messageOrOptions: ExpectMessageOrOptions, isSoft: boolean, isPoll: boolean, generator?: Generator) { @@ -178,8 +178,10 @@ class ExpectMetaInfoProxyHandler { } } - get(target: any, matcherName: any, receiver: any): any { + get(target: Object, matcherName: string | symbol, receiver: any): any { let matcher = Reflect.get(target, matcherName, receiver); + if (typeof matcherName !== 'string') + return matcher; if (matcher === undefined) throw new Error(`expect: Property '${matcherName}' not found.`); if (typeof matcher !== 'function') { diff --git a/tests/page/page-basic.spec.ts b/tests/page/page-basic.spec.ts index f0980698c3..1f2458ddc1 100644 --- a/tests/page/page-basic.spec.ts +++ b/tests/page/page-basic.spec.ts @@ -257,3 +257,11 @@ it('has navigator.webdriver set to true', async ({ page, browserName }) => { it.skip(browserName === 'firefox'); expect(await page.evaluate(() => navigator.webdriver)).toBe(true); }); + +it('should iterate over page properties', async ({ page }) => { + const props = []; + for (const prop in page) { + if (page[prop] && typeof page[prop] === 'object') + props.push(page[prop][Symbol.iterator]); + } +});