From b3f3199d10edf464a8131535eb8bd64aa3076d2b Mon Sep 17 00:00:00 2001 From: Alex Rudenko Date: Wed, 13 Sep 2023 12:15:22 +0200 Subject: [PATCH] refactor: reduce boilerplate in the emulation state management (#10895) --- .../src/common/EmulationManager.ts | 66 ++++++++++++++----- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/packages/puppeteer-core/src/common/EmulationManager.ts b/packages/puppeteer-core/src/common/EmulationManager.ts index a34b2ec8332..4e21d349e5a 100644 --- a/packages/puppeteer-core/src/common/EmulationManager.ts +++ b/packages/puppeteer-core/src/common/EmulationManager.ts @@ -26,6 +26,7 @@ import {debugError} from './util.js'; interface ViewportState { viewport?: Viewport; + active: boolean; } interface IdleOverridesState { @@ -76,6 +77,39 @@ interface JavascriptEnabledState { active: boolean; } +interface ClientProvider { + clients(): CDPSession[]; +} + +class EmulatedState { + #state: T; + #clientProvider: ClientProvider; + #updater: (client: CDPSession, state: T) => Promise; + + constructor( + initialState: T, + clientProvider: ClientProvider, + updater: (client: CDPSession, state: T) => Promise + ) { + this.#state = initialState; + this.#clientProvider = clientProvider; + this.#updater = updater; + } + + async setState(state: T): Promise { + this.#state = state; + await this.sync(); + } + + async sync(): Promise { + await Promise.all( + this.#clientProvider.clients().map(client => { + return this.#updater(client, this.#state); + }) + ); + } +} + /** * @internal */ @@ -85,7 +119,13 @@ export class EmulationManager { #emulatingMobile = false; #hasTouch = false; - #viewportState: ViewportState = {}; + #viewportState = new EmulatedState( + { + active: false, + }, + this, + this.#applyViewport + ); #idleOverridesState: IdleOverridesState = { active: false, }; @@ -133,7 +173,7 @@ export class EmulationManager { }); // We don't await here because we want to register all state changes before // the target is unpaused. - void this.#syncViewport().catch(debugError); + void this.#viewportState.sync().catch(debugError); void this.#syncIdleState().catch(debugError); void this.#syncTimezoneState().catch(debugError); void this.#syncVisionDeficiencyState().catch(debugError); @@ -149,12 +189,15 @@ export class EmulationManager { return this.#javascriptEnabledState.javaScriptEnabled; } - async emulateViewport(viewport: Viewport): Promise { - this.#viewportState = { - viewport, - }; + clients(): CDPSession[] { + return [this.#client, ...Array.from(this.#secondaryClients)]; + } - await this.#syncViewport(); + async emulateViewport(viewport: Viewport): Promise { + await this.#viewportState.setState({ + viewport, + active: true, + }); const mobile = viewport.isMobile || false; const hasTouch = viewport.hasTouch || false; @@ -166,15 +209,6 @@ export class EmulationManager { return reloadNeeded; } - async #syncViewport() { - await Promise.all([ - this.#applyViewport(this.#client, this.#viewportState), - ...Array.from(this.#secondaryClients).map(client => { - return this.#applyViewport(client, this.#viewportState); - }), - ]); - } - @invokeAtMostOnceForArguments async #applyViewport( client: CDPSession,