claude-termux 1.0.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.md +60 -0
- package/GEMINI.md +20 -0
- package/README.md +135 -0
- package/TERMUX.md +204 -0
- package/agents/accessibility-reviewer.md +96 -0
- package/agents/ai-prompt-optimizer.md +94 -0
- package/agents/api-tester.md +102 -0
- package/agents/code-generator.md +94 -0
- package/agents/code-reviewer.md +47 -0
- package/agents/component-generator.md +102 -0
- package/agents/doc-generator.md +91 -0
- package/agents/migration-generator.md +94 -0
- package/agents/performance-analyzer.md +90 -0
- package/agents/proactive-mode.md +91 -0
- package/agents/readme-generator.md +101 -0
- package/agents/security-auditor.md +86 -0
- package/agents/terraform-generator.md +94 -0
- package/agents/test-generator.md +76 -0
- package/commands/brainstorm.md +5 -0
- package/commands/execute-plan.md +5 -0
- package/commands/write-plan.md +5 -0
- package/hooks/auto-context.json +31 -0
- package/hooks/hooks.json +15 -0
- package/hooks/run-hook.cmd +19 -0
- package/hooks/session-start.sh +52 -0
- package/hooks/smart-session.sh +96 -0
- package/install.sh +210 -0
- package/lib/skills-core.js +208 -0
- package/mcp.json +34 -0
- package/package.json +49 -0
- package/plugins/README.md +47 -0
- package/plugins/installed_plugins.json +5 -0
- package/plugins/known_marketplaces.json +10 -0
- package/plugins/marketplace-info/marketplace.json +517 -0
- package/postinstall.js +238 -0
- package/settings.json +27 -0
- package/settings.local.json +25 -0
- package/skills/api-development/SKILL.md +11 -0
- package/skills/api-development/openapi/api-documentation.yaml +108 -0
- package/skills/brainstorming/SKILL.md +54 -0
- package/skills/code-quality/SKILL.md +196 -0
- package/skills/condition-based-waiting/SKILL.md +120 -0
- package/skills/condition-based-waiting/example.ts +158 -0
- package/skills/database-development/SKILL.md +11 -0
- package/skills/database-development/migrations/migration.template.sql +49 -0
- package/skills/defense-in-depth/SKILL.md +127 -0
- package/skills/deployment/SKILL.md +11 -0
- package/skills/deployment/ci-cd/github-actions.yml +95 -0
- package/skills/deployment/docker/Dockerfile.template +39 -0
- package/skills/dispatching-parallel-agents/SKILL.md +180 -0
- package/skills/documentation-generation/SKILL.md +8 -0
- package/skills/documentation-generation/templates/README.template.md +60 -0
- package/skills/error-handling/SKILL.md +267 -0
- package/skills/executing-plans/SKILL.md +76 -0
- package/skills/finishing-a-development-branch/SKILL.md +200 -0
- package/skills/frontend-design/frontend-design/SKILL.md +42 -0
- package/skills/integration-testing/SKILL.md +13 -0
- package/skills/integration-testing/examples/contract-test.py +317 -0
- package/skills/integration-testing/examples/e2e-test.js +147 -0
- package/skills/integration-testing/examples/test-isolation.md +94 -0
- package/skills/logging-monitoring/SKILL.md +66 -0
- package/skills/mobile-development/SKILL.md +11 -0
- package/skills/mobile-development/responsive/responsive.css +80 -0
- package/skills/performance-optimization/SKILL.md +9 -0
- package/skills/performance-optimization/profiling/profile.template.js +21 -0
- package/skills/receiving-code-review/SKILL.md +209 -0
- package/skills/refactoring/SKILL.md +11 -0
- package/skills/refactoring/code-smells/common-smells.md +115 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +146 -0
- package/skills/root-cause-tracing/SKILL.md +174 -0
- package/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/skills/security-review/SKILL.md +11 -0
- package/skills/security-review/checklists/owasp-checklist.md +31 -0
- package/skills/sharing-skills/SKILL.md +194 -0
- package/skills/subagent-driven-development/SKILL.md +240 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/skills/subagent-driven-development/implementer-prompt.md +78 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/skills/systematic-debugging/SKILL.md +295 -0
- package/skills/systematic-debugging/test-academic.md +14 -0
- package/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/skills/test-driven-development/SKILL.md +364 -0
- package/skills/testing-anti-patterns/SKILL.md +302 -0
- package/skills/testing-skills-with-subagents/SKILL.md +387 -0
- package/skills/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +189 -0
- package/skills/ui-ux-review/SKILL.md +13 -0
- package/skills/ui-ux-review/checklists/ux-heuristics.md +61 -0
- package/skills/using-git-worktrees/SKILL.md +213 -0
- package/skills/using-superpowers/SKILL.md +101 -0
- package/skills/verification-before-completion/SKILL.md +139 -0
- package/skills/writing-plans/SKILL.md +116 -0
- package/skills/writing-skills/SKILL.md +622 -0
- package/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/skills/writing-skills/persuasion-principles.md +187 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: finishing-a-development-branch
|
|
3
|
+
description: Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Finishing a Development Branch
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Guide completion of development work by presenting clear options and handling chosen workflow.
|
|
11
|
+
|
|
12
|
+
**Core principle:** Verify tests → Present options → Execute choice → Clean up.
|
|
13
|
+
|
|
14
|
+
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
|
|
15
|
+
|
|
16
|
+
## The Process
|
|
17
|
+
|
|
18
|
+
### Step 1: Verify Tests
|
|
19
|
+
|
|
20
|
+
**Before presenting options, verify tests pass:**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Run project's test suite
|
|
24
|
+
npm test / cargo test / pytest / go test ./...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**If tests fail:**
|
|
28
|
+
```
|
|
29
|
+
Tests failing (<N> failures). Must fix before completing:
|
|
30
|
+
|
|
31
|
+
[Show failures]
|
|
32
|
+
|
|
33
|
+
Cannot proceed with merge/PR until tests pass.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Stop. Don't proceed to Step 2.
|
|
37
|
+
|
|
38
|
+
**If tests pass:** Continue to Step 2.
|
|
39
|
+
|
|
40
|
+
### Step 2: Determine Base Branch
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Try common base branches
|
|
44
|
+
git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or ask: "This branch split from main - is that correct?"
|
|
48
|
+
|
|
49
|
+
### Step 3: Present Options
|
|
50
|
+
|
|
51
|
+
Present exactly these 4 options:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Implementation complete. What would you like to do?
|
|
55
|
+
|
|
56
|
+
1. Merge back to <base-branch> locally
|
|
57
|
+
2. Push and create a Pull Request
|
|
58
|
+
3. Keep the branch as-is (I'll handle it later)
|
|
59
|
+
4. Discard this work
|
|
60
|
+
|
|
61
|
+
Which option?
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Don't add explanation** - keep options concise.
|
|
65
|
+
|
|
66
|
+
### Step 4: Execute Choice
|
|
67
|
+
|
|
68
|
+
#### Option 1: Merge Locally
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Switch to base branch
|
|
72
|
+
git checkout <base-branch>
|
|
73
|
+
|
|
74
|
+
# Pull latest
|
|
75
|
+
git pull
|
|
76
|
+
|
|
77
|
+
# Merge feature branch
|
|
78
|
+
git merge <feature-branch>
|
|
79
|
+
|
|
80
|
+
# Verify tests on merged result
|
|
81
|
+
<test command>
|
|
82
|
+
|
|
83
|
+
# If tests pass
|
|
84
|
+
git branch -d <feature-branch>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then: Cleanup worktree (Step 5)
|
|
88
|
+
|
|
89
|
+
#### Option 2: Push and Create PR
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Push branch
|
|
93
|
+
git push -u origin <feature-branch>
|
|
94
|
+
|
|
95
|
+
# Create PR
|
|
96
|
+
gh pr create --title "<title>" --body "$(cat <<'EOF'
|
|
97
|
+
## Summary
|
|
98
|
+
<2-3 bullets of what changed>
|
|
99
|
+
|
|
100
|
+
## Test Plan
|
|
101
|
+
- [ ] <verification steps>
|
|
102
|
+
EOF
|
|
103
|
+
)"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Then: Cleanup worktree (Step 5)
|
|
107
|
+
|
|
108
|
+
#### Option 3: Keep As-Is
|
|
109
|
+
|
|
110
|
+
Report: "Keeping branch <name>. Worktree preserved at <path>."
|
|
111
|
+
|
|
112
|
+
**Don't cleanup worktree.**
|
|
113
|
+
|
|
114
|
+
#### Option 4: Discard
|
|
115
|
+
|
|
116
|
+
**Confirm first:**
|
|
117
|
+
```
|
|
118
|
+
This will permanently delete:
|
|
119
|
+
- Branch <name>
|
|
120
|
+
- All commits: <commit-list>
|
|
121
|
+
- Worktree at <path>
|
|
122
|
+
|
|
123
|
+
Type 'discard' to confirm.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Wait for exact confirmation.
|
|
127
|
+
|
|
128
|
+
If confirmed:
|
|
129
|
+
```bash
|
|
130
|
+
git checkout <base-branch>
|
|
131
|
+
git branch -D <feature-branch>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Then: Cleanup worktree (Step 5)
|
|
135
|
+
|
|
136
|
+
### Step 5: Cleanup Worktree
|
|
137
|
+
|
|
138
|
+
**For Options 1, 2, 4:**
|
|
139
|
+
|
|
140
|
+
Check if in worktree:
|
|
141
|
+
```bash
|
|
142
|
+
git worktree list | grep $(git branch --show-current)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If yes:
|
|
146
|
+
```bash
|
|
147
|
+
git worktree remove <worktree-path>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**For Option 3:** Keep worktree.
|
|
151
|
+
|
|
152
|
+
## Quick Reference
|
|
153
|
+
|
|
154
|
+
| Option | Merge | Push | Keep Worktree | Cleanup Branch |
|
|
155
|
+
|--------|-------|------|---------------|----------------|
|
|
156
|
+
| 1. Merge locally | ✓ | - | - | ✓ |
|
|
157
|
+
| 2. Create PR | - | ✓ | ✓ | - |
|
|
158
|
+
| 3. Keep as-is | - | - | ✓ | - |
|
|
159
|
+
| 4. Discard | - | - | - | ✓ (force) |
|
|
160
|
+
|
|
161
|
+
## Common Mistakes
|
|
162
|
+
|
|
163
|
+
**Skipping test verification**
|
|
164
|
+
- **Problem:** Merge broken code, create failing PR
|
|
165
|
+
- **Fix:** Always verify tests before offering options
|
|
166
|
+
|
|
167
|
+
**Open-ended questions**
|
|
168
|
+
- **Problem:** "What should I do next?" → ambiguous
|
|
169
|
+
- **Fix:** Present exactly 4 structured options
|
|
170
|
+
|
|
171
|
+
**Automatic worktree cleanup**
|
|
172
|
+
- **Problem:** Remove worktree when might need it (Option 2, 3)
|
|
173
|
+
- **Fix:** Only cleanup for Options 1 and 4
|
|
174
|
+
|
|
175
|
+
**No confirmation for discard**
|
|
176
|
+
- **Problem:** Accidentally delete work
|
|
177
|
+
- **Fix:** Require typed "discard" confirmation
|
|
178
|
+
|
|
179
|
+
## Red Flags
|
|
180
|
+
|
|
181
|
+
**Never:**
|
|
182
|
+
- Proceed with failing tests
|
|
183
|
+
- Merge without verifying tests on result
|
|
184
|
+
- Delete work without confirmation
|
|
185
|
+
- Force-push without explicit request
|
|
186
|
+
|
|
187
|
+
**Always:**
|
|
188
|
+
- Verify tests before offering options
|
|
189
|
+
- Present exactly 4 options
|
|
190
|
+
- Get typed confirmation for Option 4
|
|
191
|
+
- Clean up worktree for Options 1 & 4 only
|
|
192
|
+
|
|
193
|
+
## Integration
|
|
194
|
+
|
|
195
|
+
**Called by:**
|
|
196
|
+
- **subagent-driven-development** (Step 7) - After all tasks complete
|
|
197
|
+
- **executing-plans** (Step 5) - After all batches complete
|
|
198
|
+
|
|
199
|
+
**Pairs with:**
|
|
200
|
+
- **using-git-worktrees** - Cleans up worktree created by that skill
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
|
|
4
|
+
license: Complete terms in LICENSE.txt
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
|
|
8
|
+
|
|
9
|
+
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
|
|
10
|
+
|
|
11
|
+
## Design Thinking
|
|
12
|
+
|
|
13
|
+
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
|
14
|
+
- **Purpose**: What problem does this interface solve? Who uses it?
|
|
15
|
+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
|
|
16
|
+
- **Constraints**: Technical requirements (framework, performance, accessibility).
|
|
17
|
+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
|
18
|
+
|
|
19
|
+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
|
|
20
|
+
|
|
21
|
+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
|
|
22
|
+
- Production-grade and functional
|
|
23
|
+
- Visually striking and memorable
|
|
24
|
+
- Cohesive with a clear aesthetic point-of-view
|
|
25
|
+
- Meticulously refined in every detail
|
|
26
|
+
|
|
27
|
+
## Frontend Aesthetics Guidelines
|
|
28
|
+
|
|
29
|
+
Focus on:
|
|
30
|
+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
|
|
31
|
+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
|
|
32
|
+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
|
|
33
|
+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
|
|
34
|
+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
|
|
35
|
+
|
|
36
|
+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
|
|
37
|
+
|
|
38
|
+
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
|
|
39
|
+
|
|
40
|
+
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
|
|
41
|
+
|
|
42
|
+
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
integration-testing skill helps verify that different components of the system work together correctly through end-to-end testing and contract testing.
|
|
2
|
+
|
|
3
|
+
For code review, check that:
|
|
4
|
+
1. Critical user journeys are tested end-to-end
|
|
5
|
+
2. API contracts are tested with provider tests
|
|
6
|
+
3. Database integration is tested
|
|
7
|
+
4. External service integrations are tested
|
|
8
|
+
5. Test data is properly isolated
|
|
9
|
+
6. Tests are deterministic and repeatable
|
|
10
|
+
7. Test environments mimic production
|
|
11
|
+
8. Performance tests cover critical paths
|
|
12
|
+
9. Error scenarios are tested
|
|
13
|
+
10. Test coverage includes all integrations
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Provider Contract Test Example
|
|
2
|
+
# Verifies API contract between frontend and backend services
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
import json
|
|
6
|
+
from pact import Consumer, Provider
|
|
7
|
+
from utils.api_client import APIClient
|
|
8
|
+
from utils.test_data import generate_test_order
|
|
9
|
+
|
|
10
|
+
# Define contract
|
|
11
|
+
pact = Consumer('WebApp').has_pact_with(Provider('OrderService'))
|
|
12
|
+
|
|
13
|
+
def test_create_order_contract():
|
|
14
|
+
"""Test contract for creating an order"""
|
|
15
|
+
|
|
16
|
+
expected_order = {
|
|
17
|
+
"id": 12345,
|
|
18
|
+
"customer_id": "CUST-001",
|
|
19
|
+
"items": [
|
|
20
|
+
{
|
|
21
|
+
"product_id": "PROD-001",
|
|
22
|
+
"quantity": 2,
|
|
23
|
+
"price": 29.99
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"total": 59.98,
|
|
27
|
+
"status": "pending",
|
|
28
|
+
"created_at": "2024-01-15T10:30:00Z"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
(pact
|
|
32
|
+
.given('customer CUST-001 exists')
|
|
33
|
+
.upon_receiving('a request to create an order')
|
|
34
|
+
.with_request(
|
|
35
|
+
method='POST',
|
|
36
|
+
path='/api/orders',
|
|
37
|
+
headers={
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
'Authorization': pact.term('Bearer .*', 'Bearer token123')
|
|
40
|
+
},
|
|
41
|
+
body={
|
|
42
|
+
'customer_id': 'CUST-001',
|
|
43
|
+
'items': [
|
|
44
|
+
{
|
|
45
|
+
'product_id': 'PROD-001',
|
|
46
|
+
'quantity': 2
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
.will_respond_with(
|
|
52
|
+
status=201,
|
|
53
|
+
headers={
|
|
54
|
+
'Content-Type': 'application/json'
|
|
55
|
+
},
|
|
56
|
+
body=expected_order
|
|
57
|
+
))
|
|
58
|
+
|
|
59
|
+
with pact:
|
|
60
|
+
# Make actual request against mock server
|
|
61
|
+
client = APIClient(base_url=pact.uri)
|
|
62
|
+
response = client.create_order({
|
|
63
|
+
'customer_id': 'CUST-001',
|
|
64
|
+
'items': [
|
|
65
|
+
{
|
|
66
|
+
'product_id': 'PROD-001',
|
|
67
|
+
'quantity': 2
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}, headers={
|
|
71
|
+
'Authorization': 'Bearer token123'
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
# Verify response
|
|
75
|
+
assert response.status_code == 201
|
|
76
|
+
assert response.json() == expected_order
|
|
77
|
+
|
|
78
|
+
def test_get_products_contract():
|
|
79
|
+
"""Test contract for fetching products"""
|
|
80
|
+
|
|
81
|
+
expected_products = {
|
|
82
|
+
"products": [
|
|
83
|
+
{
|
|
84
|
+
"id": "PROD-001",
|
|
85
|
+
"name": "Test Product",
|
|
86
|
+
"price": 29.99,
|
|
87
|
+
"stock": 100,
|
|
88
|
+
"category": "electronics"
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"pagination": {
|
|
92
|
+
"page": 1,
|
|
93
|
+
"per_page": 10,
|
|
94
|
+
"total": 1,
|
|
95
|
+
"total_pages": 1
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
(pact
|
|
100
|
+
.given('products exist in the database')
|
|
101
|
+
.upon_receiving('a request to get products list')
|
|
102
|
+
.with_request(
|
|
103
|
+
method='GET',
|
|
104
|
+
path='/api/products',
|
|
105
|
+
query={
|
|
106
|
+
'page': '1',
|
|
107
|
+
'per_page': '10',
|
|
108
|
+
'category': 'electronics'
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
.will_respond_with(
|
|
112
|
+
status=200,
|
|
113
|
+
headers={
|
|
114
|
+
'Content-Type': 'application/json'
|
|
115
|
+
},
|
|
116
|
+
body=expected_products
|
|
117
|
+
))
|
|
118
|
+
|
|
119
|
+
with pact:
|
|
120
|
+
client = APIClient(base_url=pact.uri)
|
|
121
|
+
response = client.get_products(
|
|
122
|
+
page=1,
|
|
123
|
+
per_page=10,
|
|
124
|
+
category='electronics'
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
assert response.status_code == 200
|
|
128
|
+
assert response.json() == expected_products
|
|
129
|
+
|
|
130
|
+
def test_error_response_contract():
|
|
131
|
+
"""Test contract for error scenarios"""
|
|
132
|
+
|
|
133
|
+
error_response = {
|
|
134
|
+
"error": {
|
|
135
|
+
"code": "VALIDATION_ERROR",
|
|
136
|
+
"message": "Invalid input data",
|
|
137
|
+
"details": [
|
|
138
|
+
{
|
|
139
|
+
"field": "email",
|
|
140
|
+
"message": "Invalid email format"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
(pact
|
|
147
|
+
.upon_receiving('a request with invalid data')
|
|
148
|
+
.with_request(
|
|
149
|
+
method='POST',
|
|
150
|
+
path='/api/users',
|
|
151
|
+
headers={'Content-Type': 'application/json'},
|
|
152
|
+
body={
|
|
153
|
+
'email': 'invalid-email',
|
|
154
|
+
'name': ''
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
.will_respond_with(
|
|
158
|
+
status=400,
|
|
159
|
+
headers={'Content-Type': 'application/json'},
|
|
160
|
+
body=error_response
|
|
161
|
+
))
|
|
162
|
+
|
|
163
|
+
with pact:
|
|
164
|
+
client = APIClient(base_url=pact.uri)
|
|
165
|
+
response = client.create_user({
|
|
166
|
+
'email': 'invalid-email',
|
|
167
|
+
'name': ''
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
assert response.status_code == 400
|
|
171
|
+
assert response.json() == error_response
|
|
172
|
+
|
|
173
|
+
@pytest.fixture
|
|
174
|
+
def pact_setup(request):
|
|
175
|
+
"""Setup Pact contract testing"""
|
|
176
|
+
|
|
177
|
+
# Start mock service
|
|
178
|
+
pact.start_service()
|
|
179
|
+
|
|
180
|
+
# Ensure pact is verified after each test
|
|
181
|
+
request.addfinalizer(lambda: pact.verify())
|
|
182
|
+
request.addfinalizer(lambda: pact.stop_service())
|
|
183
|
+
|
|
184
|
+
class TestAPIIntegration:
|
|
185
|
+
"""Integration tests with real API service"""
|
|
186
|
+
|
|
187
|
+
@pytest.mark.integration
|
|
188
|
+
def test_full_order_flow(self):
|
|
189
|
+
"""Test complete order processing flow"""
|
|
190
|
+
|
|
191
|
+
# 1. Create customer
|
|
192
|
+
customer = APIClient().create_customer({
|
|
193
|
+
'name': 'Test Customer',
|
|
194
|
+
'email': 'test@example.com',
|
|
195
|
+
'address': '123 Test St'
|
|
196
|
+
})
|
|
197
|
+
assert customer.status_code == 201
|
|
198
|
+
customer_id = customer.json()['id']
|
|
199
|
+
|
|
200
|
+
# 2. Create order
|
|
201
|
+
order_data = generate_test_order(customer_id)
|
|
202
|
+
order = APIClient().create_order(order_data)
|
|
203
|
+
assert order.status_code == 201
|
|
204
|
+
order_id = order.json()['id']
|
|
205
|
+
|
|
206
|
+
# 3. Process payment
|
|
207
|
+
payment = APIClient().process_payment({
|
|
208
|
+
'order_id': order_id,
|
|
209
|
+
'amount': order.json()['total'],
|
|
210
|
+
'payment_method': 'credit_card'
|
|
211
|
+
})
|
|
212
|
+
assert payment.status_code == 200
|
|
213
|
+
|
|
214
|
+
# 4. Verify order status updated
|
|
215
|
+
updated_order = APIClient().get_order(order_id)
|
|
216
|
+
assert updated_order.status_code == 200
|
|
217
|
+
assert updated_order.json()['status'] == 'paid'
|
|
218
|
+
|
|
219
|
+
# 5. Trigger shipping
|
|
220
|
+
shipment = APIClient().create_shipment({
|
|
221
|
+
'order_id': order_id,
|
|
222
|
+
'carrier': 'ups',
|
|
223
|
+
'tracking_number': '1Z9999W99999999999'
|
|
224
|
+
})
|
|
225
|
+
assert shipment.status_code == 201
|
|
226
|
+
|
|
227
|
+
# 6. Verify final order status
|
|
228
|
+
final_order = APIClient().get_order(order_id)
|
|
229
|
+
assert final_order.json()['status'] == 'shipped'
|
|
230
|
+
assert 'tracking_number' in final_order.json()['shipment']
|
|
231
|
+
|
|
232
|
+
@pytest.mark.integration
|
|
233
|
+
def test_database_transaction_consistency(self):
|
|
234
|
+
"""Test that database transactions are consistent across services"""
|
|
235
|
+
|
|
236
|
+
# This test would check that related microservices maintain consistency
|
|
237
|
+
# Example: When an order is cancelled, inventory is restored and payment is refunded
|
|
238
|
+
|
|
239
|
+
# Create order with items
|
|
240
|
+
order_data = generate_test_order()
|
|
241
|
+
response = APIClient().create_order(order_data)
|
|
242
|
+
order_id = response.json()['id']
|
|
243
|
+
|
|
244
|
+
# Check inventory reduced
|
|
245
|
+
for item in order_data['items']:
|
|
246
|
+
inventory = APIClient().get_inventory(item['product_id'])
|
|
247
|
+
assert inventory.json()['available'] < 100
|
|
248
|
+
|
|
249
|
+
# Cancel order
|
|
250
|
+
cancel_response = APIClient().cancel_order(order_id)
|
|
251
|
+
assert cancel_response.status_code == 200
|
|
252
|
+
|
|
253
|
+
# Verify inventory restored
|
|
254
|
+
for item in order_data['items']:
|
|
255
|
+
inventory = APIClient().get_inventory(item['product_id'])
|
|
256
|
+
assert inventory.json()['available'] == 100
|
|
257
|
+
|
|
258
|
+
# Verify refund processed
|
|
259
|
+
refund = APIClient().get_refund(order_id)
|
|
260
|
+
assert refund.json()['status'] == 'processed'
|
|
261
|
+
|
|
262
|
+
@pytest.mark.contract
|
|
263
|
+
class TestMessageContract:
|
|
264
|
+
"""Test message contracts between services"""
|
|
265
|
+
|
|
266
|
+
def test_user_event_contract(self):
|
|
267
|
+
"""Test user event message structure"""
|
|
268
|
+
|
|
269
|
+
expected_message = {
|
|
270
|
+
'event_type': 'user_created',
|
|
271
|
+
'user_id': 'USR-12345',
|
|
272
|
+
'timestamp': pact.term(
|
|
273
|
+
matcher=r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z',
|
|
274
|
+
generator='2024-01-15T10:30:00Z'
|
|
275
|
+
),
|
|
276
|
+
'data': {
|
|
277
|
+
'email': 'test@example.com',
|
|
278
|
+
'name': 'Test User'
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
(pact
|
|
283
|
+
.upon_receiving('user created event')
|
|
284
|
+
.with_request(
|
|
285
|
+
method='POST',
|
|
286
|
+
path='/api/events',
|
|
287
|
+
headers={'Content-Type': 'application/json'},
|
|
288
|
+
body=expected_message
|
|
289
|
+
)
|
|
290
|
+
.will_respond_with(status=202))
|
|
291
|
+
|
|
292
|
+
def test_order_status_update_contract(self):
|
|
293
|
+
"""Test order status update message"""
|
|
294
|
+
|
|
295
|
+
(pact
|
|
296
|
+
.given('order 12345 exists')
|
|
297
|
+
.upon_receiving('order status update')
|
|
298
|
+
.with_request(
|
|
299
|
+
method='PATCH',
|
|
300
|
+
path='/api/orders/12345/status',
|
|
301
|
+
body={
|
|
302
|
+
'status': 'shipped',
|
|
303
|
+
'tracking_number': '1Z9999W99999999999'
|
|
304
|
+
}
|
|
305
|
+
)
|
|
306
|
+
.will_respond_with(
|
|
307
|
+
status=200,
|
|
308
|
+
body={
|
|
309
|
+
'order_id': 12345,
|
|
310
|
+
'status': 'shipped',
|
|
311
|
+
'tracking_number': '1Z9999W99999999999',
|
|
312
|
+
'updated_at': pact.term(
|
|
313
|
+
matcher=r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z',
|
|
314
|
+
generator='2024-01-15T11:00:00Z'
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
))
|