All articles

A Modern Test Automation Strategy for the AI Era

For most of my career, the slow part of automation was writing the tests. You had a backlog of scenarios and never enough hands to script them, so the suite grew a test at a time and you felt every one you added.

That friction is mostly gone. An agent will turn a user story into twenty tests before lunch, push each one down to the cheapest level it holds, run them in your continuous integration (CI), and open a pull request with the failing run and the passing run attached. A year ago that sentence would have stopped at “draft a test.”

So the hard part moved. Producing tests is easy now. The work is aiming that speed at the right level and proving the green is real. Speed without judgment is just faster guessing.

This is not only my read of it. The 2025 DORA report describes AI as an amplifier: it speeds teams up while magnifying the weaknesses they already had, and it still ties rising AI adoption to a dip in delivery stability. Its answer to that dip is the same as mine: strong automated testing and fast feedback loops. A strategy is what closes that gap.

A strategy still decides what you automate, why it matters, at which level you prove it, who maintains it, and how you will know the suite is still earning its keep. What changed is that you can hand most of the running and proving to the agent and keep your judgment for what it brings back. I make the fuller case for that in a QA control layer for AI-assisted development.

The craft underneath does not change because an agent is typing: what to automate, proving behaviour at the lowest level that holds, taking flaky tests seriously, measuring confidence over test count. I keep the full treatment of that in test automation that pays off (coming soon). Here I want the layer on top of it, the decisions and gates that get an agent to prove real behaviour instead of handing you a wall of green.

The specific traps generation stacks on top, and the one guardrail that handles each, are their own piece: new testing pitfalls in the age of AI (coming soon). Think of these two as a pair. That article is the guardrails you set once so you can trust what the agent hands back. This one is the plan those guardrails hang on: the goal, the levels, the gates, and how you know the suite still earns its keep.

Start with the goal, not the tool

The first question is not about tools, and it is definitely not “what can AI automate for us?” Before a single test gets written, name what you are trying to protect. Automation is a means to an end, and the end has to be on the table first.

Sit with your team and pick the goal that matters most right now. It is usually one of these:

  • Cut regression time so releases stop waiting on a manual sweep.
  • Protect the flows that make money: signup, checkout, payment, subscription renewal.
  • Raise release confidence so people stop holding their breath on deploy day.
  • Bring down flaky-test maintenance that is quietly eating your week.
  • Help manual testers turn their scenarios into automation without learning a framework first.
  • Give continuous integration faster, more trustworthy feedback.

The goal changes the answer completely. If you want faster feedback, piling on more end-to-end browser tests makes things worse, because those are the slowest and flakiest tests you own. If you want production confidence, a handful of well-placed monitoring checks and contract tests will do more than another fifty user-interface tests ever could.

AI is great at generating options once you know what you are aiming for. It cannot tell you what winning looks like. Once you know the goal, it is genuinely useful for turning a feature into a first-pass plan, as long as you make it surface risk rather than just list happy paths; the prompt I reach for, plus the full installable skill it comes from, lives on the AI test plan generator. What comes back is a draft, not a plan. You still decide which risks are real for this product, which cases earn a place in the suite, and what the release actually depends on.

A one-page strategy template you can fill in

A strategy that lives in someone’s head is just a preference, and it changes with whoever is in the room. Write it down on one page the whole team can see, the agent included, because a coding agent follows whatever conventions the codebase nudges it toward unless you tell it otherwise. An agent that reads this page generates tests that already fit it.

Here is the template I use. Keep it short enough that people actually read it, and specific enough that it settles arguments instead of starting them.

# Test automation strategy: <product or area>

## Why (the goal)
The one outcome this suite exists to protect, this quarter.
e.g. "Checkout and payment never break silently in production."

## What (in and out of scope)
- Protected flows: signup, checkout, payment, subscription, ...
- Explicitly NOT automated yet, and why: <list>

## Where (the levels)
- Unit: logic, calculations, edge cases.
- API / integration: authorisation, data sync, contracts, retries.
- UI: only the critical journeys a real person takes.
- The default question: cheapest reliable level to prove this behaviour.

## How (the standards)
- Driver-based interactions; no raw framework commands in a spec.
- Page objects hold every selector and visible string.
- Stable selectors only: role, label, data-* hooks. No nth-child chains.
- No fixed waits. Wait on a real signal: an API response or a visible element.
- Every test stands alone and sets up its own data.

