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,42 +1,92 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-testing-patterns
|
|
3
|
-
description:
|
|
3
|
+
description: "Comprehensive API testing patterns including contract testing, REST/GraphQL testing, and integration testing. Use when testing APIs or designing API test strategies."
|
|
4
|
+
category: testing-methodologies
|
|
5
|
+
priority: high
|
|
6
|
+
tokenEstimate: 1200
|
|
7
|
+
agents: [qe-api-contract-validator, qe-test-generator, qe-performance-tester, qe-security-scanner]
|
|
8
|
+
implementation_status: optimized
|
|
9
|
+
optimization_version: 1.0
|
|
10
|
+
last_optimized: 2025-12-02
|
|
11
|
+
dependencies: []
|
|
12
|
+
quick_reference_card: true
|
|
13
|
+
tags: [api, rest, graphql, contract-testing, pact, integration, microservices]
|
|
4
14
|
---
|
|
5
15
|
|
|
6
16
|
# API Testing Patterns
|
|
7
17
|
|
|
8
|
-
|
|
18
|
+
<default_to_action>
|
|
19
|
+
When testing APIs or designing API test strategy:
|
|
20
|
+
1. IDENTIFY testing level: contract, integration, or component
|
|
21
|
+
2. TEST the contract, not implementation (consumer perspective)
|
|
22
|
+
3. VALIDATE auth, input, errors, idempotency, concurrency
|
|
23
|
+
4. AUTOMATE in CI/CD with schema validation
|
|
24
|
+
5. MONITOR production APIs for contract drift
|
|
25
|
+
|
|
26
|
+
**Quick Pattern Selection:**
|
|
27
|
+
- Microservices → Consumer-driven contracts (Pact)
|
|
28
|
+
- REST APIs → CRUD + pagination + filtering tests
|
|
29
|
+
- GraphQL → Query validation + complexity limits
|
|
30
|
+
- External deps → Mock with component testing
|
|
31
|
+
- Performance → Load test critical endpoints
|
|
32
|
+
|
|
33
|
+
**Critical Success Factors:**
|
|
34
|
+
- APIs are contracts - test from consumer perspective
|
|
35
|
+
- Always test error scenarios, not just happy paths
|
|
36
|
+
- Version your API tests to prevent breaking changes
|
|
37
|
+
</default_to_action>
|
|
38
|
+
|
|
39
|
+
## Quick Reference Card
|
|
40
|
+
|
|
41
|
+
### When to Use
|
|
42
|
+
- Testing REST or GraphQL APIs
|
|
43
|
+
- Validating microservice contracts
|
|
44
|
+
- Designing API test strategies
|
|
45
|
+
- Preventing breaking API changes
|
|
46
|
+
|
|
47
|
+
### Testing Levels
|
|
48
|
+
| Level | Purpose | Dependencies | Speed |
|
|
49
|
+
|-------|---------|--------------|-------|
|
|
50
|
+
| Contract | Provider-consumer agreement | None | Fast |
|
|
51
|
+
| Component | API in isolation | Mocked | Fast |
|
|
52
|
+
| Integration | Real dependencies | Database, services | Slower |
|
|
53
|
+
|
|
54
|
+
### Critical Test Scenarios
|
|
55
|
+
| Scenario | Must Test | Example |
|
|
56
|
+
|----------|----------|---------|
|
|
57
|
+
| Auth | 401/403 handling | Expired token, wrong user |
|
|
58
|
+
| Input | 400 validation | Missing fields, wrong types |
|
|
59
|
+
| Errors | 500 graceful handling | DB down, timeout |
|
|
60
|
+
| Idempotency | Duplicate prevention | Same idempotency key |
|
|
61
|
+
| Concurrency | Race conditions | Parallel checkout |
|
|
62
|
+
|
|
63
|
+
### Tools
|
|
64
|
+
- **Contract**: Pact, Spring Cloud Contract
|
|
65
|
+
- **REST**: Supertest, REST-assured, Playwright
|
|
66
|
+
- **Load**: k6, Artillery, JMeter
|
|
67
|
+
|
|
68
|
+
### Agent Coordination
|
|
69
|
+
- `qe-api-contract-validator`: Validate contracts, detect breaking changes
|
|
70
|
+
- `qe-test-generator`: Generate tests from OpenAPI spec
|
|
71
|
+
- `qe-performance-tester`: Load test endpoints
|
|
72
|
+
- `qe-security-scanner`: API security testing
|
|
9
73
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Testing Levels
|
|
13
|
-
|
|
14
|
-
### 1. Contract Testing
|
|
74
|
+
---
|
|
15
75
|
|
|
16
|
-
|
|
76
|
+
## Contract Testing
|
|
17
77
|
|
|
18
78
|
**Pattern: Consumer-Driven Contracts**
|
|
19
79
|
```javascript
|
|
20
80
|
// Consumer defines expectations
|
|
21
|
-
const
|
|
22
|
-
request: {
|
|
23
|
-
|
|
24
|
-
path: '/orders',
|
|
25
|
-
body: { productId: 'abc', quantity: 2 }
|
|
26
|
-
},
|
|
27
|
-
response: {
|
|
28
|
-
status: 201,
|
|
29
|
-
body: { orderId: 'string', total: 'number' }
|
|
30
|
-
}
|
|
81
|
+
const contract = {
|
|
82
|
+
request: { method: 'POST', path: '/orders', body: { productId: 'abc', quantity: 2 } },
|
|
83
|
+
response: { status: 201, body: { orderId: 'string', total: 'number' } }
|
|
31
84
|
};
|
|
32
85
|
|
|
33
|
-
// Provider must fulfill
|
|
34
|
-
test('order API meets
|
|
35
|
-
const response = await api.post('/orders', {
|
|
36
|
-
|
|
37
|
-
quantity: 2
|
|
38
|
-
});
|
|
39
|
-
|
|
86
|
+
// Provider must fulfill
|
|
87
|
+
test('order API meets contract', async () => {
|
|
88
|
+
const response = await api.post('/orders', { productId: 'abc', quantity: 2 });
|
|
89
|
+
|
|
40
90
|
expect(response.status).toBe(201);
|
|
41
91
|
expect(response.body).toMatchSchema({
|
|
42
92
|
orderId: expect.any(String),
|
|
@@ -45,534 +95,180 @@ test('order API meets consumer contract', async () => {
|
|
|
45
95
|
});
|
|
46
96
|
```
|
|
47
97
|
|
|
48
|
-
**
|
|
98
|
+
**When:** Microservices, distributed systems, third-party integrations
|
|
49
99
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
### 2. Integration Testing
|
|
100
|
+
---
|
|
53
101
|
|
|
54
|
-
|
|
102
|
+
## Critical Test Patterns
|
|
55
103
|
|
|
56
|
-
|
|
104
|
+
### Authentication & Authorization
|
|
57
105
|
```javascript
|
|
58
|
-
describe('
|
|
59
|
-
|
|
60
|
-
await
|
|
61
|
-
await db.seed();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
afterEach(async () => {
|
|
65
|
-
await db.rollback();
|
|
106
|
+
describe('Auth', () => {
|
|
107
|
+
it('rejects without token', async () => {
|
|
108
|
+
expect((await api.get('/orders')).status).toBe(401);
|
|
66
109
|
});
|
|
67
|
-
|
|
68
|
-
it('creates order and updates inventory', async () => {
|
|
69
|
-
const response = await api.post('/orders', {
|
|
70
|
-
productId: 'product-123',
|
|
71
|
-
quantity: 2
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
expect(response.status).toBe(201);
|
|
75
|
-
|
|
76
|
-
// Verify side effects
|
|
77
|
-
const inventory = await db.inventory.findById('product-123');
|
|
78
|
-
expect(inventory.quantity).toBe(8); // Was 10, now 8
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**When to use:** Testing business logic that spans multiple components
|
|
84
110
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
**Pattern: Mock External Dependencies**
|
|
90
|
-
```javascript
|
|
91
|
-
describe('Order API component', () => {
|
|
92
|
-
it('handles payment service timeout', async () => {
|
|
93
|
-
const paymentService = mockPaymentService({
|
|
94
|
-
charge: () => { throw new TimeoutError(); }
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const api = createAPI({ paymentService });
|
|
98
|
-
const response = await api.post('/orders', orderData);
|
|
99
|
-
|
|
100
|
-
expect(response.status).toBe(503);
|
|
101
|
-
expect(response.body.error).toBe('Payment service unavailable');
|
|
111
|
+
it('rejects expired token', async () => {
|
|
112
|
+
const expired = generateExpiredToken();
|
|
113
|
+
expect((await api.get('/orders', { headers: { Authorization: `Bearer ${expired}` } })).status).toBe(401);
|
|
102
114
|
});
|
|
103
|
-
});
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**When to use:** Testing error handling, edge cases, without hitting real services
|
|
107
|
-
|
|
108
|
-
## Critical Test Scenarios
|
|
109
|
-
|
|
110
|
-
### Authentication & Authorization
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
describe('Authentication', () => {
|
|
114
|
-
it('rejects requests without token', async () => {
|
|
115
|
-
const response = await api.get('/orders');
|
|
116
|
-
expect(response.status).toBe(401);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('rejects requests with expired token', async () => {
|
|
120
|
-
const expiredToken = generateExpiredToken();
|
|
121
|
-
const response = await api.get('/orders', {
|
|
122
|
-
headers: { Authorization: `Bearer ${expiredToken}` }
|
|
123
|
-
});
|
|
124
|
-
expect(response.status).toBe(401);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('allows access only to authorized resources', async () => {
|
|
116
|
+
it('blocks cross-user access', async () => {
|
|
128
117
|
const userAToken = generateToken({ userId: 'A' });
|
|
129
|
-
|
|
130
|
-
headers: { Authorization: `Bearer ${userAToken}` }
|
|
131
|
-
});
|
|
132
|
-
expect(response.status).toBe(403);
|
|
118
|
+
expect((await api.get('/orders/user-B-order', { headers: { Authorization: `Bearer ${userAToken}` } })).status).toBe(403);
|
|
133
119
|
});
|
|
134
120
|
});
|
|
135
121
|
```
|
|
136
122
|
|
|
137
123
|
### Input Validation
|
|
138
|
-
|
|
139
124
|
```javascript
|
|
140
|
-
describe('
|
|
125
|
+
describe('Validation', () => {
|
|
141
126
|
it('validates required fields', async () => {
|
|
142
|
-
const response = await api.post('/orders', {
|
|
143
|
-
// Missing productId
|
|
144
|
-
quantity: 2
|
|
145
|
-
});
|
|
127
|
+
const response = await api.post('/orders', { quantity: 2 }); // Missing productId
|
|
146
128
|
expect(response.status).toBe(400);
|
|
147
129
|
expect(response.body.errors).toContain('productId is required');
|
|
148
130
|
});
|
|
149
|
-
|
|
150
|
-
it('validates data types', async () => {
|
|
151
|
-
const response = await api.post('/orders', {
|
|
152
|
-
productId: 'abc',
|
|
153
|
-
quantity: 'two' // Should be number
|
|
154
|
-
});
|
|
155
|
-
expect(response.status).toBe(400);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('validates value ranges', async () => {
|
|
159
|
-
const response = await api.post('/orders', {
|
|
160
|
-
productId: 'abc',
|
|
161
|
-
quantity: -5 // Negative quantity
|
|
162
|
-
});
|
|
163
|
-
expect(response.status).toBe(400);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
```
|
|
167
131
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
```javascript
|
|
171
|
-
describe('Error handling', () => {
|
|
172
|
-
it('handles database connection failure', async () => {
|
|
173
|
-
db.disconnect();
|
|
174
|
-
const response = await api.get('/orders');
|
|
175
|
-
expect(response.status).toBe(503);
|
|
176
|
-
expect(response.body.error).toMatch(/service unavailable/i);
|
|
132
|
+
it('validates types', async () => {
|
|
133
|
+
expect((await api.post('/orders', { productId: 'abc', quantity: 'two' })).status).toBe(400);
|
|
177
134
|
});
|
|
178
|
-
|
|
179
|
-
it('
|
|
180
|
-
|
|
181
|
-
method: 'POST',
|
|
182
|
-
body: 'not-json'
|
|
183
|
-
});
|
|
184
|
-
expect(response.status).toBe(400);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('handles unexpected errors gracefully', async () => {
|
|
188
|
-
// Simulate internal error
|
|
189
|
-
orderService.create = () => { throw new Error('Unexpected'); };
|
|
190
|
-
|
|
191
|
-
const response = await api.post('/orders', validOrder);
|
|
192
|
-
expect(response.status).toBe(500);
|
|
193
|
-
expect(response.body.error).not.toContain('Unexpected'); // Don't leak internals
|
|
135
|
+
|
|
136
|
+
it('validates ranges', async () => {
|
|
137
|
+
expect((await api.post('/orders', { productId: 'abc', quantity: -5 })).status).toBe(400);
|
|
194
138
|
});
|
|
195
139
|
});
|
|
196
140
|
```
|
|
197
141
|
|
|
198
142
|
### Idempotency
|
|
199
|
-
|
|
200
143
|
```javascript
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// Verify state hasn't changed incorrectly
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('POST with idempotency key prevents duplicates', async () => {
|
|
213
|
-
const idempotencyKey = 'unique-key-123';
|
|
214
|
-
const orderData = { productId: 'abc', quantity: 2 };
|
|
215
|
-
|
|
216
|
-
const response1 = await api.post('/orders', orderData, {
|
|
217
|
-
headers: { 'Idempotency-Key': idempotencyKey }
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const response2 = await api.post('/orders', orderData, {
|
|
221
|
-
headers: { 'Idempotency-Key': idempotencyKey }
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
expect(response1.body.orderId).toBe(response2.body.orderId);
|
|
225
|
-
// Verify only one order was created
|
|
226
|
-
});
|
|
144
|
+
it('prevents duplicates with idempotency key', async () => {
|
|
145
|
+
const key = 'unique-123';
|
|
146
|
+
const data = { productId: 'abc', quantity: 2 };
|
|
147
|
+
|
|
148
|
+
const r1 = await api.post('/orders', data, { headers: { 'Idempotency-Key': key } });
|
|
149
|
+
const r2 = await api.post('/orders', data, { headers: { 'Idempotency-Key': key } });
|
|
150
|
+
|
|
151
|
+
expect(r1.body.orderId).toBe(r2.body.orderId); // Same order
|
|
227
152
|
});
|
|
228
153
|
```
|
|
229
154
|
|
|
230
155
|
### Concurrency
|
|
231
|
-
|
|
232
156
|
```javascript
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// Verify inventory wasn't oversold
|
|
243
|
-
const inventory = await db.inventory.findById('abc');
|
|
244
|
-
expect(inventory.quantity).toBe(initialQuantity - successful.length);
|
|
245
|
-
});
|
|
157
|
+
it('handles race condition on inventory', async () => {
|
|
158
|
+
const promises = Array(10).fill().map(() =>
|
|
159
|
+
api.post('/orders', { productId: 'abc', quantity: 1 })
|
|
160
|
+
);
|
|
161
|
+
const responses = await Promise.all(promises);
|
|
162
|
+
const successful = responses.filter(r => r.status === 201);
|
|
163
|
+
|
|
164
|
+
const inventory = await db.inventory.findById('abc');
|
|
165
|
+
expect(inventory.quantity).toBe(initialQuantity - successful.length);
|
|
246
166
|
});
|
|
247
167
|
```
|
|
248
168
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
### CRUD Operations
|
|
169
|
+
---
|
|
252
170
|
|
|
171
|
+
## REST CRUD Pattern
|
|
253
172
|
```javascript
|
|
254
173
|
describe('Product CRUD', () => {
|
|
255
174
|
let productId;
|
|
256
|
-
|
|
257
|
-
it('CREATE: creates new product', async () => {
|
|
258
|
-
const response = await api.post('/products', {
|
|
259
|
-
name: 'Widget',
|
|
260
|
-
price: 10.00
|
|
261
|
-
});
|
|
262
|
-
expect(response.status).toBe(201);
|
|
263
|
-
expect(response.headers.location).toMatch(/\/products\/\w+/);
|
|
264
|
-
productId = response.body.id;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it('READ: retrieves product', async () => {
|
|
268
|
-
const response = await api.get(`/products/${productId}`);
|
|
269
|
-
expect(response.status).toBe(200);
|
|
270
|
-
expect(response.body.name).toBe('Widget');
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('UPDATE: modifies product', async () => {
|
|
274
|
-
const response = await api.put(`/products/${productId}`, {
|
|
275
|
-
name: 'Widget',
|
|
276
|
-
price: 12.00
|
|
277
|
-
});
|
|
278
|
-
expect(response.status).toBe(200);
|
|
279
|
-
expect(response.body.price).toBe(12.00);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('DELETE: removes product', async () => {
|
|
283
|
-
const response = await api.delete(`/products/${productId}`);
|
|
284
|
-
expect(response.status).toBe(204);
|
|
285
|
-
|
|
286
|
-
const getResponse = await api.get(`/products/${productId}`);
|
|
287
|
-
expect(getResponse.status).toBe(404);
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Pagination
|
|
293
175
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
expect(response.body.items).toHaveLength(20); // Default page size
|
|
299
|
-
expect(response.body.page).toBe(1);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('supports custom page size', async () => {
|
|
303
|
-
const response = await api.get('/products?pageSize=50');
|
|
304
|
-
expect(response.body.items).toHaveLength(50);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it('includes pagination metadata', async () => {
|
|
308
|
-
const response = await api.get('/products');
|
|
309
|
-
expect(response.body).toHaveProperty('totalItems');
|
|
310
|
-
expect(response.body).toHaveProperty('totalPages');
|
|
311
|
-
expect(response.body).toHaveProperty('nextPage');
|
|
176
|
+
it('CREATE', async () => {
|
|
177
|
+
const r = await api.post('/products', { name: 'Widget', price: 10 });
|
|
178
|
+
expect(r.status).toBe(201);
|
|
179
|
+
productId = r.body.id;
|
|
312
180
|
});
|
|
313
|
-
});
|
|
314
|
-
```
|
|
315
181
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
describe('Filtering and sorting', () => {
|
|
320
|
-
it('filters by category', async () => {
|
|
321
|
-
const response = await api.get('/products?category=electronics');
|
|
322
|
-
expect(response.body.items.every(p => p.category === 'electronics')).toBe(true);
|
|
182
|
+
it('READ', async () => {
|
|
183
|
+
const r = await api.get(`/products/${productId}`);
|
|
184
|
+
expect(r.body.name).toBe('Widget');
|
|
323
185
|
});
|
|
324
|
-
|
|
325
|
-
it('sorts by price ascending', async () => {
|
|
326
|
-
const response = await api.get('/products?sort=price:asc');
|
|
327
|
-
const prices = response.body.items.map(p => p.price);
|
|
328
|
-
expect(prices).toEqual([...prices].sort((a, b) => a - b));
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it('combines multiple filters', async () => {
|
|
332
|
-
const response = await api.get('/products?category=electronics&minPrice=100');
|
|
333
|
-
expect(response.body.items.every(p =>
|
|
334
|
-
p.category === 'electronics' && p.price >= 100
|
|
335
|
-
)).toBe(true);
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
```
|
|
339
186
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
describe('GraphQL API', () => {
|
|
344
|
-
it('queries nested data', async () => {
|
|
345
|
-
const query = `
|
|
346
|
-
query {
|
|
347
|
-
order(id: "123") {
|
|
348
|
-
id
|
|
349
|
-
items {
|
|
350
|
-
product {
|
|
351
|
-
name
|
|
352
|
-
price
|
|
353
|
-
}
|
|
354
|
-
quantity
|
|
355
|
-
}
|
|
356
|
-
total
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
`;
|
|
360
|
-
|
|
361
|
-
const response = await graphql.query(query);
|
|
362
|
-
expect(response.data.order.items).toBeDefined();
|
|
187
|
+
it('UPDATE', async () => {
|
|
188
|
+
const r = await api.put(`/products/${productId}`, { price: 12 });
|
|
189
|
+
expect(r.body.price).toBe(12);
|
|
363
190
|
});
|
|
364
|
-
|
|
365
|
-
it('handles query complexity limits', async () => {
|
|
366
|
-
const complexQuery = `
|
|
367
|
-
query {
|
|
368
|
-
orders {
|
|
369
|
-
items {
|
|
370
|
-
product {
|
|
371
|
-
reviews {
|
|
372
|
-
author {
|
|
373
|
-
orders { ... }
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
`;
|
|
381
|
-
|
|
382
|
-
const response = await graphql.query(complexQuery);
|
|
383
|
-
expect(response.errors[0].message).toMatch(/query too complex/i);
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
## Performance Testing
|
|
389
191
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const start = Date.now();
|
|
394
|
-
await api.get('/products');
|
|
395
|
-
const duration = Date.now() - start;
|
|
396
|
-
|
|
397
|
-
expect(duration).toBeLessThan(200); // 200ms SLA
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it('handles load of 100 concurrent requests', async () => {
|
|
401
|
-
const requests = Array(100).fill().map(() => api.get('/products'));
|
|
402
|
-
const responses = await Promise.all(requests);
|
|
403
|
-
|
|
404
|
-
const successful = responses.filter(r => r.status === 200);
|
|
405
|
-
expect(successful.length).toBeGreaterThan(95); // 95% success rate
|
|
192
|
+
it('DELETE', async () => {
|
|
193
|
+
expect((await api.delete(`/products/${productId}`)).status).toBe(204);
|
|
194
|
+
expect((await api.get(`/products/${productId}`)).status).toBe(404);
|
|
406
195
|
});
|
|
407
196
|
});
|
|
408
197
|
```
|
|
409
198
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
### REST APIs
|
|
413
|
-
- **Supertest** (Node.js) - HTTP assertions
|
|
414
|
-
- **REST-assured** (Java) - Fluent API testing
|
|
415
|
-
- **Postman/Newman** - Collection-based testing
|
|
416
|
-
- **Playwright API** - E2E with API calls
|
|
417
|
-
|
|
418
|
-
### Contract Testing
|
|
419
|
-
- **Pact** - Consumer-driven contracts
|
|
420
|
-
- **Spring Cloud Contract** - JVM contract testing
|
|
421
|
-
|
|
422
|
-
### Load Testing
|
|
423
|
-
- **k6** - Modern load testing
|
|
424
|
-
- **Apache JMeter** - Enterprise load testing
|
|
425
|
-
- **Artillery** - Modern performance testing
|
|
426
|
-
|
|
427
|
-
## Common Pitfalls
|
|
428
|
-
|
|
429
|
-
### ❌ Testing Implementation, Not Contract
|
|
430
|
-
Don't test internal database queries. Test the API response.
|
|
431
|
-
|
|
432
|
-
### ❌ Ignoring HTTP Semantics
|
|
433
|
-
Use correct status codes (200, 201, 400, 404, 500) and methods (GET, POST, PUT, DELETE).
|
|
434
|
-
|
|
435
|
-
### ❌ No Negative Testing
|
|
436
|
-
Always test error cases, not just happy paths.
|
|
437
|
-
|
|
438
|
-
### ❌ Brittle Tests
|
|
439
|
-
Don't assert on field order or extra fields. Focus on contract.
|
|
440
|
-
|
|
441
|
-
### ❌ Slow Tests
|
|
442
|
-
Mock external services. Don't wait for real third-party APIs.
|
|
199
|
+
---
|
|
443
200
|
|
|
444
201
|
## Best Practices
|
|
445
202
|
|
|
446
|
-
### ✅
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
### ✅ Test Error Scenarios
|
|
453
|
-
Network failures, timeouts, invalid input, authorization errors.
|
|
454
|
-
|
|
455
|
-
### ✅ Version Your API Tests
|
|
456
|
-
Keep tests for each API version to prevent breaking changes.
|
|
203
|
+
### ✅ Do This
|
|
204
|
+
- Test from consumer perspective
|
|
205
|
+
- Use schema validation (not exact values)
|
|
206
|
+
- Test error scenarios extensively
|
|
207
|
+
- Version API tests
|
|
208
|
+
- Automate in CI/CD
|
|
457
209
|
|
|
458
|
-
###
|
|
459
|
-
|
|
210
|
+
### ❌ Avoid This
|
|
211
|
+
- Testing implementation, not contract
|
|
212
|
+
- Ignoring HTTP semantics (status codes)
|
|
213
|
+
- No negative testing
|
|
214
|
+
- Asserting on field order or extra fields
|
|
215
|
+
- Slow tests (mock external services)
|
|
460
216
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
```javascript
|
|
464
|
-
describe('E-Commerce Order API', () => {
|
|
465
|
-
describe('Happy path', () => {
|
|
466
|
-
it('complete order flow', async () => {
|
|
467
|
-
// Add to cart
|
|
468
|
-
const cart = await api.post('/cart', { productId: 'abc', quantity: 2 });
|
|
469
|
-
|
|
470
|
-
// Apply discount
|
|
471
|
-
await api.post('/cart/discount', { code: 'SAVE10' });
|
|
472
|
-
|
|
473
|
-
// Checkout
|
|
474
|
-
const order = await api.post('/orders', {
|
|
475
|
-
cartId: cart.body.id,
|
|
476
|
-
payment: { method: 'card', token: 'tok_123' }
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
expect(order.status).toBe(201);
|
|
480
|
-
expect(order.body.status).toBe('pending');
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
describe('Edge cases', () => {
|
|
485
|
-
it('handles out of stock during checkout', async () => {
|
|
486
|
-
// Product sold out between cart and checkout
|
|
487
|
-
const order = await api.post('/orders', {
|
|
488
|
-
cartId: 'cart-with-sold-out-item'
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
expect(order.status).toBe(409); // Conflict
|
|
492
|
-
expect(order.body.error).toMatch(/out of stock/i);
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
});
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
## Using with QE Agents
|
|
217
|
+
---
|
|
499
218
|
|
|
500
|
-
|
|
219
|
+
## Agent-Assisted API Testing
|
|
501
220
|
|
|
502
|
-
**qe-api-contract-validator** ensures API contracts are maintained:
|
|
503
221
|
```typescript
|
|
504
|
-
//
|
|
505
|
-
await
|
|
222
|
+
// Validate contracts
|
|
223
|
+
await Task("Contract Validation", {
|
|
506
224
|
spec: 'openapi.yaml',
|
|
507
225
|
endpoint: '/orders',
|
|
508
|
-
method: 'POST',
|
|
509
226
|
checkBreakingChanges: true
|
|
510
|
-
});
|
|
227
|
+
}, "qe-api-contract-validator");
|
|
511
228
|
|
|
512
|
-
//
|
|
513
|
-
|
|
514
|
-
// valid: false,
|
|
515
|
-
// breakingChanges: [
|
|
516
|
-
// 'Field "orderId" changed from string to number'
|
|
517
|
-
// ],
|
|
518
|
-
// warnings: ['New optional field "metadata" added']
|
|
519
|
-
// }
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
### Agent-Generated API Test Suites
|
|
523
|
-
|
|
524
|
-
**qe-test-generator** creates comprehensive API tests:
|
|
525
|
-
```typescript
|
|
526
|
-
// Generate tests from OpenAPI spec
|
|
527
|
-
await agent.generateFromSpec({
|
|
229
|
+
// Generate tests from spec
|
|
230
|
+
await Task("Generate API Tests", {
|
|
528
231
|
spec: 'openapi.yaml',
|
|
529
232
|
coverage: 'comprehensive',
|
|
530
|
-
include: [
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
});
|
|
233
|
+
include: ['happy-paths', 'input-validation', 'auth-scenarios', 'error-handling']
|
|
234
|
+
}, "qe-test-generator");
|
|
235
|
+
|
|
236
|
+
// Load test
|
|
237
|
+
await Task("API Load Test", {
|
|
238
|
+
endpoint: '/orders',
|
|
239
|
+
rps: 1000,
|
|
240
|
+
duration: '5min'
|
|
241
|
+
}, "qe-performance-tester");
|
|
539
242
|
|
|
540
|
-
//
|
|
243
|
+
// Security scan
|
|
244
|
+
await Task("API Security Scan", {
|
|
245
|
+
spec: 'openapi.yaml',
|
|
246
|
+
checks: ['sql-injection', 'xss', 'broken-auth', 'rate-limiting']
|
|
247
|
+
}, "qe-security-scanner");
|
|
541
248
|
```
|
|
542
249
|
|
|
543
|
-
|
|
250
|
+
---
|
|
544
251
|
|
|
545
|
-
|
|
546
|
-
```typescript
|
|
547
|
-
// Execute API tests with intelligent retry for flakiness
|
|
548
|
-
await agent.executeAPITests({
|
|
549
|
-
suite: 'integration',
|
|
550
|
-
parallel: true,
|
|
551
|
-
retryStrategy: 'exponential-backoff',
|
|
552
|
-
flakyDetection: true
|
|
553
|
-
});
|
|
252
|
+
## Agent Coordination Hints
|
|
554
253
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
254
|
+
### Memory Namespace
|
|
255
|
+
```
|
|
256
|
+
aqe/api-testing/
|
|
257
|
+
├── contracts/* - API contract definitions
|
|
258
|
+
├── generated-tests/* - Generated test suites
|
|
259
|
+
├── validation/* - Contract validation results
|
|
260
|
+
└── performance/* - Load test results
|
|
558
261
|
```
|
|
559
262
|
|
|
560
|
-
###
|
|
561
|
-
|
|
263
|
+
### Fleet Coordination
|
|
562
264
|
```typescript
|
|
563
|
-
|
|
564
|
-
const contractFleet = await FleetManager.coordinate({
|
|
265
|
+
const apiFleet = await FleetManager.coordinate({
|
|
565
266
|
strategy: 'contract-testing',
|
|
566
|
-
agents: [
|
|
567
|
-
|
|
568
|
-
'qe-test-generator', // Generate consumer tests
|
|
569
|
-
'qe-test-executor' // Execute against provider
|
|
570
|
-
],
|
|
571
|
-
topology: 'mesh' // Consumer-provider pairs
|
|
267
|
+
agents: ['qe-api-contract-validator', 'qe-test-generator', 'qe-test-executor'],
|
|
268
|
+
topology: 'mesh'
|
|
572
269
|
});
|
|
573
270
|
|
|
574
|
-
|
|
575
|
-
await contractFleet.execute({
|
|
271
|
+
await apiFleet.execute({
|
|
576
272
|
services: [
|
|
577
273
|
{ name: 'orders-api', consumers: ['checkout-ui', 'admin-api'] },
|
|
578
274
|
{ name: 'payment-api', consumers: ['orders-api'] }
|
|
@@ -580,95 +276,19 @@ await contractFleet.execute({
|
|
|
580
276
|
});
|
|
581
277
|
```
|
|
582
278
|
|
|
583
|
-
### Performance Testing for APIs
|
|
584
|
-
|
|
585
|
-
**qe-performance-tester** load tests critical endpoints:
|
|
586
|
-
```typescript
|
|
587
|
-
// Agent runs load tests on API endpoints
|
|
588
|
-
await agent.loadTest({
|
|
589
|
-
endpoint: '/orders',
|
|
590
|
-
method: 'POST',
|
|
591
|
-
rps: 1000, // 1000 requests per second
|
|
592
|
-
duration: '5min',
|
|
593
|
-
scenarios: [
|
|
594
|
-
'create-order',
|
|
595
|
-
'concurrent-checkouts',
|
|
596
|
-
'bulk-operations'
|
|
597
|
-
]
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
// Returns:
|
|
601
|
-
// {
|
|
602
|
-
// avgResponseTime: '45ms',
|
|
603
|
-
// p95: '120ms',
|
|
604
|
-
// p99: '250ms',
|
|
605
|
-
// errorRate: 0.02, // 2% error rate
|
|
606
|
-
// bottlenecks: ['database connection pool']
|
|
607
|
-
// }
|
|
608
|
-
```
|
|
609
|
-
|
|
610
|
-
### Security Testing for APIs
|
|
611
|
-
|
|
612
|
-
**qe-security-scanner** tests API vulnerabilities:
|
|
613
|
-
```typescript
|
|
614
|
-
// Agent scans for API security issues
|
|
615
|
-
await agent.scanAPI({
|
|
616
|
-
spec: 'openapi.yaml',
|
|
617
|
-
checks: [
|
|
618
|
-
'sql-injection',
|
|
619
|
-
'xss',
|
|
620
|
-
'broken-auth',
|
|
621
|
-
'excessive-data-exposure',
|
|
622
|
-
'rate-limiting',
|
|
623
|
-
'input-validation'
|
|
624
|
-
]
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// Identifies:
|
|
628
|
-
// - Missing rate limiting on /login
|
|
629
|
-
// - No input sanitization on /search
|
|
630
|
-
// - Exposed internal IDs in responses
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
### Continuous Contract Monitoring
|
|
634
|
-
|
|
635
|
-
**qe-production-intelligence** monitors live API contracts:
|
|
636
|
-
```typescript
|
|
637
|
-
// Agent monitors production API for contract drift
|
|
638
|
-
await agent.monitorAPIContract({
|
|
639
|
-
endpoint: '/orders',
|
|
640
|
-
spec: 'openapi.yaml',
|
|
641
|
-
alertOn: 'breaking-changes',
|
|
642
|
-
sampleRate: 0.01 // Monitor 1% of traffic
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
// Alerts:
|
|
646
|
-
// "⚠️ Production API returning extra field not in spec: 'internalProcessId'"
|
|
647
|
-
// "🔴 Breaking change detected: 'quantity' changed from int to string"
|
|
648
|
-
```
|
|
649
|
-
|
|
650
279
|
---
|
|
651
280
|
|
|
652
281
|
## Related Skills
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
- [
|
|
656
|
-
- [holistic-testing-pact](../holistic-testing-pact/) - APIs in test quadrants
|
|
657
|
-
|
|
658
|
-
**Testing Approaches:**
|
|
659
|
-
- [test-automation-strategy](../test-automation-strategy/) - API tests in automation pyramid
|
|
660
|
-
- [risk-based-testing](../risk-based-testing/) - Risk-based API test prioritization
|
|
661
|
-
- [performance-testing](../performance-testing/) - API load testing patterns
|
|
282
|
+
- [agentic-quality-engineering](../agentic-quality-engineering/) - API testing with agents
|
|
283
|
+
- [tdd-london-chicago](../tdd-london-chicago/) - London school for API testing
|
|
284
|
+
- [performance-testing](../performance-testing/) - API load testing
|
|
662
285
|
- [security-testing](../security-testing/) - API security validation
|
|
663
|
-
|
|
664
|
-
**Development Practices:**
|
|
665
|
-
- [tdd-london-chicago](../tdd-london-chicago/) - London school for API testing (mocking)
|
|
666
|
-
- [code-review-quality](../code-review-quality/) - Review API test quality
|
|
286
|
+
- [contract-testing](../contract-testing/) - Consumer-driven contracts deep dive
|
|
667
287
|
|
|
668
288
|
---
|
|
669
289
|
|
|
670
290
|
## Remember
|
|
671
291
|
|
|
672
|
-
API testing
|
|
292
|
+
API testing = verifying contracts and behavior, not implementation. Focus on what matters to consumers: correct responses, proper error handling, acceptable performance.
|
|
673
293
|
|
|
674
|
-
**With Agents
|
|
294
|
+
**With Agents:** Agents automate contract validation, generate comprehensive test suites from specs, and monitor production APIs for drift. Use agents to maintain API quality at scale.
|