How to Create Stable E2E Tests Without Playwright

how to create stable e2e tests without playwright

[TABLE_OF_CONTENTS]

Your test passes on your laptop. It fails in CI at 2am, blocks the deploy, and nobody knows why. You rerun it and it goes green. You shrug and move on.

That test is now training your team to ignore red builds. And when someone finally opens it to fix it, they find a wall of selectors and waits. If they can't read it, they can't own it.

If you're avoiding Playwright, or leaving it, don't assume the tool was the problem. Stable E2E tests come from a handful of habits, and most of them work in any tool. This guide covers those habits, your realistic options, and when you should stay on Playwright.

Playwright Isn't Why Your Tests Are Flaky

Playwright is excellent. It records interactions into code, has a UI mode with time-travel debugging, and ships agents that plan, generate and repair tests. Pair it with an AI coding assistant and writing tests gets cheaper every month.

So "Playwright requires coding" is no longer a strong reason to skip it. Skip it for different reasons: nobody on your team wants to own a framework, or the people who know what to test can't read the code.

Setup still costs something, too. Teams that wire up Playwright's MCP server for AI agents report failures from outdated Node versions, missing browser binaries, and version mismatches after an unpinned @latest install. Agent-driven clicks can also get blocked by cookie banners and modals. None of that is a flaw in Playwright. It's the tax on any stack you assemble yourself.

Flaky tests have the same causes everywhere: fragile selectors, timing assumptions, shared data, and unclear ownership. Fix those and any tool gets more stable. Ignore them and the best tool won't help.

Five Habits Behind Every Stable E2E Suite

1. No Test ID, No Test

Selecting elements by CSS chains is the most common source of breakage. A designer moves a button into a new wrapper and a dozen tests fail. None of them found a bug.

Use identifiers that exist for testing: data-test-id attributes, accessible roles, and visible labels. Avoid position-based selectors and auto-generated class names.

One SaaS team we talk to takes this to its logical end. Their selectors are exclusively data-test-id. If an element doesn't have one, their tooling refuses to write the test and files a ticket against their own frontend instead. The missing ID gets treated as a product defect, not a testing inconvenience.

You don't need that level of strictness on day one. Adopt the rule for new features and fix old ones when they break.

2. Wait for State, Not for Time

A fixed sleep(3000) is a bet that your app is never slower than three seconds. On the day the CI runner is busy, you lose.

Wait for a condition instead: the element is visible, the request has finished, the button is enabled. Good tools do this by default. Datadog's browser tests, for example, keep checking whether the page is ready before each step and time out after 60 seconds unless you change it. Hard-coded waits, they note, tend to make tests less reliable, not more.

If your tool makes you write waits by hand, that's a warning sign, not a skill to be proud of.

3. Give Every Test Its Own Data

Tests that depend on the leftovers of other tests fail in ways nobody can reproduce. Test order changes, one test crashes halfway, and the next one starts from a broken state.

Each test should create what it needs and leave things as it found them. A checkout test that adds items to a cart should empty the cart afterward. Use dedicated test accounts and environments, not real customer data.

Splitting data into two pools helps at scale. The team above keeps a "stable" data set that tests only read from, and a "mutable" set for tests that change things. A read-only test can't be broken by someone else's write. They also watch for fixture drift: a database that changed while a test still hardcodes the old values.

4. Test the Flows Users Actually Run

The instinct is to cover every page. Resist it. Chasing 100% coverage produces a suite too big to maintain, and every extra test is another thing that can go flaky.

Start with 5 to 10 journeys that would hurt most if they broke: signup, login, checkout, the core action your product exists for. Add rare but critical flows too, like password reset. Nobody notices those are broken until a customer complains.

Keep each test focused on one workflow. A checkout test shouldn't create an account first. If it fails, you don't want to spend an hour figuring out which half broke. Pull repeated steps, like login, into a shared component so a change is made once.

Shared components cut both ways. Edit one to fix a single test and you've changed every test that uses it. Keep your shared library small: only sequences that are truly identical everywhere.

