Skip to content

BROWSER INTERACTIONS · LESSON 19 OF 24

Browser projects and mobile emulation

Run one behavior across browser engines and a mobile-sized context.

  • projects
  • devices
  • Chromium
  • Firefox
  • WebKit

Your runnable checkpoint

Extract into a new practice folder. Each download contains tests, configuration, the complete local practice app and an offline lesson. Use Node.js 22 or 24. Each checkpoint is independent.

Install dependencies and browser binaries using the commands below. The test runner starts the practice server on port 4174. Tests target localhost, never the production EduPoly site.

1. Understand the concepts

Projects let one suite run with different browser or environment settings. This checkpoint defines Chromium, Firefox, WebKit and a Pixel 5-style Chromium context. Install the corresponding browser binaries before running all projects.

Device descriptors configure viewport, user agent and related context settings. Emulation is useful for responsive behavior but is not a real phone, hardware keyboard, network or operating system.

Keep assertions focused on behavior that should be shared. When a feature intentionally differs across projects, document that difference rather than weakening every assertion.

Browser binaries have operating-system requirements. If a browser is unsupported on an older machine, run Chromium locally and execute the full matrix on a supported CI runner. Do not claim cross-browser coverage from a Chromium-only run.

2. Build and run

These are complete test files and configuration. The download also includes app/ and server.mjs; preserve their paths. Stop any manually started practice server before running the suite.

Terminal
npm install
npx playwright install chromium firefox webkit
npm run check
npm test

tests/lesson.spec.ts

tests/lesson.spec.ts
import { test, expect } from '@playwright/test';
test('the task form works across projects', async ({ page }) => {
  await page.goto('/');
  await page.getByLabel('Task title', { exact: true }).fill('Cross-browser task');
  await page.getByRole('button', { name: 'Add task', exact: true }).click();
  await expect(page.getByTestId('task-row')).toContainText('Cross-browser task');
});

playwright.config.ts

playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 1 : 0,
  workers: process.env.CI ? 2 : undefined,
  timeout: 30000,
  expect: { timeout: 5000 },
  reporter: [['list'], ['html', { open: 'never' }]],
  use: { baseURL: 'http://127.0.0.1:4174', trace: 'retain-on-failure', screenshot: 'only-on-failure' },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chromium', use: { ...devices['Pixel 5'] } }
  ],
  webServer: { command: 'node server.mjs', url: 'http://127.0.0.1:4174', reuseExistingServer: false, timeout: 15000 }
});

package.json

package.json
{
  "name": "edupoly-playwright-browsers-and-mobile-emulation",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "test": "playwright test",
    "test:headed": "playwright test --headed",
    "test:ui": "playwright test --ui",
    "check": "tsc --noEmit",
    "report": "playwright show-report",
    "serve": "node server.mjs"
  },
  "devDependencies": {
    "@playwright/test": "1.56.1",
    "typescript": "5.9.3",
    "@types/node": "22.20.5"
  }
}

tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "moduleResolution": "Node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "types": [
      "node"
    ],
    "noEmit": true
  },
  "include": [
    "tests/**/*.ts",
    "pages/**/*.ts",
    "playwright.config.ts"
  ]
}

.gitignore

.gitignore
node_modules/
playwright-report/
test-results/
playwright/.auth/
.env

3. Trace the code and check the result

  1. The same scenario is executed with each project’s context options.
  2. The mobile project uses Chromium with a device descriptor.
  3. A passing browser matrix is distinct from testing real mobile hardware.

Verify your result

  • npm test runs the scenario in four projects when all browsers are installed.
  • npm test -- --project=chromium selects one project.

4. Practice independently

Add a narrow custom viewport project without changing the test.

Show the explanation

Add a Chromium project with use: { browserName: "chromium", viewport: { width: 390, height: 844 } }. Run it by its project name.

When something goes wrong

If a browser executable is missing, run npx playwright install chromium in the project folder. If port 4174 is occupied, stop your manual practice server. Read assertion call logs for mismatched locators or expectations. Use npm run report to inspect failures; do not add fixed sleeps or broad resets to hide them.

Read the related official Playwright documentation ↗