## Who (accountability)
- Owner per area, for when a test breaks at 2am.
- Where AI is allowed, and where a human signs off (see the map below).

## When (the gates)
- Pull request / merge / nightly / release. See the CI gate table.

## How we know it is working
- The trust metrics, reviewed after each significant release.

For a guided way to turn this into a real plan rather than a blank file, the test strategy builder walks you through each section in order. The template is the artifact; the thinking it forces is the point.

Decide where AI is allowed, and where it is not

The most useful page in a modern strategy is a short, explicit map of where AI helps and where a human stays firmly in the loop. Without it, AI seeps into every decision by default, including the ones it should never make alone.

Here is how I draw the line. The left side is where I let an assistant move fast, because a mistake is cheap and obvious. The right side is where speed is a trap, because a mistake is quiet and expensive.

AI acceleratesCheap to get wrong, easy to catchDrafting first-pass test casesTurning manual scenarios into draftsSummarising a wall of test failuresSuggesting edge cases you missedExplaining unfamiliar codeDrafting release notes from a diffProposing a regression test for a bugA human decidesQuiet to get wrong, expensive to fixChanging production logicEditing a database migrationRewriting shared test utilitiesChanging CI configurationJudging which failures are safe to ignoreApproving a release to productionDeleting tests to make the build green

The line is not about distrust. It marks where the cost of a wrong answer shows up. A weak test draft fails review and you fix it in seconds. A subtly wrong migration, or a failure someone quietly muted, can sit unnoticed until it costs you a customer. Let the assistant speed up the work, and never let it quietly take ownership of the call.

Review generated tests against risk, not syntax

An AI-generated test has one seductive quality: it runs, and it is green. Green tells you the syntax is fine. It tells you nothing about whether the test proves anything. The full catalogue of how a green test lies, and the guardrail for each, is in new testing pitfalls in the age of AI (coming soon). The review lens a strategy adds is narrower, and it is about level: what does this prove, and is it proven where it is cheapest and most reliable, or is it a unit truth dressed up as a browser test? A test can be perfectly valid and still protect nothing, asserting that a button exists while saying nothing about the workflow behind it. Test the screen and you miss the system.

This matters more right now because of how AI generates tests. One study of GitHub Copilot generating tests in Python found that with no existing suite to learn from, the large majority of generated tests were failing, broken, or empty. The lesson there is plain: polished-looking output still needs a review, and you cannot skip it just because the test ran.

So put a small, fixed set of questions in front of every generated test before it joins the suite. I ask the same seven every time:

  • What real risk does this test cover? If you cannot name it, the test is decoration.
  • Is this the cheapest reliable level to prove this behaviour, or is it a unit truth dressed up as a browser test?
  • What is the one assertion that proves the behaviour, and is it actually checking outcome rather than presence?
  • What data does the test need, and does it set that data up itself or quietly depend on yesterday’s run?
  • How does it fail? Read the failure message. If it says “expected true, got false”, it will waste your time later.
  • Who owns it when it breaks at 2am during a release?
  • When should it run: on every commit, nightly, or only before a release?

Here is the difference in practice. An assistant will happily hand you a checkout test that looks thorough and proves nothing:

Playwright
// Weak: asserts the page rendered, not that checkout worked
test('checkout', async ({ page }) => {
  await page.goto('https://www.saucedemo.com/')
  await page.getByPlaceholder('Username').fill('standard_user')
  await page.getByPlaceholder('Password').fill('secret_sauce')
  await page.getByRole('button', { name: 'Login' }).click()
  await expect(page).toHaveURL(/inventory/)
})

That test passes whenever the inventory page loads. It stays green through a broken “add to cart” button, a payment failure, or an order that never gets created. Rewrite it to prove the behaviour the business actually cares about:

Playwright
test('verify that a shopper can complete checkout and reach the confirmation', async ({ page }) => {
  await page.goto('https://www.saucedemo.com/')
  await page.getByPlaceholder('Username').fill('standard_user')
  await page.getByPlaceholder('Password').fill('secret_sauce')
  await page.getByRole('button', { name: 'Login' }).click()

  await page.getByRole('button', { name: 'Add to cart' }).first().click()
  await page.locator('.shopping_cart_link').click()
  await page.getByRole('button', { name: 'Checkout' }).click()

  await page.getByPlaceholder('First Name').fill('Julia')
  await page.getByPlaceholder('Last Name').fill('Pottinger')
  await page.getByPlaceholder('Zip/Postal Code').fill('00000')
  await page.getByRole('button', { name: 'Continue' }).click()
  await page.getByRole('button', { name: 'Finish' }).click()

  await expect(page.getByText('Thank you for your order!')).toBeVisible()
})

