2020-08-03 13:41:48 -07:00
/ * *
* Copyright 2018 Google Inc . All rights reserved .
* Modifications copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2021-04-02 21:07:45 -07:00
2024-06-11 13:14:30 -07:00
import { devices } from '@playwright/test' ;
2022-03-25 15:05:50 -08:00
import { contextTest as it , expect } from '../config/browserTest' ;
import { browserTest } from '../config/browserTest' ;
import { verifyViewport } from '../config/utils' ;
2024-06-14 01:49:50 -07:00
import * as os from 'os' ;
2021-04-02 21:07:45 -07:00
2021-09-27 18:58:08 +02:00
it ( 'should get the proper default viewport size' , async ( { page , server } ) = > {
2020-09-18 15:52:14 -07:00
await verifyViewport ( page , 1280 , 720 ) ;
2020-08-03 13:41:48 -07:00
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should set the proper viewport size' , async ( { page , server } ) = > {
2020-09-18 15:52:14 -07:00
await verifyViewport ( page , 1280 , 720 ) ;
2022-06-08 14:13:39 -08:00
await page . setViewportSize ( { width : 345 , height : 456 } ) ;
await verifyViewport ( page , 345 , 456 ) ;
2020-08-03 13:41:48 -07:00
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should return correct outerWidth and outerHeight' , async ( { page } ) = > {
2022-05-12 18:46:03 +01:00
await page . setViewportSize ( { width : 410 , height : 420 } ) ;
2020-08-03 13:41:48 -07:00
const size = await page . evaluate ( ( ) = > {
return {
innerWidth : window.innerWidth ,
innerHeight : window.innerHeight ,
outerWidth : window.outerWidth ,
outerHeight : window.outerHeight ,
} ;
} ) ;
2022-05-12 18:46:03 +01:00
expect ( size . innerWidth ) . toBe ( 410 ) ;
expect ( size . innerHeight ) . toBe ( 420 ) ;
2020-08-03 13:41:48 -07:00
expect ( size . outerWidth >= size . innerWidth ) . toBeTruthy ( ) ;
expect ( size . outerHeight >= size . innerHeight ) . toBeTruthy ( ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should emulate device width' , async ( { page , server } ) = > {
expect ( page . viewportSize ( ) ) . toEqual ( { width : 1280 , height : 720 } ) ;
2023-05-14 16:59:15 +02:00
await page . setViewportSize ( { width : 300 , height : 300 } ) ;
expect ( await page . evaluate ( ( ) = > window . screen . width ) ) . toBe ( 300 ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-width: 200px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-width: 400px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-width: 200px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-width: 400px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-width: 600px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-width: 300px)' ) . matches ) ) . toBe ( true ) ;
2021-09-27 18:58:08 +02:00
await page . setViewportSize ( { width : 500 , height : 500 } ) ;
2020-08-03 13:41:48 -07:00
expect ( await page . evaluate ( ( ) = > window . screen . width ) ) . toBe ( 500 ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-width: 400px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-width: 600px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-width: 400px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-width: 600px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-width: 200px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-width: 500px)' ) . matches ) ) . toBe ( true ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should emulate device height' , async ( { page , server } ) = > {
expect ( page . viewportSize ( ) ) . toEqual ( { width : 1280 , height : 720 } ) ;
2023-05-14 16:59:15 +02:00
await page . setViewportSize ( { width : 300 , height : 300 } ) ;
expect ( await page . evaluate ( ( ) = > window . screen . height ) ) . toBe ( 300 ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-height: 200px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-height: 400px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-height: 200px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-height: 400px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-height: 600px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-height: 300px)' ) . matches ) ) . toBe ( true ) ;
2021-09-27 18:58:08 +02:00
await page . setViewportSize ( { width : 500 , height : 500 } ) ;
2020-08-03 13:41:48 -07:00
expect ( await page . evaluate ( ( ) = > window . screen . height ) ) . toBe ( 500 ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-height: 400px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(min-device-height: 600px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-height: 400px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(max-device-height: 600px)' ) . matches ) ) . toBe ( true ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-height: 200px)' ) . matches ) ) . toBe ( false ) ;
expect ( await page . evaluate ( ( ) = > matchMedia ( '(device-height: 500px)' ) . matches ) ) . toBe ( true ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should emulate availWidth and availHeight' , async ( { page } ) = > {
await page . setViewportSize ( { width : 500 , height : 600 } ) ;
2020-09-30 04:14:29 -07:00
expect ( await page . evaluate ( ( ) = > window . screen . availWidth ) ) . toBe ( 500 ) ;
expect ( await page . evaluate ( ( ) = > window . screen . availHeight ) ) . toBe ( 600 ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should not have touch by default' , async ( { page , server } ) = > {
2020-08-03 13:41:48 -07:00
await page . goto ( server . PREFIX + '/mobile.html' ) ;
expect ( await page . evaluate ( ( ) = > 'ontouchstart' in window ) ) . toBe ( false ) ;
await page . goto ( server . PREFIX + '/detect-touch.html' ) ;
expect ( await page . evaluate ( ( ) = > document . body . textContent . trim ( ) ) ) . toBe ( 'NO' ) ;
} ) ;
2023-01-27 15:51:57 -08:00
it ( 'should throw on tap if hasTouch is not enabled' , async ( { page } ) = > {
await page . setContent ( ` <div>a</div> ` ) ;
{
const error = await page . tap ( 'div' ) . catch ( e = > e ) ;
expect ( error ) . toBeTruthy ( ) ;
expect ( error . message ) . toContain ( 'The page does not support tap' ) ;
}
{
const error = await page . locator ( 'div' ) . tap ( ) . catch ( e = > e ) ;
expect ( error ) . toBeTruthy ( ) ;
expect ( error . message ) . toContain ( 'The page does not support tap' ) ;
}
} ) ;
2021-09-27 18:58:08 +02:00
browserTest ( 'should support touch with null viewport' , async ( { browser , server } ) = > {
2020-08-03 13:41:48 -07:00
const context = await browser . newContext ( { viewport : null , hasTouch : true } ) ;
const page = await context . newPage ( ) ;
await page . goto ( server . PREFIX + '/mobile.html' ) ;
expect ( await page . evaluate ( ( ) = > 'ontouchstart' in window ) ) . toBe ( true ) ;
await context . close ( ) ;
} ) ;
2021-10-18 10:45:47 -07:00
it ( 'should set both screen and viewport options' , async ( { contextFactory , browserName } ) = > {
it . fail ( browserName === 'firefox' , 'Screen size is reset to viewport' ) ;
const context = await contextFactory ( {
screen : { 'width' : 1280 , 'height' : 720 } ,
viewport : { 'width' : 1000 , 'height' : 600 } ,
} ) ;
const page = await context . newPage ( ) ;
const screen = await page . evaluate ( ( ) = > ( { w : screen.width , h : screen.height } ) ) ;
expect ( screen ) . toEqual ( { w : 1280 , h : 720 } ) ;
const inner = await page . evaluate ( ( ) = > ( { w : window.innerWidth , h : window.innerHeight } ) ) ;
expect ( inner ) . toEqual ( { w : 1000 , h : 600 } ) ;
} ) ;
2021-09-27 18:58:08 +02:00
browserTest ( 'should report null viewportSize when given null viewport' , async ( { browser , server } ) = > {
2020-08-03 13:41:48 -07:00
const context = await browser . newContext ( { viewport : null } ) ;
const page = await context . newPage ( ) ;
expect ( page . viewportSize ( ) ) . toBe ( null ) ;
await context . close ( ) ;
} ) ;
2021-07-12 17:20:08 -05:00
2021-09-27 18:58:08 +02:00
browserTest ( 'should drag with high dpi' , async ( { browser , server } ) = > {
2021-07-12 17:20:08 -05:00
const page = await browser . newPage ( { deviceScaleFactor : 2 } ) ;
await page . goto ( server . PREFIX + '/drag-n-drop.html' ) ;
await page . hover ( '#source' ) ;
await page . mouse . down ( ) ;
await page . hover ( '#target' ) ;
await page . mouse . up ( ) ;
expect ( await page . $eval ( '#target' , target = > target . contains ( document . querySelector ( '#source' ) ) ) ) . toBe ( true ) ; // could not find source in target
await page . close ( ) ;
} ) ;
2023-05-11 17:54:05 +02:00
it ( 'WebKit Windows headed should have a minimal viewport' , async ( { contextFactory , browserName , headless , isWindows } ) = > {
it . skip ( browserName !== 'webkit' || headless || ! isWindows , 'Not relevant for this browser' ) ;
await expect ( contextFactory ( {
viewport : { 'width' : 100 , 'height' : 100 } ,
2023-05-14 16:59:15 +02:00
} ) ) . rejects . toThrow ( 'WebKit on Windows has a minimal viewport of 250x240.' ) ;
2023-05-11 17:54:05 +02:00
const context = await contextFactory ( ) ;
const page = await context . newPage ( ) ;
2023-05-14 16:59:15 +02:00
await expect ( page . setViewportSize ( { width : 100 , height : 100 } ) ) . rejects . toThrow ( 'WebKit on Windows has a minimal viewport of 250x240.' ) ;
2023-05-11 17:54:05 +02:00
await context . close ( ) ;
} ) ;
2023-06-24 02:34:09 +08:00
browserTest ( 'should be able to get correct orientation angle on non-mobile devices' , async ( { browser , browserName , server } ) = > {
browserTest . skip ( browserName === 'webkit' , 'Desktop webkit dont support orientation API' ) ;
const context = await browser . newContext ( { viewport : { width : 300 , height : 400 } , isMobile : false } ) ;
const page = await context . newPage ( ) ;
await page . goto ( server . PREFIX + '/index.html' ) ;
expect ( await page . evaluate ( ( ) = > window . screen . orientation . angle ) ) . toBe ( 0 ) ;
await page . setViewportSize ( { width : 400 , height : 300 } ) ;
expect ( await page . evaluate ( ( ) = > window . screen . orientation . angle ) ) . toBe ( 0 ) ;
await context . close ( ) ;
} ) ;
2024-06-11 13:14:30 -07:00
2024-06-14 01:49:50 -07:00
it ( 'should set window.screen.orientation.type for mobile devices' , async ( { contextFactory , browserName , server , isMac } ) = > {
2024-06-11 13:14:30 -07:00
it . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/31151' } ) ;
it . skip ( browserName === 'firefox' , 'Firefox does not support mobile emulation' ) ;
2024-07-24 18:45:03 +02:00
it . skip ( browserName === 'webkit' && isMac && parseInt ( os . release ( ) . split ( '.' ) [ 0 ] , 10 ) <= 21 , 'WebKit on macOS 12 is frozen and does not support orientation.type override' ) ;
2024-06-11 13:14:30 -07:00
const context = await contextFactory ( devices [ 'iPhone 14' ] ) ;
const page = await context . newPage ( ) ;
await page . goto ( server . PREFIX + '/index.html' ) ;
expect ( await page . evaluate ( ( ) = > window . screen . orientation . type ) ) . toBe ( 'portrait-primary' ) ;
await context . close ( ) ;
} ) ;