fix: apply viewport emulation to prerender targets (#10804)

This commit is contained in:
Alex Rudenko 2023-08-30 11:04:28 +02:00 committed by GitHub
parent cb5ab7e02f
commit 14f0ab7397
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 9 deletions

View File

@ -19,7 +19,7 @@ import {GeolocationOptions, MediaFeature} from '../api/Page.js';
import {assert} from '../util/assert.js'; import {assert} from '../util/assert.js';
import {isErrorLike} from '../util/ErrorLike.js'; import {isErrorLike} from '../util/ErrorLike.js';
import {CDPSession} from './Connection.js'; import {CDPSession, CDPSessionEmittedEvents} from './Connection.js';
import {Viewport} from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
/** /**
@ -31,12 +31,24 @@ export class EmulationManager {
#hasTouch = false; #hasTouch = false;
#javascriptEnabled = true; #javascriptEnabled = true;
#viewport?: Viewport;
#secondaryClients = new Set<CDPSession>();
constructor(client: CDPSession) { constructor(client: CDPSession) {
this.#client = client; this.#client = client;
} }
updateClient(client: CDPSession): void { updateClient(client: CDPSession): void {
this.#client = client; this.#client = client;
this.#secondaryClients.delete(client);
}
async registerSecondaryPage(client: CDPSession): Promise<void> {
this.#secondaryClients.add(client);
await this.#applyViewport(client);
client.once(CDPSessionEmittedEvents.Disconnected, () => {
return this.#secondaryClients.delete(client);
});
} }
get javascriptEnabled(): boolean { get javascriptEnabled(): boolean {
@ -44,6 +56,33 @@ export class EmulationManager {
} }
async emulateViewport(viewport: Viewport): Promise<boolean> { async emulateViewport(viewport: Viewport): Promise<boolean> {
this.#viewport = viewport;
await this.#applyViewport(this.#client);
const mobile = viewport.isMobile || false;
const hasTouch = viewport.hasTouch || false;
const reloadNeeded =
this.#emulatingMobile !== mobile || this.#hasTouch !== hasTouch;
this.#emulatingMobile = mobile;
this.#hasTouch = hasTouch;
if (!reloadNeeded) {
// If the page will be reloaded, no need to adjust secondary clients.
await Promise.all(
Array.from(this.#secondaryClients).map(client => {
return this.#applyViewport(client);
})
);
}
return reloadNeeded;
}
async #applyViewport(client: CDPSession): Promise<void> {
const viewport = this.#viewport;
if (!viewport) {
return;
}
const mobile = viewport.isMobile || false; const mobile = viewport.isMobile || false;
const width = viewport.width; const width = viewport.width;
const height = viewport.height; const height = viewport.height;
@ -55,23 +94,17 @@ export class EmulationManager {
const hasTouch = viewport.hasTouch || false; const hasTouch = viewport.hasTouch || false;
await Promise.all([ await Promise.all([
this.#client.send('Emulation.setDeviceMetricsOverride', { client.send('Emulation.setDeviceMetricsOverride', {
mobile, mobile,
width, width,
height, height,
deviceScaleFactor, deviceScaleFactor,
screenOrientation, screenOrientation,
}), }),
this.#client.send('Emulation.setTouchEmulationEnabled', { client.send('Emulation.setTouchEmulationEnabled', {
enabled: hasTouch, enabled: hasTouch,
}), }),
]); ]);
const reloadNeeded =
this.#emulatingMobile !== mobile || this.#hasTouch !== hasTouch;
this.#emulatingMobile = mobile;
this.#hasTouch = hasTouch;
return reloadNeeded;
} }
async emulateIdleState(overrides?: { async emulateIdleState(overrides?: {

View File

@ -336,6 +336,7 @@ export class CDPPage extends Page {
return; return;
} }
this.#frameManager.registerSecondaryPage(session).catch(debugError); this.#frameManager.registerSecondaryPage(session).catch(debugError);
this.#emulationManager.registerSecondaryPage(session).catch(debugError);
} }
); );
} }

View File

@ -3911,6 +3911,12 @@
"parameters": ["firefox", "webDriverBiDi"], "parameters": ["firefox", "webDriverBiDi"],
"expectations": ["SKIP"] "expectations": ["SKIP"]
}, },
{
"testIdPattern": "[prerender.spec] Prerender with emulation can configure viewport for prerendered pages",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["SKIP"]
},
{ {
"testIdPattern": "[prerender.spec] Prerender with network requests can receive requests from the prerendered page", "testIdPattern": "[prerender.spec] Prerender with network requests can receive requests from the prerendered page",
"platforms": ["darwin", "linux", "win32"], "platforms": ["darwin", "linux", "win32"],

View File

@ -129,4 +129,33 @@ describe('Prerender', function () {
).toBeTruthy(); ).toBeTruthy();
}); });
}); });
describe('with emulation', () => {
it('can configure viewport for prerendered pages', async () => {
const {page, server} = await getTestState();
await page.setViewport({
width: 300,
height: 400,
});
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
await button?.click();
const link = await page.waitForSelector('a');
await Promise.all([page.waitForNavigation(), link?.click()]);
const result = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
dpr: window.devicePixelRatio,
};
});
expect({
width: result.width,
height: result.height,
}).toStrictEqual({
width: 300 * result.dpr,
height: 400 * result.dpr,
});
});
});
}); });