Same tool, same effort to run, completely different value. The test name reads as a sentence describing the behaviour, and when this one goes red, you know exactly what broke and that it is worth your attention.

Rebalance the pyramid before AI tips it over

AI has a quiet bias, and it is the one that matters most for a strategy. Plain-language workflows map naturally onto browser steps, so when you ask an assistant to “test the signup flow”, it reaches for the user interface. Ask for enough features and you get a top-heavy suite full of slow, brittle end-to-end tests, the most expensive shape a suite can take.

Whether you think in a test pyramid or lean more on integration tests, the rule is the same: do not prove at the user interface level what you can prove more cheaply and reliably underneath it.

The deciding question for any new test is not “can AI automate this?” It is “where is the cheapest reliable place to prove this behaviour?”

UICritical journeys onlyAPI and integrationService behaviour, contractsUnitLogic, calculations, edgesslower, costlierfaster, cheaperAI drifts upward, toward the slow and expensive top

In practice the split is straightforward:

  • UI tests for the journeys a real person takes, where a failure would be a real incident: signup, login, checkout, subscription management, publishing.
  • API and integration tests for service behaviour: authorisation rules, data sync, retries, permissions, and contracts between services, all faster to run and far less flaky than driving them through a browser.
  • Unit tests for pure logic: calculations, formatting, state transitions, and the awkward edge cases.

This is also where an agent earns its keep, if you point it right. Do not just ask it to “test the signup flow”, because that sentence pulls it straight to the browser. Ask it to prove the behaviour at the cheapest reliable level, and tell it to bring back evidence. A good prompt looks like this:

Me → agent
Prove that signing up with an already-registered email is rejected with the exact message the spec defines. Do it at the API level if the rule lives in the service, not through the UI. Run it in CI, break the rule on purpose to confirm the test goes red for the right reason, and attach both runs to the pull request.

Now the agent does the work AI is genuinely strong at, contracts and data and service behaviour, and pushes the test down the pyramid instead of up it. You are reading a pull request that already proves the case, and checking that it failed for the right reason.

Choose what to automate, and tell the agent where to stop

AI will generate every test you ask for, which makes it easy to automate things that should never have made the cut. The way you decide has not changed: score each candidate on risk, value, and cost, and let a risk-versus-stability matrix sort the backlog. Run candidates through that and the suite stays lean on purpose, because the cheap, low-risk, never-breaks tests an agent loves to churn out by the dozen are exactly the filler that scoring makes visible.

What the agent really changes is the “not yet” list. Ask an assistant to automate a feature and it automates all of it, including the parts you should have left alone:

  • A flow whose requirements are still moving.
  • A one-off check you run twice a year.
  • Anything where the real assertion is “does this look right?”
  • A behaviour with no stable hook to grab.
  • A flow nobody on the team understands yet.

That restraint is the part AI will never volunteer. The “not yet” call stays a human decision, and your strategy has to say so out loud or the agent quietly fills the suite with tests you maintain forever.

Ready for automation checklist

When a candidate clears the matrix and is off the “not yet” list, run it through this before anyone writes the test. If it fails a line, fix that first.

  • The behaviour is stable enough that the test will not need rewriting next sprint.
  • There is a real risk this protects, and you can name it in one sentence.
  • You know the cheapest reliable level to prove it: unit, API, or UI.
  • The element or endpoint has a stable hook to target, not a brittle selector.
  • The test can set up its own data and clean up after itself.
  • You know who owns it when it breaks.
  • You know which gate it runs at: pull request, nightly, or release.

Clear all seven and it is ready. Miss one and the groundwork is not there yet, and writing the test now only hides that.

Make failures diagnosable, for humans and for agents

