name: ‘step-03a-subagent-api’ description: ‘Subagent: Generate API tests only’ subagent: true
This is an isolated subagent running in parallel with E2E test generation.
What you have from parent workflow:
Your task: Generate API tests ONLY (not E2E, not fixtures, not other test types).
If use_pactjs_utils is enabled AND contract artifacts are explicitly in scope for this subagent: Apply pactjs-utils conventions from the loaded fragments (pactjs-utils-overview, pactjs-utils-consumer-helpers, pactjs-utils-provider-verifier, pactjs-utils-request-filter, pact-consumer-framework-setup) when generating contract-level API test scaffolding. Full consumer/provider suite generation — including edits to vitest.config.pact.ts, vitest.config.contract.ts, package.json scripts (test:pact:consumer, test:pact:consumer:run), and scripts/publish-pact.sh — must be triggered explicitly by the parent workflow flag tea_use_pactjs_utils: true; do not generate those artifacts implicitly. When in scope, enforce these determinism/FFI-safety rules:
pact.addInteraction() per it() block (use it.each for parameterized cases) — PactV4’s Rust FFI drops interactions otherwise.vitest.config.pact.ts must include BOTH fileParallelism: false AND pool: 'forks' + poolOptions.forks.singleFork: true. fileParallelism: false prevents workers racing on the shared pact JSON; forks + singleFork prevents the @pact-foundation/pact Rust FFI from leaking state across files on Linux CI.vitest.config.contract.ts must include pool: 'forks' + poolOptions.forks.singleFork: true (same rule as consumer) for multi-file and message-provider suites.package.json: generate both test:pact:consumer (determinism gate calling scripts/check-pact-determinism.sh) and test:pact:consumer:run (inner vitest invocation).scripts/publish-pact.sh normalizes interactions with jq -S '.interactions |= sort_by(...)' before pact-broker publish.If pact_mcp is "mcp", use SmartBear MCP tools (Fetch Provider States, Generate Pact Tests) to inform test generation.
From the coverage plan (Step 2 output), identify:
For each API endpoint, create test file in tests/api/[feature].spec.ts:
Test Structure:
import { test, expect } from '@playwright/test';
// If Playwright Utils enabled:
// import { apiRequest } from '@playwright-utils/api';
test.describe('[Feature] API Tests', () => {
test('[P0] should handle successful [operation]', async ({ request }) => {
// Use apiRequest helper if Playwright Utils enabled
// Otherwise use standard request fixture
const response = await request.post('/api/endpoint', {
data: {
/* test data */
},
});
expect(response.status()).toBe(200);
expect(await response.json()).toMatchObject({
/* expected */
});
});
test('[P1] should handle [error scenario]', async ({ request }) => {
// Test error handling
});
});
Requirements:
apiRequest() helper if Playwright Utils enabled (from api-request fragment)If Pact.js Utils enabled (from subagentContext.config.use_pactjs_utils):
pact/http/consumer/ using createProviderState({ name, params }) patternpact/http/provider/ using buildVerifierOptions({ provider, port, includeMainAndDeployed, stateHandlers }) patternpact/http/helpers/ using createRequestFilter({ tokenGenerator: () => string })pact/http/helpers/states.tspact/message/ using buildMessageVerifierOptions// Provider endpoint: <path> -> <METHOD> <route>like(), eachLike(), string(), integer() matchers ONLY in willRespondWith (responses). Request bodies in withRequest MUST use exact values — never wrap request bodies in like(). The consumer controls what it sends, so contracts should be strict about request shape.CRITICAL: Before generating ANY Pact consumer interaction, perform provider source scrutiny per the Seven-Point Scrutiny Checklist defined in contract-testing.md. Do NOT generate response matchers from consumer-side types alone — this is the #1 cause of contract verification failures.
The seven points to verify for each interaction:
Source priority: Provider source code is most authoritative. When an OpenAPI/Swagger spec exists (openapi.yaml, openapi.json, swagger.json), use it as a complementary or alternative source — it documents the provider’s contract explicitly and can be faster to parse than tracing through handler code. When both exist, cross-reference them; if they disagree, the source code wins. Document the discrepancy in the scrutiny evidence block (e.g., OpenAPI shows 200 but handler returns 201; using handler behavior) and flag it in the output JSON summary so it is discoverable by downstream consumers or audits.
Scrutiny Sequence (for each endpoint in the coverage plan):
READ provider route handler and/or OpenAPI spec: Find the handler file from subagentContext.config.provider_endpoint_map or by scanning the provider codebase. Also check for OpenAPI/Swagger spec files. Extract:
res.status(201) / OpenAPI responses keys)res.json({ data: ... }) / OpenAPI schema)READ provider type/model/DTO definitions: Find the response type referenced by the handler or OpenAPI $ref schemas. Extract:
transaction_id not transactionId)string ID vs number ID / OpenAPI type + format)required array)$ref, allOf, oneOf)READ provider validation schemas: Find Joi/Zod/class-validator schemas or OpenAPI request body schema.required. Extract:
"active" | "inactive" / OpenAPI enum)Cross-reference findings against consumer expectations:
Document scrutiny evidence as a block comment in the generated test:
/*
* Provider Scrutiny Evidence:
* - Handler: server/src/routes/userHandlers.ts:45
* - OpenAPI: server/openapi.yaml paths./api/v2/users/{userId}.get (if available)
* - Response type: UserResponseDto (server/src/types/user.ts:12)
* - Status: 201 for creation (line 52), 400 for validation error (line 48)
* - Fields: { id: number, name: string, email: string, role: "user" | "admin" }
* - Required request headers: Authorization (Bearer token)
*/
contract-testing.md):
pact_mcp is "mcp" in subagentContext.config): Use SmartBear MCP tools to fetch existing provider states and verified interactions as reference// Provider endpoint: TODO — provider source not accessible, verify manually. Set provider_scrutiny: "pending" in output JSON⚠️ Anti-pattern: Generating response matchers from consumer-side types alone. This produces contracts that reflect what the consumer wishes the provider returns, not what it actually returns. Always read provider source or OpenAPI spec first.
Identify fixtures needed for API tests:
Do NOT create fixtures yet - just track what’s needed for aggregation step.
Write JSON to temp file: /tmp/tea-automate-api-tests-{{timestamp}}.json
{
"success": true,
"subagent": "api-tests",
"tests": [
{
"file": "tests/api/auth.spec.ts",
"content": "[full TypeScript test file content]",
"description": "API tests for authentication endpoints",
"priority_coverage": {
"P0": 3,
"P1": 2,
"P2": 1,
"P3": 0
}
},
{
"file": "tests/api/checkout.spec.ts",
"content": "[full TypeScript test file content]",
"description": "API tests for checkout endpoints",
"priority_coverage": {
"P0": 2,
"P1": 3,
"P2": 1,
"P3": 0
}
}
],
"fixture_needs": ["authToken", "userDataFactory", "productDataFactory"],
"knowledge_fragments_used": ["api-request", "data-factories", "api-testing-patterns"],
"provider_scrutiny": "completed",
"provider_files_read": ["server/src/routes/authHandlers.ts", "server/src/routes/checkoutHandlers.ts", "server/src/types/auth.ts"],
"test_count": 12,
"summary": "Generated 12 API test cases covering 3 features"
}
On Error:
{
"success": false,
"subagent": "api-tests",
"error": "Error message describing what went wrong",
"partial_output": {
/* any tests generated before error */
}
}
Subagent completes when:
Subagent terminates here. Parent workflow will read output and proceed to aggregation.
// Provider endpoint: comment (if CDC enabled)