乐闻世界logo
搜索文章和话题

How does Puppeteer implement device emulation and mobile testing? What are the built-in devices and custom configuration methods?

2月19日 19:39

Puppeteer provides powerful device emulation capabilities, allowing you to simulate various mobile devices, screen sizes, user agents, and more. This is very useful for responsive design testing and mobile web testing.

1. Device Emulation Basics

Puppeteer includes preset configurations for many common devices.

javascript
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // Emulate iPhone 12 const iPhone = puppeteer.devices['iPhone 12']; await page.emulate(iPhone); await page.goto('https://example.com'); await page.screenshot({ path: 'iphone-12.png' }); await browser.close(); })();

2. Built-in Device List

Puppeteer provides the following device presets:

iPhone Series:

  • iPhone 12 Pro
  • iPhone 12
  • iPhone 11 Pro
  • iPhone 11
  • iPhone X
  • iPhone 8
  • iPhone 8 Plus
  • iPhone SE
  • iPhone 7
  • iPhone 7 Plus
  • iPhone 6
  • iPhone 6 Plus
  • iPhone 5
  • iPhone 4

iPad Series:

  • iPad Pro 11
  • iPad Pro
  • iPad Mini
  • iPad

Android Series:

  • Pixel 5
  • Pixel 4
  • Pixel 2
  • Galaxy S5
  • Galaxy Note III
  • Nexus 10
  • Nexus 7
  • Nexus 6
  • Nexus 5
  • Nexus 4

Other Devices:

  • Kindle Fire HDX
  • Blackberry Z30
  • Blackberry PlayBook
  • Nokia N9
  • Nokia Lumia 520

3. View Device Configuration

javascript
const puppeteer = require('puppeteer'); // View all available devices console.log(Object.keys(puppeteer.devices)); // View specific device configuration const iPhone = puppeteer.devices['iPhone 12']; console.log(iPhone); /* Output: { name: 'iPhone 12', userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1', viewport: { width: 390, height: 844, deviceScaleFactor: 3, isMobile: true, hasTouch: true, isLandscape: false } } */

4. Custom Device Configuration

If built-in devices don't meet your needs, you can create custom configurations.

javascript
const customDevice = { name: 'Custom Device', userAgent: 'Mozilla/5.0 (Custom Device) AppleWebKit/537.36', viewport: { width: 414, height: 896, deviceScaleFactor: 2, isMobile: true, hasTouch: true, isLandscape: false } }; await page.emulate(customDevice);

5. Manual Viewport Setting

You can set viewport parameters separately without using full device emulation.

javascript
// Set viewport size await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 1, isMobile: false, hasTouch: false, isLandscape: false }); // Set mobile device viewport await page.setViewport({ width: 375, height: 667, deviceScaleFactor: 2, isMobile: true, hasTouch: true });

6. User Agent Setting

Set user agent string separately.

javascript
// Set custom user agent await page.setUserAgent('Mozilla/5.0 (Custom User Agent) AppleWebKit/537.36'); // Set mobile device user agent await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15');

7. Geolocation Emulation

Emulate device geolocation.

javascript
// Set geolocation await page.setGeolocation({ latitude: 35.6895, longitude: 139.6917 }); // Grant geolocation permission await context.overridePermissions('https://example.com', ['geolocation']); // Usage example const browser = await puppeteer.launch(); const context = await browser.createIncognitoBrowserContext(); const page = await context.newPage(); await page.setGeolocation({ latitude: 35.6895, longitude: 139.6917 }); await context.overridePermissions('https://example.com', ['geolocation']); await page.goto('https://example.com');

8. Timezone Emulation

Emulate different timezones.

javascript
// Set timezone await page.emulateTimezone('Asia/Shanghai'); // Other timezone examples await page.emulateTimezone('America/New_York'); await page.emulateTimezone('Europe/London'); await page.emulateTimezone('UTC');

9. Language and Locale Setting

Set browser language and locale.

javascript
// Set language await page.setExtraHTTPHeaders({ 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8' }); // Set at launch const browser = await puppeteer.launch({ args: ['--lang=zh-CN'] });

10. Touch Event Emulation

Emulate touch device behavior.

javascript
const touchDevice = { viewport: { width: 375, height: 667, isMobile: true, hasTouch: true } }; await page.setViewport(touchDevice.viewport); // Emulate touch tap await page.tap('#button'); // Emulate touch swipe await page.touchscreen.tap(100, 100);

11. Practical Use Cases

Use Case 1: Responsive Design Testing

