---
name: testgen-functional
model: claude-opus-4-8
effort: high
description: >
Generate Playwright E2E test plan and specification documents from project artifacts
(user stories, module models, mockups, specifications). Produces a TEST_PLAN.md root
summary and per-module TEST_SPEC.md files containing test scenarios, data seeding
scripts, and cleanup scripts — all as detailed Markdown blueprints, not actual test code.
Input: application name (mandatory), version (mandatory), module (optional).
Output: TEST_PLAN.md + per-module TEST_SPEC.md files in the auto-resolved test output folder.
Trigger on keywords: "generate test plan",
"generate test spec", "create test specification", "E2E test plan", "Playwright test plan",
"test plan from user stories", "test spec from PRD.md", "generate test scenarios",
"create test blueprint". Accepts application name and version as input
(e.g., /testgen-functional hub_middleware v1.0.3).
Optionally accepts a module name to limit generation to test specs for that module only
(e.g., /testgen-functional hub_middleware v1.0.3 module:Location Information).
Automatically excludes strikethrough (deprecated/removed) items.
Test Generator
Generate Playwright E2E test plan and specification documents from PRD.md and related project artifacts. Outputs are Markdown documents (TEST_PLAN.md and per-module TEST_SPEC.md files) that serve as detailed blueprints for a developer or coding agent to implement actual Playwright test code. This skill does NOT generate Playwright code.
Core Concept: 4-Layer Data Seeding Strategy
Every module is classified into one of 4 data seeding layers. This classification drives the seeding strategy, execution order, and test design for each module.
| Layer | Purpose | Detection Heuristic | Seeding Tool |
|---|---|---|---|
| L1: Auth | Test user setup | Modules about User/Auth; SSO/OAuth references in CLAUDE.md | Auth provider CLI (e.g., Keycloak kcadm, Laravel artisan tinker, or DB seed) |
| L2: Reference Data | Admin-configured master data | User stories with "manage", "configure" by admin roles; no inbound message queue trigger | Direct DB insert via database CLI (e.g., mongosh, mysql, psql, artisan tinker) |
| L3: Transactional Data | Message-driven data | NFRs mentioning "incoming messages", "message queue", "inbound messages"; Reference section linking to MESSAGE_*.md files | Message queue publish via broker CLI (e.g., rabbitmqadmin) |
| L4: Side-Effect Data | Data generated as byproduct | NFRs mentioning "auto-generated", "system generated", "automatically"; modules like Activities, Audit Trail, Notifications | No seeding — asserted as side effects of L2/L3 operations |
Input
This skill uses standardized input resolution. Provide:
| Argument | Required | Example | Description |
|---|---|---|---|
<application> |
Yes | hub_middleware |
Application name to locate the context folder |
<version> |
Yes | v1.0.3 |
Version to scope processing |
module:<name> |
No | module:Location Information |
Limit to a single module |
Application Folder Resolution
The application name is matched against root-level application folders:
- Strip any leading
<number>_prefix from folder names - Match case-insensitively
- Accept snake_case, kebab-case, or title-case input
- If no match found, list available applications and stop
Auto-Resolved Paths
| File | Resolved Path |
|---|---|
| PRD.md | <app_folder>/context/PRD.md |
| Module Models | <app_folder>/context/model/ |
| Specifications | <app_folder>/context/specification/ |
| HTML Mockups | <app_folder>/context/mockup/ |
| References | <app_folder>/context/reference/ |
| Output (test) | <app_folder>/context/test/ |
Example Invocations
/testgen-functional hub_middleware v1.0.3(all modules, up to v1.0.3)/testgen-functional hub_middleware v1.0.3 module:Location Information(one module)/testgen-functional "Hub Middleware" v1.0.3 module:Employer(title-case)
Version and Module Filtering
- Only include user stories, NFRs, constraints, references, test instructions, and bug fixes from sections whose version tag is less than or equal to the target version
- If a module is provided (e.g.,
module:Location Information), only generate the test spec for that specific module. TEST_PLAN.md is still generated but scoped to that module. - If no module is provided, process all modules (default behavior)
Argument parsing: The module: prefix is the canonical form. Also accept:
module:"Location Information"(quoted, with space)module:location_information(snake_case — convert to title-case for matching)- Natural language:
for Location Information module,only Location Information
Version Gate
Before starting any work, resolve the application folder first (see Input Resolution below), then check CHANGELOG.md in the application folder (<app_folder>/CHANGELOG.md):
- If
<app_folder>/CHANGELOG.mddoes not exist, skip this check (first-ever execution for this application). - If
<app_folder>/CHANGELOG.mdexists, scan all## vX.Y.Zheadings and determine the highest version using semantic versioning comparison. - Compare the requested version against the highest version:
- If requested version >= highest version: proceed normally.
- If requested version < highest version: STOP immediately. Print:
"Version {requested} is lower than the current application version {highest} recorded in <app_folder>/CHANGELOG.md. Execution rejected."Do NOT proceed with any work.
Workflow
Step 1: Parse PRD.md
Read the file and extract:
Application name: Derive from the parent folder name containing PRD.md. Strip leading number and underscore prefix, then title-case. Example:
1_hub_middleware-> "Hub Middleware"Application initials: First letter of each word, uppercase. Example:
1_hub_middleware-> "HM"Module categories and modules: Each
# Module Categoryheading groups related modules. Each## Module Namesection under a category is a module. Record the module name, its category, and its description (the line after the heading).User stories per module: Lines matching
- [USxx#####] As a {Role} user, I want to...Extract: tag, role, action summary, sub-items (indented lines under the story).NFRs per module: Lines matching
- [NFRxx####] ...Extract: tag, full text.Constraints per module: Lines matching
- [CONSxx###] ...Extract: tag, full text.References per module: Lines matching
- [REFxx####] ...Extract: tag, description, linked file path (if any).Test instructions per module: Lines matching
- [TSTxx####] ...under### Testsections. These contain human-specified test setup instructions, test data requirements, test edge cases, and test user configurations that MUST be incorporated into the test plan and specs as additional context on top of the standard analysis of User Stories, NFRs, Constraints, Module Models, HTML Mockups, and Technical Specs. Extract: tag (e.g.,[TSTHM0003]), version tag, full text of each bullet point (including sub-bullets which provide detailed test parameters). Test instructions serve as human-guided test scenario hints and edge cases that the test spec generator should use to enrich and complement the auto-derived test scenarios.Bug fixes per module: Content under
### Bugsections. These document previously fixed bugs from prior development cycles. Each bug entry describes what was broken and how it was fixed. Extract: version tag, bug tag (e.g.,[BUG-024]), description.Unique roles: Collect all distinct roles from user stories.
Version tag per item: Each
### User Story,### Non Functional Requirement,### Constraint,### Test, and### Bugsection contains version blocks formatted
as [v1.0.x]. Items listed under a version tag belong to that version. Track the
version for every extracted user story, NFR, constraint, reference, test instruction,
and bug fix. Carry this version through to the Source Artifacts table, test scenario
Source fields, and Traceability Matrix.
- Deprecated item tracking: Items marked with strikethrough in a newer version may have been replaced by a new item. When an item is removed in version X and replaced by item Y, track this replacement. Include a "Removed / Replaced" subsection in the Source Artifacts of the TEST_SPEC.md, following the same format used in SPEC.md: | ID | Type | Removed In | Replaced By | Reason |
1a: Version Filtering and Strikethrough Exclusion (MANDATORY)
PRD.md is a version-controlled document. Each section has a version tag in square
brackets, e.g., [v1.0.1]. Items may also be marked with strikethrough (~~).
Strikethrough exclusion (always applied, regardless of version parameter):
- Any line wrapped in
~~strikethrough~~markup MUST be excluded from processing - This includes user stories, NFRs, constraints, references, test instructions, and bug fixes
- Example:
~~[USHM00006] As a Hub Administrator user, I want to...~~→ SKIP - Partially strikethrough lines (where only part is struck) should still be excluded if the tag identifier is within the strikethrough
Version filtering (applied only when a target version is provided):
- Each section under a module has one or more version tags like
[v1.0.0]or[v1.0.1] - Items listed under a version tag belong to that version
- When a target version is specified (e.g.,
v1.0.1):- Include items from sections whose version tag is <= target version
- Exclude items from sections whose version tag is > target version
- Version comparison uses semantic versioning: compare major, then minor, then patch
- When no target version is specified, include all items from all versions (but still exclude strikethrough items)
1b: Module Filtering (applied only when a module argument is provided)
When a module argument is present:
- Match the specified module against the list of parsed modules (case-insensitive). Also accept snake_case input by converting to title-case for comparison.
- If no module matches, stop and report the available module names to the user.
- When module-filtered, generate TEST_PLAN.md scoped to that module and only that module's TEST_SPEC.md file.
Step 2: Extract Project Information from CLAUDE.md (Already in Context)
CLAUDE.md is automatically loaded into context. Extract the following from it:
Project name and description
Infrastructure details:
- Database type and version (MongoDB, MySQL, PostgreSQL)
- Database name(s) and connection info
- Message Queue type and version (RabbitMQ)
- Message Queue connection info (host, port, credentials)
- SSO/Auth type and version (Keycloak)
- SSO connection info (host, admin credentials, CLI path)
CLI tools available: Map each infrastructure component to its CLI tool based on what CLAUDE.md declares. Common mappings:
- MongoDB →
mongosh(connection string from CLAUDE.md) - MySQL →
mysql(host, port, credentials from CLAUDE.md) - PostgreSQL →
psql(host, port, credentials from CLAUDE.md) - RabbitMQ →
rabbitmqadmin(host, port, credentials from CLAUDE.md) - Keycloak →
kcadm(CLI path, host, admin credentials from CLAUDE.md) - Laravel artisan →
php artisan(for seeder commands, tinker, queue management)
The skill auto-detects which tools apply from CLAUDE.md dependencies. Do not assume a specific tech stack — read it from the project context.
- MongoDB →
Application dependencies: What this application depends on (DB, MQ, SSO)
Environment variable mapping: Map each infrastructure value from CLAUDE.md to a standardized environment variable name. These env vars will be referenced in seeding scripts and helper classes so that generated Playwright tests are portable across machines. Common mappings:
- Database connection string →
TEST_DB_URI(MongoDB) orTEST_DB_HOST,TEST_DB_PORT,TEST_DB_USER,TEST_DB_PASSWORD,TEST_DB_NAME(MySQL/PostgreSQL) - Message Queue →
TEST_MQ_HOST,TEST_MQ_PORT,TEST_MQ_USER,TEST_MQ_PASSWORD,TEST_MQ_VHOST(orTEST_MQ_URLfor AMQP URL) - SSO/Auth →
TEST_SSO_HOST,TEST_SSO_ADMIN_USER,TEST_SSO_ADMIN_PASSWORD,TEST_SSO_CLI_PATH(e.g., path tokcadm.batorkcadm.sh),TEST_SSO_REALM - Application →
TEST_APP_BASE_URL(base URL for Playwright navigation) - Additional CLI paths →
TEST_PHP_PATH,TEST_JAVA_HOME,TEST_MAVEN_PATH(as needed)
Only include env vars for infrastructure components that actually exist in CLAUDE.md.
- Database connection string →
Step 2a: Extract PRD.md Extended Sections
After extracting project information, check PRD.md for the following extended sections:
Design System
If PRD.md contains a # Design System section with a file reference:
- Resolve and read the referenced
DESIGN_SYSTEM.mdfile - Extract component patterns and expected visual appearances (e.g., badge styles, button patterns)
- Use these to generate visual consistency assertions in TEST_SPEC.md (e.g., "Assert status badge has class containing 'bg-green' for Active status", "Assert buttons use rounded-lg class")
If absent, skip visual consistency assertions.
Architecture Principle
If PRD.md contains an # Architecture Principle section, extract patterns that affect test strategy:
| Pattern | Test Impact |
|---|---|
| "Event-driven" | L3 transactional data may have async propagation delay — tests MUST include wait/retry patterns (e.g., await expect.poll(() => ...).toPass({ timeout: 10000 })) for eventual consistency assertions |
| "Message driven" | Confirms L3 classification heuristics — modules receiving data via message queues are L3 |
| "Stateless" | Tests should handle token refresh/expiry scenarios; include JWT expiry test case |
| ACK/NACK patterns | Generate assertion steps verifying messages published to correct queues with expected correlation IDs |
| "At-least-once delivery" | Include idempotency test — send same message twice, verify no duplicate records |
If absent, proceed with existing layer classification heuristics.
High Level Process Flow
If PRD.md contains a # High Level Process Flow section:
- Parse all named process flows with their ordered steps
- Each process flow becomes an end-to-end test scenario (or test suite) in TEST_SPEC.md:
- Happy path: each step → a test step with specific assertions
- Error paths (if described): each generates a separate error scenario
- ACK/NACK patterns generate queue assertion steps (verify messages in outbound queues)
- Process flows are the primary source for L3 (Transactional Data) test scenarios
- Process flows reveal cross-module dependencies that must be included in the test execution order
If absent, derive L3 scenarios from NFRs mentioning "message queue" or "incoming message" only (existing behavior).
Step 3: Load Module Models
For each module, look for <app_folder>/context/model/{module-kebab}/model.md
Convert module name to kebab-case:
- Lowercase the module name, replace spaces with hyphens
- Examples: "Location Information" →
location-information, "Employer" →employer
If the model file exists, extract:
- Collection Catalog (Section 2): collection names, DDD types, document types
- Field Details (Section 5): field name, type, nullable, constraints per collection
- Embedded Document Definitions (Section 6): embedded type name and sub-fields
- Enum Definitions (Section 7): enum name and allowed values
- Index Recommendations (Section 9): indexed fields (used for search/filter identification)
- Module Prefix: The prefix used for collections (e.g.,
LIN,EMP,QUO)
This data is used to:
- Generate realistic sample data for seeding scripts
- Identify searchable/filterable fields for search test scenarios
- Determine collection names for DB insert/cleanup commands
- Map enum values to expected UI dropdown options
Step 4: Load Specifications
For each module, look for <app_folder>/context/specification/{module-kebab}/SPEC.md
If found, extract:
- Traceability section: Maps user stories → collections → mockup screens
- Public API (Service Interface): Method signatures showing available operations
- DTOs: Field definitions showing what the API exposes
- Validation rules: Any documented validation logic
- Business logic rules: Documented business rules and constraints
- Version tags: If the SPEC.md traceability section uses versioned tables (with ID | Version | Description columns), extract the version for each item. Cross-reference with PRD.md version tags for consistency.
This data enriches test scenarios with:
- Expected API behavior for assertions
- Validation rules to test (boundary conditions, required fields)
- Business rule scenarios
Step 5: Load Mockups
For each module, scan <app_folder>/context/mockup/{role_snake_case}/content/{module_snake_case}*.html
If mockup files exist, extract:
- DOM selectors: IDs and classes used on key elements (tables, forms, buttons)
- Navigation paths: HTMX
hx-getroutes showing page navigation flow - Form field names: Input names and types from form elements
- Table column headers:
<th>content from data tables - Tab structure: Tab names and their linked content files
- Action buttons: View/Edit/Delete/Create button patterns and their targets
- Sidebar navigation: Menu items and their routes for the module
This data provides:
- Actual CSS selectors for Playwright
page.locator()calls - Real navigation paths for
page.goto()and click sequences - Form field identifiers for fill operations
- Expected table column names for content assertions
Step 6: Load Message References
Scan <app_folder>/context/reference/message/MESSAGE_*.md and REF_*.md
For modules classified as L3 (Transactional Data), these files provide:
- Message structure: JSON schema of inbound messages
- Sample payloads: Expanded JSON examples with realistic sample data
- Referenced sub-structures:
$REF_*.mdreferences that compose the full message - Metadata fields: correlation ID, origin system, type, command, corridor info
This data is used to generate:
- Sample message JSON payloads for RabbitMQ seeding scripts
- Expected field values for asserting message-driven data in the UI
Step 7: Classify Modules into Layers
For each module, apply the following classification heuristics in order (first match wins):
L1: Auth — Module is classified as L1 if:
- Module name is "User" or contains "Authentication", "Authorization", "SSO"
- User stories reference "profile", "password", "login", "logout"
- NFRs reference "JWT", "SSO", "Keycloak", "token", "authentication"
L4: Side-Effect Data — Module is classified as L4 if:
- Module name is "Activities", "Audit Trail", "Notification", or similar
- NFRs mention "auto-generated", "system generated", "automatically logged"
- NFRs mention "will be logged", "will be recorded automatically"
- No user stories with "manage" or "configure" actions (only "view" actions)
L3: Transactional Data — Module is classified as L3 if:
- NFRs mention "incoming messages", "message queue", "inbound messages"
- Reference section links to
MESSAGE_*.mdfiles - NFRs mention "unique view ... based on incoming"
- User stories are primarily "view" and "search" (no "manage"/"configure"/"add"/"create")
L2: Reference Data — Module is classified as L2 if:
- User stories contain "manage", "configure", "add", "create", "edit", "delete"
- Actions are performed by admin roles
- No message queue triggers (no MESSAGE_*.md references)
- Data is master/reference data maintained through the UI
Record the classification for each module with the reasoning (which heuristic matched).
Step 8: Determine Dependencies
Build a dependency graph between modules:
Model references: If a module's model references another module's collection (e.g.,
countryCodereferencinglin_countries), the referencing module depends on the referenced module.NFR references: If NFRs state data is "based on incoming X messages" and X is another module, there is a dependency.
User story references: If user stories mention "view associated X" where X is another module, there is a dependency.
Layer ordering: L1 → L2 → L3 → L4 (higher layers depend on lower layers implicitly)
Within-layer dependencies: Within L2, reference data that other L2 modules depend on must be seeded first (e.g., Location Information before Employer, since employers have country codes).
Output: An ordered list of modules for test execution, respecting all dependencies.
Step 9: Generate TEST_PLAN.md
Write <app_folder>/context/test/TEST_PLAN.md with the following structure:
# E2E Test Plan: {Application Name}
**Generated**: {date}
**Source**: {PRD.md path}
**Version**: {target version or "all versions"}
**Versions Covered**: v1.0.0 — v{LATEST_VERSION}
**Module Filter**: {module name or "all modules"}
---
## 1. Application Overview
- **Application**: {Application Name} ({Initials})
- **Description**: {from PRD.md context line or CLAUDE.md}
- **Stack**: {from CLAUDE.md — e.g., "Spring Boot 3 + MongoDB + Keycloak + RabbitMQ" or "Laravel 12 + MySQL + Keycloak + RabbitMQ"}
---
## 2. Test Infrastructure
| Component | Type | CLI Tool | Connection |
|-----------|------|----------|------------|
| Database | {type + version from CLAUDE.md} | {CLI tool for that DB} | {connection string} |
| Message Queue | {type + version from CLAUDE.md} | {CLI tool for that MQ} | {AMQP URL} |
| SSO / Auth | {type + version from CLAUDE.md} | {CLI tool or artisan command} | {host URL} |
### CLI Commands Reference
{For each infrastructure component, provide the exact CLI command template with
connection parameters filled in from CLAUDE.md}
---
## 2a. Environment Variables (.env)
{Generate a `.env.example` block listing all environment variables needed by Playwright
test helpers and seeding scripts. Values come from CLAUDE.md. This block serves as the
template for each developer's local `.env` file (which is git-ignored). Only include
variables for infrastructure components that exist in CLAUDE.md.}
```dotenv
# Application
TEST_APP_BASE_URL={base URL from CLAUDE.md, e.g., http://localhost:8080}
# Database ({type from CLAUDE.md})
{If MongoDB:}
TEST_DB_URI={full connection string from CLAUDE.md}
{If MySQL or PostgreSQL:}
TEST_DB_HOST={host}
TEST_DB_PORT={port}
TEST_DB_USER={username}
TEST_DB_PASSWORD={password}
TEST_DB_NAME={database name}
# Message Queue ({type from CLAUDE.md}) — include only if MQ exists
TEST_MQ_HOST={host}
TEST_MQ_PORT={port}
TEST_MQ_USER={username}
TEST_MQ_PASSWORD={password}
TEST_MQ_VHOST={vhost}
TEST_MQ_URL={full AMQP URL}
# SSO / Auth ({type from CLAUDE.md}) — include only if SSO exists
TEST_SSO_HOST={host URL, e.g., http://localhost:8180}
TEST_SSO_ADMIN_USER={admin username}
TEST_SSO_ADMIN_PASSWORD={admin password}
TEST_SSO_CLI_PATH={absolute path to CLI tool, e.g., /opt/keycloak/bin/kcadm.sh}
TEST_SSO_REALM={test realm name}
Important: The .env file MUST be added to .gitignore. The .env.example file
(with placeholder descriptions, NOT actual credentials) is committed to the repository
so that other developers know which variables to configure.
3. Test Users
{Populate this table from TWO sources:
### Testsections in PRD.md — human-specified test users with exact credentials and roles. These take precedence and MUST be used as-is (e.g., the Authentication module's### Testsection may specify exact usernames, passwords, and roles).- Auto-derived from user story roles — for any role NOT already covered by a
### Testsection, generate a test user entry.}
| User | Role | Purpose | Seeding Method | Source |
|---|---|---|---|---|
| {username} | {role} | {what this user tests} | {Keycloak CLI / DB seed} | {PRD.md ### Test or Auto-derived} |
4. Layer Classification Summary
| Module | Category | Layer | Seeding Strategy | Versions | Dependencies |
|---|---|---|---|---|---|
| {module} | {System/Business} | {L1/L2/L3/L4} | {strategy} | {versions from PRD.md} | {deps} |
5. Execution Order
{Ordered list of modules, respecting layer ordering and within-layer dependencies}
- L1 — Auth Setup: {modules}
- L2 — Reference Data: {modules in dependency order}
- L3 — Transactional Data: {modules in dependency order}
- L4 — Side-Effect Assertions: {modules}
6. Table of Contents
{List all test spec files in strict dependency order derived from the dependency graph built in Step 8. A module only appears after ALL modules it depends on have been listed. Apply a topological sort within each layer, then order layers L1 → L2 → L3 → L4. Group by layer in the TOC for readability, but the numbering is globally sequential and reflects the dependency-resolved execution order throughout.}
L1 — Auth Setup
- {Module Name} — Versions: {comma-separated versions} — Summary
L2 — Reference Data
{List L2 modules in topological order: if Module B depends on Module A, Module A comes first.}
- {Module Name} — Versions: {versions} — Summary
- {Module Name} — Versions: {versions} — Summary
L3 — Transactional Data
{List L3 modules in topological order by their inter-module dependencies.}
- {Module Name} — Versions: {versions} — Summary
L4 — Side-Effect Assertions
{List L4 modules after all upstream L1–L3 modules they assert against.}
- {Module Name} — Versions: {versions} — Summary
7. Module Summaries
{One subsection per module. The order of subsections MUST follow the topological sort of the dependency graph (Step 8): a module's subsection only appears after all modules it depends on have already appeared. This is the same order as the TOC in Section 6. Each subsection summarizes what the module's TEST_SPEC.md covers, what data it seeds, what it depends on, and a breakdown of its test scenarios by type.}
Module: {Module Name} {#module-{module-anchor}}
Layer: {L1/L2/L3/L4} — {layer purpose} Seeding Strategy: {Keycloak CLI / DB Insert / MQ Publish / No seeding (side effect)} Spec File: {module-kebab}/TEST_SPEC.md
Dependencies:
| Prerequisite Module | Layer | Reason |
|---|---|---|
| {module name} | {L1/L2/L3} | {why this module must be seeded first} |
(None — this module has no prerequisites.) ↠use when no deps
Data Seeded:
| Collection / Entity | Record Count | Key Sample Fields |
|---|---|---|
| {collection} | {count} | {field: value, ...} |
(No seeding required — data is a side effect of upstream operations.) ↠use for L4
Test Scenarios Summary:
| Type | Count | Description |
|---|---|---|
| Navigation | {n} | Verify sidebar link reaches the {Module Name} screen |
| Search | {n} | Search by {param1}, {param2}, ... |
| View / Detail | {n} | View detail of {entity} with tabs: {tab names} |
| CRUD — Create | {n} | Create new {entity} with required fields |
| CRUD — Edit | {n} | Update {field} of an existing {entity} |
| CRUD — Delete | {n} | Delete {entity} with confirmation dialog |
| Validation | {n} | Required fields, {constraint description}, ... |
| Mapping | {n} | Map {entity A} to {entity B} |
| Toggle | {n} | Activate / Deactivate {entity} |
| History / Audit | {n} | View change history of {entity} |
| Raw Message | {n} | View raw inbound message payload |
| Pagination | {n} | Paginate {entity} list, change page size |
| Regression | {n} | Verify previously fixed bugs still hold |
| Test Instruction | {n} | Human-guided scenarios from ### Test section |
| Total | {total} |
{Omit rows for types with 0 scenarios.}
Roles Tested: {comma-separated list of roles exercised in this module's scenarios}
Key Assertions:
- {Brief bullet summarising the most important expected behaviours to verify}
- {e.g., "Dropdown for Country Code is populated from Location Information reference data"}
- {e.g., "Status badge changes colour immediately after toggle without page reload"}
{Repeat the Module subsection above for every module, in execution order}
8. Global Setup
8a. Auth Setup (L1)
{Keycloak CLI commands to create test realm, clients, roles, and users}
8b. Reference Data Setup (L2)
{Summary of L2 modules and their seeding order}
8c. Message Publishing (L3)
{Summary of L3 modules and the messages to publish}
9. Global Teardown
{Cleanup strategy — reverse order of setup}
9a. Database Cleanup
{CLI commands to drop test data from each collection/table, in reverse dependency order}
9b. Message Queue Cleanup
{CLI commands to purge test queues}
9c. Auth Cleanup
{CLI commands to remove test users/realm}
---
### Step 10: Generate Per-Module TEST_SPEC.md
For each module (or the filtered module), write `<app_folder>/context/test/{module-kebab}/TEST_SPEC.md`:
```markdown
# TEST_SPEC: {Module Name}
**Application**: {Application Name} ({Initials})
**Module**: {Module Name}
**Category**: {System Module / Business Module}
**Layer**: {L1 / L2 / L3 / L4} — {layer purpose}
**Seeding Strategy**: {Keycloak CLI / DB Insert / MQ Publish / No seeding (side effect)}
**Generated**: {date}
**Version**: {target version or "all versions"}
**Versions Covered**: {comma-separated list of versions present in this module}
---
## 1. Module Overview
{Module description from PRD.md}
### Layer Classification Reasoning
{Why this module was classified into its layer — which heuristic matched}
### Source Artifacts
| Artifact Type | Reference | Version |
|---------------|-----------|---------|
| User Story | {USHM tag} | {v1.0.x from PRD.md} |
| NFR | {NFRHM tag} | {v1.0.x} |
| Constraint | {CONSHM tag} | {v1.0.x} |
| Test | {TSTHM tag} | {v1.0.x} |
| Bug Fix | {BUG tag} | {v1.0.x} |
| Artifact | Path | Status |
|----------|------|--------|
| User Stories | {PRD.md path} | Found |
| Module Model | {model path or "Not found"} | {Found/Not found} |
| Specification | {spec path or "Not found"} | {Found/Not found} |
| Mockup | {mockup path or "Not found"} | {Found/Not found} |
| Message Reference | {message ref path or "Not found"} | {Found/Not found} |
{If any items were deprecated/removed and replaced, include:}
### Removed / Replaced
| ID | Type | Removed In | Replaced By | Reason |
|---|---|---|---|---|
| {old ID} | {User Story/NFR/Constraint} | {version removed} | {new ID or "—"} | {reason} |
### Test Instructions (from PRD.md)
{If the module has a `### Test` section in PRD.md, list all tagged test instructions here.
These are human-specified test scenario hints, test edge cases, test data requirements,
and test setup instructions that serve as **additional context** on top of the standard
auto-derived test scenarios from User Stories, NFRs, Constraints, Module Models, HTML
Mockups, and Technical Specs. They MUST be incorporated into the test scenarios in
Section 4.
Test instructions guide the test spec generator on specific scenarios or edge cases that
a human tester has identified as important. They do NOT replace the auto-derived scenarios
but complement them — ensuring critical test paths are not missed.
When a test instruction specifies exact test data (e.g., usernames, passwords, field values),
use those values as-is in the relevant seeding scripts and test scenarios.}
| Tag | Version | Instruction |
|-----|---------|-------------|
| {TSTHM tag} | {v1.0.x} | {Full text of the test instruction from PRD.md} |
{Example: `[TSTHM0003]` specifies exact test user credentials and roles for the Auth
module — these MUST be used in the L1 Auth seeding script instead of auto-generated
user data. `[TSTHA0006]` describes specific validation edge cases for the Employer
module — these should generate additional VAL- test scenarios in Section 4.}
_(No test instructions for this module.)_ ↠use when the `### Test` section is empty or has no tagged items
### Bug Fix Regression Coverage
{If the module has a `### Bug` section in PRD.md, list each bug fix and its corresponding
regression test requirement. Each bug fix MUST have at least one test scenario that verifies
the fix still holds — preventing the same bug from reappearing.}
| Bug Tag | Version | Description | Regression Scenario |
|---------|---------|-------------|-------------------|
| {BUG-XXX} | {v1.0.x} | {Bug fix description from PRD.md} | {REG-prefix-NNN: scenario ID in Section 4} |
_(No bug fixes recorded for this module.)_ ↠use when the `### Bug` section is empty or absent
---
## 2. Prerequisites
{What must exist before tests for this module can run}
| Prerequisite | Module | Layer | How to Verify |
|-------------|--------|-------|--------------|
| {description} | {module name} | {L1/L2/L3} | {verification method} |
---
## 3. Data Seeding
### 3a. Seeding Script
{Based on layer classification, generate appropriate seeding commands}
**IMPORTANT**: All seeding scripts MUST reference environment variables (from Section 2a
of TEST_PLAN.md) instead of hardcoded paths, credentials, or connection strings. This
ensures Playwright tests are portable across developer machines. Use `$ENV_VAR` syntax
in bash command templates and note that the actual Playwright helper code should read
these from `process.env.*` via a `.env` file.
**For L1 (Auth)** — use the auth provider's CLI or framework seeder:
*If Keycloak (detected from CLAUDE.md):*
```bash
# Create test user in Keycloak
# Env vars: TEST_SSO_CLI_PATH, TEST_SSO_HOST, TEST_SSO_ADMIN_USER, TEST_SSO_ADMIN_PASSWORD, TEST_SSO_REALM
"$TEST_SSO_CLI_PATH" config credentials --server "$TEST_SSO_HOST" --realm master --user "$TEST_SSO_ADMIN_USER" --password "$TEST_SSO_ADMIN_PASSWORD"
"$TEST_SSO_CLI_PATH" create users -r "$TEST_SSO_REALM" -s username={user} -s enabled=true ...
If Laravel with DB-backed auth (detected from CLAUDE.md):
# Seed test users via artisan
# Env vars: TEST_PHP_PATH (optional, defaults to 'php')
php artisan tinker --execute="
\App\Models\User::factory()->create([
'name' => '{user}', 'email' => '{email}', 'password' => bcrypt('{pass}')
])->assignRole('{role}');
"
For L2 (Reference Data / DB Insert) — use the database CLI matching CLAUDE.md:
If MongoDB:
# Env vars: TEST_DB_URI
mongosh "$TEST_DB_URI" --eval '
db.{collection}.insertMany([
{sample document based on model fields},
...
])
'
If MySQL:
# Env vars: TEST_DB_HOST, TEST_DB_PORT, TEST_DB_USER, TEST_DB_PASSWORD, TEST_DB_NAME
mysql -h "$TEST_DB_HOST" -P "$TEST_DB_PORT" -u "$TEST_DB_USER" -p"$TEST_DB_PASSWORD" "$TEST_DB_NAME" -e "
INSERT INTO {table} ({columns}) VALUES
({sample row based on model fields}),
...;
"
If PostgreSQL:
# Env vars: TEST_DB_HOST, TEST_DB_PORT, TEST_DB_USER, TEST_DB_PASSWORD, TEST_DB_NAME
psql "postgresql://$TEST_DB_USER:$TEST_DB_PASSWORD@$TEST_DB_HOST:$TEST_DB_PORT/$TEST_DB_NAME" -c "
INSERT INTO {table} ({columns}) VALUES
({sample row based on model fields}),
...;
"
If Laravel (alternative to raw CLI):
php artisan db:seed --class=Test{Module}Seeder
For L3 (Transactional Data / MQ Publish) — use the message broker CLI:
If RabbitMQ:
# Env vars: TEST_MQ_HOST, TEST_MQ_PORT, TEST_MQ_USER, TEST_MQ_PASSWORD, TEST_MQ_VHOST
rabbitmqadmin -H "$TEST_MQ_HOST" -P "$TEST_MQ_PORT" -u "$TEST_MQ_USER" -p "$TEST_MQ_PASSWORD" -V "$TEST_MQ_VHOST" publish exchange={exchange} routing_key={key} payload='{
{sample message JSON from MESSAGE_*.md}
}'
For L4 (Side Effect):
No seeding required — data is generated as a side effect of L2/L3 operations.
Assert existence after upstream tests complete.
3b. Seeded Data Summary
| Collection/Entity | Record Count | Key Fields | Sample Values |
|---|---|---|---|
| {collection} | {count} | {key fields from model} | {sample values} |
4. Test Scenarios
{Derived from user stories, grouped by test type. Each scenario includes:
- Scenario ID (module prefix + sequential number)
- Description
- Source user story tag(s)
- Role performing the test
- Preconditions
- Steps (numbered)
- Expected results
- Selectors (from mockups, if available)}
4a. Navigation Tests
{Derived from mockup sidebar links — verify the module screen is accessible}
NAV-{prefix}-001: Navigate to {Module} screen
- Source: Sidebar navigation [v1.0.x]
- Role: {role}
- Preconditions: User is logged in
- Steps:
- Click "{Module Name}" in the sidebar navigation
- Wait for content area to load
- Expected:
- URL contains
/{role_snake_case}/{module_snake_case} - Page title/heading shows "{Module Name}"
- {If mockup exists: specific heading selector from mockup}
- URL contains
- Selectors (from mockup):
- Sidebar link:
{selector from sidebar HTML} - Page heading:
{selector from content HTML}
- Sidebar link:
4b. Search Tests
{Derived from user stories matching "search for X based on Y"}
SRCH-{prefix}-001: Search {entity} by {parameter}
- Source: {user story tag} [v1.0.x]
- Role: {role}
- Preconditions: {seeded data exists}
- Steps:
- Navigate to {module} screen
- Enter "{sample value}" in the {parameter} filter field
- Click "Search" / press Enter
- Wait for results to load
- Expected:
- Results table shows matching records
- Each result row contains the search term in the {parameter} column
- Result count is displayed (e.g., "Showing 1-N of N results")
- Selectors (from mockup):
- Filter input:
{selector} - Search button:
{selector} - Results table:
{selector} - Result count text:
{selector}
- Filter input:
4c. View/Detail Tests
{Derived from user stories matching "view details of X"}
VIEW-{prefix}-001: View {entity} details
- Source: {user story tag} [v1.0.x]
- Role: {role}
- Preconditions: {entity exists in system}
- Steps:
- Navigate to {module} list screen
- Click "View" action on a record
- Wait for detail page to load
- Expected:
- Detail page shows all expected fields
- {For each field from model: field label and value are visible}
- Back button navigates to list
- Selectors (from mockup):
- View button:
{selector} - Detail card:
{selector} - Back button:
{selector}
- View button:
4d. CRUD Tests
{Derived from user stories matching "manage", "configure", "add/create", "edit/update", "delete"}
CRUD-{prefix}-001: Create new {entity}
- Source: {user story tag} [v1.0.x]
- Role: {role}
- Preconditions: User has create permission
- Steps:
- Navigate to {module} list screen
- Click "Add New" button
- Fill in required fields: {For each required field from model:
…(truncated)