Building an AI Agent That Writes Test Scenarios For You

July 21, 2026
|
minute read
Blog
Written By

Part 1 — AI & Software Testing: The Big Picture

If you've ever spent a Friday afternoon buried in a lengthy user story, manually dissecting requirements and writing dozens of test scenarios, you're not alone. What if, instead of starting from a blank page, you had a trusted teammate who could read requirements, understand context, identify edge cases, and draft comprehensive test scenarios in seconds?

This is where AI Agents come in.

Rather than replacing testers, AI can act as a co-worker that helps automate repetitive tasks, improve test coverage, and free us to focus on what humans do best—critical thinking, risk analysis, and delivering quality software.

Before we build anything, let's get the foundational vocabulary right — because "AI" gets used to mean wildly different things.

For test scenario generation, we want an agent — something that can read a requirements document, reason about edge cases, write test cases, verify they make sense, and save them to a file, all without you intervening.

Part 2 — Architecture of the Test-Scenario Agent

Before we write a single line of code, let's design our AI teammate.

Just like a human tester needs knowledge, tools, and context to do their job effectively, an AI Agent needs three core components:

The three pillars of any agent:

  • Brain (LLM):

The language model that understands requirements, reasons about what needs to be tested, identifies edge cases, and generates test scenarios.

  • Tools:

The capabilities available to the agent, such as reading requirement files, writing test scenarios to a document, calling APIs, or integrating with systems like Jira.

  • Memory: 

The context the agent carries throughout its work—requirements it has already analyzed, test scenarios it has generated, validation results, and previous decisions.

Agent Workflow

With these components in place, the agent follows a simple workflow:

  1. Read – Understand the requirement, business rules, actors, and expected outcomes.
  2. Analyse – Identify happy paths, negative scenarios, boundary values, edge cases, and integration points.
  3. Generate – Create structured test scenarios with preconditions, steps, expected results, and priority.
  4. Review – Validate its own output for missing coverage, duplicates, and ambiguities, then refine the results.
  5. Export – Produce the final test scenarios in formats such as JSON, CSV, Gherkin, or directly into a Test Management Tool.

Part 3 — Building It: Prompts, Tools, and Code

We'll use Node.js and the Google Gemini API (free tier — no credit card needed). The same pattern works with any LLM provider.

Step 1 — Get your free Gemini API key

  1. Go to https://aistudio.google.com
  2. Sign in with your Google account
  3. Click "Get API Key" then "Create API key"
  4. Copy the key — no billing required

Step 2 — Set up the project

mkdir test-scenario-agent

cd test-scenario-agent

npm init -y

npm install @google/genai dotenv

Create a .env file and add your key:

GEMINI_API_KEY=your-key-here

Add "type": "module" to package.json so we can use import syntax.