A strategy that plans how tests are written but not how failures are understood is half a strategy. When a test goes red in continuous integration (CI), the time you spend figuring out why is pure cost, and at AI-accelerated volume that cost multiplies. It is also where AI can genuinely earn its place, because an assistant is good at reading a wall of logs and pointing at the first thing that broke, but only if the logs are worth reading. So treat observability as part of the test strategy, not an afterthought owned by the platform team:

  • Clear, consistent event names instead of cryptic codes.
  • A stable correlation ID that follows a request across services, so a single failure does not turn into a scavenger hunt.
  • Meaningful error categories, so “payment declined” and “payment timeout” are not the same log line.
  • Enough context to debug without ever leaking secrets or customer data.
  • Failure states you can deliberately trigger in a test, not just hope to observe in the wild.
  • A trace or screenshot captured automatically when a UI test fails, so you can see the page as it was, not guess at it.

Tooling helps. Playwright’s trace viewer hands you a recorded timeline of a failed run with the DOM, network calls, and console at every step, turning “why did this flake in CI” from guesswork into watching a replay. The principle is bigger than any tool: automation is only as strong as the system underneath it is diagnosable.

Run the right tests at the right gate

A suite that runs everything on every commit teaches the team to ignore it. If a pull request takes forty minutes to come back, people stop waiting and start merging on faith. The fix is to stage the tests: fast, focused checks block a merge, and slow, thorough checks run where a few extra minutes hurt no one. This is the “when” line of the template made concrete. Decide what each gate is allowed to cost, and put only the tests that fit inside it.

GateWhat runs hereWhat it is protecting
Pull requestLint, unit tests, focused integration, and tests for the changed area onlyFast feedback while the author is still in the code. Aim for minutes, not tens of minutes.
Merge to mainFull integration suite, API contract tests, a browser smoke test of the critical pathsNothing broken across the system before it lands on the main branch.
NightlyCross-browser, visual regression, mobile, performance, and the full regression suiteThe slow, broad coverage that would strangle a pull request but matters across a day’s worth of changes.
ReleaseReal-device smoke, payment and entitlement checks, production-safe smoke against the actual buildThe last line before customers. Verify the things that cost money or trust when they break.

The split does two jobs at once. It keeps feedback fast where speed matters, and it puts the expensive, flaky-by-nature tests (cross-browser, visual, real-device) on a schedule where one slow run does not block twelve people. It also gives an assistant a clear rule to follow: a unit test for a calculation belongs in the pull request stage, a real-device payment check belongs at release. That is why the gate is on the “ready for automation” checklist.

One rule holds across every gate: a test that gates a merge has to be trustworthy. The moment a blocking test flakes, people re-run it until it passes, and a green you re-rolled for is not a green you can believe. So flaky tests get their own handling.

Handle flaky tests like the threat they are

I have done this on a real suite, about 167 test files and over 1,600 checks, run wide in parallel. The flake almost always traced back to one thing: tests pausing for a fixed number of seconds instead of waiting for the app to actually finish what it was doing. So the standard I wrote bans fixed waits outright. Every wait keys off a real signal, like the network call resolving, never a guessed number of seconds. In run mode we cap automatic retries at two, but we treat a retry as a bug to fix, not a pass to accept.

In one stabilization pass I fixed the flaky smoke tests, re-stabilized a set of favourite and unfavourite tests by intercepting the API call before acting on the screen, and brought three journey tests back out of quarantine once they could be trusted again.

The worst place a suite can be is one where a red result does not mean “something is broken” but “maybe the test is unstable, run it again.” Once the team has to ask whether the test is lying, the suite has stopped giving confidence and turned into noise. I have inherited suites like that, where every failure came with a shrug and a re-run. The hard truth is that a flaky test you re-run until it passes is worse than no test at all: it costs time, trains people to ignore red, and hides the real failure when one finally arrives.

AI raises the stakes, because it generates tests faster than anyone audits them for stability, and the flaky ones look identical to the solid ones until they run a hundred times in CI.

So treat flakiness as a defect with an owner, not as background weather. The moves are the same ones I use on any suite:

  • Quarantine, do not ignore. Pull the flaky test out of the blocking gate so it stops poisoning green builds, but tag it, give it an owner, and track it.
  • Find the cause, not a bigger timeout. A fixed wait racing a real one, a test leaning on another test’s leftover data, a brittle selector that shifts with the markup: bumping the timeout hides it for a week and it comes right back.
  • Set a flaky-rate budget. Agree on a number, watch it, and treat a breach as work to schedule.
  • Delete when you must. A test that cannot be made reliable and that nobody will own is costing you more than it protects. Removing it is the honest call.

