npx skills add https://github.com/adaptationio/skrillz --skill mobile-emulationSKILL.md
Mobile Emulation Testing with Playwright
Test responsive designs and mobile-specific features using Playwright's device emulation capabilities.
Quick Start
import { test, expect, devices } from '@playwright/test';
test.use(devices['iPhone 14']);
test('mobile navigation works', async ({ page }) => {
await page.goto('/');
// Mobile menu should be visible
await page.getByRole('button', { name: 'Menu' }).click();
await expect(page.getByRole('navigation')).toBeVisible();
});
Configuration
Project-Based Device Testing
playwright.config.ts:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
// Desktop browsers
{
name: 'Desktop Chrome',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'Desktop Firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'Desktop Safari',
use: { ...devices['Desktop Safari'] },
},
// Mobile devices
{
name: 'iPhone 14',
use: { ...devices['iPhone 14'] },
},
{
name: 'iPhone 14 Pro Max',
use: { ...devices['iPhone 14 Pro Max'] },
},
{
name: 'Pixel 7',
use: { ...devices['Pixel 7'] },
},
{
name: 'Galaxy S23',
use: { ...devices['Galaxy S III'] }, // Closest available
},
// Tablets
{
name: 'iPad Pro',
use: { ...devices['iPad Pro 11'] },
},
{
name: 'iPad Mini',
use: { ...devices['iPad Mini'] },
},
],
});
Custom Device Configuration
{
name: 'Custom Mobile',
use: {
viewport: { width: 390, height: 844 },
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...',
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true,
defaultBrowserType: 'webkit',
},
},
Available Devices
Popular Devices
import { devices } from '@playwright/test';
// iPhones
devices['iPhone 14']
devices['iPhone 14 Plus']
devices['iPhone 14 Pro']
devices['iPhone 14 Pro Max']
devices['iPhone 13']
devices['iPhone 12']
devices['iPhone SE']
// Android Phones
devices['Pixel 7']
devices['Pixel 5']
devices['Galaxy S III']
devices['Galaxy S5']
devices['Galaxy Note 3']
devices['Nexus 5']
// Tablets
devices['iPad Pro 11']
devices['iPad Pro 11 landscape']
devices['iPad Mini']
devices['iPad (gen 7)']
devices['Galaxy Tab S4']
// Desktop
devices['Desktop Chrome']
devices['Desktop Firefox']
devices['Desktop Safari']
devices['Desktop Edge']
List All Devices
import { devices } from '@playwright/test';
console.log(Object.keys(devices));
// Outputs all available device names
Responsive Breakpoint Testing
Test Multiple Viewports
const breakpoints = [
{ name: 'mobile', width: 375, height: 667 },
{ name: 'tablet', width: 768, height: 1024 },
{ name: 'desktop', width: 1280, height: 720 },
{ name: 'wide', width: 1920, height: 1080 },
];
for (const bp of breakpoints) {
test(`layout at ${bp.name}`, async ({ page }) => {
await page.setViewportSize({ width: bp.width, height: bp.height });
await page.goto('/');
await expect(page).toHaveScreenshot(`layout-${bp.name}.png`);
});
}
Dynamic Viewport Changes
test('responsive navigation', async ({ page }) => {
await page.goto('/');
// Desktop - horizontal nav
await page.setViewportSize({ width: 1280, height: 720 });
await expect(page.locator('.desktop-nav')).toBeVisible();
await expect(page.locator('.mobile-menu-button')).not.toBeVisible();
// Tablet - may show hamburger
await page.setViewportSize({ width: 768, height: 1024 });
// Mobile - hamburger menu
await page.setViewportSize({ width: 375, height: 667 });
await expect(page.locator('.desktop-nav')).not.toBeVisible();
await expect(page.locator('.mobile-menu-button')).toBeVisible();
});
Touch Interactions
Tap
test('tap interaction', async ({ page }) => {
await page.goto('/');
// Tap is equivalent to click on touch devices
await page.getByRole('button').tap();
});
Swipe
test('swipe carousel', async ({ page }) => {
await page.goto('/gallery');
const carousel = page.locator('.carousel');
const box = await carousel.boundingBox();
if (box) {
// Swipe left
await page.mouse.move(box.x + box.width - 50, box.y + box.height / 2);
await page.mouse.down();
await page.mouse.move(box.x + 50, box.y + box.height / 2, { steps: 10 });
await page.mouse.up();
}
await expect(page.locator('.slide-2')).toBeVisible();
});
Pinch to Zoom
test('pinch to zoom map', async ({ page }) => {
await page.goto('/map');
const map = page.locator('#map');
const box = await map.boundingBox();
if (box) {
const centerX = box.x + box.width / 2;
const centerY = box.y + box.height / 2;
// Simulate pinch out (zoom in)
await page.touchscreen
...
Repository
adaptationio/skrillzParent repository
Repository Stats
Stars1
Forks0