Twenty One Media
webJune 14, 2026

Nav CTAs Should Break Tests. Hero Headlines Shouldn't.

When we merged the local SEO branch, the homepage tests broke in two places. Both failures were caused by copy changes. Only one of them was the right kind of failure.

The Two Failures

The header test was checking that the nav rendered a "Contact" link:

expect(screen.getByText("Contact")).toBeInTheDocument();

That link no longer existed. We had changed the nav CTA to "Book the audit." The test failed.

That failure was correct. The nav CTA changed, and a test should catch that.

The hero test was checking a specific headline phrase:

expect(screen.getByText(/We build what others talk about/)).toBeInTheDocument();

The headline had been rewritten for a new campaign. Same component, same role in the layout, just different marketing copy. The test failed.

That failure was noise. Nothing broke. A headline changed.

Why They're Different

A nav CTA is functional. "Book the audit" tells the user what they're clicking and sets an expectation about what happens next. If someone changes it to "Schedule something" or "Learn More," the user experience changes. A failing test forces whoever made the change to update the assertion intentionally. That's the right friction.

A hero headline is prose. It exists to catch attention and frame the offer. It evolves as the positioning evolves. If a test pins the exact phrase, it will fail every time a copywriter makes a tweak. The failing test doesn't tell you anything broke. It just tells you someone changed a sentence.

The Fix Is Decided Before the Change

When we updated the tests, the hero fix was to use a shorter, more stable prefix:

expect(screen.getByText(/Building what others/)).toBeInTheDocument();

This still verifies the hero renders content inside that element. It doesn't pin the full marketing line. A future headline rewrite won't break this test unless the entire hero section disappears.

The header fix was to update the exact string:

expect(screen.getByText("Book the audit")).toBeInTheDocument();

No regex. Exact text. The next time someone changes that CTA, this test breaks again. That's intentional. You want to know.

The Rule

Test functional text exactly. Use exact strings for nav items, button labels, form submit text, and anything with a job to do beyond reading.

Test prose loosely. Use a short, stable anchor phrase (the first few distinctive words) for headlines, descriptions, and copy that's likely to evolve.

Both approaches test that content is rendering. The difference is what kind of change you want to require an intentional update. A CTA rename should require it. A headline polish shouldn't.

When the next merge breaks your tests, the question to ask is: did something actually break, or did a sentence change? If it's the second thing and you still had to fix the test, the test was written at the wrong granularity.