I keep the full playbook, the trace-reading and the quarantine log, in how to fix the suite you stopped trusting.

Most of this is preventable at the source, and this is where a strategy pays off most. Instead of re-correcting the same brittle selector and fixed sleep every session, have the agent write those corrections into a CLAUDE.md or AGENTS.md at the repo root, so it reads your standards before it writes and the common flaky causes never reach review. That is how I keep several agents to the same standard at once: encode it once, in the repo, not in everyone’s memory. Playwright now ships its own test agents, including a healer that repairs failing tests. Treat its fixes the way you treat any generated test: review them against risk before you trust them.

Define what “ready to release” actually means

Before AI, releases were gated mostly by how much a team could manually verify in the time available. That gate is dissolving, and DORA’s data on instability is what happens when nothing replaces it. Your strategy should spell out the evidence a release requires, so “ship it” means something specific rather than “the build looked green and we were tired.” Write it as a checklist the team genuinely uses:

  • Continuous integration passed on the target branch, not on a stale one.
  • Critical smoke tests passed against a real build.
  • The real-device mobile path was verified where it matters.
  • The build artifact was actually checked, not assumed.
  • Any database migration was reviewed by a person.
  • A rollback plan exists and someone could execute it under pressure.
  • The production monitor for this change is known and watched.
  • The release note names the risk that was verified.

An agent is good at the gathering part, and you should let it. It can pull the CI status, test results, and diff into a tidy release summary with the evidence linked, in seconds. What it does not do is decide the bar has been met. Gathering the evidence is the agent’s job. Deciding it is enough to ship is yours.

Measure trust, not test count

The fastest way to ruin an automation strategy is to measure it by test count, the one metric AI can inflate effortlessly. Reward volume and you get volume: thousands of shallow, overlapping, slow-to-maintain tests that make the dashboard look busy and tell you nothing you can trust.

Measure the things that actually show whether the suite is doing its job:

What to measureWhy it tells the truth
Defects caught before releaseThe whole point of the suite, stated directly
Escaped defects by feature areaShows you exactly where coverage is thin
Flaky-test rateFlaky tests erode trust faster than missing tests
Time to diagnose a failureCheap failures mean a healthy, observable system
Critical flows protectedCoverage where it counts, not coverage everywhere
Manual regression time savedThe concrete return automation was bought for
Test maintenance effortA suite that costs more than it saves is a liability

A suite of five hundred meaningful tests that catch real defects and rarely flake beats five thousand that nobody trusts and everybody reruns. Count the trust, not the tests.

Keep the strategy alive

A test automation strategy is not a document you write once and frame on the wall. AI tooling shifts every few months, product risk moves as the product grows, and your team gets sharper as it learns. The strategy has to keep up.

After every significant release, take an honest hour with the team:

  • Which tests actually caught something this cycle?
  • Which tests wasted time, flaking or failing for reasons nobody cared about?
  • Which failures were painful to diagnose, and what would have made them easy?
  • Which manual checks have earned their way into automation?
  • Which automated checks have stopped earning their place and should be deleted?
  • Where did AI genuinely help, and where did it just create more to review?

Delete the tests that lost the plot. Promote the manual checks that proved their worth. Tighten the place where AI created review burden instead of removing it. A strategy you revise is a strategy that stays true.

AI will keep changing how software gets built. None of that changes the foundation. Automate what matters, prove real behaviour at the cheapest reliable level, encode your standards once so the agent follows them by default, keep failures diagnosable, and keep a human accountable for the decisions that cost money to get wrong. Do that, and the agent becomes the fastest pair of hands you have ever worked with, running the suite and bringing back the evidence while you judge whether it proves the risk you cared about. What you are left with is a suite small enough, stable enough, and meaningful enough that when it fails, people pay attention.

Found it useful? Share it.
Julia Pottinger

Written by

Julia Pottinger

Hi, I'm Julia. I've been in QA for over a decade. I spend my days testing software and my own time building apps and games, and I write here to share what I learn, the practical, honest lessons you can actually use.

Comments 0

Share your thoughts, ask questions, or add to the conversation.

Be kind and constructive. Stay on topic. No spam or self-promotion.
Loading comments…