Two more rules:

  • Assert something. A test that clicks through a flow and verifies nothing passes forever. One team refuses to promote a test to its nightly regression suite if it has zero assertions.
  • Watch the flake rate. A flaky test is worse than no test, because it teaches people to distrust failures. Quarantine it or fix it. Don't rerun it until it passes.

There's a live debate on how many E2E tests you should have. Some vendors argue that fast, AI-assisted tooling has made the old "keep E2E tests few" advice obsolete. Datadog's guidance points the other way: cover what users do most, and skip the rest. Our view is that speed doesn't fix a suite nobody can maintain. Start small and grow only what you can keep green.

5. Make Sure Someone Can Fix a Red Test

Tests without an owner rot. It follows the usual pattern: something breaks in production, the team writes a pile of tests, and a month later a few fail and nobody fixes them. Six months on, the suite is decoration.

Name an owner for every test or suite, and tag it so a failure reaches the right person. Then check that the owner can actually read the failure.

That second check gets skipped. If understanding a red test requires reading a page of code, only developers can own it. And developers are busy shipping features.

One triage rule saves time: if every test in a suite fails with the same error at once, suspect the environment before the app. A shared outage looks nothing like ten separate regressions.

Your Options When You Skip Playwright

Every approach below can produce stable tests if you follow the five habits. They differ in who writes the tests, who maintains them, and what you have to run yourself.

Cypress Selenium Low-code recorder (e.g. BugBug) AI-agent tools
Who writes tests Developers, in JavaScript Developers, in many languages Anyone, by recording clicks An agent generates them
Setup effort Moderate Highest (drivers, grid) Lowest (browser extension) Varies by vendor
Cross-browser Yes, with limits Yes Chromium only Varies
Who reads a failure Developers Developers Anyone on the team Depends on the artifact
Watch out for Best for JS-heavy apps Most maintenance Web-only, no mobile Tests may live inside the vendor's platform

Check pricing pages before you decide. They change often, and several vendors in this space hide prices behind a sales call.

Cypress. Best for developer-led teams with JavaScript-heavy apps. Avoid it if nobody on the team wants to maintain test code.

Selenium. Best when you need maximum flexibility and language choice. Avoid it if you have no capacity to run and maintain drivers and infrastructure.

Low-code recorders. Best for web-only teams that want a first test running quickly and want non-developers to contribute. Avoid them if you need Firefox, Safari, mobile, or heavy data-driven scripting.

AI-agent tools. These split into two camps. Some automate only running tests. Others also automate writing them, reading your code and generating coverage on every pull request. Best for teams shipping a lot of AI-generated code without a QA function. Avoid them if you can't inspect what the agent produced. Also be wary of tests that pass but assert nothing. Ask any vendor what the artifact is, where it lives, and whether a person can read and edit it.

`{"name":"cta-card","children":[{"name":"cta-card-title","children":[{"name":"paragraph","children":[{"attributes":{"bold":true},"data":"Stable Tests Your Whole Team Can Fix"}]},{"name":"paragraph"}]},{"name":"cta-card-details","children":[{"name":"paragraph","children":[{"data":"Try team-owned regression with BugBug"}]},{"name":"paragraph"}]},{"name":"cta-card-cta","children":[{"name":"paragraph","children":[{"attributes":{"bold":true},"data":"Get started"}]},{"name":"paragraph"}]}]}

Stable Tests Your Whole Team Can Fix

Try team-owned regression with BugBug

Get started

`

What "No Framework to Maintain" Looks Like in Practice

BugBug is a low-code option. You install a Chrome extension, click through your app, and it records each click and keystroke as a step. There's no Selenium grid, no Docker and no VMs. You edit steps in a visual editor, and Edit & Rewind lets you fix a step and rerun from that point without re-recording the whole flow.

A typical first test looks like this:

  1. Record your login flow in the extension.
  2. Add an assertion that the dashboard loads.
  3. For signup flows, use the built-in test inbox to confirm the verification email arrives.
  4. Run it locally, then schedule it in the cloud or trigger it from CI.

For anything the recorder can't do, you can add a custom JavaScript step.

Here's a real-world example of why this matters. A SaaS team with a single manual tester needed automation without pulling developers away from product work. Their developers later suggested moving to a code framework, since that would be more convenient for them. The team declined. Their reasoning was that once tests live in code, ownership quietly shifts to developers, and the people responsible for quality can no longer touch their own work.

