The Challenge
A product team relied on slow Manual regression before every release. Coverage was undocumented, releases were delayed, and confidence in 'green' was low.
What We Built
A Playwright + TypeScript framework designed for maintainability, page-object architecture, stable data-testid selector strategy, parallel execution, and CI integration so every merge runs the suite automatically.
Where the team was starting from
Before the engagement, release confidence came from people, not systems. A shared spreadsheet held the regression cases, coverage lived in the heads of two long-tenured testers, and every release meant days of Manual clicking through the same flows. The team wasn't slow because they lacked discipline, they were slow because nothing they did on Monday saved them any work on Friday.
The deeper problem was trust. There had been earlier Automation attempts, and their remains were still in the repo: a partial suite nobody ran because nobody believed the results. That's the situation we walk into most often, and it changes the brief, the goal isn't 'write tests', it's 'produce a green signal people will bet a release on'.
The architecture decisions that mattered
We optimized for the second year, not the first month. Four decisions did most of the work:
- A selector contract with the frontend team: data-testid attributes agreed up front, enforced in code review, with layout-dependent selectors banned in lint rules.
- Test data created per test through the API, then torn down, no shared accounts, no seeded fixtures that tests quietly depend on.
- Storage-state authentication once per worker instead of a UI login per test, which removed both the slowest step and the flakiest one.
- Parallel execution and CI sharding designed in from day one, because retrofitting isolation into a suite that assumes serial execution is a rewrite.
How coverage grew without becoming a burden
We deliberately did not attempt to automate the existing Manual regression spreadsheet. Most of it was low-value repetition accumulated over years. Instead we mapped the flows that carried revenue and risk, automated those first, and let the CI gate start meaning something within weeks rather than months.
From there, coverage grew per sprint alongside feature work, new feature, new tests, reviewed in the same pull request. That cadence is what keeps a suite alive after the specialists leave.
The handover, our actual definition of done
The engagement's acceptance test wasn't a coverage percentage. It was this: the client's own Engineer writes and merges a new test without asking us anything. To get there we delivered a README that takes a new Engineer to a green local run in under fifteen minutes, a worked 'write your first test' guide, documented selector and data conventions, CI configuration with artifact retention, and a flake triage runbook, then paired once while their team did the work.
Where this pattern transfers
Almost nothing in this engagement was specific to the client's product. The situation, a Manual regression cycle that has become the release bottleneck, an abandoned earlier Automation attempt still sitting in the repository, and a team that has stopped believing green means anything, is the single most common brief we receive. The response is nearly always the same shape: fix trust before growing coverage, land architecture before volume, and treat the handover as the deliverable rather than the epilogue.
What changes by context is sequencing. A SaaS product shipping weekly needs the merge gate first, because that is where the bottleneck is. An E-commerce funnel needs the payment paths first, because that is where the money is. A streaming platform needs the device matrix decided before a single test is written, because the matrix determines what a test even means. That judgment happens in the coverage map, which is the first thing we build on any Automation engagement.
What we would do differently
Two things, honestly. We would negotiate the selector contract with the frontend team in the first week rather than the second, every day without it produces test code bound to markup that will move, and retrofitting is cheap but tedious. And we would set an explicit runtime budget for the suite on day one rather than when it started to be noticeable. A gate that outgrows its budget is a gate people begin bypassing, and holding a limit from the start is far easier than reclaiming one later.
The Results
- · Regression that took days of Manual effort now runs automatically on every merge
- · Flake-resistant selector strategy keeps green builds trustworthy
- · Framework handed over with documentation, the client's team can extend it themselves
