Why do playwright tests break the moment anything changes in the UI?

I’ve been dealing with this for months now. We have a suite of Playwright tests that work fine for like two weeks, then someone tweaks a button color or moves a form field, and suddenly half the tests are failing. It’s not even real failures—the functionality works fine, but the selectors are toast.

I’ve tried everything: waiting for elements, using more robust selectors, adding retries. But it feels like I’m just putting band-aids on a structural problem. The tests are so tightly coupled to the exact DOM structure that any UI change is basically a disaster.

Has anyone found a way to make Playwright tests actually resilient to UI changes without having to rewrite them every sprint? Or is this just the nature of the beast with browser automation?

This is exactly the problem that brittle selectors create, and it’s way more common than people admit. The issue is that you’re essentially encoding the UI structure into your test logic, which means every design tweak becomes a maintenance burden.

What I’ve started doing is using plain language descriptions of what I want to test instead of wrestling with selectors. I describe the workflow in simple terms—like “user logs in, clicks the save button, sees a success message”—and let the system generate the actual Playwright steps. When the UI changes, I just update the description, and the workflow adapts automatically.

The AI Copilot in Latenode does exactly this. You write what you want to verify, and it generates resilient Playwright workflows that don’t break the moment your designer decides buttons should be blue instead of green. It handles the selector problem for you by regenerating based on the actual current state of the page.

I dealt with the same frustration for a while. The real issue is that most people write Playwright tests as if they’re writing code, when they should be thinking about the user intent. Selectors are implementation details, not requirements.

What helped me was shifting my approach. Instead of targeting specific classes or IDs that change frequently, I started using accessible names and roles. A button is a button regardless of its styling. An input field for email is still an email input even if the wrapper div gets renamed.

That said, if you’re trying to test older or poorly structured applications without good semantic HTML, even this breaks down fast. There’s only so much resilience you can build into selectors alone.

The brittleness you’re experiencing is a symptom of how traditional test automation works. Most tools force you to record exact element paths or CSS selectors, which are fragile by design. I’ve seen teams spend more time maintaining tests than writing them because of this.

The better approach is to decouple your test logic from the UI structure. Some teams do this by building abstraction layers over selectors, others by using visual testing, but both require significant upfront investment. What actually works long-term is having a system that can understand what you’re trying to test at a higher level—not just DOM manipulations—and generate the necessary steps dynamically as the UI evolves.

You’re hitting a fundamental limitation of selector-based automation. The DOM is inherently unstable from a testing perspective because it’s designed for display, not for stable automation references. Any production UI will change frequently.

The industry has learned this lesson the hard way. The tests that actually survive long-term aren’t the ones with the most clever selectors—they’re the ones that test behavior rather than implementation. If you can describe your test in business terms rather than technical terms, you’re on the right track. That creates a buffer between UI changes and test failures.

Use role-based selectors and ARIA attributes instead of fragile class names. Test behavior, not DOM structure.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.