mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(size): emulate window.screen size (#5967)
This commit is contained in:
parent
8c6822bd32
commit
f1c0d09765
@ -216,7 +216,18 @@ Toggles bypassing page's Content-Security-Policy.
|
|||||||
- `width` <[int]> page width in pixels.
|
- `width` <[int]> page width in pixels.
|
||||||
- `height` <[int]> page height in pixels.
|
- `height` <[int]> page height in pixels.
|
||||||
|
|
||||||
Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||||
|
|
||||||
|
## context-option-screen
|
||||||
|
* langs:
|
||||||
|
- alias-java: screenSize
|
||||||
|
- alias-csharp: screenSize
|
||||||
|
- `screen` <[Object]>
|
||||||
|
- `width` <[int]> page width in pixels.
|
||||||
|
- `height` <[int]> page height in pixels.
|
||||||
|
|
||||||
|
Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the
|
||||||
|
[`option: viewport`] is set.
|
||||||
|
|
||||||
## evaluate-expression
|
## evaluate-expression
|
||||||
- `expression` <[string]>
|
- `expression` <[string]>
|
||||||
@ -546,6 +557,7 @@ is considered matching if all specified properties match.
|
|||||||
- %%-context-option-bypasscsp-%%
|
- %%-context-option-bypasscsp-%%
|
||||||
- %%-context-option-viewport-%%
|
- %%-context-option-viewport-%%
|
||||||
- %%-python-context-option-viewport-%%
|
- %%-python-context-option-viewport-%%
|
||||||
|
- %%-context-option-screen-%%
|
||||||
- %%-python-context-option-no-viewport-%%
|
- %%-python-context-option-no-viewport-%%
|
||||||
- %%-context-option-useragent-%%
|
- %%-context-option-useragent-%%
|
||||||
- %%-context-option-devicescalefactor-%%
|
- %%-context-option-devicescalefactor-%%
|
||||||
|
|||||||
@ -166,6 +166,10 @@ export type PlaywrightInitializer = {
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
},
|
},
|
||||||
|
screen?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
deviceScaleFactor: number,
|
deviceScaleFactor: number,
|
||||||
isMobile: boolean,
|
isMobile: boolean,
|
||||||
hasTouch: boolean,
|
hasTouch: boolean,
|
||||||
@ -294,6 +298,10 @@ export type BrowserTypeLaunchPersistentContextParams = {
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
},
|
},
|
||||||
|
screen?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
ignoreHTTPSErrors?: boolean,
|
ignoreHTTPSErrors?: boolean,
|
||||||
javaScriptEnabled?: boolean,
|
javaScriptEnabled?: boolean,
|
||||||
bypassCSP?: boolean,
|
bypassCSP?: boolean,
|
||||||
@ -359,6 +367,10 @@ export type BrowserTypeLaunchPersistentContextOptions = {
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
},
|
},
|
||||||
|
screen?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
ignoreHTTPSErrors?: boolean,
|
ignoreHTTPSErrors?: boolean,
|
||||||
javaScriptEnabled?: boolean,
|
javaScriptEnabled?: boolean,
|
||||||
bypassCSP?: boolean,
|
bypassCSP?: boolean,
|
||||||
@ -439,6 +451,10 @@ export type BrowserNewContextParams = {
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
},
|
},
|
||||||
|
screen?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
ignoreHTTPSErrors?: boolean,
|
ignoreHTTPSErrors?: boolean,
|
||||||
javaScriptEnabled?: boolean,
|
javaScriptEnabled?: boolean,
|
||||||
bypassCSP?: boolean,
|
bypassCSP?: boolean,
|
||||||
@ -492,6 +508,10 @@ export type BrowserNewContextOptions = {
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
},
|
},
|
||||||
|
screen?: {
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
},
|
||||||
ignoreHTTPSErrors?: boolean,
|
ignoreHTTPSErrors?: boolean,
|
||||||
javaScriptEnabled?: boolean,
|
javaScriptEnabled?: boolean,
|
||||||
bypassCSP?: boolean,
|
bypassCSP?: boolean,
|
||||||
|
|||||||
@ -275,6 +275,11 @@ ContextOptions:
|
|||||||
properties:
|
properties:
|
||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
|
screen:
|
||||||
|
type: object?
|
||||||
|
properties:
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
ignoreHTTPSErrors: boolean?
|
ignoreHTTPSErrors: boolean?
|
||||||
javaScriptEnabled: boolean?
|
javaScriptEnabled: boolean?
|
||||||
bypassCSP: boolean?
|
bypassCSP: boolean?
|
||||||
@ -351,6 +356,11 @@ Playwright:
|
|||||||
properties:
|
properties:
|
||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
|
screen:
|
||||||
|
type: object?
|
||||||
|
properties:
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
deviceScaleFactor: number
|
deviceScaleFactor: number
|
||||||
isMobile: boolean
|
isMobile: boolean
|
||||||
hasTouch: boolean
|
hasTouch: boolean
|
||||||
|
|||||||
@ -204,6 +204,10 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
width: tNumber,
|
width: tNumber,
|
||||||
height: tNumber,
|
height: tNumber,
|
||||||
})),
|
})),
|
||||||
|
screen: tOptional(tObject({
|
||||||
|
width: tNumber,
|
||||||
|
height: tNumber,
|
||||||
|
})),
|
||||||
ignoreHTTPSErrors: tOptional(tBoolean),
|
ignoreHTTPSErrors: tOptional(tBoolean),
|
||||||
javaScriptEnabled: tOptional(tBoolean),
|
javaScriptEnabled: tOptional(tBoolean),
|
||||||
bypassCSP: tOptional(tBoolean),
|
bypassCSP: tOptional(tBoolean),
|
||||||
@ -257,6 +261,10 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
|||||||
width: tNumber,
|
width: tNumber,
|
||||||
height: tNumber,
|
height: tNumber,
|
||||||
})),
|
})),
|
||||||
|
screen: tOptional(tObject({
|
||||||
|
width: tNumber,
|
||||||
|
height: tNumber,
|
||||||
|
})),
|
||||||
ignoreHTTPSErrors: tOptional(tBoolean),
|
ignoreHTTPSErrors: tOptional(tBoolean),
|
||||||
javaScriptEnabled: tOptional(tBoolean),
|
javaScriptEnabled: tOptional(tBoolean),
|
||||||
bypassCSP: tOptional(tBoolean),
|
bypassCSP: tOptional(tBoolean),
|
||||||
|
|||||||
@ -87,7 +87,7 @@ export class CRPage implements PageDelegate {
|
|||||||
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
|
const features = opener._nextWindowOpenPopupFeatures.shift() || [];
|
||||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
|
const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
|
||||||
if (viewportSize)
|
if (viewportSize)
|
||||||
this._page._state.viewportSize = viewportSize;
|
this._page._state.emulatedSize = { viewport: viewportSize, screen: viewportSize };
|
||||||
}
|
}
|
||||||
this._pagePromise = this._mainFrameSession._initialize(hasUIWindow).then(() => this._initializedPage = this._page).catch(e => e);
|
this._pagePromise = this._mainFrameSession._initialize(hasUIWindow).then(() => this._initializedPage = this._page).catch(e => e);
|
||||||
}
|
}
|
||||||
@ -162,8 +162,8 @@ export class CRPage implements PageDelegate {
|
|||||||
await this._forAllFrameSessions(frame => frame._updateHttpCredentials(false));
|
await this._forAllFrameSessions(frame => frame._updateHttpCredentials(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
|
||||||
assert(this._page._state.viewportSize === viewportSize);
|
assert(this._page._state.emulatedSize === emulatedSize);
|
||||||
await this._mainFrameSession._updateViewport();
|
await this._mainFrameSession._updateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,17 +899,19 @@ class FrameSession {
|
|||||||
return;
|
return;
|
||||||
assert(this._isMainFrame());
|
assert(this._isMainFrame());
|
||||||
const options = this._crPage._browserContext._options;
|
const options = this._crPage._browserContext._options;
|
||||||
const viewportSize = this._page._state.viewportSize;
|
const emulatedSize = this._page._state.emulatedSize;
|
||||||
if (viewportSize === null)
|
if (emulatedSize === null)
|
||||||
return;
|
return;
|
||||||
|
const viewportSize = emulatedSize.viewport;
|
||||||
|
const screenSize = emulatedSize.screen;
|
||||||
const isLandscape = viewportSize.width > viewportSize.height;
|
const isLandscape = viewportSize.width > viewportSize.height;
|
||||||
const promises = [
|
const promises = [
|
||||||
this._client.send('Emulation.setDeviceMetricsOverride', {
|
this._client.send('Emulation.setDeviceMetricsOverride', {
|
||||||
mobile: !!options.isMobile,
|
mobile: !!options.isMobile,
|
||||||
width: viewportSize.width,
|
width: viewportSize.width,
|
||||||
height: viewportSize.height,
|
height: viewportSize.height,
|
||||||
screenWidth: viewportSize.width,
|
screenWidth: screenSize.width,
|
||||||
screenHeight: viewportSize.height,
|
screenHeight: screenSize.height,
|
||||||
deviceScaleFactor: options.deviceScaleFactor || 1,
|
deviceScaleFactor: options.deviceScaleFactor || 1,
|
||||||
screenOrientation: isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' },
|
screenOrientation: isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' },
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -439,10 +439,14 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11': {
|
'iPhone 11': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
'viewport': {
|
'screen': {
|
||||||
'width': 414,
|
'width': 414,
|
||||||
'height': 896
|
'height': 896
|
||||||
},
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 414,
|
||||||
|
'height': 715
|
||||||
|
},
|
||||||
'deviceScaleFactor': 2,
|
'deviceScaleFactor': 2,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
'hasTouch': true,
|
'hasTouch': true,
|
||||||
@ -450,9 +454,13 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11 landscape': {
|
'iPhone 11 landscape': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 414,
|
||||||
|
'height': 896
|
||||||
|
},
|
||||||
'viewport': {
|
'viewport': {
|
||||||
'width': 896,
|
'width': 800,
|
||||||
'height': 414
|
'height': 364
|
||||||
},
|
},
|
||||||
'deviceScaleFactor': 2,
|
'deviceScaleFactor': 2,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
@ -461,10 +469,14 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11 Pro': {
|
'iPhone 11 Pro': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
'viewport': {
|
'screen': {
|
||||||
'width': 375,
|
'width': 375,
|
||||||
'height': 812
|
'height': 812
|
||||||
},
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 375,
|
||||||
|
'height': 635
|
||||||
|
},
|
||||||
'deviceScaleFactor': 3,
|
'deviceScaleFactor': 3,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
'hasTouch': true,
|
'hasTouch': true,
|
||||||
@ -472,9 +484,13 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11 Pro landscape': {
|
'iPhone 11 Pro landscape': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 375,
|
||||||
|
'height': 812
|
||||||
|
},
|
||||||
'viewport': {
|
'viewport': {
|
||||||
'width': 812,
|
'width': 724,
|
||||||
'height': 375
|
'height': 325
|
||||||
},
|
},
|
||||||
'deviceScaleFactor': 3,
|
'deviceScaleFactor': 3,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
@ -483,10 +499,14 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11 Pro Max': {
|
'iPhone 11 Pro Max': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
'viewport': {
|
'screen': {
|
||||||
'width': 414,
|
'width': 414,
|
||||||
'height': 896
|
'height': 896
|
||||||
},
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 414,
|
||||||
|
'height': 715
|
||||||
|
},
|
||||||
'deviceScaleFactor': 3,
|
'deviceScaleFactor': 3,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
'hasTouch': true,
|
'hasTouch': true,
|
||||||
@ -494,9 +514,103 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'iPhone 11 Pro Max landscape': {
|
'iPhone 11 Pro Max landscape': {
|
||||||
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 414,
|
||||||
|
'height': 896
|
||||||
|
},
|
||||||
'viewport': {
|
'viewport': {
|
||||||
'width': 896,
|
'width': 808,
|
||||||
'height': 414
|
'height': 364
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 844
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 664
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12 landscape': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 844
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 750,
|
||||||
|
'height': 340
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12 Pro': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 844
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 664
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12 Pro landscape': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 390,
|
||||||
|
'height': 844
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 750,
|
||||||
|
'height': 340
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12 Pro Max': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 428,
|
||||||
|
'height': 926
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 428,
|
||||||
|
'height': 746
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 3,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'webkit'
|
||||||
|
},
|
||||||
|
'iPhone 12 Pro Max landscape': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1',
|
||||||
|
'screen': {
|
||||||
|
'width': 428,
|
||||||
|
'height': 926
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 832,
|
||||||
|
'height': 378
|
||||||
},
|
},
|
||||||
'deviceScaleFactor': 3,
|
'deviceScaleFactor': 3,
|
||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
@ -854,5 +968,65 @@ module.exports = {
|
|||||||
'isMobile': true,
|
'isMobile': true,
|
||||||
'hasTouch': true,
|
'hasTouch': true,
|
||||||
'defaultBrowserType': 'chromium'
|
'defaultBrowserType': 'chromium'
|
||||||
}
|
},
|
||||||
|
'Pixel 4a (5G)': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
|
||||||
|
'screen': {
|
||||||
|
'width': 412,
|
||||||
|
'height': 892
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 412,
|
||||||
|
'height': 765
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 2.63,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'chromium'
|
||||||
|
},
|
||||||
|
'Pixel 4a (5G) landscape': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (Linux; Android 11; Pixel 4a (5G)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
|
||||||
|
'screen': {
|
||||||
|
'height': 892,
|
||||||
|
'width': 412
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 840,
|
||||||
|
'height': 312
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 2.63,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'chromium'
|
||||||
|
},
|
||||||
|
'Pixel 5': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
|
||||||
|
'screen': {
|
||||||
|
'width': 393,
|
||||||
|
'height': 851
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 393,
|
||||||
|
'height': 727
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 2.75,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'chromium'
|
||||||
|
},
|
||||||
|
'Pixel 5 landscape': {
|
||||||
|
'userAgent': 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.105 Mobile Safari/537.36',
|
||||||
|
'screen': {
|
||||||
|
'width': 851,
|
||||||
|
'height': 393
|
||||||
|
},
|
||||||
|
'viewport': {
|
||||||
|
'width': 802,
|
||||||
|
'height': 293
|
||||||
|
},
|
||||||
|
'deviceScaleFactor': 2.75,
|
||||||
|
'isMobile': true,
|
||||||
|
'hasTouch': true,
|
||||||
|
'defaultBrowserType': 'chromium'
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -315,12 +315,12 @@ export class FFPage implements PageDelegate {
|
|||||||
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page._state.extraHTTPHeaders || [] });
|
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page._state.extraHTTPHeaders || [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
|
||||||
assert(this._page._state.viewportSize === viewportSize);
|
assert(this._page._state.emulatedSize === emulatedSize);
|
||||||
await this._session.send('Page.setViewportSize', {
|
await this._session.send('Page.setViewportSize', {
|
||||||
viewportSize: {
|
viewportSize: {
|
||||||
width: viewportSize.width,
|
width: emulatedSize.viewport.width,
|
||||||
height: viewportSize.height,
|
height: emulatedSize.viewport.height,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ export interface PageDelegate {
|
|||||||
navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>;
|
navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>;
|
||||||
|
|
||||||
updateExtraHTTPHeaders(): Promise<void>;
|
updateExtraHTTPHeaders(): Promise<void>;
|
||||||
setViewportSize(viewportSize: types.Size): Promise<void>;
|
setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void>;
|
||||||
updateEmulateMedia(): Promise<void>;
|
updateEmulateMedia(): Promise<void>;
|
||||||
updateRequestInterception(): Promise<void>;
|
updateRequestInterception(): Promise<void>;
|
||||||
setFileChooserIntercepted(enabled: boolean): Promise<void>;
|
setFileChooserIntercepted(enabled: boolean): Promise<void>;
|
||||||
@ -86,7 +86,7 @@ export interface PageDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PageState = {
|
type PageState = {
|
||||||
viewportSize: types.Size | null;
|
emulatedSize: { screen: types.Size, viewport: types.Size } | null;
|
||||||
mediaType: types.MediaType | null;
|
mediaType: types.MediaType | null;
|
||||||
colorScheme: types.ColorScheme | null;
|
colorScheme: types.ColorScheme | null;
|
||||||
extraHTTPHeaders: types.HeadersArray | null;
|
extraHTTPHeaders: types.HeadersArray | null;
|
||||||
@ -163,7 +163,7 @@ export class Page extends SdkObject {
|
|||||||
this._crashedPromise = new Promise(f => this._crashedCallback = f);
|
this._crashedPromise = new Promise(f => this._crashedCallback = f);
|
||||||
this._browserContext = browserContext;
|
this._browserContext = browserContext;
|
||||||
this._state = {
|
this._state = {
|
||||||
viewportSize: browserContext._options.viewport || null,
|
emulatedSize: browserContext._options.viewport ? { viewport: browserContext._options.viewport, screen: browserContext._options.screen || browserContext._options.viewport } : null,
|
||||||
mediaType: null,
|
mediaType: null,
|
||||||
colorScheme: null,
|
colorScheme: null,
|
||||||
extraHTTPHeaders: null,
|
extraHTTPHeaders: null,
|
||||||
@ -369,13 +369,13 @@ export class Page extends SdkObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size) {
|
async setViewportSize(viewportSize: types.Size) {
|
||||||
this._state.viewportSize = { ...viewportSize };
|
this._state.emulatedSize = { viewport: { ...viewportSize }, screen: { ...viewportSize } };
|
||||||
await this._delegate.setViewportSize(this._state.viewportSize);
|
await this._delegate.setEmulatedSize(this._state.emulatedSize);
|
||||||
await this._doSlowMo();
|
await this._doSlowMo();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportSize(): types.Size | null {
|
viewportSize(): types.Size | null {
|
||||||
return this._state.viewportSize;
|
return this._state.emulatedSize?.viewport || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async bringToFront(): Promise<void> {
|
async bringToFront(): Promise<void> {
|
||||||
|
|||||||
@ -214,9 +214,12 @@ export type SetNetworkCookieParam = {
|
|||||||
sameSite?: 'Strict' | 'Lax' | 'None'
|
sameSite?: 'Strict' | 'Lax' | 'None'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type EmulatedSize = { viewport: Size, screen: Size };
|
||||||
|
|
||||||
export type BrowserContextOptions = {
|
export type BrowserContextOptions = {
|
||||||
sdkLanguage: string,
|
sdkLanguage: string,
|
||||||
viewport?: Size,
|
viewport?: Size,
|
||||||
|
screen?: Size,
|
||||||
noDefaultViewport?: boolean,
|
noDefaultViewport?: boolean,
|
||||||
ignoreHTTPSErrors?: boolean,
|
ignoreHTTPSErrors?: boolean,
|
||||||
javaScriptEnabled?: boolean,
|
javaScriptEnabled?: boolean,
|
||||||
|
|||||||
@ -97,7 +97,7 @@ export class WKPage implements PageDelegate {
|
|||||||
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
|
const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
|
||||||
opener._nextWindowOpenPopupFeatures = undefined;
|
opener._nextWindowOpenPopupFeatures = undefined;
|
||||||
if (viewportSize)
|
if (viewportSize)
|
||||||
this._page._state.viewportSize = viewportSize;
|
this._page._state.emulatedSize = { viewport: viewportSize, screen: viewportSize };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,10 +181,10 @@ export class WKPage implements PageDelegate {
|
|||||||
this._page.frames().map(frame => frame.evaluateExpression(bootstrapScript, false, undefined, 'main').catch(e => {}));
|
this._page.frames().map(frame => frame.evaluateExpression(bootstrapScript, false, undefined, 'main').catch(e => {}));
|
||||||
if (contextOptions.bypassCSP)
|
if (contextOptions.bypassCSP)
|
||||||
promises.push(session.send('Page.setBypassCSP', { enabled: true }));
|
promises.push(session.send('Page.setBypassCSP', { enabled: true }));
|
||||||
if (this._page._state.viewportSize) {
|
if (this._page._state.emulatedSize) {
|
||||||
promises.push(session.send('Page.setScreenSizeOverride', {
|
promises.push(session.send('Page.setScreenSizeOverride', {
|
||||||
width: this._page._state.viewportSize.width,
|
width: this._page._state.emulatedSize.screen.width,
|
||||||
height: this._page._state.viewportSize.height,
|
height: this._page._state.emulatedSize.screen.height,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
promises.push(this.updateEmulateMedia());
|
promises.push(this.updateEmulateMedia());
|
||||||
@ -603,8 +603,8 @@ export class WKPage implements PageDelegate {
|
|||||||
await this._forAllSessions(session => WKPage._setEmulateMedia(session, this._page._state.mediaType, colorScheme));
|
await this._forAllSessions(session => WKPage._setEmulateMedia(session, this._page._state.mediaType, colorScheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
|
||||||
assert(this._page._state.viewportSize === viewportSize);
|
assert(this._page._state.emulatedSize === emulatedSize);
|
||||||
await this._updateViewport();
|
await this._updateViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,9 +616,11 @@ export class WKPage implements PageDelegate {
|
|||||||
|
|
||||||
async _updateViewport(): Promise<void> {
|
async _updateViewport(): Promise<void> {
|
||||||
const options = this._browserContext._options;
|
const options = this._browserContext._options;
|
||||||
const viewportSize = this._page._state.viewportSize;
|
const deviceSize = this._page._state.emulatedSize;
|
||||||
if (viewportSize === null)
|
if (deviceSize === null)
|
||||||
return;
|
return;
|
||||||
|
const viewportSize = deviceSize.viewport;
|
||||||
|
const screenSize = deviceSize.screen;
|
||||||
const promises: Promise<any>[] = [
|
const promises: Promise<any>[] = [
|
||||||
this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {
|
this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {
|
||||||
width: viewportSize.width,
|
width: viewportSize.width,
|
||||||
@ -627,8 +629,8 @@ export class WKPage implements PageDelegate {
|
|||||||
deviceScaleFactor: options.deviceScaleFactor || 1
|
deviceScaleFactor: options.deviceScaleFactor || 1
|
||||||
}),
|
}),
|
||||||
this._session.send('Page.setScreenSizeOverride', {
|
this._session.send('Page.setScreenSizeOverride', {
|
||||||
width: viewportSize.width,
|
width: screenSize.width,
|
||||||
height: viewportSize.height,
|
height: screenSize.height,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
if (options.isMobile) {
|
if (options.isMobile) {
|
||||||
|
|||||||
@ -114,4 +114,47 @@ describe('device', (suite, { browserName }) => {
|
|||||||
await context.close();
|
await context.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should emulate viewport and screen size', async ({server, contextFactory, playwright, contextOptions}) => {
|
||||||
|
const device = playwright.devices['iPhone 12'];
|
||||||
|
const context = await contextFactory({
|
||||||
|
...contextOptions,
|
||||||
|
...device,
|
||||||
|
});
|
||||||
|
const page = await context.newPage();
|
||||||
|
await page.setContent(`<meta name="viewport" content="width=device-width, user-scalable=no" />`);
|
||||||
|
|
||||||
|
expect(await page.evaluate(() => ({
|
||||||
|
width: window.screen.width,
|
||||||
|
height: window.screen.height
|
||||||
|
}))).toEqual({ width: 390, height: 844 });
|
||||||
|
|
||||||
|
expect(await page.evaluate(() => ({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight
|
||||||
|
}))).toEqual({ width: 390, height: 664 });
|
||||||
|
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emulate viewport without screen size', async ({server, contextFactory, playwright, contextOptions}) => {
|
||||||
|
const device = playwright.devices['iPhone 6'];
|
||||||
|
const context = await contextFactory({
|
||||||
|
...contextOptions,
|
||||||
|
...device,
|
||||||
|
});
|
||||||
|
const page = await context.newPage();
|
||||||
|
await page.setContent(`<meta name="viewport" content="width=device-width, user-scalable=no" />`);
|
||||||
|
|
||||||
|
expect(await page.evaluate(() => ({
|
||||||
|
width: window.screen.width,
|
||||||
|
height: window.screen.height
|
||||||
|
}))).toEqual({ width: 375, height: 667 });
|
||||||
|
|
||||||
|
expect(await page.evaluate(() => ({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight
|
||||||
|
}))).toEqual({ width: 375, height: 667 });
|
||||||
|
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -69,7 +69,7 @@ it('should print the correct context options when using a device and additional
|
|||||||
const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||||
.setColorScheme(ColorScheme.LIGHT)
|
.setColorScheme(ColorScheme.LIGHT)
|
||||||
.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1")
|
.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1")
|
||||||
.setViewportSize(414, 896)
|
.setViewportSize(414, 715)
|
||||||
.setDeviceScaleFactor(2)
|
.setDeviceScaleFactor(2)
|
||||||
.setIsMobile(true)
|
.setIsMobile(true)
|
||||||
.setHasTouch(true));`;
|
.setHasTouch(true));`;
|
||||||
|
|||||||
82
types/types.d.ts
vendored
82
types/types.d.ts
vendored
@ -6576,6 +6576,22 @@ export interface BrowserType<Browser> {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport`
|
||||||
|
* is set.
|
||||||
|
*/
|
||||||
|
screen?: {
|
||||||
|
/**
|
||||||
|
* page width in pixels.
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* page height in pixels.
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||||
* Defaults to 0.
|
* Defaults to 0.
|
||||||
@ -6623,7 +6639,7 @@ export interface BrowserType<Browser> {
|
|||||||
videosPath?: string;
|
videosPath?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||||
*/
|
*/
|
||||||
viewport?: null|{
|
viewport?: null|{
|
||||||
/**
|
/**
|
||||||
@ -7666,6 +7682,22 @@ export interface AndroidDevice {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport`
|
||||||
|
* is set.
|
||||||
|
*/
|
||||||
|
screen?: {
|
||||||
|
/**
|
||||||
|
* page width in pixels.
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* page height in pixels.
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the timezone of the context. See
|
* Changes the timezone of the context. See
|
||||||
* [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1)
|
* [ICU's metaZones.txt](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1)
|
||||||
@ -7701,7 +7733,7 @@ export interface AndroidDevice {
|
|||||||
videosPath?: string;
|
videosPath?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||||
*/
|
*/
|
||||||
viewport?: null|{
|
viewport?: null|{
|
||||||
/**
|
/**
|
||||||
@ -8418,6 +8450,22 @@ export interface Browser extends EventEmitter {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport`
|
||||||
|
* is set.
|
||||||
|
*/
|
||||||
|
screen?: {
|
||||||
|
/**
|
||||||
|
* page width in pixels.
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* page height in pixels.
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||||
* obtained via
|
* obtained via
|
||||||
@ -8518,7 +8566,7 @@ export interface Browser extends EventEmitter {
|
|||||||
videosPath?: string;
|
videosPath?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||||
*/
|
*/
|
||||||
viewport?: null|{
|
viewport?: null|{
|
||||||
/**
|
/**
|
||||||
@ -10500,6 +10548,22 @@ export interface BrowserContextOptions {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates consistent window screen size available inside web page via `window.screen`. Is only used when the `viewport`
|
||||||
|
* is set.
|
||||||
|
*/
|
||||||
|
screen?: {
|
||||||
|
/**
|
||||||
|
* page width in pixels.
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* page height in pixels.
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||||
* obtained via
|
* obtained via
|
||||||
@ -10600,7 +10664,7 @@ export interface BrowserContextOptions {
|
|||||||
videosPath?: string;
|
videosPath?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. `null` disables the default viewport.
|
||||||
*/
|
*/
|
||||||
viewport?: null|ViewportSize;
|
viewport?: null|ViewportSize;
|
||||||
}
|
}
|
||||||
@ -10907,6 +10971,12 @@ type Devices = {
|
|||||||
"iPhone 11 Pro landscape": DeviceDescriptor;
|
"iPhone 11 Pro landscape": DeviceDescriptor;
|
||||||
"iPhone 11 Pro Max": DeviceDescriptor;
|
"iPhone 11 Pro Max": DeviceDescriptor;
|
||||||
"iPhone 11 Pro Max landscape": DeviceDescriptor;
|
"iPhone 11 Pro Max landscape": DeviceDescriptor;
|
||||||
|
"iPhone 12": DeviceDescriptor;
|
||||||
|
"iPhone 12 landscape": DeviceDescriptor;
|
||||||
|
"iPhone 12 Pro": DeviceDescriptor;
|
||||||
|
"iPhone 12 Pro landscape": DeviceDescriptor;
|
||||||
|
"iPhone 12 Pro Max": DeviceDescriptor;
|
||||||
|
"iPhone 12 Pro Max landscape": DeviceDescriptor;
|
||||||
"JioPhone 2": DeviceDescriptor;
|
"JioPhone 2": DeviceDescriptor;
|
||||||
"JioPhone 2 landscape": DeviceDescriptor;
|
"JioPhone 2 landscape": DeviceDescriptor;
|
||||||
"Kindle Fire HDX": DeviceDescriptor;
|
"Kindle Fire HDX": DeviceDescriptor;
|
||||||
@ -10939,5 +11009,9 @@ type Devices = {
|
|||||||
"Pixel 2 landscape": DeviceDescriptor;
|
"Pixel 2 landscape": DeviceDescriptor;
|
||||||
"Pixel 2 XL": DeviceDescriptor;
|
"Pixel 2 XL": DeviceDescriptor;
|
||||||
"Pixel 2 XL landscape": DeviceDescriptor;
|
"Pixel 2 XL landscape": DeviceDescriptor;
|
||||||
|
"Pixel 4a (5G)": DeviceDescriptor;
|
||||||
|
"Pixel 4a (5G) landscape": DeviceDescriptor;
|
||||||
|
"Pixel 5": DeviceDescriptor;
|
||||||
|
"Pixel 5 landscape": DeviceDescriptor;
|
||||||
[key: string]: DeviceDescriptor;
|
[key: string]: DeviceDescriptor;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user