Test on real mobile devices and viewports
Verify your application on real mobile devices and browser DevTools device emulation to catch touch interaction issues, viewport bugs, and mobile-specific rendering problems.
- Desktop DevTools device emulation catches layout issues but not real touch behavior
- Test on at least one Android (Chrome) and one iOS (Safari) real device
- Test common viewport breakpoints: 375px (iPhone SE), 390px (iPhone 14), 768px (iPad)
- Use BrowserStack or similar services for testing on devices you don't own
Rule Details
Mobile testing catches an entire class of issues that are invisible on desktop browsers.
Code Examples
// playwright.config.js
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
projects: [
// Desktop
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
// Mobile
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 7'] },
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 14'] },
},
{
name: 'Tablet',
use: { ...devices['iPad Pro 11'] },
}
]
})// tests/mobile/navigation.spec.js
import { test, expect, devices } from '@playwright/test'
test.use({ ...devices['iPhone 14'] })
test('mobile navigation opens and closes', async ({ page }) => {
await page.goto('/')
// Mobile menu should be closed initially
await expect(page.locator('[data-mobile-menu]')).not.toBeVisible()
// Open mobile menu
await page.locator('[data-hamburger]').tap() // Use tap, not click
await expect(page.locator('[data-mobile-menu]')).toBeVisible()
// Close with X button
await page.locator('[data-menu-close]').tap()
await expect(page.locator('[data-mobile-menu]')).not.toBeVisible()
})
test('checkout form works on mobile keyboard', async ({ page }) => {
await page.goto('/checkout')
// Test that virtual keyboard doesn't cover the active input
const emailInput = page.locator('#email')
await emailInput.tap()
// Scroll the page to verify the input is in view when keyboard opens
await expect(emailInput).toBeInViewport()
})Why It Matters
More than 55% of global web traffic comes from mobile devices. Mobile browsers have different rendering engines, different font rendering, limited memory, real touch events that differ from mouse events, and system UI (notch, home indicator, keyboard) that intrudes on your layout. Issues like sticky hover states, touch target sizes, and keyboard layout shifts only appear on real devices.
Mobile-Specific Issues to Test
Layout and viewport:
✓ No horizontal scroll on any viewport width
✓ Content doesn't overflow on 375px viewport
✓ Notch/safe-area-inset doesn't hide content
✓ Virtual keyboard doesn't cover active inputs
Touch interactions:
✓ Tap targets are at least 44x44px
✓ No hover-dependent functionality (hover doesn't persist on touch)
✓ Swipe gestures work on carousels and drawers
✓ Pinch-to-zoom works (unless disabled intentionally)
Forms:
✓ Correct keyboard type appears for each input (numeric, email, etc.)
✓ Autocomplete suggestions appear
✓ Form doesn't jump when keyboard opens/closes
Performance:
✓ App is usable on throttled 3G
✓ No excessive memory usage during scroll
✓ Animations run at 60fpsChrome DevTools Quick Checks
// Test responsive breakpoints programmatically
const viewports = [
{ width: 375, height: 667, name: 'iPhone SE' },
{ width: 390, height: 844, name: 'iPhone 14' },
{ width: 430, height: 932, name: 'iPhone 14 Plus' },
{ width: 768, height: 1024, name: 'iPad Mini' },
{ width: 1024, height: 1366, name: 'iPad Pro' }
]
for (const viewport of viewports) {
test(`layout correct on ${viewport.name}`, async ({ page }) => {
await page.setViewportSize(viewport)
await page.goto('/')
// Check no horizontal scroll
const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth)
const clientWidth = await page.evaluate(() => document.documentElement.clientWidth)
expect(scrollWidth).toBeLessThanOrEqual(clientWidth)
})
}Real Device Testing Priority
- iOS Safari (unique rendering engine, unique bugs)
- Android Chrome (most common Android browser)
- Chrome DevTools emulation (fast, covers layout basics)
- Samsung Internet (if your audience uses Samsung devices)
Verification
Automated Checks
- Run the relevant test or CI step locally and confirm it fails when the rule is violated.
Manual Checks
- Ensure the automation blocks regressions instead of only printing warnings.
- Cover at least one representative high-risk flow, component, or route.
- Keep thresholds or assertions in version control so changes remain reviewable.
Use with AI
Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.
Check
Verify implementation
Does this project have any mobile-specific test configurations? Check for Playwright device emulation, mobile viewport tests, or notes about mobile testing.
Fix
Auto-fix issues
Add Playwright tests using mobile device presets to cover key user flows on mobile viewports.
Explain
Learn more
Explain the difference between DevTools emulation and real device testing, common mobile-specific issues to test for, and how to use Playwright's device emulation.
Review
Code review
Review tests, CI workflows, and enforcement points related to Test on real mobile devices and viewports. Flag exact gaps where the rule is not automatically verified or where failures do not block regressions.