Frontend Testing 2026: Vitest, Playwright, and Visual Regression

Updated · techinterview.org

Frontend testing matured considerably between 2020 and 2026. Vitest replaced Jest for most modern projects; Playwright is the dominant E2E tool; visual-regression testing matured; AI-assisted test generation arrived. Senior interviews increasingly probe for understanding of the modern stack and what is worth running in CI. This guide is the working state of frontend testing in 2026.

The 2026 stack

  • Unit and component tests use Vitest + Testing Library. Vitest runs the assertions and Testing Library renders components and queries them the way a user would, so this pair covers most of what you write day to day.
  • Integration tests use Vitest with MSW for API mocking, or Playwright Component Testing. MSW intercepts network calls so components get realistic responses without a live backend; reach for Playwright Component Testing when the component leans on real browser APIs that jsdom fakes poorly.
  • E2E uses Playwright (sometimes Cypress for legacy). It drives a real browser through full journeys, so keep the suite small and reserve it for flows you cannot verify any cheaper way.
  • Visual regression uses Chromatic, Percy, or Playwright’s built-in screenshot diffing. Chromatic and Percy are hosted services with review UIs for approving diffs, while Playwright keeps screenshot baselines in your repo for free, so start there before paying for a service.
  • Accessibility uses axe-core in tests and Pa11y for CI. axe-core runs inside your existing tests and fails on WCAG violations, while Pa11y crawls deployed URLs on a schedule to catch what slips past.
  • Performance uses Lighthouse CI plus the web-vitals library in production. Lighthouse CI scores a preview build against budgets before merge; web-vitals measures the same metrics on real visitors, so your lab scores stay grounded in what users actually experience.

Why Vitest replaced Jest

  • Native ESM support — it runs test files as native ES modules, so modern import and export syntax and top-level await work without the extra transform step Jest needs.
  • 10x faster on most projects — the speed comes from reusing Vite’s transform pipeline and running tests in worker threads, which shows up most on large suites and in watch mode.
  • First-class Vite integration (config sharing) — your app’s Vite config (aliases, plugins, environment handling) is the same config your tests use, so behavior does not drift between build and test.
  • Compatible Jest API (most migrations are mechanical) — describe, it, expect, and most matchers carry over, so migrating is mostly swapping the runner and fixing a few mock APIs rather than rewriting tests.
  • Better TypeScript story — it reads your tsconfig and handles TypeScript through Vite without a separate ts-jest layer, so type-aware tests run with less setup.

Many large codebases still use Jest; new projects rarely choose it.

What to test at each level

Unit tests

  • Pure functions, utility methods, hooks — target code with clear inputs and outputs, like formatters, reducers, and custom hooks, where you can assert a return value without mounting a UI.
  • Aim: high coverage of business logic — spend your coverage budget on the logic that would cost you money or data if it broke, not on trivial getters.
  • Fast, parallelizable, run on every PR — these should finish in seconds so they can gate every pull request; if a unit test needs a network or a timer, it usually belongs a level up.
  • Avoid testing implementation details — assert on what the function returns or the state it produces, not on which private helpers it called, since tests coupled to internals break on every refactor. This is a favorite interview follow-up.

Component tests

  • Render a component in isolation — mount just the component with controlled props so a failure points at that component, not at its parents or the router.
  • Test rendering, prop handling, user interactions — cover the branches that matter, like a loading state, an error state, and a disabled button, and drive interactions through real click and type events rather than calling handlers directly.
  • Use Testing Library queries (by role, by label) — accessible by default; querying by role and label doubles as an accessibility check, since anything you cannot find by role is often unreachable for a screen reader too.
  • Mock complex dependencies (data fetching, contexts) — stub data fetching with MSW and wrap the component in the same providers it sees in the app, so context-dependent behavior still runs.

