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 {isErrorLike} from '../util/ErrorLike.js';
import {CDPSession} from './Connection.js';
import {CDPSession, CDPSessionEmittedEvents} from './Connection.js';
import {Viewport} from './PuppeteerViewport.js';
/**
@ -31,12 +31,24 @@ export class EmulationManager {
#hasTouch = false;
#javascriptEnabled = true;
#viewport?: Viewport;
#secondaryClients = new Set<CDPSession>();
constructor(client: CDPSession) {
this.#client = client;
}
updateClient(client: CDPSession): void {
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 {
@ -44,6 +56,33 @@ export class EmulationManager {
}
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 width = viewport.width;
const height = viewport.height;
@ -55,23 +94,17 @@ export class EmulationManager {
const hasTouch = viewport.hasTouch || false;
await Promise.all([
this.#client.send('Emulation.setDeviceMetricsOverride', {
client.send('Emulation.setDeviceMetricsOverride', {
mobile,
width,
height,
deviceScaleFactor,
screenOrientation,
}),
this.#client.send('Emulation.setTouchEmulationEnabled', {
client.send('Emulation.setTouchEmulationEnabled', {
enabled: hasTouch,
}),
]);
const reloadNeeded =
this.#emulatingMobile !== mobile || this.#hasTouch !== hasTouch;
this.#emulatingMobile = mobile;
this.#hasTouch = hasTouch;
return reloadNeeded;
}
async emulateIdleState(overrides?: {

View File

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

View File

@ -3911,6 +3911,12 @@
"parameters": ["firefox", "webDriverBiDi"],
"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",
"platforms": ["darwin", "linux", "win32"],

View File

@ -129,4 +129,33 @@ describe('Prerender', function () {
).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,
});
});
});
});