They now have an AI agent write their tests through BugBug's API. When a test fails, the tester opens the BugBug UI, sees why, and fixes or reruns it herself. The writing is automated, but the tests aren't a black box. Their suite runs around 250 tests, and their selectors are exclusively test IDs.

That's the setup BugBug fits best: a web-only team where the people who understand the product need to own the tests.

The limits are real. BugBug runs on Chromium and Chrome only, with no Firefox or Safari and no mobile app testing. It doesn't test desktop applications. It's also less flexible than a code framework, so it's a weaker fit if you need deep customization or heavy data-driven scripting.

When You Should Stay on Playwright

Stay on Playwright if any of these describe you:

  • Developers own quality. If your engineers write and maintain the tests as part of shipping, a code framework fits their workflow. Tests in the repo, reviewed in pull requests, is a strength.
  • You need real cross-browser coverage. Playwright supports Chromium, Firefox and WebKit. A Chromium-only tool can't cover Safari users.
  • Your app needs deep control. Complex JavaScript-heavy interactions, network mocking, and custom fixtures are natural in code and awkward elsewhere.
  • You already have a working suite. If your Playwright tests are stable and owned, don't migrate for the sake of it.

The same goes for Cypress. Neither is a mistake. They're the right answer for a different kind of team.

Which Approach Should You Actually Pick?

Match your situation to a profile:

  • You have developers who own tests and want full control. Stay on Playwright or Cypress. Apply the five habits and pin your dependency versions.
  • You have a small QA team or none, and you want AI to write tests. Look at ai testing tools. Check if a person can read and fix what the agent produces.
  • You need Firefox, Safari or mobile coverage. Use a code framework with cross-browser support, or a cloud device platform. A Chromium-only recorder won't get you there.
  • You're a web-only team on Chromium with no dedicated automation engineer, and the people who know the product should own the tests. Try a low-code recorder. BugBug's free plan is a perfect place to start.

Whichever tool you choose, start with five journeys, use stable IDs, wait for state, isolate your data, and name an owner. That will do more for stability than any tool.

Happy (automated) testing!

FAQ

Can non-developers create stable E2E tests?

Yes, if the tool gives them stable selectors, automatic waiting, and readable failures. Stability comes from test design, so the same habits apply. A recorder makes creation accessible, but someone still needs to decide what to test and own the results.

Do I need Selenium or Playwright for E2E testing?

No. They're common choices for teams that write tests in code, but low-code recorders and AI-agent tools can also run real browser tests. Pick based on who writes and maintains the tests, and which browsers you must cover.

How many E2E tests should I have?

There's no universal number. Start with 5 to 10 critical journeys and grow from there. A small suite you trust beats a large one you rerun until it passes.

Why do E2E tests fail in CI but pass locally?

Usually timing, data or environment: a slower runner, leftover state from another test, or a different configuration. Wait for conditions instead of fixed delays, give each test its own data, and check whether an entire suite fails identically, which points to the environment.

Your next release. Properly tested.

Join 1,200+ QA teams that automated their
regression coverage with BugBug.

Start testing. It's free.
  • Free plan
  • No credit card
  • 14-days trial

Author

Dominik Szahidewicz

Software Quality Evangelist

Dominik Szahidewicz is a Software Quality Evangelist specialising in quality assurance, test automation, and modern software testing practices. He creates practical, research-driven content that helps QA professionals, developers, and product teams improve test coverage, automate repetitive testing, and release more reliable web applications.

Drawing on his experience in technical writing, data analysis, and application consulting, Dominik translates complex testing concepts into clear, actionable guidance. His areas of interest include end-to-end testing, low-code test automation, regression testing, and the use of AI in software quality assurance.

Reviewer

Mariusz Wójcik photo
Mariusz Wójcik

Senior Software Engineer

Senior software engineer at BugBug, where he's spent 6 years helping shape the product. He's a T-shaped developer skilled in frontend with React and TypeScript, browser extensions, backend work, and building AI agents and tooling. His strengths also include UX instincts, a product-minded approach, and process automation.