diff --git a/docs/api.md b/docs/api.md index a70d06bb97..d25f231f68 100644 --- a/docs/api.md +++ b/docs/api.md @@ -484,13 +484,13 @@ page.removeListener('request', logRequest); - [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) - [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders) - [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled) -- [page.setViewport(viewport)](#pagesetviewportviewport) +- [page.setViewportSize(viewportSize)](#pagesetviewportsizeviewportsize) - [page.title()](#pagetitle) - [page.tripleclick(selector[, options])](#pagetripleclickselector-options) - [page.type(selector, text[, options])](#pagetypeselector-text-options) - [page.uncheck(selector, [options])](#pageuncheckselector-options) - [page.url()](#pageurl) -- [page.viewport()](#pageviewport) +- [page.viewportSize()](#pageviewportsize) - [page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]])](#pagewaitforselectororfunctionortimeout-options-args) - [page.waitForEvent(event[, optionsOrPredicate])](#pagewaitforeventevent-optionsorpredicate) - [page.waitForFunction(pageFunction[, options[, ...args]])](#pagewaitforfunctionpagefunction-options-args) @@ -1338,26 +1338,21 @@ The extra HTTP headers will be sent with every request the page initiates. - `enabled` <[boolean]> When `true`, enables offline mode for the page. - returns: <[Promise]> -#### page.setViewport(viewport) -- `viewport` <[Object]> +#### page.setViewportSize(viewportSize) +- `viewportSize` <[Object]> - `width` <[number]> page width in pixels. **required** - `height` <[number]> page height in pixels. **required** - - `deviceScaleFactor` <[number]> Specify device scale factor (can be thought of as dpr). Defaults to `1`. - - `isMobile` <[boolean]> Whether the `meta viewport` tag is taken into account. Defaults to `false`. - returns: <[Promise]> -> **NOTE** in certain cases, setting viewport will reload the page in order to set the `isMobile` property. +In the case of multiple pages in a single browser, each page can have its own viewport size. However, [browser.newContext(options)](#browsernewcontextoptions) allows to set viewport size (and more) for all pages in the context at once. -In the case of multiple pages in a single browser, each page can have its own viewport size. - -`page.setViewport` will resize the page. A lot of websites don't expect phones to change size, so you should set the viewport before navigating to the page. +`page.setViewportSize` will resize the page. A lot of websites don't expect phones to change size, so you should set the viewport size before navigating to the page. ```js const page = await browser.newPage(); -await page.setViewport({ +await page.setViewportSize({ width: 640, height: 480, - deviceScaleFactor: 1, }); await page.goto('https://example.com'); ``` @@ -1426,12 +1421,10 @@ Shortcut for [page.mainFrame().uncheck(selector[, options])](#frameuncheckselect This is a shortcut for [page.mainFrame().url()](#frameurl) -#### page.viewport() +#### page.viewportSize() - returns: - `width` <[number]> page width in pixels. - `height` <[number]> page height in pixels. - - `deviceScaleFactor` <[number]> Specify device scale factor (can be though of as dpr). Defaults to `1`. - - `isMobile` <[boolean]> Whether the `meta viewport` tag is taken into account. Defaults to `false`. #### page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]]) - `selectorOrFunctionOrTimeout` <[string]|[number]|[function]> A [selector], predicate or timeout to wait for @@ -1499,7 +1492,7 @@ const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'. const browser = await webkit.launch(); const page = await browser.newPage(); const watchDog = page.waitForFunction('window.innerWidth < 100'); - await page.setViewport({width: 50, height: 50}); + await page.setViewportSize({width: 50, height: 50}); await watchDog; await browser.close(); })(); @@ -2136,7 +2129,7 @@ const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'. const browser = await firefox.launch(); const page = await browser.newPage(); const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100'); - page.setViewport({width: 50, height: 50}); + page.setViewportSize({width: 50, height: 50}); await watchDog; await browser.close(); })(); diff --git a/src/chromium/crPage.ts b/src/chromium/crPage.ts index 83e125087c..bcb5b79173 100644 --- a/src/chromium/crPage.ts +++ b/src/chromium/crPage.ts @@ -18,7 +18,7 @@ import * as dom from '../dom'; import * as js from '../javascript'; import * as frames from '../frames'; -import { debugError, helper, RegisteredListener } from '../helper'; +import { debugError, helper, RegisteredListener, assert } from '../helper'; import * as network from '../network'; import { CRSession, CRConnection } from './crConnection'; import { EVALUATION_SCRIPT_URL, CRExecutionContext } from './crExecutionContext'; @@ -106,7 +106,7 @@ export class CRPage implements PageDelegate { if (options.ignoreHTTPSErrors) promises.push(this._client.send('Security.setIgnoreCertificateErrors', { ignore: true })); if (options.viewport) - promises.push(this.setViewport(options.viewport)); + promises.push(this._updateViewport(true /* updateTouch */)); if (options.javaScriptEnabled === false) promises.push(this._client.send('Emulation.setScriptExecutionDisabled', { value: true })); if (options.userAgent) @@ -317,19 +317,29 @@ export class CRPage implements PageDelegate { await this._client.send('Network.setExtraHTTPHeaders', { headers }); } - async setViewport(viewport: types.Viewport): Promise { - const { - width, - height, - isMobile = false, - deviceScaleFactor = 1, - } = viewport; - const isLandscape = width > height; - const screenOrientation: Protocol.Emulation.ScreenOrientation = isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' }; - await Promise.all([ - this._client.send('Emulation.setDeviceMetricsOverride', { mobile: isMobile, width, height, deviceScaleFactor, screenOrientation }), - this._client.send('Emulation.setTouchEmulationEnabled', { enabled: isMobile }) - ]); + async setViewportSize(viewportSize: types.Size): Promise { + assert(this._page._state.viewportSize === viewportSize); + await this._updateViewport(false /* updateTouch */); + } + + async _updateViewport(updateTouch: boolean): Promise { + let viewport = this._page.browserContext()._options.viewport || { width: 0, height: 0 }; + const viewportSize = this._page._state.viewportSize; + if (viewportSize) + viewport = { ...viewport, ...viewportSize }; + const isLandscape = viewport.width > viewport.height; + const promises = [ + this._client.send('Emulation.setDeviceMetricsOverride', { + mobile: !!viewport.isMobile, + width: viewport.width, + height: viewport.height, + deviceScaleFactor: viewport.deviceScaleFactor || 1, + screenOrientation: isLandscape ? { angle: 90, type: 'landscapePrimary' } : { angle: 0, type: 'portraitPrimary' }, + }), + ]; + if (updateTouch) + promises.push(this._client.send('Emulation.setTouchEmulationEnabled', { enabled: !!viewport.isMobile })); + await Promise.all(promises); } async setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise { @@ -414,7 +424,7 @@ export class CRPage implements PageDelegate { await this._client.send('Emulation.setDefaultBackgroundColorOverride', { color }); } - async takeScreenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions): Promise { + async takeScreenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewportSize: types.Size): Promise { await this._client.send('Page.bringToFront', {}); const clip = options.clip ? { ...options.clip, scale: 1 } : undefined; const result = await this._client.send('Page.captureScreenshot', { format, quality: options.quality, clip }); diff --git a/src/firefox/ffPage.ts b/src/firefox/ffPage.ts index 12666b6a4d..3eacd0d9d8 100644 --- a/src/firefox/ffPage.ts +++ b/src/firefox/ffPage.ts @@ -16,7 +16,7 @@ */ import * as frames from '../frames'; -import { helper, RegisteredListener, debugError } from '../helper'; +import { helper, RegisteredListener, debugError, assert } from '../helper'; import * as dom from '../dom'; import { FFSession } from './ffConnection'; import { FFExecutionContext } from './ffExecutionContext'; @@ -84,7 +84,7 @@ export class FFPage implements PageDelegate { ]; const options = this._page.browserContext()._options; if (options.viewport) - promises.push(this.setViewport(options.viewport)); + promises.push(this._updateViewport()); if (options.bypassCSP) promises.push(this._session.send('Page.setBypassCSP', { enabled: true })); if (options.javaScriptEnabled === false) @@ -266,15 +266,25 @@ export class FFPage implements PageDelegate { await this._session.send('Network.setExtraHTTPHeaders', { headers: array }); } - async setViewport(viewport: types.Viewport): Promise { - const { - width, - height, - isMobile = false, - deviceScaleFactor = 1, - } = viewport; + async setViewportSize(viewportSize: types.Size): Promise { + assert(this._page._state.viewportSize === viewportSize); + await this._updateViewport(); + } + + async _updateViewport() { + let viewport = this._page.browserContext()._options.viewport || { width: 0, height: 0 }; + const viewportSize = this._page._state.viewportSize; + if (viewportSize) + viewport = { ...viewport, ...viewportSize }; await this._session.send('Page.setViewport', { - viewport: { width, height, isMobile, deviceScaleFactor, hasTouch: isMobile, isLandscape: width > height }, + viewport: { + width: viewport.width, + height: viewport.height, + isMobile: !!viewport.isMobile, + deviceScaleFactor: viewport.deviceScaleFactor || 1, + hasTouch: !!viewport.isMobile, + isLandscape: viewport.width > viewport.height + }, }); } @@ -349,7 +359,7 @@ export class FFPage implements PageDelegate { throw new Error('Not implemented'); } - async takeScreenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions): Promise { + async takeScreenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewportSize: types.Size): Promise { const { data } = await this._session.send('Page.screenshot', { mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'), fullPage: options.fullPage, diff --git a/src/page.ts b/src/page.ts index 62c64cd731..c022f8e04f 100644 --- a/src/page.ts +++ b/src/page.ts @@ -46,7 +46,7 @@ export interface PageDelegate { navigateFrame(frame: frames.Frame, url: string, referrer: string | undefined): Promise; setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise; - setViewport(viewport: types.Viewport): Promise; + setViewportSize(viewportSize: types.Size): Promise; setEmulateMedia(mediaType: types.MediaType | null, colorScheme: types.ColorScheme | null): Promise; setCacheEnabled(enabled: boolean): Promise; setRequestInterception(enabled: boolean): Promise; @@ -57,7 +57,7 @@ export interface PageDelegate { getBoundingBoxForScreenshot(handle: dom.ElementHandle): Promise; canScreenshotOutsideViewport(): boolean; setBackgroundColor(color?: { r: number; g: number; b: number; a: number; }): Promise; - takeScreenshot(format: string, options: types.ScreenshotOptions, viewport: types.Viewport): Promise; + takeScreenshot(format: string, options: types.ScreenshotOptions, viewportSize: types.Size): Promise; resetViewport(oldSize: types.Size): Promise; isElementHandle(remoteObject: any): boolean; @@ -76,7 +76,7 @@ export interface PageDelegate { } type PageState = { - viewport: types.Viewport | null; + viewportSize: types.Size | null; mediaType: types.MediaType | null; colorScheme: types.ColorScheme | null; extraHTTPHeaders: network.Headers | null; @@ -122,8 +122,15 @@ export class Page extends platform.EventEmitter { this._disconnectedCallback = () => {}; this._disconnectedPromise = new Promise(f => this._disconnectedCallback = f); this._browserContext = browserContext; + let viewportSize: types.Size | null = null; + if (browserContext._options.viewport) { + viewportSize = { + width: browserContext._options.viewport.width, + height: browserContext._options.viewport.height, + }; + } this._state = { - viewport: browserContext._options.viewport || null, + viewportSize, mediaType: null, colorScheme: null, extraHTTPHeaders: null, @@ -390,17 +397,13 @@ export class Page extends platform.EventEmitter { await this._delegate.setEmulateMedia(this._state.mediaType, this._state.colorScheme); } - async setViewport(viewport: types.Viewport) { - const oldIsMobile = this._state.viewport ? !!this._state.viewport.isMobile : false; - const newIsMobile = !!viewport.isMobile; - this._state.viewport = { ...viewport }; - await this._delegate.setViewport(viewport); - if (oldIsMobile !== newIsMobile) - await this.reload(); + async setViewportSize(viewportSize: types.Size) { + this._state.viewportSize = { ...viewportSize }; + await this._delegate.setViewportSize(this._state.viewportSize); } - viewport(): types.Viewport | null { - return this._state.viewport; + viewportSize(): types.Size | null { + return this._state.viewportSize; } evaluate: types.Evaluate = async (pageFunction, ...args) => { diff --git a/src/screenshotter.ts b/src/screenshotter.ts index 3cfe046099..c60f4e1db4 100644 --- a/src/screenshotter.ts +++ b/src/screenshotter.ts @@ -39,10 +39,10 @@ export class Screenshotter { async screenshotPage(options: types.ScreenshotOptions = {}): Promise { const format = validateScreeshotOptions(options); return this._queue.postTask(async () => { - let overridenViewport: types.Viewport | undefined; - const viewport = this._page.viewport(); + let overridenViewportSize: types.Size | undefined; + const originalViewportSize = this._page.viewportSize(); let viewportSize: types.Size | undefined; - if (!viewport) { + if (!originalViewportSize) { viewportSize = await this._page.evaluate(() => { if (!document.body || !document.documentElement) return; @@ -73,17 +73,17 @@ export class Screenshotter { }); if (!fullPageRect) throw new Error(kScreenshotDuringNavigationError); - overridenViewport = viewport ? { ...viewport, ...fullPageRect } : fullPageRect; - await this._page.setViewport(overridenViewport); + overridenViewportSize = fullPageRect; + await this._page.setViewportSize(overridenViewportSize); } else if (options.clip) { - options.clip = trimClipToViewport(viewport, options.clip); + options.clip = trimClipToViewport(originalViewportSize, options.clip); } - const result = await this._screenshot(format, options, (overridenViewport || viewport)!); + const result = await this._screenshot(format, options, (overridenViewportSize || originalViewportSize)!); - if (overridenViewport) { - if (viewport) - await this._page.setViewport(viewport); + if (overridenViewportSize) { + if (originalViewportSize) + await this._page.setViewportSize(originalViewportSize); else await this._page._delegate.resetViewport(viewportSize!); } @@ -95,7 +95,7 @@ export class Screenshotter { const format = validateScreeshotOptions(options); const rewrittenOptions: types.ScreenshotOptions = { ...options }; return this._queue.postTask(async () => { - let overridenViewport: types.Viewport | undefined; + let overridenViewportSize: types.Size | undefined; let viewportSize: types.Size; let maybeBoundingBox = await this._page._delegate.getBoundingBoxForScreenshot(handle); @@ -105,9 +105,9 @@ export class Screenshotter { assert(boundingBox.height !== 0, 'Node has 0 height.'); boundingBox = enclosingIntRect(boundingBox); - const viewport = this._page.viewport(); + const originalViewportSize = this._page.viewportSize(); if (!this._page._delegate.canScreenshotOutsideViewport()) { - if (!viewport) { + if (!originalViewportSize) { const maybeViewportSize = await this._page.evaluate(() => { if (!document.body || !document.documentElement) return; @@ -120,13 +120,14 @@ export class Screenshotter { throw new Error(kScreenshotDuringNavigationError); viewportSize = maybeViewportSize!; } else { - viewportSize = viewport; + viewportSize = originalViewportSize; } if (boundingBox.width > viewportSize.width || boundingBox.height > viewportSize.height) { - overridenViewport = {... (viewport || viewportSize)}; - overridenViewport.width = Math.max(viewportSize.width, boundingBox.width); - overridenViewport.height = Math.max(viewportSize.height, boundingBox.height); - await this._page.setViewport(overridenViewport); + overridenViewportSize = { + width: Math.max(viewportSize.width, boundingBox.width), + height: Math.max(viewportSize.height, boundingBox.height), + }; + await this._page.setViewportSize(overridenViewportSize); } await handle.scrollIntoViewIfNeeded(); @@ -135,14 +136,14 @@ export class Screenshotter { boundingBox = enclosingIntRect(maybeBoundingBox!); } - if (!overridenViewport) + if (!overridenViewportSize) rewrittenOptions.clip = boundingBox; - const result = await this._screenshot(format, rewrittenOptions, (overridenViewport || viewport)!); + const result = await this._screenshot(format, rewrittenOptions, (overridenViewportSize || originalViewportSize)!); - if (overridenViewport) { - if (viewport) - await this._page.setViewport(viewport); + if (overridenViewportSize) { + if (originalViewportSize) + await this._page.setViewportSize(originalViewportSize); else await this._page._delegate.resetViewport(viewportSize!); } @@ -151,11 +152,11 @@ export class Screenshotter { }).catch(rewriteError); } - private async _screenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewport: types.Viewport): Promise { + private async _screenshot(format: 'png' | 'jpeg', options: types.ScreenshotOptions, viewportSize: types.Size): Promise { const shouldSetDefaultBackground = options.omitBackground && format === 'png'; if (shouldSetDefaultBackground) await this._page._delegate.setBackgroundColor({ r: 0, g: 0, b: 0, a: 0}); - const buffer = await this._page._delegate.takeScreenshot(format, options, viewport); + const buffer = await this._page._delegate.takeScreenshot(format, options, viewportSize); if (shouldSetDefaultBackground) await this._page._delegate.setBackgroundColor(); if (options.path) @@ -180,11 +181,11 @@ class TaskQueue { } } -function trimClipToViewport(viewport: types.Viewport | null, clip: types.Rect | undefined): types.Rect | undefined { - if (!clip || !viewport) +function trimClipToViewport(viewportSize: types.Size | null, clip: types.Rect | undefined): types.Rect | undefined { + if (!clip || !viewportSize) return clip; - const p1 = { x: Math.min(clip.x, viewport.width), y: Math.min(clip.y, viewport.height) }; - const p2 = { x: Math.min(clip.x + clip.width, viewport.width), y: Math.min(clip.y + clip.height, viewport.height) }; + const p1 = { x: Math.min(clip.x, viewportSize.width), y: Math.min(clip.y, viewportSize.height) }; + const p2 = { x: Math.min(clip.x + clip.width, viewportSize.width), y: Math.min(clip.y + clip.height, viewportSize.height) }; const result = { x: p1.x, y: p1.y, width: p2.x - p1.x, height: p2.y - p1.y }; assert(result.width && result.height, 'Clipped area is either empty or outside the viewport'); return result; diff --git a/src/webkit/wkPage.ts b/src/webkit/wkPage.ts index ed669ff4e9..b12f39f7d7 100644 --- a/src/webkit/wkPage.ts +++ b/src/webkit/wkPage.ts @@ -73,8 +73,8 @@ export class WKPage implements PageDelegate { const contextOptions = this._page.browserContext()._options; if (contextOptions.javaScriptEnabled === false) promises.push(this._pageProxySession.send('Emulation.setJavaScriptEnabled', { enabled: false })); - if (this._page._state.viewport) - promises.push(this.setViewport(this._page._state.viewport)); + if (this._page._state.viewportSize || contextOptions.viewport) + promises.push(this._updateViewport(true /* updateTouch */)); await Promise.all(promises); } @@ -384,16 +384,27 @@ export class WKPage implements PageDelegate { await this._forAllSessions(session => WKPage._setEmulateMedia(session, mediaType, colorScheme)); } - async setViewport(viewport: types.Viewport): Promise { - const width = viewport.width; - const height = viewport.height; - const fixedLayout = !!viewport.isMobile; - const deviceScaleFactor = viewport.deviceScaleFactor || 1; - this._page._state.hasTouch = !!viewport.isMobile; - await Promise.all([ - this._pageProxySession.send('Emulation.setDeviceMetricsOverride', {width, height, fixedLayout, deviceScaleFactor }), - this._updateState('Page.setTouchEmulationEnabled', { enabled: !!viewport.isMobile }), - ]); + async setViewportSize(viewportSize: types.Size): Promise { + assert(this._page._state.viewportSize === viewportSize); + await this._updateViewport(false /* updateTouch */); + } + + async _updateViewport(updateTouch: boolean): Promise { + let viewport = this._page.browserContext()._options.viewport || { width: 0, height: 0 }; + const viewportSize = this._page._state.viewportSize; + if (viewportSize) + viewport = { ...viewport, ...viewportSize }; + const promises: Promise[] = [ + this._pageProxySession.send('Emulation.setDeviceMetricsOverride', { + width: viewport.width, + height: viewport.height, + fixedLayout: !!viewport.isMobile, + deviceScaleFactor: viewport.deviceScaleFactor || 1 + }), + ]; + if (updateTouch) + promises.push(this._updateState('Page.setTouchEmulationEnabled', { enabled: !!viewport.isMobile })); + await Promise.all(promises); } async setCacheEnabled(enabled: boolean): Promise { @@ -478,8 +489,8 @@ export class WKPage implements PageDelegate { await this._session.send('Page.setDefaultBackgroundColorOverride', { color }); } - async takeScreenshot(format: string, options: types.ScreenshotOptions, viewport: types.Viewport): Promise { - const rect = options.clip || { x: 0, y: 0, width: viewport.width, height: viewport.height }; + async takeScreenshot(format: string, options: types.ScreenshotOptions, viewportSize: types.Size): Promise { + const rect = options.clip || { x: 0, y: 0, width: viewportSize.width, height: viewportSize.height }; const result = await this._session.send('Page.snapshotRect', { ...rect, coordinateSystem: options.fullPage ? 'Page' : 'Viewport' }); const prefix = 'data:image/png;base64,'; let buffer = platform.Buffer.from(result.dataURL.substr(prefix.length), 'base64'); diff --git a/test/browsercontext.spec.js b/test/browsercontext.spec.js index 3eecf0aa22..756e36f18f 100644 --- a/test/browsercontext.spec.js +++ b/test/browsercontext.spec.js @@ -100,8 +100,8 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE }); it('should propagate default viewport to the page', async({ newPage }) => { const page = await newPage({ viewport: { width: 456, height: 789 } }); - expect(page.viewport().width).toBe(456); - expect(page.viewport().height).toBe(789); + expect(page.viewportSize().width).toBe(456); + expect(page.viewportSize().height).toBe(789); expect(await page.evaluate('window.innerWidth')).toBe(456); expect(await page.evaluate('window.innerHeight')).toBe(789); }); @@ -120,14 +120,14 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE }); it('should restore default viewport after fullPage screenshot', async({ newPage }) => { const page = await newPage({ viewport: { width: 456, height: 789 } }); - expect(page.viewport().width).toBe(456); - expect(page.viewport().height).toBe(789); + expect(page.viewportSize().width).toBe(456); + expect(page.viewportSize().height).toBe(789); expect(await page.evaluate('window.innerWidth')).toBe(456); expect(await page.evaluate('window.innerHeight')).toBe(789); const screenshot = await page.screenshot({ fullPage: true }); expect(screenshot).toBeInstanceOf(Buffer); - expect(page.viewport().width).toBe(456); - expect(page.viewport().height).toBe(789); + expect(page.viewportSize().width).toBe(456); + expect(page.viewportSize().height).toBe(789); expect(await page.evaluate('window.innerWidth')).toBe(456); expect(await page.evaluate('window.innerHeight')).toBe(789); }); @@ -136,8 +136,8 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE const context = await newContext({ viewport }); viewport.width = 567; const page = await context.newPage(); - expect(page.viewport().width).toBe(456); - expect(page.viewport().height).toBe(789); + expect(page.viewportSize().width).toBe(456); + expect(page.viewportSize().height).toBe(789); expect(await page.evaluate('window.innerWidth')).toBe(456); expect(await page.evaluate('window.innerHeight')).toBe(789); }); diff --git a/test/click.spec.js b/test/click.spec.js index c0e3c8ae3c..07e7a9e0f4 100644 --- a/test/click.spec.js +++ b/test/click.spec.js @@ -219,8 +219,9 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI expect(error.message).toBe('No node found for selector: button.does-not-exist'); }); // @see https://github.com/GoogleChrome/puppeteer/issues/161 - it('should not hang with touch-enabled viewports', async({page, server}) => { - await page.setViewport(playwright.devices['iPhone 6'].viewport); + it('should not hang with touch-enabled viewports', async({server, newContext}) => { + const context = await newContext({ viewport: playwright.devices['iPhone 6'].viewport }); + const page = await context.newPage(); await page.mouse.down(); await page.mouse.move(100, 10); await page.mouse.up(); @@ -284,7 +285,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI // @see https://github.com/GoogleChrome/puppeteer/issues/4110 xit('should click the button with fixed position inside an iframe', async({page, server}) => { await page.goto(server.EMPTY_PAGE); - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.setContent('
spacer
'); await utils.attachFrame(page, 'button-test', server.CROSS_PROCESS_PREFIX + '/input/button.html'); const frame = page.frames()[1]; @@ -292,8 +293,9 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI await frame.click('button'); expect(await frame.evaluate(() => window.result)).toBe('Clicked'); }); - it('should click the button with deviceScaleFactor set', async({page, server}) => { - await page.setViewport({width: 400, height: 400, deviceScaleFactor: 5}); + it('should click the button with deviceScaleFactor set', async({newContext, server}) => { + const context = await newContext({ viewport: {width: 400, height: 400, deviceScaleFactor: 5} }); + const page = await context.newPage(); expect(await page.evaluate(() => window.devicePixelRatio)).toBe(5); await page.setContent('
spacer
'); await utils.attachFrame(page, 'button-test', server.PREFIX + '/input/button.html'); diff --git a/test/elementhandle.spec.js b/test/elementhandle.spec.js index bb876e9a85..a4aaf1a40a 100644 --- a/test/elementhandle.spec.js +++ b/test/elementhandle.spec.js @@ -24,14 +24,14 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT}) describe('ElementHandle.boundingBox', function() { it('should work', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const elementHandle = await page.$('.box:nth-of-type(13)'); const box = await elementHandle.boundingBox(); expect(box).toEqual({ x: 100, y: 50, width: 50, height: 50 }); }); it('should handle nested frames', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/frames/nested-frames.html'); const nestedFrame = page.frames().find(frame => frame.name() === 'dos'); const elementHandle = await nestedFrame.$('div'); @@ -44,7 +44,7 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT}) expect(await element.boundingBox()).toBe(null); }); it('should force a layout', async({page, server}) => { - await page.setViewport({ width: 500, height: 500 }); + await page.setViewportSize({ width: 500, height: 500 }); await page.setContent('
hello
'); const elementHandle = await page.$('div'); await page.evaluate(element => element.style.height = '200px', elementHandle); diff --git a/test/emulation.spec.js b/test/emulation.spec.js index d8471c5c2f..2e849252d8 100644 --- a/test/emulation.spec.js +++ b/test/emulation.spec.js @@ -24,26 +24,30 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI describe('Page.viewport', function() { it('should get the proper viewport size', async({page, server}) => { - expect(page.viewport()).toEqual({width: 800, height: 600}); - await page.setViewport({width: 123, height: 456}); - expect(page.viewport()).toEqual({width: 123, height: 456}); + expect(page.viewportSize()).toEqual({width: 800, height: 600}); + await page.setViewportSize({width: 123, height: 456}); + expect(page.viewportSize()).toEqual({width: 123, height: 456}); }); - it('should support mobile emulation', async({page, server}) => { + it('should support mobile emulation', async({newContext, server}) => { + const context = await newContext({ viewport: iPhone.viewport }); + const page = await context.newPage(); await page.goto(server.PREFIX + '/mobile.html'); - expect(await page.evaluate(() => window.innerWidth)).toBe(800); - await page.setViewport(iPhone.viewport); expect(await page.evaluate(() => window.innerWidth)).toBe(375); - await page.setViewport({width: 400, height: 300}); + await page.setViewportSize({width: 400, height: 300}); expect(await page.evaluate(() => window.innerWidth)).toBe(400); }); - it('should support touch emulation', async({page, server}) => { + it('should not have touch by default', async({page, server}) => { await page.goto(server.PREFIX + '/mobile.html'); expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(false); - await page.setViewport(iPhone.viewport); + await page.goto(server.PREFIX + '/detect-touch.html'); + expect(await page.evaluate(() => document.body.textContent.trim())).toBe('NO'); + }); + it('should support touch emulation', async({newContext, server}) => { + const context = await newContext({ viewport: iPhone.viewport }); + const page = await context.newPage(); + await page.goto(server.PREFIX + '/mobile.html'); expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true); expect(await page.evaluate(dispatchTouch)).toBe('Received touch'); - await page.setViewport({width: 100, height: 100}); - expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(false); function dispatchTouch() { let fulfill; @@ -58,48 +62,54 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI return promise; } }); - it('should be detectable by Modernizr', async({page, server}) => { - await page.goto(server.PREFIX + '/detect-touch.html'); - expect(await page.evaluate(() => document.body.textContent.trim())).toBe('NO'); - await page.setViewport(iPhone.viewport); + it('should be detectable by Modernizr', async({newContext, server}) => { + const context = await newContext({ viewport: iPhone.viewport }); + const page = await context.newPage(); await page.goto(server.PREFIX + '/detect-touch.html'); expect(await page.evaluate(() => document.body.textContent.trim())).toBe('YES'); }); - it('should detect touch when applying viewport with touches', async({page, server}) => { - await page.setViewport({ width: 800, height: 600, isMobile: true }); + it('should detect touch when applying viewport with touches', async({newContext, server}) => { + const context = await newContext({ viewport: { width: 800, height: 600, isMobile: true } }); + const page = await context.newPage(); + await page.goto(server.EMPTY_PAGE); await page.addScriptTag({url: server.PREFIX + '/modernizr.js'}); expect(await page.evaluate(() => Modernizr.touchevents)).toBe(true); }); - it.skip(FFOX)('should support landscape emulation', async({page, server}) => { - await page.goto(server.PREFIX + '/mobile.html'); - await page.setViewport(iPhone.viewport); - expect(await page.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(false); - await page.setViewport(iPhoneLandscape.viewport); - expect(await page.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(true) + it.skip(FFOX)('should support landscape emulation', async({newContext, server}) => { + const context1 = await newContext({ viewport: iPhone.viewport }); + const page1 = await context1.newPage(); + await page1.goto(server.PREFIX + '/mobile.html'); + expect(await page1.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(false); + const context2 = await newContext({ viewport: iPhoneLandscape.viewport }); + const page2 = await context2.newPage(); + expect(await page2.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(true); }); - it.skip(FFOX || WEBKIT)('should fire orientationchange event', async({page, server}) => { + it.skip(FFOX || WEBKIT)('should fire orientationchange event', async({newContext, server}) => { + const context = await newContext({ viewport: { width: 300, height: 400, isMobile: true } }); + const page = await context.newPage(); await page.goto(server.PREFIX + '/mobile.html'); - await page.setViewport(iPhone.viewport); await page.evaluate(() => { window.counter = 0; window.addEventListener('orientationchange', () => console.log(++window.counter)); }); const event1 = page.waitForEvent('console'); - await page.setViewport(iPhoneLandscape.viewport); + await page.setViewportSize({width: 400, height: 300}); expect((await event1).text()).toBe('1'); const event2 = page.waitForEvent('console'); - await page.setViewport(iPhone.viewport); + await page.setViewportSize({width: 300, height: 400}); expect((await event2).text()).toBe('2'); }); - it.skip(FFOX)('default mobile viewports to 980 width', async({page, server}) => { - await page.setViewport({width: 320, height: 480, isMobile: true}); + it.skip(FFOX)('default mobile viewports to 980 width', async({newContext, server}) => { + const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} }); + const page = await context.newPage(); await page.goto(server.PREFIX + '/empty.html'); expect(await page.evaluate(() => window.innerWidth)).toBe(980); }); - it.skip(FFOX)('respect meta viewport tag', async({page, server}) => { - await page.setViewport({width: 320, height: 480, isMobile: true}); + it.skip(FFOX)('respect meta viewport tag', async({newContext, server}) => { + const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} }); + const page = await context.newPage(); await page.goto(server.PREFIX + '/mobile.html'); expect(await page.evaluate(() => window.innerWidth)).toBe(320); }); diff --git a/test/mouse.spec.js b/test/mouse.spec.js index 60a60be52c..9024d17757 100644 --- a/test/mouse.spec.js +++ b/test/mouse.spec.js @@ -130,9 +130,10 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT, ]); }); // @see https://crbug.com/929806 - it('should work with mobile viewports and cross process navigations', async({page, server}) => { + it('should work with mobile viewports and cross process navigations', async({newContext, server}) => { + const context = await newContext({ viewport: {width: 360, height: 640, isMobile: true} }); + const page = await context.newPage(); await page.goto(server.EMPTY_PAGE); - await page.setViewport({width: 360, height: 640, isMobile: true}); await page.goto(server.CROSS_PROCESS_PREFIX + '/mobile.html'); await page.evaluate(() => { document.addEventListener('click', event => { diff --git a/test/screenshot.spec.js b/test/screenshot.spec.js index f4c9ae4237..c2c216a30c 100644 --- a/test/screenshot.spec.js +++ b/test/screenshot.spec.js @@ -22,13 +22,13 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, describe('Page.screenshot', function() { it('should work', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('screenshot-sanity.png'); }); it('should clip rect', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshot = await page.screenshot({ clip: { @@ -41,7 +41,7 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, expect(screenshot).toBeGolden('screenshot-clip-rect.png'); }); it('should clip elements to the viewport', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshot = await page.screenshot({ clip: { @@ -54,7 +54,7 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, expect(screenshot).toBeGolden('screenshot-offscreen-clip.png'); }); it('should throw on clip outside the viewport', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshotError = await page.screenshot({ clip: { @@ -67,7 +67,7 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, expect(screenshotError.message).toBe('Clipped area is either empty or outside the viewport'); }); it('should run in parallel', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const promises = []; for (let i = 0; i < 3; ++i) { @@ -84,7 +84,7 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, expect(screenshots[1]).toBeGolden('grid-cell-1.png'); }); it('should take fullPage screenshots', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshot = await page.screenshot({ fullPage: true @@ -92,12 +92,12 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, expect(screenshot).toBeGolden('screenshot-grid-fullpage.png'); }); it('should restore viewport after fullPage screenshot', async({page, server}) => { - await page.setViewport({width: 500, height: 500}); + await page.setViewportSize({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); const screenshot = await page.screenshot({ fullPage: true }); expect(screenshot).toBeInstanceOf(Buffer); - expect(page.viewport().width).toBe(500); - expect(page.viewport().height).toBe(500); + expect(page.viewportSize().width).toBe(500); + expect(page.viewportSize().height).toBe(500); }); it('should run in parallel in multiple pages', async({page, server, context}) => { const N = 2; @@ -115,7 +115,7 @@ module.exports.describe = function({testRunner, expect, product, FFOX, CHROMIUM, await Promise.all(pages.map(page => page.close())); }); it.skip(FFOX)('should allow transparency', async({page, server}) => { - await page.setViewport({ width: 50, height: 150 }); + await page.setViewportSize({ width: 50, height: 150 }); await page.setContent(`