chore: get rid of page state overrides (#15470)

This commit is contained in:
Pavel Feldman 2022-07-07 15:28:20 -08:00 committed by GitHub
parent 738d71ebc2
commit 0781d04a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 66 deletions

View File

@ -98,7 +98,7 @@ export class CRPage implements PageDelegate {
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
if (viewportSize)
this._page._state.emulatedSize = { viewport: viewportSize, screen: viewportSize };
this._page._emulatedSize = { viewport: viewportSize, screen: viewportSize };
}
// Note: it is important to call |reportAsNew| before resolving pageOrError promise,
// so that anyone who awaits pageOrError got a ready and reported page.
@ -199,8 +199,7 @@ export class CRPage implements PageDelegate {
await this._forAllFrameSessions(frame => frame._updateHttpCredentials(false));
}
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
assert(this._page._state.emulatedSize === emulatedSize);
async updateEmulatedViewportSize(): Promise<void> {
await this._mainFrameSession._updateViewport();
}
@ -972,7 +971,7 @@ class FrameSession {
async _updateExtraHTTPHeaders(initial: boolean): Promise<void> {
const headers = network.mergeHeaders([
this._crPage._browserContext._options.extraHTTPHeaders,
this._page._state.extraHTTPHeaders
this._page.extraHTTPHeaders()
]);
if (!initial || headers.length)
await this._client.send('Network.setExtraHTTPHeaders', { headers: headersArrayToObject(headers, false /* lowerCase */) });
@ -1001,7 +1000,7 @@ class FrameSession {
return;
assert(this._isMainFrame());
const options = this._crPage._browserContext._options;
const emulatedSize = this._page._state.emulatedSize;
const emulatedSize = this._page.emulatedSize();
if (emulatedSize === null)
return;
const viewportSize = emulatedSize.viewport;
@ -1059,16 +1058,17 @@ class FrameSession {
}
async _updateEmulateMedia(initial: boolean): Promise<void> {
const colorScheme = this._page._state.colorScheme === null ? '' : this._page._state.colorScheme;
const reducedMotion = this._page._state.reducedMotion === null ? '' : this._page._state.reducedMotion;
const forcedColors = this._page._state.forcedColors === null ? '' : this._page._state.forcedColors;
const emulatedMedia = this._page.emulatedMedia();
const colorScheme = emulatedMedia.colorScheme === null ? '' : emulatedMedia.colorScheme;
const reducedMotion = emulatedMedia.reducedMotion === null ? '' : emulatedMedia.reducedMotion;
const forcedColors = emulatedMedia.forcedColors === null ? '' : emulatedMedia.forcedColors;
const features = [
{ name: 'prefers-color-scheme', value: colorScheme },
{ name: 'prefers-reduced-motion', value: reducedMotion },
{ name: 'forced-colors', value: forcedColors },
];
// Empty string disables the override.
await this._client.send('Emulation.setEmulatedMedia', { media: this._page._state.mediaType || '', features });
await this._client.send('Emulation.setEmulatedMedia', { media: emulatedMedia.media || '', features });
}
private async _setDefaultFontFamilies(session: CRSession) {
@ -1081,7 +1081,7 @@ class FrameSession {
}
async _updateFileChooserInterception(initial: boolean) {
const enabled = this._page._state.interceptFileChooser;
const enabled = this._page.fileChooserIntercepted();
if (initial && !enabled)
return;
await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.

View File

@ -20,7 +20,6 @@ import * as dom from '../dom';
import type * as frames from '../frames';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { assert } from '../../utils';
import type { PageBinding, PageDelegate } from '../page';
import { Page, Worker } from '../page';
import type * as types from '../types';
@ -352,17 +351,12 @@ export class FFPage implements PageDelegate {
}
async updateExtraHTTPHeaders(): Promise<void> {
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page._state.extraHTTPHeaders || [] });
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page.extraHTTPHeaders() || [] });
}
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
assert(this._page._state.emulatedSize === emulatedSize);
await this._session.send('Page.setViewportSize', {
viewportSize: {
width: emulatedSize.viewport.width,
height: emulatedSize.viewport.height,
},
});
async updateEmulatedViewportSize(): Promise<void> {
const viewportSize = this._page.viewportSize();
await this._session.send('Page.setViewportSize', { viewportSize });
}
async bringToFront(): Promise<void> {
@ -370,12 +364,13 @@ export class FFPage implements PageDelegate {
}
async updateEmulateMedia(): Promise<void> {
const colorScheme = this._page._state.colorScheme === null ? undefined : this._page._state.colorScheme;
const reducedMotion = this._page._state.reducedMotion === null ? undefined : this._page._state.reducedMotion;
const forcedColors = this._page._state.forcedColors === null ? undefined : this._page._state.forcedColors;
const emulatedMedia = this._page.emulatedMedia();
const colorScheme = emulatedMedia.colorScheme ?? undefined;
const reducedMotion = emulatedMedia.reducedMotion ?? undefined;
const forcedColors = emulatedMedia.forcedColors ?? undefined;
await this._session.send('Page.setEmulatedMedia', {
// Empty string means reset.
type: this._page._state.mediaType === null ? '' : this._page._state.mediaType,
type: emulatedMedia.media === null ? '' : emulatedMedia.media,
colorScheme,
reducedMotion,
forcedColors,

View File

@ -653,7 +653,7 @@ export class Frame extends SdkObject {
private async _gotoAction(progress: Progress, url: string, options: types.GotoOptions): Promise<network.Response | null> {
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
progress.log(`navigating to "${url}", waiting until "${waitUntil}"`);
const headers = this._page._state.extraHTTPHeaders || [];
const headers = this._page.extraHTTPHeaders() || [];
const refererHeader = headers.find(h => h.name.toLowerCase() === 'referer');
let referer = refererHeader ? refererHeader.value : undefined;
if (options.referer !== undefined) {

View File

@ -65,7 +65,7 @@ export interface PageDelegate {
navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>;
updateExtraHTTPHeaders(): Promise<void>;
setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void>;
updateEmulatedViewportSize(): Promise<void>;
updateEmulateMedia(): Promise<void>;
updateRequestInterception(): Promise<void>;
updateFileChooserInterception(enabled: boolean): Promise<void>;
@ -98,14 +98,13 @@ export interface PageDelegate {
readonly cspErrorsAsynchronousForInlineScipts?: boolean;
}
type PageState = {
emulatedSize: { screen: types.Size, viewport: types.Size } | null;
mediaType: types.MediaType | null;
type EmulatedSize = { screen: types.Size, viewport: types.Size };
type EmulatedMedia = {
media: types.MediaType | null;
colorScheme: types.ColorScheme | null;
reducedMotion: types.ReducedMotion | null;
forcedColors: types.ForcedColors | null;
extraHTTPHeaders: types.HeadersArray | null;
interceptFileChooser: boolean;
};
type ExpectScreenshotOptions = {
@ -152,7 +151,10 @@ export class Page extends SdkObject {
readonly touchscreen: input.Touchscreen;
readonly _timeoutSettings: TimeoutSettings;
readonly _delegate: PageDelegate;
readonly _state: PageState;
_emulatedSize: EmulatedSize | undefined;
private _extraHTTPHeaders: types.HeadersArray | undefined;
private _emulatedMedia: Partial<EmulatedMedia> = {};
private _interceptFileChooser = false;
private readonly _pageBindings = new Map<string, PageBinding>();
readonly initScripts: string[] = [];
readonly _screenshotter: Screenshotter;
@ -176,15 +178,6 @@ export class Page extends SdkObject {
this.attribution.page = this;
this._delegate = delegate;
this._browserContext = browserContext;
this._state = {
emulatedSize: browserContext._options.viewport ? { viewport: browserContext._options.viewport, screen: browserContext._options.screen || browserContext._options.viewport } : null,
mediaType: null,
colorScheme: browserContext._options.colorScheme !== undefined ? browserContext._options.colorScheme : 'light',
reducedMotion: browserContext._options.reducedMotion !== undefined ? browserContext._options.reducedMotion : 'no-preference',
forcedColors: browserContext._options.forcedColors !== undefined ? browserContext._options.forcedColors : 'none',
extraHTTPHeaders: null,
interceptFileChooser: false,
};
this.accessibility = new accessibility.Accessibility(delegate.getAccessibilityTree.bind(delegate));
this.keyboard = new input.Keyboard(delegate.rawKeyboard, this);
this.mouse = new input.Mouse(delegate.rawMouse, this);
@ -327,10 +320,14 @@ export class Page extends SdkObject {
}
setExtraHTTPHeaders(headers: types.HeadersArray) {
this._state.extraHTTPHeaders = headers;
this._extraHTTPHeaders = headers;
return this._delegate.updateExtraHTTPHeaders();
}
extraHTTPHeaders(): types.HeadersArray | undefined {
return this._extraHTTPHeaders;
}
async _onBindingCalled(payload: string, context: dom.FrameExecutionContext) {
if (this._disconnected || this._closedState === 'closed')
return;
@ -402,27 +399,44 @@ export class Page extends SdkObject {
}), this._timeoutSettings.navigationTimeout(options));
}
async emulateMedia(options: { media?: types.MediaType | null, colorScheme?: types.ColorScheme | null, reducedMotion?: types.ReducedMotion | null, forcedColors?: types.ForcedColors | null }) {
async emulateMedia(options: Partial<EmulatedMedia>) {
if (options.media !== undefined)
this._state.mediaType = options.media;
this._emulatedMedia.media = options.media;
if (options.colorScheme !== undefined)
this._state.colorScheme = options.colorScheme;
this._emulatedMedia.colorScheme = options.colorScheme;
if (options.reducedMotion !== undefined)
this._state.reducedMotion = options.reducedMotion;
this._emulatedMedia.reducedMotion = options.reducedMotion;
if (options.forcedColors !== undefined)
this._state.forcedColors = options.forcedColors;
this._emulatedMedia.forcedColors = options.forcedColors;
await this._delegate.updateEmulateMedia();
await this._doSlowMo();
}
emulatedMedia(): EmulatedMedia {
const contextOptions = this._browserContext._options;
return {
media: this._emulatedMedia.media || null,
colorScheme: this._emulatedMedia.colorScheme !== undefined ? this._emulatedMedia.colorScheme : contextOptions.colorScheme ?? 'light',
reducedMotion: this._emulatedMedia.reducedMotion !== undefined ? this._emulatedMedia.reducedMotion : contextOptions.reducedMotion ?? 'no-preference',
forcedColors: this._emulatedMedia.forcedColors !== undefined ? this._emulatedMedia.forcedColors : contextOptions.forcedColors ?? 'none',
};
}
async setViewportSize(viewportSize: types.Size) {
this._state.emulatedSize = { viewport: { ...viewportSize }, screen: { ...viewportSize } };
await this._delegate.setEmulatedSize(this._state.emulatedSize);
this._emulatedSize = { viewport: { ...viewportSize }, screen: { ...viewportSize } };
await this._delegate.updateEmulatedViewportSize();
await this._doSlowMo();
}
viewportSize(): types.Size | null {
return this._state.emulatedSize?.viewport || null;
return this.emulatedSize()?.viewport || null;
}
emulatedSize(): EmulatedSize | null {
if (this._emulatedSize)
return this._emulatedSize;
const contextOptions = this._browserContext._options;
return contextOptions.viewport ? { viewport: contextOptions.viewport, screen: contextOptions.screen || contextOptions.viewport } : null;
}
async bringToFront(): Promise<void> {
@ -604,10 +618,14 @@ export class Page extends SdkObject {
}
async setFileChooserIntercepted(enabled: boolean): Promise<void> {
this._state.interceptFileChooser = enabled;
this._interceptFileChooser = enabled;
await this._delegate.updateFileChooserInterception(enabled);
}
fileChooserIntercepted() {
return this._interceptFileChooser;
}
frameNavigatedToNewDocument(frame: frames.Frame) {
this.emit(Page.Events.InternalFrameNavigatedToNewDocument, frame);
const url = frame.url();

View File

@ -106,7 +106,7 @@ export class WKPage implements PageDelegate {
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
opener._nextWindowOpenPopupFeatures = undefined;
if (viewportSize)
this._page._state.emulatedSize = { viewport: viewportSize, screen: viewportSize };
this._page._emulatedSize = { viewport: viewportSize, screen: viewportSize };
}
}
@ -194,18 +194,20 @@ export class WKPage implements PageDelegate {
const contextOptions = this._browserContext._options;
if (contextOptions.userAgent)
promises.push(session.send('Page.overrideUserAgent', { value: contextOptions.userAgent }));
if (this._page._state.mediaType || this._page._state.colorScheme || this._page._state.reducedMotion)
promises.push(WKPage._setEmulateMedia(session, this._page._state.mediaType, this._page._state.colorScheme, this._page._state.reducedMotion));
const emulatedMedia = this._page.emulatedMedia();
if (emulatedMedia.media || emulatedMedia.colorScheme || emulatedMedia.reducedMotion)
promises.push(WKPage._setEmulateMedia(session, emulatedMedia.media, emulatedMedia.colorScheme, emulatedMedia.reducedMotion));
const bootstrapScript = this._calculateBootstrapScript();
if (bootstrapScript.length)
promises.push(session.send('Page.setBootstrapScript', { source: bootstrapScript }));
this._page.frames().map(frame => frame.evaluateExpression(bootstrapScript, false, undefined).catch(e => {}));
if (contextOptions.bypassCSP)
promises.push(session.send('Page.setBypassCSP', { enabled: true }));
if (this._page._state.emulatedSize) {
const emulatedSize = this._page.emulatedSize();
if (emulatedSize) {
promises.push(session.send('Page.setScreenSizeOverride', {
width: this._page._state.emulatedSize.screen.width,
height: this._page._state.emulatedSize.screen.height,
width: emulatedSize.screen.width,
height: emulatedSize.screen.height,
}));
}
promises.push(this.updateEmulateMedia());
@ -217,7 +219,7 @@ export class WKPage implements PageDelegate {
promises.push(session.send('Page.setTimeZone', { timeZone: contextOptions.timezoneId }).
catch(e => { throw new Error(`Invalid timezone ID: ${contextOptions.timezoneId}`); }));
}
if (this._page._state.interceptFileChooser)
if (this._page.fileChooserIntercepted())
promises.push(session.send('Page.setInterceptFileChooserDialog', { enabled: true }));
promises.push(session.send('Page.overrideSetting', { setting: 'DeviceOrientationEventEnabled' as any, value: contextOptions.isMobile }));
promises.push(session.send('Page.overrideSetting', { setting: 'FullScreenEnabled' as any, value: !contextOptions.isMobile }));
@ -658,20 +660,20 @@ export class WKPage implements PageDelegate {
const locale = this._browserContext._options.locale;
const headers = network.mergeHeaders([
this._browserContext._options.extraHTTPHeaders,
this._page._state.extraHTTPHeaders,
this._page.extraHTTPHeaders(),
locale ? network.singleHeader('Accept-Language', locale) : undefined,
]);
return headers;
}
async updateEmulateMedia(): Promise<void> {
const colorScheme = this._page._state.colorScheme;
const reducedMotion = this._page._state.reducedMotion;
await this._forAllSessions(session => WKPage._setEmulateMedia(session, this._page._state.mediaType, colorScheme, reducedMotion));
const emulatedMedia = this._page.emulatedMedia();
const colorScheme = emulatedMedia.colorScheme;
const reducedMotion = emulatedMedia.reducedMotion;
await this._forAllSessions(session => WKPage._setEmulateMedia(session, emulatedMedia.media, colorScheme, reducedMotion));
}
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
assert(this._page._state.emulatedSize === emulatedSize);
async updateEmulatedViewportSize(): Promise<void> {
await this._updateViewport();
}
@ -683,7 +685,7 @@ export class WKPage implements PageDelegate {
async _updateViewport(): Promise<void> {
const options = this._browserContext._options;
const deviceSize = this._page._state.emulatedSize;
const deviceSize = this._page.emulatedSize();
if (deviceSize === null)
return;
const viewportSize = deviceSize.viewport;
@ -725,7 +727,7 @@ export class WKPage implements PageDelegate {
}
async updateFileChooserInterception() {
const enabled = this._page._state.interceptFileChooser;
const enabled = this._page.fileChooserIntercepted();
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
}