Mac-first testing stack
Use the fastest layer that can answer the question, then move to a more realistic environment only when needed.
Recommended default: manual browser checks + Playwright automation + Safari/Xcode verification + at least one real-device pass before important releases.
Tool picker
These are complementary tools. The strongest workflow uses several layers instead of expecting one tool to prove everything.
Manual browser & device checks
Three columns show Use it for → macOS setup/open → best practice.
Do not confuse responsive emulation with real-device testing. Emulation is fast and valuable, but it cannot reproduce every CPU, GPU, keyboard, browser chrome, OS integration, memory, and touch behavior.
Use it for
Viewport resizing, DPR presets, CPU/network throttling, geolocation, orientation, layout inspection.
Open on Mac⌥⌘I for DevTools, then toggle the device toolbar. Chrome Device Mode is an approximation, not a real phone.
Best use
Fast first-pass responsive debugging. Follow failures or suspicious behavior with a physical device or simulator.
Use it for
Responsive layout in Gecko, viewport size, touch simulation, DPR/device presets, and Firefox-specific CSS behavior.
Open on Mac⌘⌥M or Firefox → Tools/Browser Tools → Responsive Design Mode.
Best use
Run after Chromium checks so Gecko-specific layout and standards differences are not missed.
Use it for
WebKit/Safari layout, media queries, pixel ratio, Web Inspector, Apple-platform browser behavior.
Enable on Mac
Safari → Settings → Advanced → Show features for web developers. Enter Responsive Design Mode with ⌃⌘R; Web Inspector with ⌥⌘I.
Best use
Required macOS check for Safari. Use Xcode Simulator or a physical iPhone/iPad when mobile Safari behavior matters.
Use it for
iPhone/iPad Safari in simulated iOS/iPadOS environments, different device sizes, OS versions, and Apple-specific behavior.
Install
Install Xcode from the Mac App Store, launch it once, then add runtimes in Xcode → Settings → Components. Safari can open pages in installed simulators from the Develop menu.
Best use
Closer to iOS than desktop viewport emulation, but still not physical hardware. Keep one real-device pass for release confidence.
Automation frameworks
Use automation for behaviors you need to verify repeatedly: navigation, forms, authentication, responsive menus, critical flows, and regressions.
Do not automate every visual detail. Automate stable user outcomes and critical UI states; keep exploratory and visual judgment in manual testing.
Modern cross-engine E2E testing with a strong TypeScript/JavaScript workflow, automatic waiting, traces, screenshots, network control, projects, and device profiles.
Install: run npm init playwright@latest in a project. The initializer can add TypeScript, tests, browsers, and a GitHub Actions workflow.
- Use when: you want one test API for Chromium, Firefox, WebKit, desktop, and emulated mobile.
- Best implementation: define browser/device projects in
playwright.config.ts; keep locators user-facing; use web-first assertions; run a small smoke matrix on every change and the full matrix in CI. - Important: Playwright WebKit/mobile profiles are excellent engine/emulation coverage, but they are not a substitute for every branded Safari + real iPhone/iPad behavior.
Open-source testing tool with an excellent interactive app, time-travel-style command debugging, network stubbing, E2E testing, and component testing.
Install: npm install cypress --save-dev, then npx cypress open.
- Use when: the team is strongly JavaScript/TypeScript and values a highly visual local authoring/debugging loop or component testing.
- Best implementation: use Chrome for Testing for deterministic Chromium runs; add Firefox; treat WebKit as experimental unless your release process also includes Safari/real-device validation.
- Tradeoff: excellent developer workflow, but less straightforward as a single all-engine mobile-web answer than Playwright.
Long-lived open-source browser automation built around W3C WebDriver, with language bindings, Selenium Grid, and broad browser/ecosystem support.
Install for JavaScript: npm install selenium-webdriver. Current Selenium uses Selenium Manager automatically, so ordinary setups no longer need manual ChromeDriver/GeckoDriver downloads.
- Use when: you need Java/Python/C#/Ruby/JS teams, existing Selenium infrastructure, remote grids, or broad/legacy browser coverage.
- Best implementation: use current Selenium 4+, explicit user-focused waits/assertions, and WebDriver BiDi capabilities where needed; avoid old tutorials that instruct you to hand-maintain browser drivers.
- Tradeoff: broader ecosystem and language reach, but usually more framework/infrastructure work than Playwright for a new JS/TS web project.
BrowserSync is not an E2E assertion framework. It is an open-source local server/proxy and synchronization tool for testing the same page across several real browsers/devices at once.
Install locally: npm install browser-sync --save-dev. Local installation is preferred for project reproducibility.
- Use when: you have phones/tablets on the same network and want one development URL, live reload, CSS injection, and optional scroll/click/form mirroring.
- Best implementation: use server mode for static sites and proxy mode when a PHP/Node/etc. server already exists. Open BrowserSync's External URL on each physical device.
- Tradeoff: excellent for visual/manual cross-device sweeps; it does not replace automated assertions or a real-device cloud.
Copy/paste setup & examples
These examples are macOS-friendly and assume a current Node.js project. Install project tooling locally unless there is a strong reason to install it globally.
Scaffold Playwright Test, install browser binaries, run all projects, open UI mode, and show the report.
npm init playwright@latest
# If browsers were not installed during setup:
npx playwright install
# Run the suite
npx playwright test
# Interactive test UI
npx playwright test --ui
# Open the last HTML report
npx playwright show-reportRun the same tests against the three major browser engines plus representative mobile profiles. Device names below are from Playwright's documented device registry.
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'http://127.0.0.1:4173',
trace: 'on-first-retry'
},
projects: [
{
name: 'Chromium',
use: { ...devices['Desktop Chrome'] }
},
{
name: 'Firefox',
use: { ...devices['Desktop Firefox'] }
},
{
name: 'WebKit',
use: { ...devices['Desktop Safari'] }
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] }
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 12'] }
}
]
});Example of testing a user-visible responsive behavior instead of only checking a viewport size.
import { test, expect } from '@playwright/test';
test('mobile navigation opens', async ({ page }) => {
await page.goto('/');
const menuButton = page.getByRole('button', { name: /menu/i });
await expect(menuButton).toBeVisible();
await menuButton.click();
await expect(
page.getByRole('navigation')
).toBeVisible();
});Install locally, use the Cypress App while authoring, then run repeatable headless checks in chosen browsers.
npm install cypress --save-dev
# Open the interactive Cypress App
npx cypress open
# Headless run in Chrome
npx cypress run --browser chrome
# Headless run in Firefox
npx cypress run --browser firefoxUse viewport changes to exercise responsive behavior, then assert the outcome users actually need.
describe('responsive navigation', () => {
it('opens the mobile menu', () => {
cy.viewport(390, 844);
cy.visit('/');
cy.findByRole('button', { name: /menu/i }).click();
cy.findByRole('navigation').should('be.visible');
});
});Selenium Manager handles the ordinary browser-driver setup automatically in current Selenium.
npm install selenium-webdriver
# example.mjs
import { Builder, Browser } from 'selenium-webdriver';
const driver = await new Builder()
.forBrowser(Browser.CHROME)
.build();
try {
await driver.get('http://127.0.0.1:4173');
console.log(await driver.getTitle());
} finally {
await driver.quit();
}Use the External URL printed by BrowserSync on other devices connected to the same local network.
npm install browser-sync --save-dev
# Static HTML/CSS/JS site
npx browser-sync start --server --files "css/*.css, js/*.js, *.html"
# Existing local server (example)
npx browser-sync start --proxy "http://localhost:3000" --files "css/*.css, js/*.js, *.html"
# Show CLI help
npx browser-sync start --helpChrome DevTools already includes Lighthouse. The CLI is useful for repeatable local or scripted audits.
npm install -g lighthouse
# Audit a running page
lighthouse http://127.0.0.1:4173
# See all CLI options
lighthouse --helpAdd automated accessibility checks to a browser test. Automated checks catch only part of accessibility; continue keyboard, focus, zoom, contrast, and screen-reader review manually.
npm install -D @axe-core/playwright
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('page has no automatically detectable a11y violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});Quality checks beyond layout
Cross-device quality includes more than width. Test performance, input methods, accessibility preferences, network behavior, and failure states.
Catches quickly
Performance opportunities, accessibility signals, best-practice issues, and SEO basics.
Best implementation
Use Chrome DevTools while developing; use the CLI or CI tooling when you need repeatable audits. Treat scores as signals, not as a substitute for real-user performance data.
Catches quickly
Many automatically detectable accessibility violations in rendered UI.
Best implementation
Run axe after important UI states become visible. Pair it with keyboard-only navigation, visible focus checks, zoom/reflow checks, labels, reading order, and manual assistive-technology review.
Catches quickly
Slow-loading assets, blocking requests, loading-state bugs, timeouts, and code that assumes desktop CPU/network speed.
Best implementation
Throttle network/CPU in Chrome DevTools and test slow-state UI. Real mobile hardware remains the stronger performance check because desktop throttling cannot reproduce every mobile processor/GPU condition.
Catches quickly
Controls too small for touch, hover-only interactions, motion problems, dark/light mode issues, and reduced-motion behavior.
Best implementation
Use browser emulation and Playwright context options for touch/user preferences, then physically use the interface on a touch device. Every important action should remain keyboard accessible.
Real-device strategy
Use real hardware whenever the bug could depend on the operating system, browser chrome, touch, virtual keyboard, device performance, memory, or hardware integration.
Free with Xcode on macOS and far more realistic for iOS/iPadOS Safari behavior than simply shrinking a desktop browser window.
Install Xcode from the Mac App Store, finish first-launch setup, then add simulator runtimes in Xcode → Settings → Components. Safari's Develop menu can open pages in installed simulators. Use several OS/runtime versions when compatibility matters.
Use a real Apple device for the highest-confidence Safari/touch/keyboard/performance check you can do locally.
Enable Safari developer features on the Mac, connect/pair the iPhone or iPad, enable inspection on the device as required, then inspect the device's Safari page from the Mac Develop menu. This is the right escalation step for bugs that only appear on actual hardware.
BrowserSync gives a local development URL that other phones/tablets/computers can open, with synchronized reloads and optional mirrored interactions.
Start BrowserSync in server or proxy mode. Copy the printed External URL into each device. Keep devices on the same trusted network. Disable Ghost Mode when mirrored clicks/scroll/forms would interfere with independent testing.
Use a cloud service when you need device/OS combinations you do not own, remote team access, screenshots/video, or repeatable release checks across real hardware.
BrowserStack is commercial rather than open source, but it supports manual and automated testing on remote browsers/devices and can reach localhost/staging through BrowserStack Local. Comparable paid services include Sauce Labs and LambdaTest. Use cloud hardware strategically rather than replacing fast local checks with expensive remote sessions.
Practical release matrix
Adapt the matrix to your analytics and audience. The goal is representative coverage, not testing every device ever made.
Downloads & official documentation
Prefer official documentation and current install commands. Tooling changes quickly; old tutorials often preserve obsolete driver, browser, or configuration steps.
Install: npm init playwright@latest
Browsers · Projects · Device emulation
Install: npm install cypress --save-dev
Launching browsers · Cross-browser testing
JS install: npm install selenium-webdriver
JavaScript API · Selenium Manager
Download Chrome · Device Mode docs explain viewport simulation, CPU/network throttling, sensors, and the limitations of desktop emulation.
Download Firefox · Responsive Design Mode is built into Firefox and opens on macOS with ⌘⌥M.
Safari ships with macOS. Enable developer features at Safari → Settings → Advanced → Show features for web developers. Responsive Design Mode.
Xcode is free from the Mac App Store. After first launch, install additional iOS/iPadOS runtimes from Xcode → Settings → Components as needed.
Preferred project install: npm install browser-sync --save-dev
CLI · Options / Ghost Mode · Gulp integration
Built into Chrome DevTools. Optional CLI: npm install -g lighthouse. Use it for repeatable performance/accessibility/best-practice/SEO audits.
Open-source accessibility engine. Core install: npm install axe-core --save-dev. Playwright integration: npm install -D @axe-core/playwright.