claude-mpm 4.15.6__py3-none-any.whl → 4.21.3__py3-none-any.whl
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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +272 -23
- claude_mpm/agents/PM_INSTRUCTIONS.md +49 -0
- claude_mpm/agents/agent_loader.py +4 -4
- claude_mpm/agents/templates/engineer.json +5 -1
- claude_mpm/agents/templates/php-engineer.json +10 -4
- claude_mpm/agents/templates/python_engineer.json +8 -3
- claude_mpm/agents/templates/rust_engineer.json +12 -7
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +525 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +67 -1
- claude_mpm/cli/commands/skills.py +488 -0
- claude_mpm/cli/executor.py +2 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
- claude_mpm/cli/parsers/skills_parser.py +137 -0
- claude_mpm/cli/startup.py +57 -0
- claude_mpm/commands/mpm-auto-configure.md +52 -0
- claude_mpm/commands/mpm-help.md +6 -0
- claude_mpm/commands/mpm-init.md +112 -6
- claude_mpm/commands/mpm-resume.md +372 -0
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +2 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/constants.py +12 -0
- claude_mpm/core/config.py +42 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/hooks/__init__.py +8 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/recommender.py +47 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +87 -0
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +372 -0
- claude_mpm/services/core/base.py +26 -11
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/models/agent_config.py +3 -0
- claude_mpm/services/core/models/process.py +4 -0
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/models.py +21 -0
- claude_mpm/services/event_bus/relay.py +23 -7
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +2 -0
- claude_mpm/services/mcp_config_manager.py +7 -131
- claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
- claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
- claude_mpm/services/memory/failure_tracker.py +19 -4
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/unified/deployment_strategies/local.py +1 -1
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/agent_skills_injector.py +324 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +97 -9
- claude_mpm/skills/skills_registry.py +348 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/METADATA +211 -33
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/RECORD +206 -64
- claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
- claude_mpm/cli/commands/mpm_init.py +0 -2008
- claude_mpm/tools/code_tree_analyzer.py +0 -1825
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
# Detection Guide: Identifying Testing Anti-Patterns
|
|
2
|
+
|
|
3
|
+
Comprehensive guide for detecting testing anti-patterns before they cause problems. Includes red flags, warning signs, gate functions, and diagnostic checklists.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Prevention is easier than cure. This guide helps you identify anti-patterns during code review, test writing, or debugging test failures.
|
|
8
|
+
|
|
9
|
+
## Universal Detection Checklist
|
|
10
|
+
|
|
11
|
+
Run before committing any test:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
□ Am I asserting on mock elements? (testId='*-mock')
|
|
15
|
+
→ If yes: STOP - Test real component or unmock
|
|
16
|
+
|
|
17
|
+
□ Does this method only exist for tests?
|
|
18
|
+
→ If yes: STOP - Move to test utilities
|
|
19
|
+
|
|
20
|
+
□ Do I fully understand what I'm mocking?
|
|
21
|
+
→ If no: STOP - Run with real impl first, then mock minimally
|
|
22
|
+
|
|
23
|
+
□ Is my mock missing fields the real API has?
|
|
24
|
+
→ If yes: STOP - Mirror complete API structure
|
|
25
|
+
|
|
26
|
+
□ Did I write implementation before test?
|
|
27
|
+
→ If yes: STOP - Delete impl, write test first (TDD)
|
|
28
|
+
|
|
29
|
+
□ Is mock setup >50% of test code?
|
|
30
|
+
→ If yes: Consider integration test with real components
|
|
31
|
+
|
|
32
|
+
□ Can I explain what real behavior this test verifies?
|
|
33
|
+
→ If no: STOP - Clarify what you're testing
|
|
34
|
+
|
|
35
|
+
□ Would this test fail if I removed mocks?
|
|
36
|
+
→ If no: You're testing mock behavior
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Anti-Pattern 1: Testing Mock Behavior
|
|
40
|
+
|
|
41
|
+
### Red Flags
|
|
42
|
+
|
|
43
|
+
**Code indicators:**
|
|
44
|
+
```typescript
|
|
45
|
+
// 🚩 Test ID contains "mock"
|
|
46
|
+
expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument();
|
|
47
|
+
|
|
48
|
+
// 🚩 Asserting mock was called
|
|
49
|
+
expect(mockFunction).toHaveBeenCalled();
|
|
50
|
+
|
|
51
|
+
// 🚩 Checking mock return values
|
|
52
|
+
expect(result).toBe(mockReturnValue);
|
|
53
|
+
|
|
54
|
+
// 🚩 Test fails when mock removed
|
|
55
|
+
// Remove mock → test fails → you're testing mock
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Language patterns:**
|
|
59
|
+
- "Make sure the mock..."
|
|
60
|
+
- "Test that component renders mock"
|
|
61
|
+
- "Verify mock is present"
|
|
62
|
+
- "Check if mock function called"
|
|
63
|
+
|
|
64
|
+
**Diagnostic questions:**
|
|
65
|
+
1. **"If I remove this mock, does test still make sense?"**
|
|
66
|
+
- No → You're testing mock behavior
|
|
67
|
+
- Yes → Good, test tests real behavior
|
|
68
|
+
|
|
69
|
+
2. **"What production behavior does this verify?"**
|
|
70
|
+
- Can't answer → Testing mock behavior
|
|
71
|
+
- Clear answer → Good
|
|
72
|
+
|
|
73
|
+
3. **"Would this test catch real bugs?"**
|
|
74
|
+
- No → Testing mock behavior
|
|
75
|
+
- Yes → Good
|
|
76
|
+
|
|
77
|
+
### Detection Script
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Run this check on your tests
|
|
81
|
+
function detectsMockTesting(testFile: string): string[] {
|
|
82
|
+
const warnings: string[] = [];
|
|
83
|
+
|
|
84
|
+
// Pattern: testId with 'mock'
|
|
85
|
+
if (testFile.includes("getByTestId('") && testFile.includes('-mock')) {
|
|
86
|
+
warnings.push('Testing mock element by test ID');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Pattern: expecting on mock objects
|
|
90
|
+
if (testFile.includes('expect(mock') && testFile.includes('toBe')) {
|
|
91
|
+
warnings.push('Asserting on mock values');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Pattern: mock call assertions without behavior check
|
|
95
|
+
if (testFile.includes('toHaveBeenCalled') &&
|
|
96
|
+
!testFile.includes('expect(result)')) {
|
|
97
|
+
warnings.push('Only checking mock calls, not results');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return warnings;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Anti-Pattern 2: Test-Only Methods in Production
|
|
105
|
+
|
|
106
|
+
### Red Flags
|
|
107
|
+
|
|
108
|
+
**Code indicators:**
|
|
109
|
+
```typescript
|
|
110
|
+
// 🚩 Method only called in test files
|
|
111
|
+
// Search: "destroy(" → Only in *.test.ts files
|
|
112
|
+
|
|
113
|
+
// 🚩 Method names suggesting test use
|
|
114
|
+
class Session {
|
|
115
|
+
reset() // 🚩
|
|
116
|
+
destroy() // 🚩
|
|
117
|
+
clear() // 🚩
|
|
118
|
+
mock() // 🚩
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 🚩 Comments acknowledging test-only use
|
|
122
|
+
// "For testing only"
|
|
123
|
+
// "Used by test cleanup"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**File analysis:**
|
|
127
|
+
```bash
|
|
128
|
+
# Find methods only called in tests
|
|
129
|
+
grep -r "\.destroy\(" --include="*.ts" | grep -v ".test.ts"
|
|
130
|
+
# If empty → method only in tests → move to test utils
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Diagnostic questions:**
|
|
134
|
+
1. **"Is this method called outside test files?"**
|
|
135
|
+
- No → Test-only method, move to utilities
|
|
136
|
+
- Yes → Keep in production
|
|
137
|
+
|
|
138
|
+
2. **"Would production code ever need this?"**
|
|
139
|
+
- No → Move to test utilities
|
|
140
|
+
- Yes → Keep in production
|
|
141
|
+
|
|
142
|
+
3. **"Does this class own this resource's lifecycle?"**
|
|
143
|
+
- No → Wrong place for this method
|
|
144
|
+
- Yes → Consider if needed in production
|
|
145
|
+
|
|
146
|
+
### Detection Script
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Analyze method usage
|
|
150
|
+
function findTestOnlyMethods(codebase: string[]): Report {
|
|
151
|
+
const methods = extractMethods(codebase);
|
|
152
|
+
|
|
153
|
+
return methods.filter(method => {
|
|
154
|
+
const usages = findUsages(method);
|
|
155
|
+
const testUsages = usages.filter(u => u.file.includes('.test.'));
|
|
156
|
+
const prodUsages = usages.filter(u => !u.file.includes('.test.'));
|
|
157
|
+
|
|
158
|
+
return testUsages.length > 0 && prodUsages.length === 0;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Anti-Pattern 3: Mocking Without Understanding
|
|
164
|
+
|
|
165
|
+
### Red Flags
|
|
166
|
+
|
|
167
|
+
**Code indicators:**
|
|
168
|
+
```typescript
|
|
169
|
+
// 🚩 Mocking without reading implementation
|
|
170
|
+
vi.mock('SomeModule'); // What does it do? Unknown.
|
|
171
|
+
|
|
172
|
+
// 🚩 "Just to be safe" mocking
|
|
173
|
+
// Mock everything, understand nothing
|
|
174
|
+
|
|
175
|
+
// 🚩 Test mysteriously fails/passes
|
|
176
|
+
// You can't explain why
|
|
177
|
+
|
|
178
|
+
// 🚩 Mock prevents test logic from working
|
|
179
|
+
vi.mock('UserService'); // Breaks user creation test needs
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Language patterns:**
|
|
183
|
+
- "I'll mock this to be safe"
|
|
184
|
+
- "This might be slow"
|
|
185
|
+
- "Let's mock everything"
|
|
186
|
+
- "Not sure why test fails"
|
|
187
|
+
|
|
188
|
+
**Diagnostic questions:**
|
|
189
|
+
1. **"What side effects does the real method have?"**
|
|
190
|
+
- Can't answer → Don't mock yet
|
|
191
|
+
- Know all effects → Can mock safely
|
|
192
|
+
|
|
193
|
+
2. **"Does my test depend on any of those side effects?"**
|
|
194
|
+
- Yes → Don't mock at this level
|
|
195
|
+
- No → Safe to mock
|
|
196
|
+
|
|
197
|
+
3. **"Where is the actual slow/external operation?"**
|
|
198
|
+
- Unclear → Study code first
|
|
199
|
+
- Clear → Mock at that level
|
|
200
|
+
|
|
201
|
+
### Detection Strategy
|
|
202
|
+
|
|
203
|
+
**Before mocking:**
|
|
204
|
+
```
|
|
205
|
+
1. Read the implementation
|
|
206
|
+
- What does it do?
|
|
207
|
+
- What are side effects?
|
|
208
|
+
- What does it return?
|
|
209
|
+
|
|
210
|
+
2. Run test with real implementation
|
|
211
|
+
- How slow is it? (measure!)
|
|
212
|
+
- What behavior occurs?
|
|
213
|
+
- What's actually needed?
|
|
214
|
+
|
|
215
|
+
3. Identify minimal mock point
|
|
216
|
+
- Where is the slow/external operation?
|
|
217
|
+
- Can I mock below this level?
|
|
218
|
+
- What behavior must be preserved?
|
|
219
|
+
|
|
220
|
+
4. Mock at correct level
|
|
221
|
+
- Mock boundary of slow operation
|
|
222
|
+
- Preserve logic test depends on
|
|
223
|
+
- Verify test still tests intended behavior
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Speed Measurement
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Measure before mocking
|
|
230
|
+
test('user registration', async () => {
|
|
231
|
+
const start = performance.now();
|
|
232
|
+
await registerUser(userData);
|
|
233
|
+
const duration = performance.now() - start;
|
|
234
|
+
|
|
235
|
+
console.log(`Test took ${duration}ms`);
|
|
236
|
+
// If <100ms → Don't mock
|
|
237
|
+
// If >1000ms → Identify slow part
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Anti-Pattern 4: Incomplete Mocks
|
|
242
|
+
|
|
243
|
+
### Red Flags
|
|
244
|
+
|
|
245
|
+
**Code indicators:**
|
|
246
|
+
```typescript
|
|
247
|
+
// 🚩 Mock created from memory
|
|
248
|
+
const mock = { id: '123' }; // What other fields exist?
|
|
249
|
+
|
|
250
|
+
// 🚩 Partial type annotation
|
|
251
|
+
const mock: Partial<User> = { id: '123' };
|
|
252
|
+
|
|
253
|
+
// 🚩 Different tests, different mock shapes
|
|
254
|
+
// test1.ts: { id, name }
|
|
255
|
+
// test2.ts: { id, name, email, profile }
|
|
256
|
+
|
|
257
|
+
// 🚩 Comment acknowledging incompleteness
|
|
258
|
+
// "TODO: add more fields"
|
|
259
|
+
// "Add fields as needed"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Missing documentation:**
|
|
263
|
+
- No reference to API docs
|
|
264
|
+
- No TypeScript interface
|
|
265
|
+
- No factory function
|
|
266
|
+
- Copy-pasted mock variations
|
|
267
|
+
|
|
268
|
+
**Diagnostic questions:**
|
|
269
|
+
1. **"What does the real API return?"**
|
|
270
|
+
- Can't answer → Check docs before mocking
|
|
271
|
+
- Know structure → Use it in mock
|
|
272
|
+
|
|
273
|
+
2. **"Am I using TypeScript types?"**
|
|
274
|
+
- No → Add types to enforce completeness
|
|
275
|
+
- Yes → Good
|
|
276
|
+
|
|
277
|
+
3. **"Do other tests mock this differently?"**
|
|
278
|
+
- Yes → Inconsistent mocks, need factory
|
|
279
|
+
- No → Good
|
|
280
|
+
|
|
281
|
+
### Detection Script
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
// Find incomplete mocks
|
|
285
|
+
function detectIncompleteMocks(testFile: string): Warning[] {
|
|
286
|
+
const warnings: Warning[] = [];
|
|
287
|
+
|
|
288
|
+
// Pattern: Partial<T> in test
|
|
289
|
+
if (testFile.includes('Partial<') && testFile.includes('mock')) {
|
|
290
|
+
warnings.push('Using Partial type for mock - likely incomplete');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Pattern: Object literals without types
|
|
294
|
+
const mockPattern = /const mock\w+ = \{[^}]+\};/g;
|
|
295
|
+
const mocks = testFile.match(mockPattern);
|
|
296
|
+
|
|
297
|
+
if (mocks) {
|
|
298
|
+
mocks.forEach(mock => {
|
|
299
|
+
if (!mock.includes(': ')) { // No type annotation
|
|
300
|
+
warnings.push('Mock without type annotation');
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return warnings;
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Completeness Checklist
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
□ Referenced API documentation
|
|
313
|
+
□ Used TypeScript interface/type
|
|
314
|
+
□ Included all required fields
|
|
315
|
+
□ Included optional fields (as null/undefined)
|
|
316
|
+
□ Nested objects complete
|
|
317
|
+
□ Arrays have realistic length/content
|
|
318
|
+
□ Metadata fields included
|
|
319
|
+
□ Timestamps/IDs present
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Anti-Pattern 5: Tests as Afterthought
|
|
323
|
+
|
|
324
|
+
### Red Flags
|
|
325
|
+
|
|
326
|
+
**Process indicators:**
|
|
327
|
+
```
|
|
328
|
+
🚩 PR has implementation commits, then "add tests" commit
|
|
329
|
+
🚩 "Ready for testing" status on untested feature
|
|
330
|
+
🚩 Test coverage added after code review
|
|
331
|
+
🚩 Tests written to pass, not fail first
|
|
332
|
+
🚩 Implementation complete, tests pending
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Language patterns:**
|
|
336
|
+
- "I'll add tests next"
|
|
337
|
+
- "Implementation done, needs tests"
|
|
338
|
+
- "Ready for testing phase"
|
|
339
|
+
- "Tests coming soon"
|
|
340
|
+
|
|
341
|
+
**Code indicators:**
|
|
342
|
+
```typescript
|
|
343
|
+
// 🚩 Tests that can't fail
|
|
344
|
+
test('feature works', () => {
|
|
345
|
+
const result = newFeature();
|
|
346
|
+
expect(result).toBe(result); // Always passes
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// 🚩 Tests with no assertions
|
|
350
|
+
test('feature runs', () => {
|
|
351
|
+
newFeature(); // No expect()
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Diagnostic questions:**
|
|
356
|
+
1. **"Did I write test before implementation?"**
|
|
357
|
+
- No → Not following TDD
|
|
358
|
+
- Yes → Good
|
|
359
|
+
|
|
360
|
+
2. **"Did I watch test fail first?"**
|
|
361
|
+
- No → Can't verify test works
|
|
362
|
+
- Yes → Good
|
|
363
|
+
|
|
364
|
+
3. **"Are there commits without tests?"**
|
|
365
|
+
- Yes → Tests afterthought
|
|
366
|
+
- No → Good
|
|
367
|
+
|
|
368
|
+
### Git History Analysis
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Check if tests come after implementation
|
|
372
|
+
git log --oneline --name-only | grep -A5 "feature"
|
|
373
|
+
|
|
374
|
+
# Red flag pattern:
|
|
375
|
+
# abc123 Add feature X
|
|
376
|
+
# src/feature.ts
|
|
377
|
+
# def456 Add tests for feature X ← Tests after
|
|
378
|
+
# src/feature.test.ts
|
|
379
|
+
|
|
380
|
+
# Good pattern:
|
|
381
|
+
# abc123 Add feature X with tests
|
|
382
|
+
# src/feature.test.ts ← Test file in same commit
|
|
383
|
+
# src/feature.ts
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Warning Signs: When Mocks Become Too Complex
|
|
387
|
+
|
|
388
|
+
### Complexity Indicators
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// 🚩 Mock setup longer than test
|
|
392
|
+
const setup = 50 lines;
|
|
393
|
+
const test = 10 lines;
|
|
394
|
+
// Ratio > 3:1 → Too complex
|
|
395
|
+
|
|
396
|
+
// 🚩 Mocking everything
|
|
397
|
+
vi.mock('ModuleA');
|
|
398
|
+
vi.mock('ModuleB');
|
|
399
|
+
vi.mock('ModuleC');
|
|
400
|
+
vi.mock('ModuleD');
|
|
401
|
+
// 4+ mocks → Consider integration test
|
|
402
|
+
|
|
403
|
+
// 🚩 Nested mock setup
|
|
404
|
+
const mockA = { mock: mockB };
|
|
405
|
+
const mockB = { mock: mockC };
|
|
406
|
+
const mockC = { /* ... */ };
|
|
407
|
+
|
|
408
|
+
// 🚩 Mock setup in beforeEach for single test
|
|
409
|
+
beforeEach(() => {
|
|
410
|
+
// 30 lines of setup
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
test('one thing', () => {
|
|
414
|
+
// 5 lines
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Your human partner's question:** "Do we need to be using a mock here?"
|
|
419
|
+
|
|
420
|
+
**Consider:** Integration tests with real components often simpler than complex mocks.
|
|
421
|
+
|
|
422
|
+
### Complexity Metrics
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
function calculateMockComplexity(test: TestFile): ComplexityScore {
|
|
426
|
+
return {
|
|
427
|
+
mockCount: countMocks(test), // >4 is high
|
|
428
|
+
setupLines: countSetupLines(test), // >30 is high
|
|
429
|
+
setupToTestRatio: setupLines / testLines, // >3 is high
|
|
430
|
+
mockNestingDepth: calculateNesting(test), // >2 is high
|
|
431
|
+
|
|
432
|
+
recommendation: score > 10 ? 'Use integration test' : 'OK'
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Comprehensive Code Review Checklist
|
|
438
|
+
|
|
439
|
+
Use this when reviewing tests (yours or others'):
|
|
440
|
+
|
|
441
|
+
### Structure
|
|
442
|
+
```
|
|
443
|
+
□ Test files exist for new code
|
|
444
|
+
□ Tests in same commit as implementation
|
|
445
|
+
□ Tests follow TDD pattern (fail first)
|
|
446
|
+
□ Clear test names describe behavior
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Mock Usage
|
|
450
|
+
```
|
|
451
|
+
□ Mocks used sparingly (only when needed)
|
|
452
|
+
□ Mock setup is simple (<20 lines)
|
|
453
|
+
□ Mocks at correct level (I/O boundaries)
|
|
454
|
+
□ No assertions on mock elements
|
|
455
|
+
□ Complete mock structures (all fields)
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Production Code
|
|
459
|
+
```
|
|
460
|
+
□ No test-only methods in production classes
|
|
461
|
+
□ No test-specific logic in production
|
|
462
|
+
□ Clean separation of concerns
|
|
463
|
+
□ No test imports in production code
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Test Quality
|
|
467
|
+
```
|
|
468
|
+
□ Tests verify real behavior
|
|
469
|
+
□ Assertions on meaningful results
|
|
470
|
+
□ Edge cases covered
|
|
471
|
+
□ Error conditions tested
|
|
472
|
+
□ Integration tests for critical paths
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Red Flags
|
|
476
|
+
```
|
|
477
|
+
□ No 'testId="*-mock"' assertions
|
|
478
|
+
□ No Partial<T> for mocks
|
|
479
|
+
□ No "for testing" comments in production
|
|
480
|
+
□ No untested implementation commits
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## Automated Detection Tools
|
|
484
|
+
|
|
485
|
+
### ESLint Rules
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
// .eslintrc.js
|
|
489
|
+
module.exports = {
|
|
490
|
+
rules: {
|
|
491
|
+
// Prevent test-only methods
|
|
492
|
+
'no-restricted-syntax': [
|
|
493
|
+
'error',
|
|
494
|
+
{
|
|
495
|
+
selector: 'MethodDefinition[key.name=/^(reset|destroy|clear|mock)$/]',
|
|
496
|
+
message: 'Potential test-only method in production code'
|
|
497
|
+
}
|
|
498
|
+
],
|
|
499
|
+
|
|
500
|
+
// Prevent mock test IDs
|
|
501
|
+
'testing-library/prefer-screen-queries': 'error',
|
|
502
|
+
'testing-library/no-node-access': 'error',
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Pre-commit Hook
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
#!/bin/bash
|
|
511
|
+
# .git/hooks/pre-commit
|
|
512
|
+
|
|
513
|
+
# Check for mock test IDs
|
|
514
|
+
if git diff --cached | grep -q "testId=.*-mock"; then
|
|
515
|
+
echo "Error: Found mock test ID in tests"
|
|
516
|
+
echo "Are you testing mock behavior?"
|
|
517
|
+
exit 1
|
|
518
|
+
fi
|
|
519
|
+
|
|
520
|
+
# Check for test-only methods
|
|
521
|
+
if git diff --cached -- "*.ts" "*.js" | \
|
|
522
|
+
grep -v ".test." | \
|
|
523
|
+
grep -q "destroy()\|reset()\|clear()"; then
|
|
524
|
+
echo "Warning: Potential test-only method in production code"
|
|
525
|
+
fi
|
|
526
|
+
|
|
527
|
+
# Check test coverage
|
|
528
|
+
npm test -- --coverage --coverageThreshold='{"global":{"lines":80}}'
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Quick Reference: Detection Summary
|
|
532
|
+
|
|
533
|
+
| Anti-Pattern | Key Indicator | Quick Check |
|
|
534
|
+
|--------------|---------------|-------------|
|
|
535
|
+
| Testing Mock Behavior | testId='*-mock' | Remove mock - test still valid? |
|
|
536
|
+
| Test-Only Methods | Method only in .test. files | grep production files |
|
|
537
|
+
| Mocking Without Understanding | Can't explain why mocking | Read implementation first |
|
|
538
|
+
| Incomplete Mocks | Partial<T> or no types | Check against API docs |
|
|
539
|
+
| Tests as Afterthought | Implementation before tests | Check git history |
|
|
540
|
+
|
|
541
|
+
## When to Seek Help
|
|
542
|
+
|
|
543
|
+
**STOP and ask your human partner if:**
|
|
544
|
+
- Mock setup exceeds 50 lines
|
|
545
|
+
- You've mocked >5 modules in one test
|
|
546
|
+
- Test mysteriously passes/fails
|
|
547
|
+
- You can't explain what test verifies
|
|
548
|
+
- Same test needs different mocks in different runs
|
|
549
|
+
- Integration test seems simpler than mocks
|
|
550
|
+
|
|
551
|
+
**Questions to ask:**
|
|
552
|
+
- "Do we need to be using a mock here?"
|
|
553
|
+
- "Should this be an integration test?"
|
|
554
|
+
- "Am I testing the right thing?"
|
|
555
|
+
- "Is this test-only method necessary?"
|
|
556
|
+
|
|
557
|
+
## Prevention Mindset
|
|
558
|
+
|
|
559
|
+
**Before writing any test:**
|
|
560
|
+
1. Understand what you're testing (real behavior)
|
|
561
|
+
2. Write test first (TDD)
|
|
562
|
+
3. Watch it fail
|
|
563
|
+
4. Minimal implementation
|
|
564
|
+
5. Watch it pass
|
|
565
|
+
6. Refactor
|
|
566
|
+
|
|
567
|
+
**This workflow prevents all five anti-patterns naturally.**
|
|
568
|
+
|
|
569
|
+
See [test-driven-development skill](../../test-driven-development/) for complete TDD workflow.
|