Reliable automation needs more than generation.
A practical way to think about AI-generated tests: generation, repair, and evaluation as separate responsibilities.
Generating code is a useful first step. Getting code that runs, tests the intended behavior, and fits the repository is a different problem.
The AI-powered Playwright framework in my résumé used specialized generation, repair, and evaluation agents alongside deterministic validation. It supported the generation of more than 1,500 end-to-end test cases during a UI modernization initiative.
The useful design idea is the separation of responsibilities.
A passing test is not the whole goal
A generated test can pass without checking the behavior that matters. It may use weak assertions, omit an important step, or interact with a different element than the original test case intended.
“Runs successfully” and “covers the requirement” are distinct questions. A workflow needs evidence for both.
| Responsibility | Question to answer |
|---|---|
| Generation | Does the test express the supplied manual scenario? |
| Validation | Is the output well formed and compatible with the repository? |
| Execution | Can the test run against the application? |
| Evaluation | Do the actions and assertions cover the intended behavior? |
Keeping those questions explicit makes failures easier to understand.
Use deterministic checks where possible
Schema validation can check the shape of generated output. TypeScript compilation can catch invalid references and type errors. Playwright execution can surface runtime and interaction failures.
These checks do not prove complete test quality, but they provide concrete feedback. They are usually a stronger basis for a repair loop than an agent’s confidence in its own output.
Repair should have boundaries
An autonomous repair loop needs a clear objective. Fixing an invalid import or a broken selector can be useful. Removing a failing assertion just to produce a green run can erase the purpose of the test.
A practical review should ask whether the repaired test preserves the original scenario and its expected result. The loop also needs a stopping condition so that unresolved failures become visible to an engineer.
This is an illustrative control flow, rather than the production implementation:
const candidate = await generateTest(manualScenario);
const validation = await validateTest(candidate);
if (!validation.ok) {
return requestRepair(candidate, validation.errors);
}
const execution = await runTest(candidate);
return evaluateCoverage(manualScenario, candidate, execution);Keep engineers in the feedback loop
Generated tests are engineering artifacts. They benefit from the same review questions as manually written tests: is the intent clear, are the assertions meaningful, and will the test remain maintainable as the application changes?
The objective is to reduce repetitive effort while preserving those standards. Generation accelerates the first draft; validation and evaluation help make that draft worth keeping.