Integration tests

  • Test multiple components or a full page — render a whole page or feature so you catch the wiring between components, like state that one component sets and another reads.
  • Use MSW (Mock Service Worker) for API mocking — MSW mocks at the network boundary, so the code under test runs its real fetch logic, loading and error handling included, against canned responses.
  • Cover important user flows (login, checkout, settings) — walk the happy path and one or two failure paths, like a rejected login or a declined card, since those branches are where real bugs hide.

E2E tests

  • Test the full app in a real browser — run against a real build with a real backend so you exercise routing, auth, and cross-page state that mocks paper over.
  • Limit to top 5–10 critical paths — pick the flows that lose revenue or lock users out if they break, like sign-up, checkout, and the core create/save loop, and stop there.
  • Run against staging or a freshly-deployed test env — point them at an environment that mirrors production and reset test data per run so one test does not poison the next.
  • Slow; do not gate every PR on full E2E — run a tiny smoke subset per PR and the full suite nightly or before deploy, since blocking every PR on the whole suite trains people to ignore it.

Playwright over Cypress in 2026

  • Multi-browser support (Chromium, WebKit, Firefox) — one test runs against all three, so you catch Safari-only layout and API differences that a Chromium-only tool misses.
  • True parallelism out of the box — it shards tests across workers by default, which keeps wall-clock time flat as the suite grows.
  • Faster test execution — auto-waiting on elements removes most fixed sleeps, so tests run at the speed of the app instead of padded delays.
  • Better network interception API — you can mock, modify, or assert on requests at the browser level, which makes it easy to force error responses and slow networks.
  • Visual testing built in — screenshot assertions ship in the box, so you do not need a separate service for basic pixel diffing.
  • Component testing supported — it can mount individual components in a real browser, which covers cases where jsdom’s fake DOM behaves differently from Chromium.

Cypress remains popular at companies that adopted it earlier; new projects mostly choose Playwright.

The Testing Library philosophy

Test from the user’s perspective:

  • Query by role, label, text — what the user perceives; reach for role and accessible name first, since these mirror how a user and a screen reader locate things and they survive markup refactors.
  • Avoid querying by class names or test IDs unless necessary — those couple tests to structure the user never sees, so fall back to a test ID only when no accessible query exists.
  • If a component is hard to test, it is often hard to use — a component you cannot query by role usually has a missing label or a div acting as a button, and the testing pain is telling you about a real usability gap.

Visual regression

  • Capture screenshots; compare to baseline; flag differences — the tool renders a component, diffs the pixels against a stored baseline, and fails when they drift beyond a threshold.
  • Catches CSS regressions that other tests miss — a broken flexbox or a dropped border passes every assertion-based test but shows up instantly in a pixel diff.
  • Hard to maintain — every UI change requires baseline approval, so an intentional redesign turns the suite red until someone signs off on the new baselines.
  • Best at the component-library level (Storybook + Chromatic) — snapshotting isolated Storybook stories keeps inputs deterministic, which cuts the false positives that plague full-page shots.
  • Riskier at the page level; many false positives from dynamic content — timestamps, ads, avatars, and animations change every run, so page-level shots need heavy masking or they cry wolf.

Accessibility testing

  • axe-core inside Vitest / Playwright tests catches the WCAG A and AA violations programmatically — drop an axe assertion into an existing component test and it flags missing labels, bad roles, and ARIA misuse as part of the normal run.
  • Cannot catch all issues (color contrast in some contexts, focus order) — automated tools find only a portion of real problems, so contrast in overlapping layers and a sensible focus order still need a human.
  • Integrate as a check in component tests — running axe per component localizes the failure and keeps the rule close to the code that broke it.
  • Pair with manual screen-reader testing for critical flows — tab through checkout and sign-up with VoiceOver or NVDA at least once a release, which catches order and announcement problems no scanner reports.

