</>

Technology

Playwright

Difficulty

Advanced

Interview Question

How would you set up Playwright to run tests on mobile, tablet, and desktop in a single CI run?

Answer

Scenario: Multi-Device Testing (Mobile, Tablet, Desktop)

Configure Projects for Each Device

TypeScript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  workers: 6, // 6 devices running simultaneously

  projects: [
    // ── Desktop ─────────────────────────────────────
    {
      name: 'Desktop Chrome',
      use: { ...devices['Desktop Chrome'] },
      // viewport: 1280x720
    },
    {
      name: 'Desktop Firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'Desktop Safari',
      use: { ...devices['Desktop Safari'] },
    },

    // ── Tablet ──────────────────────────────────────
    {
      name: 'iPad Pro',
      use: { ...devices['iPad Pro'] },
      // viewport: 1024x1366
    },
    {
      name: 'iPad Mini',
      use: { ...devices['iPad Mini'] },
      // viewport: 768x1024
    },

    // ── Mobile ──────────────────────────────────────
    {
      name: 'Pixel 5 (Android)',
      use: { ...devices['Pixel 5'] },
      // viewport: 393x851
    },
    {
      name: 'iPhone 12',
      use: { ...devices['iPhone 12'] },
      // viewport: 390x844
    },
    {
      name: 'Galaxy S21',
      use: { ...devices['Galaxy S21'] },
    },
  ],
});

Tests That Run on All Devices

TypeScript
// tests/responsive/navigation.spec.ts
import { test, expect } from '@playwright/test';

test('navigation is accessible on all devices', async ({ page, isMobile }) => {
  await page.goto('/');

  if (isMobile) {
    // Mobile shows hamburger menu
    await expect(page.getByRole('button', { name: 'Menu' })).toBeVisible();
    await expect(page.getByRole('navigation').locator('a')).not.toBeVisible();

    // Open mobile menu
    await page.getByRole('button', { name: 'Menu' }).click();
    await expect(page.getByRole('navigation').locator('a')).toBeVisible();
  } else {
    // Desktop shows full navigation
    await expect(page.getByRole('navigation').locator('a')).toBeVisible();
    await expect(page.getByRole('button', { name: 'Menu' })).not.toBeVisible();
  }
});

Device-Specific Tests

TypeScript
// tests/responsive/product-layout.spec.ts
import { test, expect } from '@playwright/test';

test('product grid layout', async ({ page, viewport }) => {
  await page.goto('/products');
  await expect(page.locator('.product-card')).toBeVisible();

  // Determine expected columns based on viewport width
  const width = viewport?.width || 1280;

  if (width < 640) {
    // Mobile: 1 column
    await expect(page.locator('.product-grid')).toHaveClass(/grid-cols-1/);
  } else if (width < 1024) {
    // Tablet: 2 columns
    await expect(page.locator('.product-grid')).toHaveClass(/grid-cols-2/);
  } else {
    // Desktop: 3 or 4 columns
    await expect(page.locator('.product-grid')).toHaveClass(/grid-cols-[34]/);
  }
});

Run Specific Device Profiles

Bash
# Run only mobile tests
npx playwright test --project="Pixel 5 (Android)"
npx playwright test --project="iPhone 12"

# Run only desktop
npx playwright test --project="Desktop Chrome"

# Run all devices
npx playwright test

# Skip specific device
npx playwright test --ignore-snapshots --project="Desktop Chrome" --project="iPhone 12"

Visual Regression Per Device

TypeScript
test('hero section renders correctly', async ({ page }) => {
  await page.goto('/');

  // Each device gets its own baseline snapshot
  await expect(page.locator('.hero')).toHaveScreenshot('hero.png');
  // Automatically creates: hero-Desktop-Chrome-darwin.png, hero-iPhone-12-darwin.png, etc.
});

GitHub Actions with All Devices

YAML
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        project: ['Desktop Chrome', 'Pixel 5 (Android)', 'iPad Pro']
    steps:
      - run: npx playwright test --project="${{ matrix.project }}"

Follow AutomateQA

Related Topics