Updating Tests After UI Changes

8 min read

A developer ships a redesigned checkout page on Friday afternoon. Monday morning: 30 tests are failing. The logic they test is unchanged — only selectors, labels, and structure changed. Manual fixes mean opening 30 files, finding the broken locators, updating each one. With Claude Code and a well-structured Page Object layer, this is a 10-minute task.

The core workflow

Point Claude Code at the failing tests, the changed page structure, and give it a clear constraint:

The checkout page was redesigned. 12 tests in tests/checkout/ are now failing.
 
The relevant changes:
- "Card number" input now has data-testid="card-num" (was getByLabel)
- "Submit order" button now has data-testid="submit-order-btn"
- The cart summary moved into a sub-component with data-testid="cart-summary"
 
Read tests/checkout/*.spec.ts and src/pages/CheckoutPage.ts.
Update selectors to match the new structure.
Do not change any test logic — only fix broken locators.

The "do not change test logic" constraint is important. Without it, Claude might improve assertions, add edge cases, or restructure tests while you only wanted broken selectors fixed. Scope the task precisely.

Why Page Objects make this fast

If your tests use a Page Object for the checkout flow, the selector change affects exactly one file. Claude updates CheckoutPage.ts and all 12 tests automatically pick up the correct locators:

Only src/pages/CheckoutPage.ts needs updating.
The three changed elements are documented above.
Update the POM only — the tests themselves should not need changes.

This is the return on investment from the Page Object pattern. Without it, Claude must find and update every inline selector across 12 test files — still faster than manual, but with a higher risk of a missed instance.

When the structure changed significantly

For larger UI overhauls where page structure changed, not just selector values, use the plan-first pattern:

We've moved from an inline cart on /products to a dedicated /cart page.
 
Step 1: Read all tests that interact with cart functionality.
Step 2: List what needs to change for each test — be specific.
Step 3: Show me the list before making any changes.

Review the list. Some tests might need logical changes, not just selector fixes — for example, tests that assumed the cart was visible on the product page now need a navigation step. You want to know about those before Claude starts editing.

Once the plan is approved:

The plan looks right. Apply all the changes.
Start with the POM update, then the tests that need navigation changes, 
then the tests that only need selector fixes.

Combining with Playwright MCP

When Playwright MCP is connected, Claude can visit the new page and derive the correct selectors itself rather than relying on your description:

Visit https://staging.myapp.com/checkout and analyse the new page structure.
Then update src/pages/CheckoutPage.ts to match what you find.

Claude navigates the live page, reads the DOM, identifies the real locators, and updates the POM. This is more reliable than manually describing the changes, especially for complex pages.

Choosing robust selectors to reduce future breakage

When Claude updates selectors after a UI change, it is worth asking it to prefer locators that will survive future changes:

While updating CheckoutPage.ts, prefer getByRole and getByLabel over 
data-testid where the element has a clear semantic role.
For elements that lack stable roles, use data-testid.
Avoid text-based selectors for anything that might be localised or reworded.

The goal is to make the next UI change a smaller fix.

Selector maintenance cost — inline selectors vs Page Object pattern

Inline selectors everywhere

  • Same selector repeated across 30 test files

  • UI change = 30 files to find and edit

  • High risk of a missed instance causing silent failure

  • Even Claude needs time to find all occurrences

  • Maintenance cost grows with suite size

Page Object Model

  • Selector defined once in the POM

  • UI change = 1 file to update

  • Claude updates the POM in seconds

  • All tests pick up the fix automatically

  • Maintenance cost stays flat as suite grows

⚠️ Common Mistakes

  • Changing test logic when only selectors need fixing. UI changes should not require rewriting what a test asserts — only how it finds elements. Scope the fix narrowly to avoid introducing new issues.
  • Not verifying the updated tests still run. After selector changes, always run the affected tests before committing. A changed selector might fix the broken locator but introduce a new one that was previously shadowed.
  • Deleting tests that broke rather than fixing them. Tests that break after a UI change are usually still valuable. The feature they cover still exists — the selectors just need updating. Delete tests that cover removed features, not redesigned ones.

🎯 Practice Task

Simulate a selector update task. 15–20 minutes.

  1. Find a page in a project where you recently changed some UI or where you know selectors are fragile.
  2. Ask Claude Code to audit the tests for that page and list every selector — note which ones would break if specific elements were renamed.
  3. Ask Claude to refactor the brittle ones to more stable locator strategies (role-based over class-based, for example).
  4. Run the tests after the refactor to confirm nothing broke.

The next lesson covers the most ambitious maintenance task of all: migrating an entire test suite from one framework to another.

// tip to track lessons you complete and pick up where you left off across devices.