Performance testing

  • Lighthouse CI runs on PRs against the deployed preview — point it at the preview URL so you score the real bundle and network cost of the change, not a local dev build.
  • Set budgets for LCP, INP, CLS — pick thresholds from the Core Web Vitals “good” bands and tighten from there as the app improves.
  • Fail PR if budgets are missed — a hard failure stops slow images and layout shift from creeping in one merge at a time.
  • web-vitals library reports real user metrics in production — lab scores miss slow devices and networks, so field data from real users tells you what actually shipped.

AI-assisted test generation

By 2026, AI tools generate tests from code:

  • Cursor / Copilot can suggest tests for selected functions — highlight a function and these tools draft a matching test file, which is a fast start for well-typed, side-effect-free code.
  • Specialized tools (CodeRabbit, Stainless) generate tests as part of review — they propose tests against the diff, so gaps show up in the pull request instead of weeks later.
  • Quality varies — generated tests need human review; they often assert the current behavior rather than the intended behavior, so a bug baked into the code gets locked in unless someone checks the assertions.
  • Best for boilerplate (component snapshots, prop variation tests) — this work is repetitive and low-judgment, which is exactly where generation saves the most time.
  • Less good for tricky edge cases that require domain understanding — the model does not know your business rules, so an off-by-one in a billing proration or a rare permission combo still needs a person who understands the domain.

What to run in CI

  • On every PR, run unit tests, component tests, lint, type check, accessibility checks (in unit tests), and Lighthouse CI on the preview deployment.
  • Nightly or pre-deploy, run the full E2E suite and visual regression.
  • On merge to main, deploy and run smoke tests.
  • In production, run real-user monitoring (web-vitals, Sentry).

Coverage targets

  • 80% line coverage for unit / component tests is reasonable
  • Coverage is necessary but insufficient — high coverage with bad assertions still fails to catch bugs
  • Focus on coverage of business-critical paths
  • Do not chase 100% — diminishing returns

Common interview questions

  • “How would you test this component?” (given a component) — they want to hear you split unit, component, and E2E, name the Testing Library queries you would use, and say what you would mock, not a single tool name.
  • “What is the difference between testing implementation vs behavior?” — answer with a concrete example: asserting a returned value or rendered text is behavior, while asserting that a specific internal method ran is implementation and breaks on refactors.
  • “How do you decide what to test E2E vs unit?” — talk about cost and confidence: push logic down to fast unit tests and spend the slow, flaky E2E budget only on flows you cannot verify any other way.
  • “Walk me through a flaky test you debugged.” — have a real story ready with the symptom, how you found the cause (timing, shared state, or network), and the fix; this is a behavioral prompt, so structure it as situation, action, result.
  • “What is the role of visual regression in your test strategy?” — show you know where it pays off (a component library) and where it hurts (dynamic pages), and that you treat baseline approval as a maintenance cost rather than a free check.

What separates senior from staff

Senior candidates know the tools and write good tests. Staff candidates think about the test strategy at the team level — what is worth running, what to mock, the cost of flaky tests, the CI economy. Principal candidates discuss the long-term cost of test maintenance and the trade between coverage and velocity.

Frequently Asked Questions

Should I migrate from Jest to Vitest?

Worth it for projects on Vite. For Webpack-based projects with stable Jest setup, the gain is smaller. New projects: Vitest.

How do I handle flaky E2E tests?

Common causes: timing (use Playwright auto-wait, avoid fixed delays), shared state (each test should set up its own data), network noise (mock with MSW or Playwright route handlers). If a test is flaky, fix or quarantine — do not retry.

Is Cypress dying?

Not dying, but Playwright is the modern default. Cypress is still actively developed. New teams pick Playwright; existing Cypress shops do not need to migrate.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

1972 Soviet postage stamp commemorating the Mars 2 probe

worth a read

Mars For The Rest of Us — a weekly-or-more deep dive on the technical side of Mars exploration: rocket propulsion, microbiology, mission architecture, and everything in between. Written by Maciej Ceglowski.

Read it on Substack
Scroll to Top