JS Sketchbooksee JavaScript think ✏️
← back to phase 11

11.12 — Cross-browser projects & devices

Your suite is green — on chromium. But 11.1 warned you about the engine that surprises everyone. The projects array runs your ENTIRE suite once per named config variant — three engines and a phone, from one set of specs, unchanged. Plus the config block that finally kills “oh, was the dev server running?”

watch it happen
projects: [
  { name: "chromium",
    use: { ...devices["Desktop Chrome"] } },
  { name: "firefox",
    use: { ...devices["Desktop Firefox"] } },
  { name: "webkit",
    use: { ...devices["Desktop Safari"] } },
  { name: "mobile",
    use: { ...devices["iPhone 14"] } },
],
webServer: {
  command: "npm run start",
  url: "http://localhost:3000",
  reuseExistingServer: !process.env.CI,
},

// $ npx playwright test --project=webkit

“Works in Chrome” is a fact about ONE engine. 9.1 taught that different runtimes wrap the same language differently — browsers too: chromium, firefox, and webkit each render, scroll, and focus with their own quirks. Safari’s webkit is the classic ambusher, and your users are on it.

one suite, parallel lanesthe suite50 specs, unchangedchromiumlane 1firefoxlane 2webkitlane 3the question your suite can’t answer yet: it passes on chromium — does the appWORK on Safari?
under the hood

The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”

Projects can form a DEPENDENCY graph: a setup project (11.11’s login bottling) with dependencies: ["setup"] on the browser projects — the runner topologically orders them (8.1’s graph, once more): bottle once, every lane drinks.

Projects aren’t only for browsers: teams define an api project (request-only tests, no browser — 11.10), a smoke project with a grep filter baked in (11.13), or per-environment projects with different baseURLs. “Named config variant” is the general tool; cross-browser is just its most famous use.

Mobile presets can be composed manually too: use: { viewport: { width: 390, height: 844 }, hasTouch: true } — the registry entries are just objects (4.x) with good defaults. Print one in the REPL (9.1) someday; demystification is a hobby now.

Job note: when asked “how do you handle cross-browser testing?”, the mature answer names the budget, not just the feature: all engines from one suite via projects, chromium per change, full matrix nightly — because engine-specific bugs are real but rare, and quadrupling every run buys little. Feature + judgment is what seniority sounds like.

your turn

⌨️ expand the project matrix

The runner multiplies suite × projects into a run matrix. Build the expander: every test on every project lane, named like the real report — with the total computed, not counted on fingers.

requirements:

  • Create tests as ["login works", "coupon applies"] and projects as ["chromium", "firefox", "webkit"].
  • Write expandMatrix(tests, projects): for every project, for every test (2.7’s clock — the inner hand spins fully per outer click), collect test [project] name lines into an array and return it.
  • Print each line, then the summary total runs: 6 — from the array’s length.

when you press RUN, the console must show exactly:

test [chromium] login works
test [chromium] coupon applies
test [firefox] login works
test [firefox] coupon applies
test [webkit] login works
test [webkit] coupon applies
total runs: 6

✏️ Quick check 1

50 tests, 4 projects (3 engines + mobile). How many test RUNS does a full pass execute?

✏️ Quick check 2

Is devices["iPhone 14"] a real phone? What is it actually? (short phrase)

✏️ Quick check 3

Which config block starts your app and waits for it to answer before tests run?

teach it back

🗣️ Now teach it back

Explain projects to a friend: what a project is, what the array does to your suite, what devices presets contain (and emulation’s honest limits), what webServer solves, and the cross-browser budget.

Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.

a few sentences, minimum — you’ve got this
to remember
A PROJECT = a named config variant; the projects array runs the WHOLE suite per variant — 3 engines + mobile from one set of specs. Reports group by project: “failed on webkit only” = precise diagnosis.
devices["iPhone 14"] = a preset bundle (viewport/touch/UA) spread into use (4.11). Emulation honesty: real engine, phone costume — layout/touch yes, device hardware no.
webServer boots the app and waits before testing (reuseExistingServer: !CI — 9.4 again). Budget: chromium every change; full matrix nightly/pre-release. Projects also do setup-dependencies (11.11’s bottle) and api/smoke variants.