/
githubmirror
/
puppeteer
Обзор
Документация
Войти
/
githubmirror
/
puppeteer
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/src/emulation.test.ts
722 строки
21 KB
Luiz Miguel
chore: fix the typos on the code test and API documentation (#15169)
30 июн 2026, 15:01
Не верифицирован
30 июн 2026, 15:01
54143a6
Код
Авторство
О чём код?
/** * @license * Copyright 2018 Google Inc. * SPDX-License-Identifier: Apache-2.0 */ import expect from 'expect'; import {KnownDevices, PredefinedNetworkConditions} from 'puppeteer'; import {getTestState, setupTestBrowserHooks} from './mocha-utils.js'; const iPhone = KnownDevices['iPhone 6']; const iPhoneLandscape = KnownDevices['iPhone 6 landscape']; describe('Emulation', () => { setupTestBrowserHooks(); describe('Page.viewport', function () { it('should get the proper viewport size', async () => { const {page} = await getTestState(); expect(page.viewport()).toEqual({width: 800, height: 600}); await page.setViewport({width: 123, height: 456}); expect(page.viewport()).toEqual({width: 123, height: 456}); }); it('should support mobile emulation', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/mobile.html'); expect( await page.evaluate(() => { return window.innerWidth; }), ).toBe(800); await page.setViewport(iPhone.viewport); expect( await page.evaluate(() => { return window.innerWidth; }), ).toBe(375); await page.setViewport({width: 400, height: 300}); expect( await page.evaluate(() => { return window.innerWidth; }), ).toBe(400); }); it('should support touch emulation', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/mobile.html'); expect( await page.evaluate(() => { return 'ontouchstart' in window; }), ).toBe(false); await page.setViewport(iPhone.viewport); expect( await page.evaluate(() => { return 'ontouchstart' in window; }), ).toBe(true); expect(await page.evaluate(dispatchTouch)).toBe('Received touch'); await page.setViewport({width: 100, height: 100}); expect( await page.evaluate(() => { return 'ontouchstart' in window; }), ).toBe(false); function dispatchTouch() { let fulfill!: (value: string) => void; const promise = new Promise(x => { fulfill = x; }); window.ontouchstart = () => { fulfill('Received touch'); }; window.dispatchEvent(new Event('touchstart')); fulfill('Did not receive touch'); return promise; } }); it('should be detectable by Modernizr', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/detect-touch.html'); expect( await page.evaluate(() => { return document.body.textContent!.trim(); }), ).toBe('NO'); await page.setViewport(iPhone.viewport); await page.goto(server.PREFIX + '/detect-touch.html'); expect( await page.evaluate(() => { return document.body.textContent!.trim(); }), ).toBe('YES'); }); it('should detect touch when applying viewport with touches', async () => { const {page, server} = await getTestState(); await page.setViewport({width: 800, height: 600, hasTouch: true}); await page.addScriptTag({url: server.PREFIX + '/modernizr.js'}); expect( await page.evaluate(() => { return (globalThis as any).Modernizr.touchevents; }), ).toBe(true); }); it('should support landscape emulation', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/mobile.html'); expect( await page.evaluate(() => { return screen.orientation.type; }), ).toBe('portrait-primary'); await page.setViewport(iPhoneLandscape.viewport); expect( await page.evaluate(() => { return screen.orientation.type; }), ).toBe('landscape-primary'); await page.setViewport({width: 100, height: 100}); expect( await page.evaluate(() => { return screen.orientation.type; }), ).toBe('portrait-primary'); }); it('should update media queries when resolution changes', async () => { const {page, server} = await getTestState(); async function getFontSize() { return await page.evaluate(() => { return parseInt( window.getComputedStyle(document.querySelector('p')!).fontSize, 10, ); }); } for (const dpr of [1, 2, 3]) { await page.setViewport({ width: 800, height: 600, deviceScaleFactor: dpr, }); await page.goto(server.PREFIX + '/resolution.html'); await expect(getFontSize()).resolves.toEqual(dpr); const screenshot = await page.screenshot({ fullPage: false, }); expect(screenshot).toBeGolden(`device-pixel-ratio${dpr}.png`); } }); it('should load correct pictures when emulation dpr', async () => { const {page, server} = await getTestState(); async function getCurrentSrc() { return await page.evaluate(() => { return document.querySelector('img')!.currentSrc; }); } for (const dpr of [1, 2, 3]) { await page.setViewport({ width: 800, height: 600, deviceScaleFactor: dpr, }); await page.goto(server.PREFIX + '/picture.html'); await expect(getCurrentSrc()).resolves.toMatch( new RegExp(`logo-${dpr}x.png`), ); } }); }); describe('Page.emulate', function () { it('should work', async () => { const {page, server} = await getTestState(); await page.goto(server.PREFIX + '/mobile.html'); await page.emulate(iPhone); expect( await page.evaluate(() => { return window.innerWidth; }), ).toBe(375); expect( await page.evaluate(() => { return navigator.userAgent; }), ).toContain('iPhone'); }); it('should work twice on about:blank', async () => { const {page} = await getTestState(); await page.goto('about:blank'); await page.emulate(KnownDevices['iPhone 13']); await page.emulate(KnownDevices['iPad Pro landscape']); }); it('should support clicking', async () => { const {page, server} = await getTestState(); await page.emulate(iPhone); await page.goto(server.PREFIX + '/input/button.html'); using button = (await page.$('button'))!; await page.evaluate(button => { return (button.style.marginTop = '200px'); }, button); await button.click(); expect( await page.evaluate(() => { return (globalThis as any).result; }), ).toBe('Clicked'); }); }); describe('Page.emulateMediaType', function () { it('should work', async () => { const {page} = await getTestState(); expect( await page.evaluate(() => { return matchMedia('screen').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('print').matches; }), ).toBe(false); await page.emulateMediaType('print'); expect( await page.evaluate(() => { return matchMedia('screen').matches; }), ).toBe(false); expect( await page.evaluate(() => { return matchMedia('print').matches; }), ).toBe(true); await page.emulateMediaType(); expect( await page.evaluate(() => { return matchMedia('screen').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('print').matches; }), ).toBe(false); }); it('should throw in case of bad argument', async () => { const {page} = await getTestState(); let error!: Error; await page.emulateMediaType('bad').catch(error_ => { return (error = error_); }); expect(error.message).toBe('Unsupported media type: bad'); }); }); describe('Page.emulateMediaFeatures', function () { it('should work', async () => { const {page} = await getTestState(); await page.emulateMediaFeatures([ {name: 'prefers-reduced-motion', value: 'reduce'}, ]); expect( await page.evaluate(() => { return matchMedia('(prefers-reduced-motion: reduce)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(prefers-reduced-motion: no-preference)').matches; }), ).toBe(false); await page.emulateMediaFeatures([ {name: 'prefers-color-scheme', value: 'light'}, ]); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: light)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: dark)').matches; }), ).toBe(false); await page.emulateMediaFeatures([ {name: 'prefers-color-scheme', value: 'dark'}, ]); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: dark)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: light)').matches; }), ).toBe(false); await page.emulateMediaFeatures([ {name: 'prefers-reduced-motion', value: 'reduce'}, {name: 'prefers-color-scheme', value: 'light'}, ]); expect( await page.evaluate(() => { return matchMedia('(prefers-reduced-motion: reduce)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(prefers-reduced-motion: no-preference)').matches; }), ).toBe(false); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: light)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(prefers-color-scheme: dark)').matches; }), ).toBe(false); await page.emulateMediaFeatures([{name: 'color-gamut', value: 'srgb'}]); expect( await page.evaluate(() => { return matchMedia('(color-gamut: p3)').matches; }), ).toBe(false); expect( await page.evaluate(() => { return matchMedia('(color-gamut: srgb)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(color-gamut: rec2020)').matches; }), ).toBe(false); await page.emulateMediaFeatures([{name: 'color-gamut', value: 'p3'}]); expect( await page.evaluate(() => { return matchMedia('(color-gamut: p3)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(color-gamut: srgb)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(color-gamut: rec2020)').matches; }), ).toBe(false); await page.emulateMediaFeatures([ {name: 'color-gamut', value: 'rec2020'}, ]); expect( await page.evaluate(() => { return matchMedia('(color-gamut: p3)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(color-gamut: srgb)').matches; }), ).toBe(true); expect( await page.evaluate(() => { return matchMedia('(color-gamut: rec2020)').matches; }), ).toBe(true); }); it('should throw in case of bad argument', async () => { const {page} = await getTestState(); let error!: Error; await page .emulateMediaFeatures([{name: 'bad', value: ''}]) .catch(error_ => { return (error = error_); }); expect(error.message).toBe('Unsupported media feature: bad'); }); }); describe('Page.emulateTimezone', function () { it('should work', async () => { const {page} = await getTestState(); await page.evaluate(() => { (globalThis as any).date = new Date(1479579154987); }); await page.emulateTimezone('America/Jamaica'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe('Sat Nov 19 2016 13:12:34 GMT-0500 (Eastern Standard Time)'); await page.emulateTimezone('Pacific/Honolulu'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe( 'Sat Nov 19 2016 08:12:34 GMT-1000 (Hawaii-Aleutian Standard Time)', ); await page.emulateTimezone('America/Buenos_Aires'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe('Sat Nov 19 2016 15:12:34 GMT-0300 (Argentina Standard Time)'); await page.emulateTimezone('Europe/Berlin'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe( 'Sat Nov 19 2016 19:12:34 GMT+0100 (Central European Standard Time)', ); }); it('should support timezone offset', async () => { const {page} = await getTestState(); await page.evaluate(() => { (globalThis as any).date = new Date(1479579154987); }); await page.emulateTimezone('GMT+10:00'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe('Sun Nov 20 2016 04:12:34 GMT+1000 (GMT+10:00)'); await page.emulateTimezone('GMT-12:34'); expect( await page.evaluate(() => { return (globalThis as any).date.toString(); }), ).toBe('Sat Nov 19 2016 05:38:34 GMT-1234 (GMT-12:34)'); }); it('should throw for invalid timezone IDs', async () => { const {page} = await getTestState(); let error!: Error; await page.emulateTimezone('Foo/Bar').catch(error_ => { return (error = error_); }); expect(error.message).atLeastOneToContain([ 'Invalid timezone ID: Foo/Bar', // CDP 'invalid argument', // BiDi. ]); // Assert the error message is informative. expect(error.message).toContain('Foo/Bar'); await page.emulateTimezone('Baz/Qux').catch(error_ => { return (error = error_); }); expect(error.message).atLeastOneToContain([ 'Invalid timezone ID: Baz/Qux', // CDP 'invalid argument', // BiDi. ]); // Assert the error message is informative. expect(error.message).toContain('Baz/Qux'); }); }); describe('Page.emulateLocale', function () { it('should work', async () => { const {page} = await getTestState(); const defaultLocale = await page.evaluate(() => { return Intl.NumberFormat().resolvedOptions().locale; }); const defaultLanguage = await page.evaluate(() => { return navigator.language; }); await page.emulateLocale('de-DE'); expect( await page.evaluate(() => { return Intl.NumberFormat().resolvedOptions().locale; }), ).toBe('de-DE'); expect( await page.evaluate(() => { return new Intl.NumberFormat().format(123456.78); }), ).toBe('123.456,78'); expect( await page.evaluate(() => { return navigator.language; }), ).toBe('de-DE'); expect( await page.evaluate(() => { return navigator.languages[0]; }), ).toBe('de-DE'); await page.emulateLocale('fr-FR'); expect( await page.evaluate(() => { return Intl.DateTimeFormat().resolvedOptions().locale; }), ).toBe('fr-FR'); await page.emulateLocale(); expect( await page.evaluate(() => { return Intl.NumberFormat().resolvedOptions().locale; }), ).toBe(defaultLocale); expect( await page.evaluate(() => { return navigator.language; }), ).toBe(defaultLanguage); }); }); describe('Page.emulateVisionDeficiency', function () { it('should work', async () => { const {page, server} = await getTestState(); await page.setViewport({width: 500, height: 500}); await page.goto(server.PREFIX + '/grid.html'); { await page.emulateVisionDeficiency('none'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('screenshot-sanity.png'); } { await page.emulateVisionDeficiency('achromatopsia'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-achromatopsia.png'); } { await page.emulateVisionDeficiency('blurredVision'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-blurredVision.png'); } { await page.emulateVisionDeficiency('deuteranopia'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-deuteranopia.png'); } { await page.emulateVisionDeficiency('protanopia'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-protanopia.png'); } { await page.emulateVisionDeficiency('tritanopia'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-tritanopia.png'); } { await page.emulateVisionDeficiency('none'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('screenshot-sanity.png'); } { await page.emulateVisionDeficiency('reducedContrast'); const screenshot = await page.screenshot(); expect(screenshot).toBeGolden('vision-deficiency-reducedContrast.png'); } }); it('should throw for invalid vision deficiencies', async () => { const {page} = await getTestState(); let error!: Error; await page // @ts-expect-error deliberately passing invalid deficiency .emulateVisionDeficiency('invalid') .catch(error_ => { return (error = error_); }); expect(error.message).toBe('Unsupported vision deficiency: invalid'); }); }); describe('Page.emulateNetworkConditions', function () { it('should support offline', async () => { const {isFirefox, page, server} = await getTestState(); await page.emulateNetworkConditions({ offline: true, download: 0, upload: 0, latency: 0, }); try { await page.goto(server.EMPTY_PAGE); throw new Error('not reached'); } catch (err) { let expectedError; if (isFirefox) { expectedError = /NS_ERROR_OFFLINE/; } else { expectedError = /ERR_INTERNET_DISCONNECTED/; } expect((err as Error).message).toMatch(expectedError); } }); it('should change navigator.connection.effectiveType', async () => { const {page} = await getTestState(); const slow3G = PredefinedNetworkConditions['Slow 3G']!; const fast3G = PredefinedNetworkConditions['Fast 3G']!; expect( await page.evaluate('window.navigator.connection.effectiveType'), ).toBe('4g'); await page.emulateNetworkConditions(fast3G); expect( await page.evaluate('window.navigator.connection.effectiveType'), ).toBe('3g'); await page.emulateNetworkConditions(slow3G); expect( await page.evaluate('window.navigator.connection.effectiveType'), ).toBe('2g'); await page.emulateNetworkConditions(null); }); }); describe('Page.emulateCPUThrottling', function () { it('should change the CPU throttling rate successfully', async () => { const {page} = await getTestState(); await page.emulateCPUThrottling(100); await page.emulateCPUThrottling(null); }); }); describe('Page.emulateFocusedPage', function () { it('should emulate focus', async () => { const {page, context} = await getTestState(); await page.emulateFocusedPage(true); expect( await page.evaluate(() => { return document.hasFocus(); }), ).toBe(true); const page2 = await context.newPage(); // Move page into background by focusing page2. await page2.bringToFront(); expect( await page.evaluate(() => { return document.hasFocus(); }), ).toBe(true); }); it('should reset focus', async () => { const {page, context} = await getTestState(); await page.emulateFocusedPage(true); const page2 = await context.newPage(); // Move page into background by focusing page2. await page2.bringToFront(); expect( await page.evaluate(() => { return document.hasFocus(); }), ).toBe(true); await page.emulateFocusedPage(false); expect( await page.evaluate(() => { return document.hasFocus(); }), ).toBe(false); }); }); });