fix: apply viewport emulation to prerender targets (#10804)
This commit is contained in:
parent
cb5ab7e02f
commit
14f0ab7397
@ -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?: {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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"],
|
||||||
|
@ -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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user