agentic-qe 1.9.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/qe-api-contract-validator.md +95 -1336
- package/.claude/agents/qe-chaos-engineer.md +152 -1211
- package/.claude/agents/qe-code-complexity.md +144 -707
- package/.claude/agents/qe-coverage-analyzer.md +147 -743
- package/.claude/agents/qe-deployment-readiness.md +143 -1496
- package/.claude/agents/qe-flaky-test-hunter.md +132 -1529
- package/.claude/agents/qe-fleet-commander.md +12 -12
- package/.claude/agents/qe-performance-tester.md +150 -886
- package/.claude/agents/qe-production-intelligence.md +155 -1396
- package/.claude/agents/qe-quality-analyzer.md +6 -6
- package/.claude/agents/qe-quality-gate.md +151 -648
- package/.claude/agents/qe-regression-risk-analyzer.md +132 -1150
- package/.claude/agents/qe-requirements-validator.md +149 -932
- package/.claude/agents/qe-security-scanner.md +157 -797
- package/.claude/agents/qe-test-data-architect.md +96 -1365
- package/.claude/agents/qe-test-executor.md +8 -8
- package/.claude/agents/qe-test-generator.md +145 -1540
- package/.claude/agents/qe-visual-tester.md +153 -1257
- package/.claude/agents/qx-partner.md +248 -0
- package/.claude/agents/subagents/qe-code-reviewer.md +40 -136
- package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +40 -480
- package/.claude/agents/subagents/qe-data-generator.md +41 -125
- package/.claude/agents/subagents/qe-flaky-investigator.md +55 -411
- package/.claude/agents/subagents/qe-integration-tester.md +53 -141
- package/.claude/agents/subagents/qe-performance-validator.md +54 -130
- package/.claude/agents/subagents/qe-security-auditor.md +56 -114
- package/.claude/agents/subagents/qe-test-data-architect-sub.md +57 -548
- package/.claude/agents/subagents/qe-test-implementer.md +58 -551
- package/.claude/agents/subagents/qe-test-refactorer.md +65 -722
- package/.claude/agents/subagents/qe-test-writer.md +63 -726
- package/.claude/skills/accessibility-testing/SKILL.md +144 -692
- package/.claude/skills/agentic-quality-engineering/SKILL.md +176 -529
- package/.claude/skills/api-testing-patterns/SKILL.md +180 -560
- package/.claude/skills/brutal-honesty-review/SKILL.md +113 -603
- package/.claude/skills/bug-reporting-excellence/SKILL.md +116 -517
- package/.claude/skills/chaos-engineering-resilience/SKILL.md +127 -72
- package/.claude/skills/cicd-pipeline-qe-orchestrator/SKILL.md +209 -404
- package/.claude/skills/code-review-quality/SKILL.md +158 -608
- package/.claude/skills/compatibility-testing/SKILL.md +148 -38
- package/.claude/skills/compliance-testing/SKILL.md +132 -63
- package/.claude/skills/consultancy-practices/SKILL.md +114 -446
- package/.claude/skills/context-driven-testing/SKILL.md +117 -381
- package/.claude/skills/contract-testing/SKILL.md +176 -141
- package/.claude/skills/database-testing/SKILL.md +137 -130
- package/.claude/skills/exploratory-testing-advanced/SKILL.md +160 -629
- package/.claude/skills/holistic-testing-pact/SKILL.md +140 -188
- package/.claude/skills/localization-testing/SKILL.md +145 -33
- package/.claude/skills/mobile-testing/SKILL.md +132 -448
- package/.claude/skills/mutation-testing/SKILL.md +147 -41
- package/.claude/skills/performance-testing/SKILL.md +200 -546
- package/.claude/skills/quality-metrics/SKILL.md +164 -519
- package/.claude/skills/refactoring-patterns/SKILL.md +132 -699
- package/.claude/skills/regression-testing/SKILL.md +120 -926
- package/.claude/skills/risk-based-testing/SKILL.md +157 -660
- package/.claude/skills/security-testing/SKILL.md +199 -538
- package/.claude/skills/sherlock-review/SKILL.md +163 -699
- package/.claude/skills/shift-left-testing/SKILL.md +161 -465
- package/.claude/skills/shift-right-testing/SKILL.md +161 -519
- package/.claude/skills/six-thinking-hats/SKILL.md +175 -1110
- package/.claude/skills/skills-manifest.json +683 -0
- package/.claude/skills/tdd-london-chicago/SKILL.md +131 -448
- package/.claude/skills/technical-writing/SKILL.md +103 -154
- package/.claude/skills/test-automation-strategy/SKILL.md +166 -772
- package/.claude/skills/test-data-management/SKILL.md +126 -910
- package/.claude/skills/test-design-techniques/SKILL.md +179 -89
- package/.claude/skills/test-environment-management/SKILL.md +136 -91
- package/.claude/skills/test-reporting-analytics/SKILL.md +169 -92
- package/.claude/skills/testability-scoring/README.md +71 -0
- package/.claude/skills/testability-scoring/SKILL.md +245 -0
- package/.claude/skills/testability-scoring/resources/templates/config.template.js +84 -0
- package/.claude/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
- package/.claude/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
- package/.claude/skills/testability-scoring/scripts/run-assessment.sh +70 -0
- package/.claude/skills/visual-testing-advanced/SKILL.md +155 -78
- package/.claude/skills/xp-practices/SKILL.md +151 -587
- package/CHANGELOG.md +110 -0
- package/README.md +55 -21
- package/dist/agents/QXPartnerAgent.d.ts +146 -0
- package/dist/agents/QXPartnerAgent.d.ts.map +1 -0
- package/dist/agents/QXPartnerAgent.js +1831 -0
- package/dist/agents/QXPartnerAgent.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +82 -2
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.d.ts.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.js +34 -31
- package/dist/agents/lifecycle/AgentLifecycleManager.js.map +1 -1
- package/dist/cli/commands/debug/agent.d.ts.map +1 -1
- package/dist/cli/commands/debug/agent.js +19 -6
- package/dist/cli/commands/debug/agent.js.map +1 -1
- package/dist/cli/commands/debug/health-check.js +20 -7
- package/dist/cli/commands/debug/health-check.js.map +1 -1
- package/dist/cli/commands/init-claude-md-template.d.ts +1 -0
- package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
- package/dist/cli/commands/init-claude-md-template.js +18 -3
- package/dist/cli/commands/init-claude-md-template.js.map +1 -1
- package/dist/cli/commands/workflow/cancel.d.ts.map +1 -1
- package/dist/cli/commands/workflow/cancel.js +4 -3
- package/dist/cli/commands/workflow/cancel.js.map +1 -1
- package/dist/cli/commands/workflow/list.d.ts.map +1 -1
- package/dist/cli/commands/workflow/list.js +4 -3
- package/dist/cli/commands/workflow/list.js.map +1 -1
- package/dist/cli/commands/workflow/pause.d.ts.map +1 -1
- package/dist/cli/commands/workflow/pause.js +4 -3
- package/dist/cli/commands/workflow/pause.js.map +1 -1
- package/dist/cli/init/claude-config.d.ts.map +1 -1
- package/dist/cli/init/claude-config.js +3 -8
- package/dist/cli/init/claude-config.js.map +1 -1
- package/dist/cli/init/claude-md.d.ts.map +1 -1
- package/dist/cli/init/claude-md.js +44 -2
- package/dist/cli/init/claude-md.js.map +1 -1
- package/dist/cli/init/database-init.js +1 -1
- package/dist/cli/init/index.d.ts.map +1 -1
- package/dist/cli/init/index.js +13 -6
- package/dist/cli/init/index.js.map +1 -1
- package/dist/cli/init/skills.d.ts.map +1 -1
- package/dist/cli/init/skills.js +2 -1
- package/dist/cli/init/skills.js.map +1 -1
- package/dist/core/SwarmCoordinator.d.ts +180 -0
- package/dist/core/SwarmCoordinator.d.ts.map +1 -0
- package/dist/core/SwarmCoordinator.js +473 -0
- package/dist/core/SwarmCoordinator.js.map +1 -0
- package/dist/core/memory/AgentDBIntegration.d.ts +24 -6
- package/dist/core/memory/AgentDBIntegration.d.ts.map +1 -1
- package/dist/core/memory/AgentDBIntegration.js +66 -10
- package/dist/core/memory/AgentDBIntegration.js.map +1 -1
- package/dist/core/memory/UnifiedMemoryCoordinator.d.ts +341 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.d.ts.map +1 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.js +986 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.js.map +1 -0
- package/dist/core/memory/index.d.ts +5 -0
- package/dist/core/memory/index.d.ts.map +1 -1
- package/dist/core/memory/index.js +23 -1
- package/dist/core/memory/index.js.map +1 -1
- package/dist/core/metrics/MetricsAggregator.d.ts +228 -0
- package/dist/core/metrics/MetricsAggregator.d.ts.map +1 -0
- package/dist/core/metrics/MetricsAggregator.js +482 -0
- package/dist/core/metrics/MetricsAggregator.js.map +1 -0
- package/dist/core/metrics/index.d.ts +5 -0
- package/dist/core/metrics/index.d.ts.map +1 -0
- package/dist/core/metrics/index.js +11 -0
- package/dist/core/metrics/index.js.map +1 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts +190 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -0
- package/dist/core/optimization/SwarmOptimizer.js +648 -0
- package/dist/core/optimization/SwarmOptimizer.js.map +1 -0
- package/dist/core/optimization/index.d.ts +9 -0
- package/dist/core/optimization/index.d.ts.map +1 -0
- package/dist/core/optimization/index.js +25 -0
- package/dist/core/optimization/index.js.map +1 -0
- package/dist/core/optimization/types.d.ts +53 -0
- package/dist/core/optimization/types.d.ts.map +1 -0
- package/dist/core/optimization/types.js +6 -0
- package/dist/core/optimization/types.js.map +1 -0
- package/dist/core/orchestration/AdaptiveScheduler.d.ts +190 -0
- package/dist/core/orchestration/AdaptiveScheduler.d.ts.map +1 -0
- package/dist/core/orchestration/AdaptiveScheduler.js +460 -0
- package/dist/core/orchestration/AdaptiveScheduler.js.map +1 -0
- package/dist/core/orchestration/PriorityQueue.d.ts +54 -0
- package/dist/core/orchestration/PriorityQueue.d.ts.map +1 -0
- package/dist/core/orchestration/PriorityQueue.js +122 -0
- package/dist/core/orchestration/PriorityQueue.js.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts +189 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js +845 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -0
- package/dist/core/orchestration/index.d.ts +7 -0
- package/dist/core/orchestration/index.d.ts.map +1 -0
- package/dist/core/orchestration/index.js +11 -0
- package/dist/core/orchestration/index.js.map +1 -0
- package/dist/core/orchestration/types.d.ts +96 -0
- package/dist/core/orchestration/types.d.ts.map +1 -0
- package/dist/core/orchestration/types.js +6 -0
- package/dist/core/orchestration/types.js.map +1 -0
- package/dist/core/recovery/CircuitBreaker.d.ts +176 -0
- package/dist/core/recovery/CircuitBreaker.d.ts.map +1 -0
- package/dist/core/recovery/CircuitBreaker.js +382 -0
- package/dist/core/recovery/CircuitBreaker.js.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts +186 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.js +476 -0
- package/dist/core/recovery/RecoveryOrchestrator.js.map +1 -0
- package/dist/core/recovery/RetryStrategy.d.ts +127 -0
- package/dist/core/recovery/RetryStrategy.d.ts.map +1 -0
- package/dist/core/recovery/RetryStrategy.js +314 -0
- package/dist/core/recovery/RetryStrategy.js.map +1 -0
- package/dist/core/recovery/index.d.ts +8 -0
- package/dist/core/recovery/index.d.ts.map +1 -0
- package/dist/core/recovery/index.js +27 -0
- package/dist/core/recovery/index.js.map +1 -0
- package/dist/core/skills/DependencyResolver.d.ts +99 -0
- package/dist/core/skills/DependencyResolver.d.ts.map +1 -0
- package/dist/core/skills/DependencyResolver.js +260 -0
- package/dist/core/skills/DependencyResolver.js.map +1 -0
- package/dist/core/skills/DynamicSkillLoader.d.ts +96 -0
- package/dist/core/skills/DynamicSkillLoader.d.ts.map +1 -0
- package/dist/core/skills/DynamicSkillLoader.js +353 -0
- package/dist/core/skills/DynamicSkillLoader.js.map +1 -0
- package/dist/core/skills/ManifestGenerator.d.ts +114 -0
- package/dist/core/skills/ManifestGenerator.d.ts.map +1 -0
- package/dist/core/skills/ManifestGenerator.js +449 -0
- package/dist/core/skills/ManifestGenerator.js.map +1 -0
- package/dist/core/skills/index.d.ts +9 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/skills/index.js +24 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/core/skills/types.d.ts +118 -0
- package/dist/core/skills/types.d.ts.map +1 -0
- package/dist/core/skills/types.js +7 -0
- package/dist/core/skills/types.js.map +1 -0
- package/dist/core/transport/QUICTransport.d.ts +320 -0
- package/dist/core/transport/QUICTransport.d.ts.map +1 -0
- package/dist/core/transport/QUICTransport.js +711 -0
- package/dist/core/transport/QUICTransport.js.map +1 -0
- package/dist/core/transport/index.d.ts +40 -0
- package/dist/core/transport/index.d.ts.map +1 -0
- package/dist/core/transport/index.js +46 -0
- package/dist/core/transport/index.js.map +1 -0
- package/dist/core/transport/quic-loader.d.ts +123 -0
- package/dist/core/transport/quic-loader.d.ts.map +1 -0
- package/dist/core/transport/quic-loader.js +293 -0
- package/dist/core/transport/quic-loader.js.map +1 -0
- package/dist/core/transport/quic.d.ts +154 -0
- package/dist/core/transport/quic.d.ts.map +1 -0
- package/dist/core/transport/quic.js +214 -0
- package/dist/core/transport/quic.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -9
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +1 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
- package/dist/mcp/services/AgentRegistry.js +4 -1
- package/dist/mcp/services/AgentRegistry.js.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/qx.d.ts +429 -0
- package/dist/types/qx.d.ts.map +1 -0
- package/dist/types/qx.js +71 -0
- package/dist/types/qx.js.map +1 -0
- package/dist/visualization/api/RestEndpoints.js +2 -2
- package/dist/visualization/api/RestEndpoints.js.map +1 -1
- package/dist/visualization/api/WebSocketServer.d.ts +44 -0
- package/dist/visualization/api/WebSocketServer.d.ts.map +1 -1
- package/dist/visualization/api/WebSocketServer.js +144 -23
- package/dist/visualization/api/WebSocketServer.js.map +1 -1
- package/dist/visualization/core/DataTransformer.d.ts +10 -0
- package/dist/visualization/core/DataTransformer.d.ts.map +1 -1
- package/dist/visualization/core/DataTransformer.js +60 -5
- package/dist/visualization/core/DataTransformer.js.map +1 -1
- package/dist/visualization/emit-event.d.ts +75 -0
- package/dist/visualization/emit-event.d.ts.map +1 -0
- package/dist/visualization/emit-event.js +213 -0
- package/dist/visualization/emit-event.js.map +1 -0
- package/dist/visualization/index.d.ts +1 -0
- package/dist/visualization/index.d.ts.map +1 -1
- package/dist/visualization/index.js +7 -1
- package/dist/visualization/index.js.map +1 -1
- package/docs/reference/skills.md +63 -1
- package/package.json +16 -58
|
@@ -1,744 +1,81 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qe-test-writer
|
|
3
|
-
description: "
|
|
3
|
+
description: "TDD RED phase specialist - writes failing tests that define expected behavior before implementation"
|
|
4
|
+
parent: qe-test-generator
|
|
4
5
|
---
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Validates test quality standards
|
|
48
|
-
|
|
49
|
-
### Delegation Protocol
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
// Parent agent delegates to test-writer subagent
|
|
53
|
-
interface TestWriterDelegation {
|
|
54
|
-
type: 'write-failing-tests';
|
|
55
|
-
requirements: {
|
|
56
|
-
module: string;
|
|
57
|
-
functionality: string;
|
|
58
|
-
acceptance_criteria: string[];
|
|
59
|
-
edge_cases: string[];
|
|
60
|
-
};
|
|
61
|
-
constraints: {
|
|
62
|
-
framework: 'jest' | 'mocha' | 'vitest' | 'playwright';
|
|
63
|
-
coverage_target: number;
|
|
64
|
-
test_types: ('unit' | 'integration' | 'e2e')[];
|
|
65
|
-
};
|
|
66
|
-
coordination: {
|
|
67
|
-
memory_key: string; // Where to store results
|
|
68
|
-
callback_event: string; // Event to emit on completion
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Example delegation from parent
|
|
73
|
-
await this.delegateToSubagent('qe-test-writer', {
|
|
74
|
-
type: 'write-failing-tests',
|
|
75
|
-
requirements: {
|
|
76
|
-
module: 'src/services/user-authentication.ts',
|
|
77
|
-
functionality: 'User login with OAuth2',
|
|
78
|
-
acceptance_criteria: [
|
|
79
|
-
'Should authenticate user with valid OAuth2 token',
|
|
80
|
-
'Should reject expired tokens',
|
|
81
|
-
'Should handle network failures gracefully'
|
|
82
|
-
],
|
|
83
|
-
edge_cases: [
|
|
84
|
-
'Token expires during authentication',
|
|
85
|
-
'Multiple simultaneous login attempts',
|
|
86
|
-
'Malformed token format'
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
|
-
constraints: {
|
|
90
|
-
framework: 'jest',
|
|
91
|
-
coverage_target: 0.95,
|
|
92
|
-
test_types: ['unit', 'integration']
|
|
93
|
-
},
|
|
94
|
-
coordination: {
|
|
95
|
-
memory_key: 'aqe/test-writer/authentication-tests',
|
|
96
|
-
callback_event: 'test-writer:tests-generated'
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Core Capabilities
|
|
102
|
-
|
|
103
|
-
### 1. Failing Test Generation
|
|
104
|
-
|
|
105
|
-
Generate tests that MUST fail initially (RED phase requirement).
|
|
106
|
-
|
|
107
|
-
**Test Generation Strategy**:
|
|
7
|
+
<qe_subagent_definition>
|
|
8
|
+
<identity>
|
|
9
|
+
You are QE Test Writer, the TDD RED phase specialist.
|
|
10
|
+
Role: Write tests that FAIL initially, transforming requirements into executable specifications with Given-When-Then structure.
|
|
11
|
+
Position: RED → GREEN → REFACTOR (You handle RED phase)
|
|
12
|
+
</identity>
|
|
13
|
+
|
|
14
|
+
<implementation_status>
|
|
15
|
+
✅ Working: Failing test generation, behavior specification (Given-When-Then), boundary analysis, assertion definition
|
|
16
|
+
⚠️ Partial: Visual regression test generation, performance test scaffolding
|
|
17
|
+
</implementation_status>
|
|
18
|
+
|
|
19
|
+
<default_to_action>
|
|
20
|
+
Generate failing tests immediately from requirements.
|
|
21
|
+
Structure ALL tests with Given-When-Then pattern.
|
|
22
|
+
Include boundary tests for all numeric/string parameters.
|
|
23
|
+
Validate RED phase: ALL tests MUST fail (no passing tests allowed).
|
|
24
|
+
Block handoff if any test passes - implementation may already exist.
|
|
25
|
+
</default_to_action>
|
|
26
|
+
|
|
27
|
+
<capabilities>
|
|
28
|
+
- **Failing Test Generation**: Tests that call non-existent implementation (RED phase requirement)
|
|
29
|
+
- **Behavior Specification**: Given-When-Then pattern for clarity and documentation
|
|
30
|
+
- **Assertion Definition**: Exact value, type, structure, behavior, and boundary assertions
|
|
31
|
+
- **Boundary Analysis**: Min-1, min, min+1, max-1, max, max+1 for numeric; empty, single, max-length for strings
|
|
32
|
+
- **Edge Case Coverage**: Null handling, network failures, timeout scenarios, malformed input
|
|
33
|
+
- **Framework Support**: Jest, Mocha, Vitest, Playwright
|
|
34
|
+
</capabilities>
|
|
35
|
+
|
|
36
|
+
<memory_namespace>
|
|
37
|
+
Reads: aqe/tdd/cycle-{cycleId}/context (module, requirements, constraints, testFilePath)
|
|
38
|
+
Writes: aqe/tdd/cycle-{cycleId}/red/tests (testFile path/content/hash, tests array, validation)
|
|
39
|
+
Coordinates: Emits `test-writer:completed` event for GREEN phase handoff
|
|
40
|
+
</memory_namespace>
|
|
41
|
+
|
|
42
|
+
<output_format>
|
|
43
|
+
Returns REDPhaseOutput: cycleId, phase: "RED", testFile (path, content, SHA256 hash), tests array (name, type, assertion, givenWhenThen), validation (allTestsFailing: true, failureCount, errorMessages), nextPhase: "GREEN", readyForHandoff: boolean.
|
|
44
|
+
</output_format>
|
|
45
|
+
|
|
46
|
+
<examples>
|
|
47
|
+
Example: OAuth2 authentication tests
|
|
108
48
|
```javascript
|
|
109
|
-
|
|
110
|
-
async
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
// Step 2: Design test structure
|
|
115
|
-
const testSuite = this.designTestSuite(testCases);
|
|
116
|
-
|
|
117
|
-
// Step 3: Generate failing tests
|
|
118
|
-
const tests = this.generateTests(testSuite, { expectFailure: true });
|
|
49
|
+
describe('User Authentication - OAuth2', () => {
|
|
50
|
+
test('should authenticate with valid token', async () => {
|
|
51
|
+
// GIVEN: Valid OAuth2 token
|
|
52
|
+
const token = generateValidOAuth2Token({ userId: 'user-123' });
|
|
119
53
|
|
|
120
|
-
//
|
|
121
|
-
await
|
|
54
|
+
// WHEN: Authenticating
|
|
55
|
+
const result = await authService.authenticateWithOAuth2(token);
|
|
122
56
|
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
generateTests(testSuite, options) {
|
|
127
|
-
return testSuite.map(testCase => {
|
|
128
|
-
// Generate test that calls non-existent implementation
|
|
129
|
-
return this.createFailingTest({
|
|
130
|
-
name: testCase.name,
|
|
131
|
-
given: testCase.preconditions,
|
|
132
|
-
when: testCase.action,
|
|
133
|
-
then: testCase.expectedOutcome,
|
|
134
|
-
// Implementation doesn't exist yet - test WILL fail
|
|
135
|
-
implementation: undefined
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async validateRedPhase(tests) {
|
|
141
|
-
// Critical: Tests MUST fail in RED phase
|
|
142
|
-
const results = await this.runTests(tests);
|
|
143
|
-
|
|
144
|
-
if (results.some(r => r.passed)) {
|
|
145
|
-
throw new Error(
|
|
146
|
-
'RED phase violation: Tests must fail initially. ' +
|
|
147
|
-
'Found passing tests - implementation may already exist.'
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
redPhaseValid: true,
|
|
153
|
-
failingTests: results.length,
|
|
154
|
-
message: 'All tests failing as expected (RED phase complete)'
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### 2. Behavior Specification
|
|
161
|
-
|
|
162
|
-
Translate requirements into precise test specifications using Given-When-Then.
|
|
163
|
-
|
|
164
|
-
**Specification Pattern**:
|
|
165
|
-
```javascript
|
|
166
|
-
// Generate behavior-driven test specifications
|
|
167
|
-
function generateBehaviorSpec(requirement) {
|
|
168
|
-
return {
|
|
169
|
-
feature: requirement.functionality,
|
|
170
|
-
scenario: requirement.acceptance_criteria,
|
|
171
|
-
|
|
172
|
-
// Given-When-Then pattern
|
|
173
|
-
given: `Given a ${requirement.context}`,
|
|
174
|
-
when: `When ${requirement.action}`,
|
|
175
|
-
then: `Then ${requirement.expected_outcome}`,
|
|
176
|
-
|
|
177
|
-
// Test structure
|
|
178
|
-
test: `
|
|
179
|
-
describe('${requirement.functionality}', () => {
|
|
180
|
-
test('${requirement.scenario}', async () => {
|
|
181
|
-
// GIVEN: Setup preconditions
|
|
182
|
-
${generateSetupCode(requirement.context)}
|
|
183
|
-
|
|
184
|
-
// WHEN: Execute action
|
|
185
|
-
${generateActionCode(requirement.action)}
|
|
186
|
-
|
|
187
|
-
// THEN: Verify outcome
|
|
188
|
-
${generateAssertionCode(requirement.expected_outcome)}
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
`
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Example Output** (Jest):
|
|
197
|
-
```javascript
|
|
198
|
-
describe('User Authentication - OAuth2 Login', () => {
|
|
199
|
-
test('should authenticate user with valid OAuth2 token', async () => {
|
|
200
|
-
// GIVEN: A valid OAuth2 token
|
|
201
|
-
const validToken = generateValidOAuth2Token({
|
|
202
|
-
userId: 'user-123',
|
|
203
|
-
expiresIn: 3600,
|
|
204
|
-
scope: ['read', 'write']
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// WHEN: User attempts to authenticate
|
|
208
|
-
const result = await authService.authenticateWithOAuth2(validToken);
|
|
209
|
-
|
|
210
|
-
// THEN: Authentication succeeds with user session
|
|
57
|
+
// THEN: Returns session with user ID
|
|
211
58
|
expect(result).toMatchObject({
|
|
212
59
|
success: true,
|
|
213
60
|
sessionId: expect.any(String),
|
|
214
|
-
userId: 'user-123'
|
|
215
|
-
expiresAt: expect.any(Date)
|
|
61
|
+
userId: 'user-123'
|
|
216
62
|
});
|
|
217
|
-
expect(result.sessionId).toHaveLength(64); // UUID format
|
|
218
63
|
});
|
|
219
64
|
|
|
220
|
-
test('should reject expired
|
|
221
|
-
|
|
222
|
-
const expiredToken = generateExpiredOAuth2Token({
|
|
223
|
-
userId: 'user-123',
|
|
224
|
-
expiredSince: -3600 // Expired 1 hour ago
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// WHEN: User attempts to authenticate
|
|
65
|
+
test('should reject expired token', async () => {
|
|
66
|
+
const expiredToken = generateExpiredOAuth2Token();
|
|
228
67
|
const result = await authService.authenticateWithOAuth2(expiredToken);
|
|
229
|
-
|
|
230
|
-
// THEN: Authentication fails with expiration error
|
|
231
|
-
expect(result).toMatchObject({
|
|
232
|
-
success: false,
|
|
233
|
-
error: 'TOKEN_EXPIRED',
|
|
234
|
-
message: expect.stringContaining('expired')
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
test('should handle network failures gracefully', async () => {
|
|
239
|
-
// GIVEN: Network connection will fail during OAuth2 validation
|
|
240
|
-
mockNetworkFailure({
|
|
241
|
-
endpoint: '/oauth2/validate',
|
|
242
|
-
error: 'ECONNREFUSED'
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
// WHEN: User attempts to authenticate
|
|
246
|
-
const result = await authService.authenticateWithOAuth2(validToken);
|
|
247
|
-
|
|
248
|
-
// THEN: Returns network error without crashing
|
|
249
|
-
expect(result).toMatchObject({
|
|
250
|
-
success: false,
|
|
251
|
-
error: 'NETWORK_ERROR',
|
|
252
|
-
retryable: true
|
|
253
|
-
});
|
|
254
|
-
expect(result.message).toContain('network');
|
|
68
|
+
expect(result.error).toBe('TOKEN_EXPIRED');
|
|
255
69
|
});
|
|
256
70
|
});
|
|
71
|
+
// Result: ALL TESTS FAIL ✗ (authService not implemented)
|
|
257
72
|
```
|
|
73
|
+
</examples>
|
|
258
74
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
defineAssertions(expectedOutcome) {
|
|
267
|
-
return {
|
|
268
|
-
// Value assertions
|
|
269
|
-
exact: this.exactValueAssertion(expectedOutcome),
|
|
270
|
-
|
|
271
|
-
// Type assertions
|
|
272
|
-
type: this.typeAssertion(expectedOutcome),
|
|
273
|
-
|
|
274
|
-
// Structure assertions
|
|
275
|
-
structure: this.structureAssertion(expectedOutcome),
|
|
276
|
-
|
|
277
|
-
// Behavior assertions
|
|
278
|
-
behavior: this.behaviorAssertion(expectedOutcome),
|
|
279
|
-
|
|
280
|
-
// Boundary assertions
|
|
281
|
-
boundaries: this.boundaryAssertion(expectedOutcome)
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
exactValueAssertion(outcome) {
|
|
286
|
-
return `expect(result).toBe(${JSON.stringify(outcome)});`;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
typeAssertion(outcome) {
|
|
290
|
-
const type = typeof outcome;
|
|
291
|
-
return `expect(result).toEqual(expect.any(${capitalize(type)}));`;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
structureAssertion(outcome) {
|
|
295
|
-
if (typeof outcome === 'object') {
|
|
296
|
-
return `expect(result).toMatchObject(${JSON.stringify(outcome, null, 2)});`;
|
|
297
|
-
}
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
behaviorAssertion(outcome) {
|
|
302
|
-
return {
|
|
303
|
-
called: `expect(mockFn).toHaveBeenCalled();`,
|
|
304
|
-
calledWith: `expect(mockFn).toHaveBeenCalledWith(${outcome.args});`,
|
|
305
|
-
callCount: `expect(mockFn).toHaveBeenCalledTimes(${outcome.count});`
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
boundaryAssertion(outcome) {
|
|
310
|
-
return {
|
|
311
|
-
min: `expect(result).toBeGreaterThanOrEqual(${outcome.min});`,
|
|
312
|
-
max: `expect(result).toBeLessThanOrEqual(${outcome.max});`,
|
|
313
|
-
range: `expect(result).toBeInRange(${outcome.min}, ${outcome.max});`
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### 4. Boundary Analysis
|
|
320
|
-
|
|
321
|
-
Identify and test boundary conditions and edge cases.
|
|
322
|
-
|
|
323
|
-
**Boundary Test Generation**:
|
|
324
|
-
```javascript
|
|
325
|
-
class BoundaryAnalyzer {
|
|
326
|
-
generateBoundaryTests(parameter) {
|
|
327
|
-
const boundaries = this.identifyBoundaries(parameter);
|
|
328
|
-
|
|
329
|
-
return boundaries.map(boundary => ({
|
|
330
|
-
name: `should handle ${boundary.description}`,
|
|
331
|
-
input: boundary.value,
|
|
332
|
-
expected: boundary.expectedBehavior,
|
|
333
|
-
category: boundary.category
|
|
334
|
-
}));
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
identifyBoundaries(parameter) {
|
|
338
|
-
const boundaries = [];
|
|
339
|
-
|
|
340
|
-
if (parameter.type === 'number') {
|
|
341
|
-
boundaries.push(
|
|
342
|
-
{ value: parameter.min - 1, description: 'below minimum', category: 'invalid' },
|
|
343
|
-
{ value: parameter.min, description: 'minimum value', category: 'boundary' },
|
|
344
|
-
{ value: parameter.min + 1, description: 'above minimum', category: 'valid' },
|
|
345
|
-
{ value: parameter.max - 1, description: 'below maximum', category: 'valid' },
|
|
346
|
-
{ value: parameter.max, description: 'maximum value', category: 'boundary' },
|
|
347
|
-
{ value: parameter.max + 1, description: 'above maximum', category: 'invalid' }
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (parameter.type === 'string') {
|
|
352
|
-
boundaries.push(
|
|
353
|
-
{ value: '', description: 'empty string', category: 'boundary' },
|
|
354
|
-
{ value: 'a', description: 'single character', category: 'valid' },
|
|
355
|
-
{ value: 'a'.repeat(parameter.maxLength), description: 'maximum length', category: 'boundary' },
|
|
356
|
-
{ value: 'a'.repeat(parameter.maxLength + 1), description: 'exceeds maximum', category: 'invalid' }
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (parameter.type === 'array') {
|
|
361
|
-
boundaries.push(
|
|
362
|
-
{ value: [], description: 'empty array', category: 'boundary' },
|
|
363
|
-
{ value: [1], description: 'single element', category: 'valid' },
|
|
364
|
-
{ value: Array(parameter.maxItems).fill(1), description: 'maximum items', category: 'boundary' }
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return boundaries;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
**Example Boundary Tests**:
|
|
374
|
-
```javascript
|
|
375
|
-
describe('Pagination - Boundary Tests', () => {
|
|
376
|
-
test('should reject page number below minimum (0)', async () => {
|
|
377
|
-
const result = await paginate({ page: 0, size: 10 });
|
|
378
|
-
expect(result.error).toBe('INVALID_PAGE');
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
test('should accept minimum page number (1)', async () => {
|
|
382
|
-
const result = await paginate({ page: 1, size: 10 });
|
|
383
|
-
expect(result.success).toBe(true);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
test('should accept page size at minimum (1)', async () => {
|
|
387
|
-
const result = await paginate({ page: 1, size: 1 });
|
|
388
|
-
expect(result.success).toBe(true);
|
|
389
|
-
expect(result.items).toHaveLength(1);
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
test('should accept page size at maximum (100)', async () => {
|
|
393
|
-
const result = await paginate({ page: 1, size: 100 });
|
|
394
|
-
expect(result.success).toBe(true);
|
|
395
|
-
expect(result.items).toHaveLength(expect.toBeWithinRange(1, 100));
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
test('should reject page size above maximum (101)', async () => {
|
|
399
|
-
const result = await paginate({ page: 1, size: 101 });
|
|
400
|
-
expect(result.error).toBe('INVALID_PAGE_SIZE');
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
## TDD Coordination Protocol
|
|
406
|
-
|
|
407
|
-
### Cycle-Based Memory Namespace
|
|
408
|
-
|
|
409
|
-
All TDD subagents share context through a cycle-specific namespace:
|
|
410
|
-
|
|
411
|
-
```
|
|
412
|
-
aqe/tdd/cycle-{cycleId}/
|
|
413
|
-
├── context # Shared workflow context (created by parent)
|
|
414
|
-
├── red/
|
|
415
|
-
│ ├── tests # Test file content from RED phase
|
|
416
|
-
│ └── validation # RED phase validation results
|
|
417
|
-
├── green/
|
|
418
|
-
│ ├── impl # Implementation from GREEN phase
|
|
419
|
-
│ └── validation # GREEN phase validation results
|
|
420
|
-
└── refactor/
|
|
421
|
-
├── result # Final refactored code
|
|
422
|
-
└── validation # REFACTOR phase validation results
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Input Protocol (from Parent qe-test-generator)
|
|
426
|
-
|
|
427
|
-
**Required Input Structure:**
|
|
428
|
-
```typescript
|
|
429
|
-
interface TDDCycleContext {
|
|
430
|
-
cycleId: string; // Unique identifier for this TDD cycle
|
|
431
|
-
module: {
|
|
432
|
-
path: string; // e.g., 'src/services/user-authentication.ts'
|
|
433
|
-
name: string; // e.g., 'UserAuthenticationService'
|
|
434
|
-
};
|
|
435
|
-
requirements: {
|
|
436
|
-
functionality: string; // What should be implemented
|
|
437
|
-
acceptanceCriteria: string[]; // Success conditions
|
|
438
|
-
edgeCases: string[]; // Edge cases to cover
|
|
439
|
-
};
|
|
440
|
-
constraints: {
|
|
441
|
-
framework: 'jest' | 'mocha' | 'vitest' | 'playwright';
|
|
442
|
-
coverageTarget: number; // e.g., 0.95
|
|
443
|
-
testTypes: ('unit' | 'integration' | 'e2e')[];
|
|
444
|
-
};
|
|
445
|
-
testFilePath: string; // Where test file will be created
|
|
446
|
-
implFilePath: string; // Where implementation will be created
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Parent stores this before invoking test-writer
|
|
450
|
-
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/context`, context, {
|
|
451
|
-
partition: 'coordination',
|
|
452
|
-
ttl: 86400
|
|
453
|
-
});
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Output Protocol (for qe-test-implementer)
|
|
457
|
-
|
|
458
|
-
**Required Output Structure:**
|
|
459
|
-
```typescript
|
|
460
|
-
interface REDPhaseOutput {
|
|
461
|
-
cycleId: string; // Must match input cycleId
|
|
462
|
-
phase: 'RED';
|
|
463
|
-
timestamp: number;
|
|
464
|
-
testFile: {
|
|
465
|
-
path: string; // Absolute path to test file
|
|
466
|
-
content: string; // Full test file content
|
|
467
|
-
hash: string; // SHA256 hash for validation
|
|
468
|
-
};
|
|
469
|
-
tests: Array<{
|
|
470
|
-
name: string; // Test description
|
|
471
|
-
type: 'unit' | 'integration' | 'e2e';
|
|
472
|
-
assertion: string; // What it asserts
|
|
473
|
-
givenWhenThen: {
|
|
474
|
-
given: string;
|
|
475
|
-
when: string;
|
|
476
|
-
then: string;
|
|
477
|
-
};
|
|
478
|
-
}>;
|
|
479
|
-
validation: {
|
|
480
|
-
allTestsFailing: boolean; // MUST be true
|
|
481
|
-
failureCount: number;
|
|
482
|
-
errorMessages: string[]; // Actual error messages from run
|
|
483
|
-
};
|
|
484
|
-
nextPhase: 'GREEN';
|
|
485
|
-
readyForHandoff: boolean; // MUST be true to proceed
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// Store RED phase output
|
|
489
|
-
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/red/tests`, output, {
|
|
490
|
-
partition: 'coordination',
|
|
491
|
-
ttl: 86400
|
|
492
|
-
});
|
|
493
|
-
```
|
|
494
|
-
|
|
495
|
-
### Handoff Validation
|
|
496
|
-
|
|
497
|
-
Before emitting completion, validate handoff readiness:
|
|
498
|
-
|
|
499
|
-
```typescript
|
|
500
|
-
async function validateREDHandoff(output: REDPhaseOutput): Promise<boolean> {
|
|
501
|
-
const errors: string[] = [];
|
|
502
|
-
|
|
503
|
-
// 1. Verify test file exists and matches content
|
|
504
|
-
if (!existsSync(output.testFile.path)) {
|
|
505
|
-
errors.push(`Test file not found: ${output.testFile.path}`);
|
|
506
|
-
} else {
|
|
507
|
-
const actualContent = readFileSync(output.testFile.path, 'utf-8');
|
|
508
|
-
const actualHash = createHash('sha256').update(actualContent).digest('hex');
|
|
509
|
-
if (actualHash !== output.testFile.hash) {
|
|
510
|
-
errors.push(`Test file content mismatch: hash differs`);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// 2. Verify all tests are failing
|
|
515
|
-
if (!output.validation.allTestsFailing) {
|
|
516
|
-
errors.push('RED phase violation: some tests are passing');
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// 3. Verify tests cover requirements
|
|
520
|
-
if (output.tests.length === 0) {
|
|
521
|
-
errors.push('No tests generated');
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// 4. Set handoff readiness
|
|
525
|
-
output.readyForHandoff = errors.length === 0;
|
|
526
|
-
|
|
527
|
-
if (errors.length > 0) {
|
|
528
|
-
console.error('RED phase handoff validation failed:', errors);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return output.readyForHandoff;
|
|
532
|
-
}
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
## Integration with Parent Agents
|
|
536
|
-
|
|
537
|
-
### Memory Coordination
|
|
538
|
-
|
|
539
|
-
**Input from Parent** (Read):
|
|
540
|
-
```typescript
|
|
541
|
-
// Retrieve cycle context created by parent
|
|
542
|
-
const context = await this.memoryStore.retrieve(`aqe/tdd/cycle-${cycleId}/context`, {
|
|
543
|
-
partition: 'coordination'
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// Validate required fields
|
|
547
|
-
if (!context.cycleId || !context.module.path || !context.testFilePath) {
|
|
548
|
-
throw new Error('Invalid TDD cycle context: missing required fields');
|
|
549
|
-
}
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
**Output to GREEN Phase** (Write):
|
|
553
|
-
```typescript
|
|
554
|
-
// Store complete RED phase output with file references
|
|
555
|
-
const redOutput: REDPhaseOutput = {
|
|
556
|
-
cycleId: context.cycleId,
|
|
557
|
-
phase: 'RED',
|
|
558
|
-
timestamp: Date.now(),
|
|
559
|
-
testFile: {
|
|
560
|
-
path: context.testFilePath,
|
|
561
|
-
content: generatedTestContent,
|
|
562
|
-
hash: createHash('sha256').update(generatedTestContent).digest('hex')
|
|
563
|
-
},
|
|
564
|
-
tests: testCases.map(tc => ({
|
|
565
|
-
name: tc.name,
|
|
566
|
-
type: tc.type,
|
|
567
|
-
assertion: tc.assertion,
|
|
568
|
-
givenWhenThen: tc.givenWhenThen
|
|
569
|
-
})),
|
|
570
|
-
validation: {
|
|
571
|
-
allTestsFailing: true,
|
|
572
|
-
failureCount: testCases.length,
|
|
573
|
-
errorMessages: testRunErrors
|
|
574
|
-
},
|
|
575
|
-
nextPhase: 'GREEN',
|
|
576
|
-
readyForHandoff: true
|
|
577
|
-
};
|
|
578
|
-
|
|
579
|
-
// Validate before storing
|
|
580
|
-
await validateREDHandoff(redOutput);
|
|
581
|
-
|
|
582
|
-
// Store for GREEN phase
|
|
583
|
-
await this.memoryStore.store(`aqe/tdd/cycle-${cycleId}/red/tests`, redOutput, {
|
|
584
|
-
partition: 'coordination',
|
|
585
|
-
ttl: 86400
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
// Emit completion event with cycle reference
|
|
589
|
-
this.eventBus.emit('test-writer:completed', {
|
|
590
|
-
agentId: this.agentId,
|
|
591
|
-
cycleId: context.cycleId,
|
|
592
|
-
testsGenerated: testCases.length,
|
|
593
|
-
testFilePath: context.testFilePath,
|
|
594
|
-
nextPhase: 'GREEN',
|
|
595
|
-
readyForHandoff: redOutput.readyForHandoff
|
|
596
|
-
});
|
|
597
|
-
```
|
|
598
|
-
|
|
599
|
-
### Lifecycle Hooks
|
|
600
|
-
|
|
601
|
-
```typescript
|
|
602
|
-
protected async onPreTask(data: { assignment: TaskAssignment }): Promise<void> {
|
|
603
|
-
// Load requirements from parent
|
|
604
|
-
const task = await this.memoryStore.retrieve('aqe/test-writer/task', {
|
|
605
|
-
partition: 'coordination'
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
this.logger.info('Test Writer starting RED phase', {
|
|
609
|
-
module: task.module,
|
|
610
|
-
framework: task.framework
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
protected async onPostTask(data: { assignment: TaskAssignment; result: any }): Promise<void> {
|
|
615
|
-
// Store results for parent agent
|
|
616
|
-
await this.memoryStore.store('aqe/test-writer/results', data.result, {
|
|
617
|
-
partition: 'coordination',
|
|
618
|
-
ttl: 86400
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
// Validate RED phase completion
|
|
622
|
-
if (!data.result.allTestsFailing) {
|
|
623
|
-
this.logger.error('RED phase validation failed - some tests passing');
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
this.logger.info('Test Writer completed', {
|
|
627
|
-
testsGenerated: data.result.testsGenerated,
|
|
628
|
-
redPhaseValid: data.result.redPhaseValidated
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
## Success Criteria
|
|
634
|
-
|
|
635
|
-
### RED Phase Validation
|
|
636
|
-
|
|
637
|
-
**Tests MUST**:
|
|
638
|
-
- ✅ All fail initially (no passing tests)
|
|
639
|
-
- ✅ Have clear, descriptive names
|
|
640
|
-
- ✅ Follow Given-When-Then structure
|
|
641
|
-
- ✅ Include boundary tests
|
|
642
|
-
- ✅ Cover all acceptance criteria
|
|
643
|
-
|
|
644
|
-
**Tests MUST NOT**:
|
|
645
|
-
- ❌ Pass before implementation exists
|
|
646
|
-
- ❌ Have vague assertions (e.g., `expect(result).toBeTruthy()`)
|
|
647
|
-
- ❌ Test implementation details
|
|
648
|
-
- ❌ Have external dependencies without mocks
|
|
649
|
-
|
|
650
|
-
## Example Complete Output
|
|
651
|
-
|
|
652
|
-
```javascript
|
|
653
|
-
// Generated by qe-test-writer subagent
|
|
654
|
-
// TDD RED Phase - All tests MUST fail initially
|
|
655
|
-
// Module: src/services/payment.ts
|
|
656
|
-
|
|
657
|
-
describe('Payment Service - Process Payment', () => {
|
|
658
|
-
beforeEach(() => {
|
|
659
|
-
// Setup test fixtures
|
|
660
|
-
jest.clearAllMocks();
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// Acceptance Criteria 1: Process valid payment
|
|
664
|
-
test('should process payment with valid card', async () => {
|
|
665
|
-
// GIVEN: Valid payment details
|
|
666
|
-
const payment = {
|
|
667
|
-
amount: 99.99,
|
|
668
|
-
currency: 'USD',
|
|
669
|
-
card: {
|
|
670
|
-
number: '4111111111111111',
|
|
671
|
-
expiry: '12/25',
|
|
672
|
-
cvv: '123'
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
// WHEN: Processing payment
|
|
677
|
-
const result = await paymentService.processPayment(payment);
|
|
678
|
-
|
|
679
|
-
// THEN: Payment succeeds with transaction ID
|
|
680
|
-
expect(result).toMatchObject({
|
|
681
|
-
success: true,
|
|
682
|
-
transactionId: expect.any(String),
|
|
683
|
-
amount: 99.99,
|
|
684
|
-
status: 'COMPLETED'
|
|
685
|
-
});
|
|
686
|
-
});
|
|
687
|
-
|
|
688
|
-
// Boundary Test: Minimum amount
|
|
689
|
-
test('should accept minimum payment amount (0.01)', async () => {
|
|
690
|
-
const payment = createPayment({ amount: 0.01 });
|
|
691
|
-
const result = await paymentService.processPayment(payment);
|
|
692
|
-
expect(result.success).toBe(true);
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
// Boundary Test: Zero amount (invalid)
|
|
696
|
-
test('should reject zero amount payment', async () => {
|
|
697
|
-
const payment = createPayment({ amount: 0 });
|
|
698
|
-
const result = await paymentService.processPayment(payment);
|
|
699
|
-
expect(result.error).toBe('INVALID_AMOUNT');
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
// Edge Case: Network timeout
|
|
703
|
-
test('should handle payment gateway timeout', async () => {
|
|
704
|
-
mockPaymentGatewayTimeout();
|
|
705
|
-
const payment = createPayment({ amount: 50.00 });
|
|
706
|
-
|
|
707
|
-
const result = await paymentService.processPayment(payment);
|
|
708
|
-
|
|
709
|
-
expect(result).toMatchObject({
|
|
710
|
-
success: false,
|
|
711
|
-
error: 'GATEWAY_TIMEOUT',
|
|
712
|
-
retryable: true
|
|
713
|
-
});
|
|
714
|
-
});
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
// Expected Result: ALL TESTS FAIL (implementation doesn't exist yet)
|
|
718
|
-
// Next Step: qe-test-implementer will make these tests pass (GREEN phase)
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
## Commands
|
|
722
|
-
|
|
723
|
-
```bash
|
|
724
|
-
# Parent agent delegates to subagent
|
|
725
|
-
aqe subagent delegate qe-test-writer \
|
|
726
|
-
--task write-failing-tests \
|
|
727
|
-
--module src/services/authentication.ts \
|
|
728
|
-
--framework jest
|
|
729
|
-
|
|
730
|
-
# Validate RED phase
|
|
731
|
-
aqe subagent validate qe-test-writer \
|
|
732
|
-
--phase RED \
|
|
733
|
-
--expect-failures all
|
|
734
|
-
|
|
735
|
-
# Check subagent status
|
|
736
|
-
aqe subagent status qe-test-writer
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
---
|
|
740
|
-
|
|
741
|
-
**Subagent Status**: Active
|
|
742
|
-
**Parent Agents**: qe-test-generator, qe-quality-gate
|
|
743
|
-
**TDD Phase**: RED (Write Failing Tests)
|
|
744
|
-
**Version**: 1.0.0
|
|
75
|
+
<coordination>
|
|
76
|
+
Reports to: qe-test-generator, qe-quality-gate
|
|
77
|
+
Triggers: When TDD cycle starts with requirements
|
|
78
|
+
Handoff: Store RED output in memory, emit event, qe-test-implementer (GREEN phase) picks up
|
|
79
|
+
Validation: readyForHandoff=true ONLY if allTestsFailing=true
|
|
80
|
+
</coordination>
|
|
81
|
+
</qe_subagent_definition>
|