Step 3 — The system prompt (your agent's DNA)

The system prompt is the most important thing you'll write. It defines how the agent thinks, what it prioritises, and what format it outputs.

Think of the system prompt as the job description you hand to a new QA engineer on their first day. It sets the rules for everything that follows.

const SYSTEM_PROMPT = `You are a senior QA engineer with 10 years of experience.

When given a software requirement, you will:

1. Identify ALL testable scenarios: happy path, edge cases, negative tests,

   boundary values, security, and accessibility.

2. Write each scenario with these exact fields:

   - id: TC-001, TC-002, etc.

   - title: a short descriptive name

   - preconditions: array of strings

   - steps: array of strings (numbered actions)

   - expected_result: specific and measurable

   - severity: critical / high / medium / low

3. Output ONLY valid JSON — no explanation, no markdown backticks.

`;

Step 4 — The full agent code (agent.js)

import { GoogleGenAI } from "@google/genai";

import * as dotenv from "dotenv";

import { writeFileSync } from "fs";

dotenv.config();

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const MODEL = "gemini-2.5-flash"; // Free tier, fast, reliable

// ─────────────────────────────────────────────

// THE SYSTEM PROMPT — the agent's brain

// ─────────────────────────────────────────────

const SYSTEM_PROMPT = `You are a senior QA engineer with 10 years of experience.

When given a software requirement, you will:

1. Identify ALL testable scenarios: happy path, edge cases, negative tests,

   boundary values, security, and accessibility.

2. Write each scenario with these exact fields:

   - id: "TC-001", "TC-002", etc.

   - title: a short descriptive name

   - preconditions: array of strings (what must be true before the test)

   - steps: array of strings (numbered actions the tester performs)

   - expected_result: what should happen (must be specific and measurable)

   - severity: one of "critical", "high", "medium", "low"

3. Output ONLY valid JSON — no explanation, no markdown, no extra text.

JSON format:

{

  "scenarios": [

    {

      "id": "TC-001",

      "title": "...",

      "preconditions": ["..."],

      "steps": ["1. ...", "2. ..."],

      "expected_result": "...",

      "severity": "critical"

    }

  ]

}`;

/ ─────────────────────────────────────────────

// Helper: safely parse JSON from AI response

// Gemini sometimes wraps output in ```json ... ```

// ─────────────────────────────────────────────
function parseJSON(text) {

  const cleaned = text.replace(/```json|```/g, "").trim();

  return JSON.parse(cleaned);

}

// ─────────────────────────────────────────────

// STEP A: Generate test scenarios

// Note: systemInstruction now goes inside config, not getGenerativeModel

// Note: response.text is a property now, not response.text()

// ─────────────────────────────────────────────

async function generateScenarios(requirement) {

  console.log("Generating test scenarios...");

  const response = await ai.models.generateContent({

    model: MODEL,

    contents: `Generate test scenarios for this requirement:\n\n${requirement}`,

    config: {

      systemInstruction: SYSTEM_PROMPT,

    },

  });

  return parseJSON(response.text);

}

// ─────────────────────────────────────────────

// STEP B: Quality review — a second AI call acting as the critic

// ─────────────────────────────────────────────

async function critiqueScenarios(scenarios) {

  console.log("Running quality review...");

  const response = await ai.models.generateContent({

    model: MODEL,

    contents: `Review these test scenarios and find any that have:

- Ambiguous steps (could be interpreted in 2+ ways)

- Missing preconditions (the starting state is unclear)

- Vague expected results (no clear pass/fail criterion)

Return ONLY a JSON array of issues. If everything looks good, return [].

Format: [{ "id": "TC-001", "issue": "describe the problem" }]

Scenarios to review:

${JSON.stringify(scenarios, null, 2)}`,

    config: {

      systemInstruction:

        "You are a strict QA reviewer. You only respond with valid JSON arrays.",

    },

  });

  return parseJSON(response.text);

}

// ─────────────────────────────────────────────

// STEP C: Fix the issues found

// ─────────────────────────────────────────────

async function fixScenarios(scenarios, issues) {

  console.log(`Fixing ${issues.length} quality issue(s)...`);

  const response = await ai.models.generateContent({

    model: MODEL,

    contents: `Fix these specific issues in the test scenarios and return the complete updated list as JSON.

Issues to fix:

${JSON.stringify(issues, null, 2)}

Current scenarios:

${JSON.stringify(scenarios, null, 2)}`,

    config: {

      systemInstruction: SYSTEM_PROMPT,

    },

  });

  return parseJSON(response.text);

}

Part 4 — Feedback Loop: True Autonomy

A single-shot agent (prompt -> output) is useful, but it still needs a human to review the results. Loop engineering is the practice of designing feedback cycles so the agent evaluates and improves its own output — removing the human reviewer entirely.

What is a loop?

Instead of generating once and hoping for the best, the agent goes through this cycle automatically:

Generate  -->  Validate  -->  Score  -->  Critique  -->  Refine  -->  (loops back until quality threshold is met)

The three loops to build

A — Coverage Loop: Did I miss anything?

The agent compares generated tests against original requirements, producing more scenarios if any conditions, actors, or edge cases lack coverage.

B — Quality Loop: Are these well-written?

A critic agent reviews each scenario to flag ambiguous steps, missing preconditions, or vague expected results for the first agent to revise.

C — Deduplication Loop: Did I repeat myself?

The agent identifies and merges duplicate scenarios testing the same functionality, keeping the test suite lean.

The main loop code

// ─────────────────────────────────────────────

// THE MAIN LOOP — generate → review → fix → repeat

// ─────────────────────────────────────────────

async function runAgent(requirement) {

  const MAX_LOOPS = 3;

  // Generate first draft

  let result = await generateScenarios(requirement);

  console.log(`Generated ${result.scenarios.length} scenarios`);

  // Review and fix in a loop until clean

  for (let loop = 1; loop <= MAX_LOOPS; loop++) {

    const issues = await critiqueScenarios(result.scenarios);

    if (issues.length === 0) {

      console.log(`Quality check passed on loop ${loop} — no issues found!`);

      break;

    }

    console.log(`Found ${issues.length} issue(s) on loop ${loop}, fixing...`);

    result = await fixScenarios(result.scenarios, issues);

    if (loop === MAX_LOOPS) {

      console.log("Reached max loops — saving best version so far");

    }

  }

  // Save output to file

  const outputFile = "test-scenarios.json";

  writeFileSync(outputFile, JSON.stringify(result, null, 2));

  console.log(`\n Saved to ${outputFile}`);

  console.log(`Total scenarios: ${result.scenarios.length}`);

  return result;

}

// ─────────────────────────────────────────────

// YOUR REQUIREMENT — change this to anything you want

// ─────────────────────────────────────────────

const requirement = `

As a registered user, I should be able to reset my password by 

entering my email address on the forgot password page. 

The system should send a password reset link to my email 

that is valid for 24 hours and can only be used once.

`;

runAgent(requirement);

Run it

node agent.js

What you will see in the terminal

Generating test scenarios...

Generated 11 scenarios

Running quality review...

Found 2 issue(s) on loop 1, fixing...

Running quality review...

Quality check passed on loop 2 — no issues found!

Saved to test-scenarios.json

Total scenarios: 18

Key insight: Each "check" function is itself an AI call with a specific prompt. You're using AI to evaluate AI — this is the core pattern behind autonomous quality control. The MAX_LOOPS guard prevents infinite loops in edge cases.

Part 5 — Making It Production-Ready

Generating test scenarios is just the beginning. To make the agent truly useful in a real-world testing workflow, the next step is to integrate it with your Test Management Tool.

Once the agent generates and validates the test scenarios, it can automatically create test cases in tools such as Jira, TestRail, Xray, or Zephyr using their APIs. Instead of manually copying scenarios from a document into your test management system, the agent can populate fields such as the test case title, preconditions, test steps, expected results, priority, and labels.

This not only saves significant manual effort but also ensures that your test repository stays up to date with the latest requirements. By combining AI-generated scenarios with your existing test management workflow, you can move from requirements to executable test cases in a matter of minutes.

Where to go next: Once you have test scenario generation working, the same loop architecture extends naturally to generating test data, writing automation code (Playwright/Cypress steps), detecting flaky tests, and triaging failed test runs. The pattern is always the same — give the agent a goal, tools, and a feedback loop.

Author