100xprism 2.3.1
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/LICENSE +21 -0
- package/README.md +196 -0
- package/VERSION +1 -0
- package/adapters/antigravity.sh +14 -0
- package/adapters/claude-code.sh +160 -0
- package/adapters/codex.sh +13 -0
- package/adapters/copilot.sh +13 -0
- package/adapters/cursor.sh +13 -0
- package/adapters/gemini.sh +13 -0
- package/adapters/lib/__pycache__/modules.cpython-312.pyc +0 -0
- package/adapters/lib/modules.py +592 -0
- package/adapters/lib/shared.sh +83 -0
- package/adapters/lib/sync_plugins.py +113 -0
- package/adapters/windsurf.sh +15 -0
- package/bin/100xprism.js +29 -0
- package/get.sh +24 -0
- package/install-project.sh +82 -0
- package/install.sh +281 -0
- package/lib/adapters/windows.js +429 -0
- package/lib/bootstrap.js +33 -0
- package/lib/init.js +19 -0
- package/lib/install.js +18 -0
- package/lib/migrate.js +52 -0
- package/lib/platform.js +22 -0
- package/lib/update.js +29 -0
- package/modules/_lib/reference.md +77 -0
- package/modules/a11y-auditor/SKILL.md +151 -0
- package/modules/ab-test-setup/SKILL.md +266 -0
- package/modules/ab-test-setup/evals/evals.json +105 -0
- package/modules/ab-test-setup/references/sample-size-guide.md +263 -0
- package/modules/ab-test-setup/references/test-templates.md +277 -0
- package/modules/ad-creative/SKILL.md +362 -0
- package/modules/ad-creative/evals/evals.json +90 -0
- package/modules/ad-creative/references/generative-tools.md +637 -0
- package/modules/ad-creative/references/platform-specs.md +213 -0
- package/modules/ai-seo/SKILL.md +398 -0
- package/modules/ai-seo/evals/evals.json +90 -0
- package/modules/ai-seo/references/content-patterns.md +285 -0
- package/modules/ai-seo/references/platform-ranking-factors.md +152 -0
- package/modules/analytics-tracking/SKILL.md +309 -0
- package/modules/analytics-tracking/evals/evals.json +90 -0
- package/modules/analytics-tracking/references/event-library.md +260 -0
- package/modules/analytics-tracking/references/ga4-implementation.md +300 -0
- package/modules/analytics-tracking/references/gtm-implementation.md +390 -0
- package/modules/architect/SKILL.md +282 -0
- package/modules/branch/SKILL.md +105 -0
- package/modules/churn-prevention/SKILL.md +424 -0
- package/modules/churn-prevention/evals/evals.json +93 -0
- package/modules/churn-prevention/references/cancel-flow-patterns.md +316 -0
- package/modules/churn-prevention/references/dunning-playbook.md +408 -0
- package/modules/cloud-security/SKILL.md +240 -0
- package/modules/cold-email/SKILL.md +178 -0
- package/modules/cold-email/evals/evals.json +94 -0
- package/modules/cold-email/references/benchmarks.md +83 -0
- package/modules/cold-email/references/follow-up-sequences.md +81 -0
- package/modules/cold-email/references/frameworks.md +90 -0
- package/modules/cold-email/references/personalization.md +79 -0
- package/modules/cold-email/references/subject-lines.md +53 -0
- package/modules/commit/SKILL.md +195 -0
- package/modules/competitor-alternatives/SKILL.md +256 -0
- package/modules/competitor-alternatives/evals/evals.json +93 -0
- package/modules/competitor-alternatives/references/content-architecture.md +271 -0
- package/modules/competitor-alternatives/references/templates.md +223 -0
- package/modules/connect/SKILL.md +894 -0
- package/modules/content-strategy/SKILL.md +359 -0
- package/modules/content-strategy/evals/evals.json +90 -0
- package/modules/context-dump/SKILL.md +67 -0
- package/modules/copy-editing/SKILL.md +447 -0
- package/modules/copy-editing/evals/evals.json +89 -0
- package/modules/copy-editing/references/plain-english-alternatives.md +394 -0
- package/modules/copywriting/SKILL.md +271 -0
- package/modules/copywriting/evals/evals.json +111 -0
- package/modules/copywriting/references/cold-email-benchmarks.md +83 -0
- package/modules/copywriting/references/cold-email-follow-ups.md +81 -0
- package/modules/copywriting/references/cold-email-frameworks.md +90 -0
- package/modules/copywriting/references/cold-email-personalization.md +79 -0
- package/modules/copywriting/references/cold-email-subject-lines.md +53 -0
- package/modules/copywriting/references/copy-frameworks.md +344 -0
- package/modules/copywriting/references/email-copy-guidelines.md +113 -0
- package/modules/copywriting/references/email-types.md +515 -0
- package/modules/copywriting/references/natural-transitions.md +272 -0
- package/modules/copywriting/references/sequence-templates.md +168 -0
- package/modules/data-query/SKILL.md +58 -0
- package/modules/data-viz/SKILL.md +225 -0
- package/modules/db/SKILL.md +205 -0
- package/modules/db/db-engines/_router.md +24 -0
- package/modules/db/db-engines/athena.md +16 -0
- package/modules/db/db-engines/cloud-sql.md +16 -0
- package/modules/db/db-engines/databricks.md +14 -0
- package/modules/db/db-engines/oracle.md +14 -0
- package/modules/db/db-engines/postgres.md +15 -0
- package/modules/db/db-engines/presto.md +14 -0
- package/modules/db/db-engines/snowflake.md +14 -0
- package/modules/docs/SKILL.md +100 -0
- package/modules/email-sequence/SKILL.md +309 -0
- package/modules/email-sequence/evals/evals.json +93 -0
- package/modules/email-sequence/references/copy-guidelines.md +113 -0
- package/modules/email-sequence/references/email-types.md +515 -0
- package/modules/email-sequence/references/sequence-templates.md +168 -0
- package/modules/enterprise-design/SKILL.md +75 -0
- package/modules/eval/SKILL.md +105 -0
- package/modules/figma-translator/SKILL.md +49 -0
- package/modules/fix-bugs/SKILL.md +104 -0
- package/modules/form-cro/SKILL.md +429 -0
- package/modules/form-cro/evals/evals.json +90 -0
- package/modules/free-tool-strategy/SKILL.md +178 -0
- package/modules/free-tool-strategy/evals/evals.json +90 -0
- package/modules/free-tool-strategy/references/tool-types.md +217 -0
- package/modules/gate/SKILL.md +232 -0
- package/modules/grill-me/SKILL.md +59 -0
- package/modules/interaction-engineer/SKILL.md +49 -0
- package/modules/issue/SKILL.md +272 -0
- package/modules/launch/SKILL.md +345 -0
- package/modules/launch-strategy/SKILL.md +353 -0
- package/modules/launch-strategy/evals/evals.json +91 -0
- package/modules/lint/SKILL.md +126 -0
- package/modules/marketing-ideas/SKILL.md +167 -0
- package/modules/marketing-ideas/evals/evals.json +90 -0
- package/modules/marketing-ideas/references/ideas-by-category.md +366 -0
- package/modules/marketing-psychology/SKILL.md +455 -0
- package/modules/marketing-psychology/evals/evals.json +88 -0
- package/modules/motion-designer/SKILL.md +214 -0
- package/modules/onboarding-cro/SKILL.md +220 -0
- package/modules/onboarding-cro/evals/evals.json +92 -0
- package/modules/onboarding-cro/references/experiments.md +258 -0
- package/modules/orchestrate/SKILL.md +77 -0
- package/modules/page-cro/SKILL.md +182 -0
- package/modules/page-cro/evals/evals.json +111 -0
- package/modules/page-cro/references/experiments.md +248 -0
- package/modules/page-cro/references/paywall-experiments.md +164 -0
- package/modules/paid-ads/SKILL.md +315 -0
- package/modules/paid-ads/evals/evals.json +90 -0
- package/modules/paid-ads/references/ad-copy-templates.md +207 -0
- package/modules/paid-ads/references/audience-targeting.md +243 -0
- package/modules/paid-ads/references/platform-setup-checklists.md +277 -0
- package/modules/paywall-upgrade-cro/SKILL.md +227 -0
- package/modules/paywall-upgrade-cro/evals/evals.json +93 -0
- package/modules/paywall-upgrade-cro/references/experiments.md +164 -0
- package/modules/popup-cro/SKILL.md +453 -0
- package/modules/popup-cro/evals/evals.json +94 -0
- package/modules/pr/SKILL.md +203 -0
- package/modules/pricing-strategy/SKILL.md +231 -0
- package/modules/pricing-strategy/evals/evals.json +90 -0
- package/modules/pricing-strategy/references/research-methods.md +152 -0
- package/modules/pricing-strategy/references/tier-structure.md +232 -0
- package/modules/product-marketing-context/SKILL.md +241 -0
- package/modules/product-marketing-context/evals/evals.json +85 -0
- package/modules/programmatic-seo/SKILL.md +238 -0
- package/modules/programmatic-seo/evals/evals.json +94 -0
- package/modules/programmatic-seo/references/playbooks.md +308 -0
- package/modules/push/SKILL.md +202 -0
- package/modules/referral-program/SKILL.md +255 -0
- package/modules/referral-program/evals/evals.json +89 -0
- package/modules/referral-program/references/affiliate-programs.md +164 -0
- package/modules/referral-program/references/program-examples.md +143 -0
- package/modules/release/SKILL.md +293 -0
- package/modules/revops/SKILL.md +343 -0
- package/modules/revops/evals/evals.json +91 -0
- package/modules/revops/references/automation-playbooks.md +290 -0
- package/modules/revops/references/lifecycle-definitions.md +278 -0
- package/modules/revops/references/routing-rules.md +203 -0
- package/modules/revops/references/scoring-models.md +247 -0
- package/modules/sales-enablement/SKILL.md +349 -0
- package/modules/sales-enablement/evals/evals.json +91 -0
- package/modules/sales-enablement/references/deck-frameworks.md +263 -0
- package/modules/sales-enablement/references/demo-scripts.md +355 -0
- package/modules/sales-enablement/references/objection-library.md +270 -0
- package/modules/sales-enablement/references/one-pager-templates.md +208 -0
- package/modules/schema-markup/SKILL.md +179 -0
- package/modules/schema-markup/evals/evals.json +87 -0
- package/modules/schema-markup/references/schema-examples.md +398 -0
- package/modules/security/SKILL.md +138 -0
- package/modules/seo-audit/SKILL.md +412 -0
- package/modules/seo-audit/evals/evals.json +136 -0
- package/modules/seo-audit/references/ai-writing-detection.md +200 -0
- package/modules/seo-audit/references/content-patterns.md +285 -0
- package/modules/seo-audit/references/platform-ranking-factors.md +152 -0
- package/modules/signup-flow-cro/SKILL.md +359 -0
- package/modules/signup-flow-cro/evals/evals.json +88 -0
- package/modules/site-architecture/SKILL.md +357 -0
- package/modules/site-architecture/evals/evals.json +88 -0
- package/modules/site-architecture/references/mermaid-templates.md +216 -0
- package/modules/site-architecture/references/navigation-patterns.md +305 -0
- package/modules/site-architecture/references/site-type-templates.md +293 -0
- package/modules/social-content/SKILL.md +278 -0
- package/modules/social-content/evals/evals.json +92 -0
- package/modules/social-content/references/platforms.md +170 -0
- package/modules/social-content/references/post-templates.md +177 -0
- package/modules/social-content/references/reverse-engineering.md +195 -0
- package/modules/spec/SKILL.md +81 -0
- package/modules/subagents/SKILL.md +123 -0
- package/modules/techdebt/SKILL.md +71 -0
- package/modules/terminal-setup/SKILL.md +49 -0
- package/modules/test/SKILL.md +493 -0
- package/modules/test/references/e2e-patterns.md +294 -0
- package/modules/update-claude-md/SKILL.md +52 -0
- package/modules/visual-system-architect/SKILL.md +53 -0
- package/package.json +44 -0
- package/plugins/plugins.json +43 -0
- package/shell/aliases.sh +24 -0
- package/shell/check-update.sh +212 -0
- package/templates/.env.example +199 -0
- package/templates/docker-compose.md +46 -0
- package/templates/node-frontend.md +56 -0
- package/templates/node-fullstack.md +59 -0
- package/templates/python-api.md +57 -0
- package/update.sh +231 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test
|
|
3
|
+
description: You are a senior test engineer. Auto-detect all test layers (unit, integration, frontend, backend, E2E/system), run them all, write more if coverage is below threshold, and loop until everything passes.
|
|
4
|
+
category: quality
|
|
5
|
+
tier: on-demand
|
|
6
|
+
slash_command: /test
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Test — Run All Tests: Unit → Integration → E2E
|
|
10
|
+
|
|
11
|
+
You are a senior test engineer. Auto-detect all test layers (unit, integration, frontend, backend, E2E/system), run them all, write more if coverage is below threshold, and loop until everything passes.
|
|
12
|
+
|
|
13
|
+
## Do NOT ask for permission. Do NOT stop until coverage is met.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Testing philosophy
|
|
18
|
+
|
|
19
|
+
**Prefer real implementations over mocks.**
|
|
20
|
+
|
|
21
|
+
| Layer | Environment | What to mock |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Unit | In-process only | External APIs that cannot run locally (Stripe, Firebase Auth, Resend, Twilio, cloud SDKs) |
|
|
24
|
+
| Integration | Real DB + real app via Docker | Only payment gateways and third-party external APIs |
|
|
25
|
+
| E2E / System | Full stack via `docker compose up` | Nothing — zero mocks |
|
|
26
|
+
|
|
27
|
+
**Never mock:** the database, internal services, business logic, utilities, or pure functions.
|
|
28
|
+
**Only mock:** services that are genuinely unreachable locally (payment processors, auth providers, email senders, external SaaS APIs).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## How to use
|
|
33
|
+
|
|
34
|
+
- `/test` — all layers for files changed since last commit
|
|
35
|
+
- `/test --all` — full pass across the entire codebase
|
|
36
|
+
- `/test <file>` — target a specific source file
|
|
37
|
+
- `/test --unit` — unit tests only
|
|
38
|
+
- `/test --integration` — integration tests only (spins up Docker services)
|
|
39
|
+
- `/test --e2e` — E2E/system tests only (full docker compose stack)
|
|
40
|
+
- `/test --e2e staging` — E2E against staging environment
|
|
41
|
+
- `/test --e2e prod` — E2E against production
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Coverage thresholds (unit + integration — not E2E)
|
|
46
|
+
|
|
47
|
+
These are **defaults, used only when the project does not declare its own.** Check first
|
|
48
|
+
and honor a project-declared threshold:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Project-declared thresholds win over the defaults below. Look, in order, at:
|
|
52
|
+
# - the instruction file (CLAUDE.md/AGENTS.md/…): a line like "coverage: lines 80, branches 70"
|
|
53
|
+
# - jest/vitest config: coverageThreshold.global.{lines,functions,statements,branches}
|
|
54
|
+
# - pyproject.toml / .coveragerc: [tool.coverage.report] fail_under
|
|
55
|
+
grep -hiE "coverage(Threshold)?|fail_under" CLAUDE.md AGENTS.md GEMINI.md jest.config.* vitest.config.* vite.config.* pyproject.toml .coveragerc 2>/dev/null | head
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Metric | Default threshold (override if the project declares one) |
|
|
59
|
+
|---|---|
|
|
60
|
+
| Lines | ≥ 95% |
|
|
61
|
+
| Functions | ≥ 95% |
|
|
62
|
+
| Statements | ≥ 95% |
|
|
63
|
+
| Branches | ≥ 90% |
|
|
64
|
+
|
|
65
|
+
**The coverage loop does not exit until ALL thresholds (project-declared or the defaults
|
|
66
|
+
above) are met AND zero unit/integration tests fail — or the iteration cap is reached
|
|
67
|
+
(see Phase 3).**
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Phase 0 — Docker test environment setup
|
|
72
|
+
|
|
73
|
+
Before running integration or E2E tests, check if Docker services are required and start them.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
PROJECT_ROOT=$(git rev-parse --show-toplevel)
|
|
77
|
+
cd "$PROJECT_ROOT"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Detect test service requirements
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Check for docker-compose test config
|
|
84
|
+
TEST_COMPOSE=""
|
|
85
|
+
for f in docker-compose.test.yml docker-compose.testing.yml docker-compose.yml compose.yml; do
|
|
86
|
+
[ -f "$PROJECT_ROOT/$f" ] && TEST_COMPOSE="$f" && break
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
# Check for service dependencies in pyproject.toml or package.json
|
|
90
|
+
grep -qE "postgres|redis|mysql|mongodb|elasticsearch" \
|
|
91
|
+
"$PROJECT_ROOT/pyproject.toml" \
|
|
92
|
+
"$PROJECT_ROOT/requirements*.txt" \
|
|
93
|
+
"$PROJECT_ROOT/package.json" \
|
|
94
|
+
"$PROJECT_ROOT/api/package.json" 2>/dev/null && NEEDS_SERVICES=true || NEEDS_SERVICES=false
|
|
95
|
+
|
|
96
|
+
echo "Test compose file: ${TEST_COMPOSE:-none}"
|
|
97
|
+
echo "Needs services: $NEEDS_SERVICES"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Start test services (if needed)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Auto-detect and start required services
|
|
104
|
+
TEST_COMPOSE=$(ls docker-compose.test.yml docker-compose.testing.yml docker-compose.yml compose.yml 2>/dev/null | head -1 || true)
|
|
105
|
+
NEEDS_SERVICES=$(grep -qE "postgres|redis|mysql|mongodb|elasticsearch" \
|
|
106
|
+
"$PROJECT_ROOT/pyproject.toml" "$PROJECT_ROOT/requirements"*.txt "$PROJECT_ROOT/package.json" 2>/dev/null && echo true || echo false)
|
|
107
|
+
|
|
108
|
+
if [ -n "$TEST_COMPOSE" ]; then
|
|
109
|
+
docker compose -f "$TEST_COMPOSE" up -d --wait 2>/dev/null || true
|
|
110
|
+
elif $NEEDS_SERVICES; then
|
|
111
|
+
# Match the version the project already declares — don't pin a version it doesn't use.
|
|
112
|
+
# Look in any compose file for the image tag; fall back to a current LTS only if absent.
|
|
113
|
+
PG_IMAGE=$(grep -hoE "postgres:[0-9.]+(-[a-z0-9]+)?" "$PROJECT_ROOT"/docker-compose*.y*ml "$PROJECT_ROOT"/compose*.y*ml 2>/dev/null | head -1)
|
|
114
|
+
REDIS_IMAGE=$(grep -hoE "redis:[0-9.]+(-[a-z0-9]+)?" "$PROJECT_ROOT"/docker-compose*.y*ml "$PROJECT_ROOT"/compose*.y*ml 2>/dev/null | head -1)
|
|
115
|
+
: "${PG_IMAGE:=postgres:16}"; : "${REDIS_IMAGE:=redis:7}" # defaults only when undeclared
|
|
116
|
+
docker run -d --name test-postgres \
|
|
117
|
+
-e POSTGRES_USER=test -e POSTGRES_PASSWORD=test -e POSTGRES_DB=test \
|
|
118
|
+
-p 5432:5432 "$PG_IMAGE" 2>/dev/null || true
|
|
119
|
+
grep -qE "redis" "$PROJECT_ROOT/package.json" "$PROJECT_ROOT/pyproject.toml" 2>/dev/null && \
|
|
120
|
+
docker run -d --name test-redis -p 6379:6379 "$REDIS_IMAGE" 2>/dev/null || true
|
|
121
|
+
sleep 3 && docker exec test-postgres pg_isready -U test 2>/dev/null || sleep 3
|
|
122
|
+
fi
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Run migrations against test DB:**
|
|
126
|
+
```bash
|
|
127
|
+
# Django
|
|
128
|
+
[ -f manage.py ] && ./venv/bin/python manage.py migrate --settings=config.settings.test 2>/dev/null || true
|
|
129
|
+
# Alembic
|
|
130
|
+
[ -f alembic.ini ] && ./venv/bin/alembic upgrade head 2>/dev/null || true
|
|
131
|
+
# Prisma
|
|
132
|
+
[ -f prisma/schema.prisma ] && npx prisma migrate deploy 2>/dev/null || true
|
|
133
|
+
# Custom
|
|
134
|
+
[ -f scripts/migrate.sh ] && bash scripts/migrate.sh 2>/dev/null || true
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Verify services are healthy before proceeding:**
|
|
138
|
+
```bash
|
|
139
|
+
docker compose ps 2>/dev/null || docker ps --filter "name=test-" 2>/dev/null
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**GATE: Required services must be running before integration or E2E tests.**
|
|
143
|
+
|
|
144
|
+
### Cleanup (run after all tests complete)
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Stop test compose
|
|
148
|
+
[ -n "$TEST_COMPOSE" ] && docker compose -f "$TEST_COMPOSE" down -v 2>/dev/null || true
|
|
149
|
+
# Stop standalone containers
|
|
150
|
+
docker rm -f test-postgres test-redis 2>/dev/null || true
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Step 1 — Detect test stack
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
ls package.json api/package.json requirements.txt pyproject.toml 2>/dev/null
|
|
159
|
+
cat package.json 2>/dev/null | grep -E '"vitest"|"jest"' || true
|
|
160
|
+
cat api/package.json 2>/dev/null | grep '"jest"' || true
|
|
161
|
+
ls e2e/ tests/e2e/ playwright.config.* e2e/playwright.config.* 2>/dev/null || true
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Determine which layers apply:
|
|
165
|
+
- **Frontend unit/integration (Vitest)**: root `package.json` has `vitest`
|
|
166
|
+
- **Backend unit/integration (Jest)**: `api/package.json` has `jest`
|
|
167
|
+
- **Python unit/integration (pytest)**: `pyproject.toml` or `requirements.txt` present
|
|
168
|
+
- **E2E/System (Playwright)**: `playwright.config.*` found anywhere
|
|
169
|
+
- **E2E/System (pytest)**: `tests/e2e/` directory found in Python project
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Phase 1 — Unit Tests
|
|
174
|
+
|
|
175
|
+
Run smallest-scope tests first to get fast feedback.
|
|
176
|
+
|
|
177
|
+
The detected unit layers (**Frontend Vitest / Backend Jest / Python pytest**) are
|
|
178
|
+
independent — they run in separate processes and share no state — so **fan them out** per
|
|
179
|
+
the `subagents` skill ladder (Workflow tool → parallel subagents → serial fallback)
|
|
180
|
+
instead of running them one after another. Each layer returns
|
|
181
|
+
`{ layer, status, passed, failed, coverage }`; the parent collects them. This is safe
|
|
182
|
+
*before* Phase 2 only — the integration phase shares one Docker DB and stays serial.
|
|
183
|
+
|
|
184
|
+
### Frontend unit (Vitest):
|
|
185
|
+
```bash
|
|
186
|
+
cd "$PROJECT_ROOT"
|
|
187
|
+
npm run test:unit 2>&1
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Backend unit (Jest):
|
|
191
|
+
```bash
|
|
192
|
+
cd "$PROJECT_ROOT/api"
|
|
193
|
+
npm run test:unit 2>&1
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Python unit (pytest):
|
|
197
|
+
```bash
|
|
198
|
+
cd "$PROJECT_ROOT"
|
|
199
|
+
./venv/bin/python -m pytest tests/unit/ -v --tb=short -q
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Test patterns:**
|
|
203
|
+
- Pure functions, hooks, utilities, lib modules
|
|
204
|
+
- Every code path: success, error, edge cases, empty input, boundary values
|
|
205
|
+
- Mock ONLY genuinely unreachable external services: Stripe, Firebase Auth, Resend, Twilio, AWS SES
|
|
206
|
+
- Do NOT mock the database — unit tests that need DB state should use the real test DB started in Phase 0
|
|
207
|
+
- Do NOT mock internal services, business logic, or utilities
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Phase 2 — Integration Tests
|
|
212
|
+
|
|
213
|
+
Run against real services started in Phase 0. No mocking of internal infrastructure.
|
|
214
|
+
|
|
215
|
+
### Frontend integration (Vitest):
|
|
216
|
+
```bash
|
|
217
|
+
cd "$PROJECT_ROOT"
|
|
218
|
+
npm run test:integration 2>&1
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Backend integration (Jest + supertest):
|
|
222
|
+
```bash
|
|
223
|
+
cd "$PROJECT_ROOT/api"
|
|
224
|
+
# Set test DB URL — real Docker DB from Phase 0
|
|
225
|
+
DATABASE_URL="${TEST_DATABASE_URL:-postgresql://test:test@localhost:5432/test}" \
|
|
226
|
+
REDIS_URL="${TEST_REDIS_URL:-redis://localhost:6379}" \
|
|
227
|
+
npm run test:integration 2>&1
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Python integration (pytest):
|
|
231
|
+
```bash
|
|
232
|
+
cd "$PROJECT_ROOT"
|
|
233
|
+
DATABASE_URL="${TEST_DATABASE_URL:-postgresql+asyncpg://test:test@localhost:5432/test}" \
|
|
234
|
+
REDIS_URL="${TEST_REDIS_URL:-redis://localhost:6379}" \
|
|
235
|
+
./venv/bin/python -m pytest tests/integration/ -v --tb=short -q
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Test patterns:**
|
|
239
|
+
- Full HTTP request → response through the real app against a real DB
|
|
240
|
+
- Multi-component flows, context providers, routing, auth state
|
|
241
|
+
- Real DB reads and writes — assert actual persisted state, not mock return values
|
|
242
|
+
- Mock ONLY payment gateways (Stripe) and third-party external APIs (email providers, SMS)
|
|
243
|
+
- Do NOT mock: your own DB, Redis, internal queues, internal services
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Phase 3 — Coverage loop (unit + integration)
|
|
248
|
+
|
|
249
|
+
Run coverage for all detected stacks and loop until thresholds are met:
|
|
250
|
+
|
|
251
|
+
### Vitest (frontend):
|
|
252
|
+
```bash
|
|
253
|
+
cd "$PROJECT_ROOT"
|
|
254
|
+
npm run test:coverage 2>&1
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Jest (backend):
|
|
258
|
+
```bash
|
|
259
|
+
cd "$PROJECT_ROOT/api"
|
|
260
|
+
DATABASE_URL="${TEST_DATABASE_URL:-postgresql://test:test@localhost:5432/test}" \
|
|
261
|
+
npm run test:coverage 2>&1
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### pytest (Python):
|
|
265
|
+
```bash
|
|
266
|
+
cd "$PROJECT_ROOT"
|
|
267
|
+
DATABASE_URL="${TEST_DATABASE_URL:-postgresql+asyncpg://test:test@localhost:5432/test}" \
|
|
268
|
+
./venv/bin/python -m pytest tests/unit/ tests/integration/ --cov=. --cov-report=term-missing -q
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Loop logic (bounded — never spin forever):**
|
|
272
|
+
1. Parse coverage output — find files below threshold, find failing tests
|
|
273
|
+
2. If all thresholds met AND zero failures → **exit loop ✅**
|
|
274
|
+
3. Otherwise, if fewer than **MAX_ITERATIONS (default 6)** iterations have run:
|
|
275
|
+
- For each uncovered file: read it, write tests targeting uncovered lines/branches
|
|
276
|
+
- For each failing test: fix the test or the underlying code
|
|
277
|
+
- Re-run from top of loop
|
|
278
|
+
4. **If the cap is reached without converging → STOP and escalate.** Report the remaining
|
|
279
|
+
gap (which files/metrics are short, which tests still fail) and ask the user whether to
|
|
280
|
+
keep going, lower a threshold, or investigate a stuck test. Do not loop indefinitely on
|
|
281
|
+
an unreachable target (e.g. coverage blocked by an untestable external dependency).
|
|
282
|
+
|
|
283
|
+
**Rules inside the loop:**
|
|
284
|
+
- Read the source file before writing tests — understand all code paths
|
|
285
|
+
- Test ALL paths: success, error, edge cases, auth failures, DB errors, empty state
|
|
286
|
+
- Write integration tests that assert real DB state — not mock return values
|
|
287
|
+
- Never skip, xfail, or comment-out failing tests — fix the code or the test
|
|
288
|
+
- Each iteration targets the files with lowest coverage first
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Phase 4 — E2E / System Tests (Docker full-stack)
|
|
293
|
+
|
|
294
|
+
Run after unit + integration pass. Spins up the complete application stack via Docker and runs real browser or API tests against it. **Zero mocks.**
|
|
295
|
+
|
|
296
|
+
### 4a. Split Playwright configs
|
|
297
|
+
|
|
298
|
+
Use **two separate Playwright config files** — one for component/browser-unit tests that don't need the full stack, and one for true E2E against docker compose:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
playwright.config.ts ← component tests (no server required)
|
|
302
|
+
playwright.e2e.config.ts ← full-stack E2E (requires docker compose)
|
|
303
|
+
e2e/
|
|
304
|
+
fixtures/
|
|
305
|
+
auth.ts ← real auth fixture (creates user, gets JWT)
|
|
306
|
+
api.ts ← API helper (authenticated HTTP client)
|
|
307
|
+
smoke/
|
|
308
|
+
health.spec.ts ← health + smoke tests
|
|
309
|
+
auth/
|
|
310
|
+
login.spec.ts ← real browser login flow
|
|
311
|
+
agents/
|
|
312
|
+
crud.spec.ts ← real CRUD tests via browser
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**`playwright.config.ts`** (component tests — no docker required):
|
|
316
|
+
```typescript
|
|
317
|
+
import { defineConfig } from '@playwright/test'
|
|
318
|
+
|
|
319
|
+
export default defineConfig({
|
|
320
|
+
testDir: './src',
|
|
321
|
+
testMatch: '**/*.spec.ts',
|
|
322
|
+
use: { baseURL: 'http://localhost:5173' },
|
|
323
|
+
webServer: {
|
|
324
|
+
command: 'npm run dev',
|
|
325
|
+
port: 5173,
|
|
326
|
+
reuseExistingServer: !process.env.CI,
|
|
327
|
+
},
|
|
328
|
+
})
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**`playwright.e2e.config.ts`** (full-stack E2E — requires `docker compose up`):
|
|
332
|
+
```typescript
|
|
333
|
+
import { defineConfig } from '@playwright/test'
|
|
334
|
+
|
|
335
|
+
export default defineConfig({
|
|
336
|
+
testDir: './e2e',
|
|
337
|
+
testMatch: '**/*.spec.ts',
|
|
338
|
+
timeout: 60_000,
|
|
339
|
+
retries: process.env.CI ? 2 : 0,
|
|
340
|
+
reporter: [['html', { open: 'never' }], ['list']],
|
|
341
|
+
use: {
|
|
342
|
+
baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
|
|
343
|
+
trace: 'retain-on-failure',
|
|
344
|
+
screenshot: 'only-on-failure',
|
|
345
|
+
video: 'retain-on-failure',
|
|
346
|
+
},
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 4b. Docker Compose E2E override file
|
|
351
|
+
|
|
352
|
+
Create `docker-compose.e2e.yml` to override production compose settings for E2E testing (seed data, test credentials, exposed ports):
|
|
353
|
+
|
|
354
|
+
```yaml
|
|
355
|
+
# docker-compose.e2e.yml
|
|
356
|
+
# Extend your base docker-compose.yml for E2E tests
|
|
357
|
+
# Usage: docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d
|
|
358
|
+
|
|
359
|
+
services:
|
|
360
|
+
api:
|
|
361
|
+
environment:
|
|
362
|
+
- NODE_ENV=test
|
|
363
|
+
- DATABASE_URL=postgresql://test:test@db:5432/testdb
|
|
364
|
+
- REDIS_URL=redis://redis:6379
|
|
365
|
+
- JWT_SECRET=e2e-test-secret-not-for-production
|
|
366
|
+
- SEED_TEST_DATA=true # trigger seed on startup
|
|
367
|
+
ports:
|
|
368
|
+
- "8000:8000"
|
|
369
|
+
|
|
370
|
+
web:
|
|
371
|
+
environment:
|
|
372
|
+
- VITE_API_URL=http://localhost:8000
|
|
373
|
+
ports:
|
|
374
|
+
- "3000:3000"
|
|
375
|
+
|
|
376
|
+
db:
|
|
377
|
+
image: postgres:16 # match your base docker-compose.yml version — don't drift the test DB
|
|
378
|
+
environment:
|
|
379
|
+
POSTGRES_USER: test
|
|
380
|
+
POSTGRES_PASSWORD: test
|
|
381
|
+
POSTGRES_DB: testdb
|
|
382
|
+
ports:
|
|
383
|
+
- "5432:5432"
|
|
384
|
+
tmpfs:
|
|
385
|
+
- /var/lib/postgresql/data # ephemeral — fast, discarded after tests
|
|
386
|
+
|
|
387
|
+
redis:
|
|
388
|
+
image: redis:7 # match your base docker-compose.yml version
|
|
389
|
+
ports:
|
|
390
|
+
- "6379:6379"
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Detection and start:**
|
|
394
|
+
```bash
|
|
395
|
+
cd "$PROJECT_ROOT"
|
|
396
|
+
|
|
397
|
+
# Prefer e2e override, fall back to test compose, fall back to main
|
|
398
|
+
if [ -f docker-compose.e2e.yml ] && [ -f docker-compose.yml ]; then
|
|
399
|
+
COMPOSE_CMD="docker compose -f docker-compose.yml -f docker-compose.e2e.yml"
|
|
400
|
+
echo "Starting E2E stack with override: docker-compose.e2e.yml"
|
|
401
|
+
elif [ -f docker-compose.test.yml ]; then
|
|
402
|
+
COMPOSE_CMD="docker compose -f docker-compose.test.yml"
|
|
403
|
+
else
|
|
404
|
+
COMPOSE_CMD="docker compose"
|
|
405
|
+
fi
|
|
406
|
+
|
|
407
|
+
$COMPOSE_CMD up -d --build --wait
|
|
408
|
+
$COMPOSE_CMD ps
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### 4c–4g. Fixtures, smoke tests, auth E2E, CRUD E2E, running
|
|
412
|
+
|
|
413
|
+
See **[references/e2e-patterns.md](references/e2e-patterns.md)** for complete templates:
|
|
414
|
+
- API helper + real auth fixture
|
|
415
|
+
- Docker Compose E2E override file
|
|
416
|
+
- Smoke / health tests
|
|
417
|
+
- Real auth browser flows
|
|
418
|
+
- Real CRUD tests (browser → API → DB assertion)
|
|
419
|
+
- How to start the full stack and run in order
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## When writing new tests
|
|
424
|
+
|
|
425
|
+
### Integration test — Python example (real DB, no mocks):
|
|
426
|
+
```python
|
|
427
|
+
import pytest
|
|
428
|
+
import httpx
|
|
429
|
+
|
|
430
|
+
@pytest.mark.asyncio
|
|
431
|
+
async def test_create_agent_persists(async_client: httpx.AsyncClient, db_session):
|
|
432
|
+
# Act — call real API against real test DB
|
|
433
|
+
response = await async_client.post("/api/agents", json={"name": "test-agent"})
|
|
434
|
+
assert response.status_code == 201
|
|
435
|
+
agent_id = response.json()["id"]
|
|
436
|
+
|
|
437
|
+
# Assert — verify it actually persisted in the real DB
|
|
438
|
+
row = await db_session.execute("SELECT name FROM agents WHERE id = $1", agent_id)
|
|
439
|
+
assert row["name"] == "test-agent"
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Integration test — JS/TS example (real DB via supertest):
|
|
443
|
+
```typescript
|
|
444
|
+
it("POST /agents persists to database", async () => {
|
|
445
|
+
const res = await request(app).post("/agents").send({ name: "test-agent" })
|
|
446
|
+
expect(res.status).toBe(201)
|
|
447
|
+
|
|
448
|
+
// Assert real DB state — not a mock return value
|
|
449
|
+
const row = await db.query("SELECT name FROM agents WHERE id = $1", [res.body.id])
|
|
450
|
+
expect(row.rows[0].name).toBe("test-agent")
|
|
451
|
+
})
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Unit test — mock only external APIs:
|
|
455
|
+
```python
|
|
456
|
+
# ✅ Correct: mock only the external payment API
|
|
457
|
+
async def test_create_subscription(monkeypatch):
|
|
458
|
+
monkeypatch.setattr("stripe.Subscription.create", AsyncMock(return_value={"id": "sub_test"}))
|
|
459
|
+
result = await billing_service.create_subscription(user_id=1, plan="pro")
|
|
460
|
+
assert result.stripe_subscription_id == "sub_test"
|
|
461
|
+
|
|
462
|
+
# ❌ Wrong: don't mock the DB
|
|
463
|
+
async def test_create_subscription(monkeypatch):
|
|
464
|
+
monkeypatch.setattr("db.session.add", MagicMock()) # Never do this
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Output at each coverage iteration
|
|
470
|
+
|
|
471
|
+
```
|
|
472
|
+
=== Test Iteration N ===
|
|
473
|
+
Frontend: lines X% | functions X% | branches X%
|
|
474
|
+
Backend: lines X% | functions X% | branches X%
|
|
475
|
+
Python: lines X% | functions X% | branches X%
|
|
476
|
+
Failing: N tests
|
|
477
|
+
Action: [what's being written / fixed]
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Final output
|
|
481
|
+
|
|
482
|
+
```
|
|
483
|
+
=== /test Complete ===
|
|
484
|
+
Docker env: ✅ services running | skipped (not needed)
|
|
485
|
+
Unit: ✅ X passed
|
|
486
|
+
Integration: ✅ X passed (real DB)
|
|
487
|
+
Frontend: lines ✅ X% | functions ✅ X% | branches ✅ X%
|
|
488
|
+
Backend: lines ✅ X% | functions ✅ X% | branches ✅ X%
|
|
489
|
+
E2E: ✅ X passed (full-stack Docker) | ⚠️ X failed (non-blocking) | skipped
|
|
490
|
+
Failures: 0 ✅
|
|
491
|
+
New files: [list]
|
|
492
|
+
Status: COVERAGE MET ✅
|
|
493
|
+
```
|