javascript
async function testResponsiveDesign(url) { const browser = await puppeteer.launch(); const page = await browser.newPage(); const viewports = [ { name: 'Desktop', width: 1920, height: 1080 }, { name: 'Tablet', width: 768, height: 1024 }, { name: 'Mobile', width: 375, height: 667 } ]; for (const viewport of viewports) { await page.setViewport({ width: viewport.width, height: viewport.height }); await page.goto(url, { waitUntil: 'networkidle2' }); // Check if layout is correct const isLayoutCorrect = await page.evaluate(() => { const header = document.querySelector('header'); return header && header.offsetWidth <= viewport.width; }); console.log(`${viewport.name}: ${isLayoutCorrect ? '✓' : '✗'}`); await page.screenshot({ path: `${viewport.name.toLowerCase()}.png` }); } await browser.close(); } testResponsiveDesign('https://example.com');

Use Case 2: Multi-Device Compatibility Testing

javascript
async function testMultiDeviceCompatibility(url) { const browser = await puppeteer.launch(); const page = await browser.newPage(); const devices = [ 'iPhone 12', 'iPad Pro', 'Pixel 5' ]; for (const deviceName of devices) { const device = puppeteer.devices[deviceName]; await page.emulate(device); await page.goto(url, { waitUntil: 'networkidle2' }); // Check if functionality works const isFunctional = await page.evaluate(() => { const buttons = document.querySelectorAll('button'); return buttons.length > 0 && buttons[0].click(); }); console.log(`${deviceName}: ${isFunctional ? '✓' : '✗'}`); await page.screenshot({ path: `${deviceName.replace(/\s/g, '_')}.png` }); } await browser.close(); } testMultiDeviceCompatibility('https://example.com');

Use Case 3: Mobile UX Testing

javascript
async function testMobileUX(url) { const browser = await puppeteer.launch(); const context = await browser.createIncognitoBrowserContext(); const page = await context.newPage(); // Emulate mobile device await page.emulate(puppeteer.devices['iPhone 12']); // Set geolocation await page.setGeolocation({ latitude: 35.6895, longitude: 139.6917 }); await context.overridePermissions(url, ['geolocation']); await page.goto(url, { waitUntil: 'networkidle2' }); // Test touch interactions await page.tap('#menu-button'); await page.waitForSelector('.menu', { visible: true }); // Test scrolling await page.evaluate(() => { window.scrollBy(0, 500); }); // Check response time const startTime = Date.now(); await page.click('#action-button'); const responseTime = Date.now() - startTime; console.log(`Response time: ${responseTime}ms`); await browser.close(); } testMobileUX('https://example.com');

Use Case 4: Internationalization Testing

javascript
async function testInternationalization(url) { const browser = await puppeteer.launch(); const page = await browser.newPage(); const locales = [ { code: 'zh-CN', language: '中文' }, { code: 'en-US', language: 'English' }, { code: 'ja-JP', language: '日本語' } ]; for (const locale of locales) { // Set language await page.setExtraHTTPHeaders({ 'Accept-Language': locale.code }); // Set timezone await page.emulateTimezone(locale.code === 'zh-CN' ? 'Asia/Shanghai' : locale.code === 'en-US' ? 'America/New_York' : 'Asia/Tokyo'); await page.goto(url, { waitUntil: 'networkidle2' }); // Check if language is correct const pageLanguage = await page.evaluate(() => { return document.documentElement.lang; }); console.log(`${locale.language}: ${pageLanguage}`); await page.screenshot({ path: `${locale.code}.png` }); } await browser.close(); } testInternationalization('https://example.com');

12. Best Practices

1. Use built-in device presets:

javascript
// Recommended await page.emulate(puppeteer.devices['iPhone 12']); // Not recommended (unless special requirements) await page.setViewport({ width: 390, height: 844 });

2. Reset state before testing:

javascript
async function resetPage(page) { await page.emulate(puppeteer.devices['Desktop']); await page.setGeolocation({ latitude: 0, longitude: 0 }); await page.emulateTimezone('UTC'); }

3. Use context for test isolation:

javascript
const context = await browser.createIncognitoBrowserContext(); const page = await context.newPage(); // Test code await context.close();

4. Record test results:

javascript
const testResults = []; for (const device of devices) { const result = await testDevice(device); testResults.push({ device, result }); } console.log(JSON.stringify(testResults, null, 2));

13. Important Notes

  1. Performance Impact: Device emulation may affect performance, especially when switching frequently
  2. Cache Issues: Different devices may require cache clearing for accurate results
  3. Network Conditions: Consider simulating different network speeds
  4. Real Device Differences: Emulation may have subtle differences from real devices
  5. Permission Management: Ensure proper setup of permissions like geolocation
标签:Puppeteer