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.
 | 
			
		||||
  - `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
 | 
			
		||||
- `expression` <[string]>
 | 
			
		||||
@ -546,6 +557,7 @@ is considered matching if all specified properties match.
 | 
			
		||||
- %%-context-option-bypasscsp-%%
 | 
			
		||||
- %%-context-option-viewport-%%
 | 
			
		||||
- %%-python-context-option-viewport-%%
 | 
			
		||||
- %%-context-option-screen-%%
 | 
			
		||||
- %%-python-context-option-no-viewport-%%
 | 
			
		||||
- %%-context-option-useragent-%%
 | 
			
		||||
- %%-context-option-devicescalefactor-%%
 | 
			
		||||
 | 
			
		||||
@ -166,6 +166,10 @@ export type PlaywrightInitializer = {
 | 
			
		||||
        width: number,
 | 
			
		||||
        height: number,
 | 
			
		||||
      },
 | 
			
		||||
      screen?: {
 | 
			
		||||
        width: number,
 | 
			
		||||
        height: number,
 | 
			
		||||
      },
 | 
			
		||||
      deviceScaleFactor: number,
 | 
			
		||||
      isMobile: boolean,
 | 
			
		||||
      hasTouch: boolean,
 | 
			
		||||
@ -294,6 +298,10 @@ export type BrowserTypeLaunchPersistentContextParams = {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  screen?: {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  ignoreHTTPSErrors?: boolean,
 | 
			
		||||
  javaScriptEnabled?: boolean,
 | 
			
		||||
  bypassCSP?: boolean,
 | 
			
		||||
@ -359,6 +367,10 @@ export type BrowserTypeLaunchPersistentContextOptions = {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  screen?: {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  ignoreHTTPSErrors?: boolean,
 | 
			
		||||
  javaScriptEnabled?: boolean,
 | 
			
		||||
  bypassCSP?: boolean,
 | 
			
		||||
@ -439,6 +451,10 @@ export type BrowserNewContextParams = {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  screen?: {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  ignoreHTTPSErrors?: boolean,
 | 
			
		||||
  javaScriptEnabled?: boolean,
 | 
			
		||||
  bypassCSP?: boolean,
 | 
			
		||||
@ -492,6 +508,10 @@ export type BrowserNewContextOptions = {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  screen?: {
 | 
			
		||||
    width: number,
 | 
			
		||||
    height: number,
 | 
			
		||||
  },
 | 
			
		||||
  ignoreHTTPSErrors?: boolean,
 | 
			
		||||
  javaScriptEnabled?: boolean,
 | 
			
		||||
  bypassCSP?: boolean,
 | 
			
		||||
 | 
			
		||||
@ -275,6 +275,11 @@ ContextOptions:
 | 
			
		||||
      properties:
 | 
			
		||||
        width: number
 | 
			
		||||
        height: number
 | 
			
		||||
    screen:
 | 
			
		||||
      type: object?
 | 
			
		||||
      properties:
 | 
			
		||||
        width: number
 | 
			
		||||
        height: number
 | 
			
		||||
    ignoreHTTPSErrors: boolean?
 | 
			
		||||
    javaScriptEnabled: boolean?
 | 
			
		||||
    bypassCSP: boolean?
 | 
			
		||||
@ -351,6 +356,11 @@ Playwright:
 | 
			
		||||
                properties:
 | 
			
		||||
                  width: number
 | 
			
		||||
                  height: number
 | 
			
		||||
              screen:
 | 
			
		||||
                type: object?
 | 
			
		||||
                properties:
 | 
			
		||||
                  width: number
 | 
			
		||||
                  height: number
 | 
			
		||||
              deviceScaleFactor: number
 | 
			
		||||
              isMobile: boolean
 | 
			
		||||
              hasTouch: boolean
 | 
			
		||||
 | 
			
		||||
@ -204,6 +204,10 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
 | 
			
		||||
      width: tNumber,
 | 
			
		||||
      height: tNumber,
 | 
			
		||||
    })),
 | 
			
		||||
    screen: tOptional(tObject({
 | 
			
		||||
      width: tNumber,
 | 
			
		||||
      height: tNumber,
 | 
			
		||||
    })),
 | 
			
		||||
    ignoreHTTPSErrors: tOptional(tBoolean),
 | 
			
		||||
    javaScriptEnabled: tOptional(tBoolean),
 | 
			
		||||
    bypassCSP: tOptional(tBoolean),
 | 
			
		||||
@ -257,6 +261,10 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
 | 
			
		||||
      width: tNumber,
 | 
			
		||||
      height: tNumber,
 | 
			
		||||
    })),
 | 
			
		||||
    screen: tOptional(tObject({
 | 
			
		||||
      width: tNumber,
 | 
			
		||||
      height: tNumber,
 | 
			
		||||
    })),
 | 
			
		||||
    ignoreHTTPSErrors: tOptional(tBoolean),
 | 
			
		||||
    javaScriptEnabled: tOptional(tBoolean),
 | 
			
		||||
    bypassCSP: tOptional(tBoolean),
 | 
			
		||||
 | 
			
		||||
@ -87,7 +87,7 @@ export class CRPage implements PageDelegate {
 | 
			
		||||
      const features = opener._nextWindowOpenPopupFeatures.shift() || [];
 | 
			
		||||
      const viewportSize = helper.getViewportSizeFromWindowFeatures(features);
 | 
			
		||||
      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);
 | 
			
		||||
  }
 | 
			
		||||
@ -162,8 +162,8 @@ export class CRPage implements PageDelegate {
 | 
			
		||||
    await this._forAllFrameSessions(frame => frame._updateHttpCredentials(false));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setViewportSize(viewportSize: types.Size): Promise<void> {
 | 
			
		||||
    assert(this._page._state.viewportSize === viewportSize);
 | 
			
		||||
  async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
 | 
			
		||||
    assert(this._page._state.emulatedSize === emulatedSize);
 | 
			
		||||
    await this._mainFrameSession._updateViewport();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -899,17 +899,19 @@ class FrameSession {
 | 
			
		||||
      return;
 | 
			
		||||
    assert(this._isMainFrame());
 | 
			
		||||
    const options = this._crPage._browserContext._options;
 | 
			
		||||
    const viewportSize = this._page._state.viewportSize;
 | 
			
		||||
    if (viewportSize === null)
 | 
			
		||||
    const emulatedSize = this._page._state.emulatedSize;
 | 
			
		||||
    if (emulatedSize === null)
 | 
			
		||||
      return;
 | 
			
		||||
    const viewportSize = emulatedSize.viewport;
 | 
			
		||||
    const screenSize = emulatedSize.screen;
 | 
			
		||||
    const isLandscape = viewportSize.width > viewportSize.height;
 | 
			
		||||
    const promises = [
 | 
			
		||||
      this._client.send('Emulation.setDeviceMetricsOverride', {
 | 
			
		||||
        mobile: !!options.isMobile,
 | 
			
		||||
        width: viewportSize.width,
 | 
			
		||||
        height: viewportSize.height,
 | 
			
		||||
        screenWidth: viewportSize.width,
 | 
			
		||||
        screenHeight: viewportSize.height,
 | 
			
		||||
        screenWidth: screenSize.width,
 | 
			
		||||
        screenHeight: screenSize.height,
 | 
			
		||||
        deviceScaleFactor: options.deviceScaleFactor || 1,
 | 
			
		||||
        screenOrientation: isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' },
 | 
			
		||||
      }),
 | 
			
		||||
 | 
			
		||||
@ -439,10 +439,14 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'viewport': {
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 896
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 715
 | 
			
		||||
    },
 | 
			
		||||
    'deviceScaleFactor': 2,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
    'hasTouch': true,
 | 
			
		||||
@ -450,9 +454,13 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 896
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 896,
 | 
			
		||||
      'height': 414
 | 
			
		||||
      'width': 800,
 | 
			
		||||
      'height': 364
 | 
			
		||||
    },
 | 
			
		||||
    'deviceScaleFactor': 2,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
@ -461,10 +469,14 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'viewport': {
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 375,
 | 
			
		||||
      'height': 812
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 375,
 | 
			
		||||
      'height': 635
 | 
			
		||||
    },
 | 
			
		||||
    'deviceScaleFactor': 3,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
    'hasTouch': true,
 | 
			
		||||
@ -472,9 +484,13 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 375,
 | 
			
		||||
      'height': 812
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 812,
 | 
			
		||||
      'height': 375
 | 
			
		||||
      'width': 724,
 | 
			
		||||
      'height': 325
 | 
			
		||||
    },
 | 
			
		||||
    'deviceScaleFactor': 3,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
@ -483,10 +499,14 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'viewport': {
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 896
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 715
 | 
			
		||||
    },
 | 
			
		||||
    'deviceScaleFactor': 3,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
    'hasTouch': true,
 | 
			
		||||
@ -494,9 +514,103 @@ module.exports = {
 | 
			
		||||
  },
 | 
			
		||||
  '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',
 | 
			
		||||
    'screen': {
 | 
			
		||||
      'width': 414,
 | 
			
		||||
      'height': 896
 | 
			
		||||
    },
 | 
			
		||||
    'viewport': {
 | 
			
		||||
      'width': 896,
 | 
			
		||||
      'height': 414
 | 
			
		||||
      'width': 808,
 | 
			
		||||
      '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,
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
@ -854,5 +968,65 @@ module.exports = {
 | 
			
		||||
    'isMobile': true,
 | 
			
		||||
    'hasTouch': true,
 | 
			
		||||
    '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 || [] });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setViewportSize(viewportSize: types.Size): Promise<void> {
 | 
			
		||||
    assert(this._page._state.viewportSize === viewportSize);
 | 
			
		||||
  async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
 | 
			
		||||
    assert(this._page._state.emulatedSize === emulatedSize);
 | 
			
		||||
    await this._session.send('Page.setViewportSize', {
 | 
			
		||||
      viewportSize: {
 | 
			
		||||
        width: viewportSize.width,
 | 
			
		||||
        height: viewportSize.height,
 | 
			
		||||
        width: emulatedSize.viewport.width,
 | 
			
		||||
        height: emulatedSize.viewport.height,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@ export interface PageDelegate {
 | 
			
		||||
  navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise<frames.GotoResult>;
 | 
			
		||||
 | 
			
		||||
  updateExtraHTTPHeaders(): Promise<void>;
 | 
			
		||||
  setViewportSize(viewportSize: types.Size): Promise<void>;
 | 
			
		||||
  setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void>;
 | 
			
		||||
  updateEmulateMedia(): Promise<void>;
 | 
			
		||||
  updateRequestInterception(): Promise<void>;
 | 
			
		||||
  setFileChooserIntercepted(enabled: boolean): Promise<void>;
 | 
			
		||||
@ -86,7 +86,7 @@ export interface PageDelegate {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PageState = {
 | 
			
		||||
  viewportSize: types.Size | null;
 | 
			
		||||
  emulatedSize: { screen: types.Size, viewport: types.Size } | null;
 | 
			
		||||
  mediaType: types.MediaType | null;
 | 
			
		||||
  colorScheme: types.ColorScheme | null;
 | 
			
		||||
  extraHTTPHeaders: types.HeadersArray | null;
 | 
			
		||||
@ -163,7 +163,7 @@ export class Page extends SdkObject {
 | 
			
		||||
    this._crashedPromise = new Promise(f => this._crashedCallback = f);
 | 
			
		||||
    this._browserContext = browserContext;
 | 
			
		||||
    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,
 | 
			
		||||
      colorScheme: null,
 | 
			
		||||
      extraHTTPHeaders: null,
 | 
			
		||||
@ -369,13 +369,13 @@ export class Page extends SdkObject {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setViewportSize(viewportSize: types.Size) {
 | 
			
		||||
    this._state.viewportSize = { ...viewportSize };
 | 
			
		||||
    await this._delegate.setViewportSize(this._state.viewportSize);
 | 
			
		||||
    this._state.emulatedSize = { viewport: { ...viewportSize }, screen: { ...viewportSize } };
 | 
			
		||||
    await this._delegate.setEmulatedSize(this._state.emulatedSize);
 | 
			
		||||
    await this._doSlowMo();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  viewportSize(): types.Size | null {
 | 
			
		||||
    return this._state.viewportSize;
 | 
			
		||||
    return this._state.emulatedSize?.viewport || null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async bringToFront(): Promise<void> {
 | 
			
		||||
 | 
			
		||||
@ -214,9 +214,12 @@ export type SetNetworkCookieParam = {
 | 
			
		||||
  sameSite?: 'Strict' | 'Lax' | 'None'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type EmulatedSize = { viewport: Size, screen: Size };
 | 
			
		||||
 | 
			
		||||
export type BrowserContextOptions = {
 | 
			
		||||
  sdkLanguage: string,
 | 
			
		||||
  viewport?: Size,
 | 
			
		||||
  screen?: Size,
 | 
			
		||||
  noDefaultViewport?: boolean,
 | 
			
		||||
  ignoreHTTPSErrors?: boolean,
 | 
			
		||||
  javaScriptEnabled?: boolean,
 | 
			
		||||
 | 
			
		||||
@ -97,7 +97,7 @@ export class WKPage implements PageDelegate {
 | 
			
		||||
      const viewportSize = helper.getViewportSizeFromWindowFeatures(opener._nextWindowOpenPopupFeatures);
 | 
			
		||||
      opener._nextWindowOpenPopupFeatures = undefined;
 | 
			
		||||
      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 => {}));
 | 
			
		||||
    if (contextOptions.bypassCSP)
 | 
			
		||||
      promises.push(session.send('Page.setBypassCSP', { enabled: true }));
 | 
			
		||||
    if (this._page._state.viewportSize) {
 | 
			
		||||
    if (this._page._state.emulatedSize) {
 | 
			
		||||
      promises.push(session.send('Page.setScreenSizeOverride', {
 | 
			
		||||
        width: this._page._state.viewportSize.width,
 | 
			
		||||
        height: this._page._state.viewportSize.height,
 | 
			
		||||
        width: this._page._state.emulatedSize.screen.width,
 | 
			
		||||
        height: this._page._state.emulatedSize.screen.height,
 | 
			
		||||
      }));
 | 
			
		||||
    }
 | 
			
		||||
    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));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setViewportSize(viewportSize: types.Size): Promise<void> {
 | 
			
		||||
    assert(this._page._state.viewportSize === viewportSize);
 | 
			
		||||
  async setEmulatedSize(emulatedSize: types.EmulatedSize): Promise<void> {
 | 
			
		||||
    assert(this._page._state.emulatedSize === emulatedSize);
 | 
			
		||||
    await this._updateViewport();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -616,9 +616,11 @@ export class WKPage implements PageDelegate {
 | 
			
		||||
 | 
			
		||||
  async _updateViewport(): Promise<void> {
 | 
			
		||||
    const options = this._browserContext._options;
 | 
			
		||||
    const viewportSize = this._page._state.viewportSize;
 | 
			
		||||
    if (viewportSize === null)
 | 
			
		||||
    const deviceSize = this._page._state.emulatedSize;
 | 
			
		||||
    if (deviceSize === null)
 | 
			
		||||
      return;
 | 
			
		||||
    const viewportSize = deviceSize.viewport;
 | 
			
		||||
    const screenSize = deviceSize.screen;
 | 
			
		||||
    const promises: Promise<any>[] = [
 | 
			
		||||
      this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {
 | 
			
		||||
        width: viewportSize.width,
 | 
			
		||||
@ -627,8 +629,8 @@ export class WKPage implements PageDelegate {
 | 
			
		||||
        deviceScaleFactor: options.deviceScaleFactor || 1
 | 
			
		||||
      }),
 | 
			
		||||
      this._session.send('Page.setScreenSizeOverride', {
 | 
			
		||||
        width: viewportSize.width,
 | 
			
		||||
        height: viewportSize.height,
 | 
			
		||||
        width: screenSize.width,
 | 
			
		||||
        height: screenSize.height,
 | 
			
		||||
      }),
 | 
			
		||||
    ];
 | 
			
		||||
    if (options.isMobile) {
 | 
			
		||||
 | 
			
		||||
@ -114,4 +114,47 @@ describe('device', (suite, { browserName }) => {
 | 
			
		||||
    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()
 | 
			
		||||
        .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")
 | 
			
		||||
        .setViewportSize(414, 896)
 | 
			
		||||
        .setViewportSize(414, 715)
 | 
			
		||||
        .setDeviceScaleFactor(2)
 | 
			
		||||
        .setIsMobile(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.
 | 
			
		||||
     * Defaults to 0.
 | 
			
		||||
@ -6623,7 +6639,7 @@ export interface BrowserType<Browser> {
 | 
			
		||||
    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|{
 | 
			
		||||
      /**
 | 
			
		||||
@ -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
 | 
			
		||||
     * [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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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|{
 | 
			
		||||
      /**
 | 
			
		||||
@ -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
 | 
			
		||||
     * obtained via
 | 
			
		||||
@ -8518,7 +8566,7 @@ export interface Browser extends EventEmitter {
 | 
			
		||||
    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|{
 | 
			
		||||
      /**
 | 
			
		||||
@ -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
 | 
			
		||||
   * obtained via
 | 
			
		||||
@ -10600,7 +10664,7 @@ export interface BrowserContextOptions {
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
@ -10907,6 +10971,12 @@ type Devices = {
 | 
			
		||||
  "iPhone 11 Pro landscape": DeviceDescriptor;
 | 
			
		||||
  "iPhone 11 Pro Max": 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 landscape": DeviceDescriptor;
 | 
			
		||||
  "Kindle Fire HDX": DeviceDescriptor;
 | 
			
		||||
@ -10939,5 +11009,9 @@ type Devices = {
 | 
			
		||||
  "Pixel 2 landscape": DeviceDescriptor;
 | 
			
		||||
  "Pixel 2 XL": 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user