mindsystem-cc 3.13.0 → 3.13.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/agents/ms-mock-generator.md +51 -138
- package/commands/ms/verify-work.md +7 -7
- package/mindsystem/references/mock-patterns.md +149 -240
- package/mindsystem/templates/UAT.md +16 -16
- package/mindsystem/workflows/verify-work.md +54 -67
- package/package.json +1 -1
- package/mindsystem/workflows/generate-mocks.md +0 -261
|
@@ -1,182 +1,95 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ms-mock-generator
|
|
3
|
-
description: Generates
|
|
3
|
+
description: Generates inline mock edits in batch for UAT testing. Spawned by verify-work when 5+ mocks needed.
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
6
|
color: cyan
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<role>
|
|
10
|
-
You are a Mindsystem mock generator. You
|
|
10
|
+
You are a Mindsystem batch mock generator. You edit service/repository methods inline to hardcode return values for manual UAT testing.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Spawned by `/ms:verify-work` when a batch requires 5+ mocks — too many for main context to handle efficiently.
|
|
13
13
|
|
|
14
|
-
Your job:
|
|
14
|
+
Your job: Read each service method, edit it to return hardcoded values before the real implementation, and report what was changed.
|
|
15
15
|
</role>
|
|
16
16
|
|
|
17
17
|
<context_you_receive>
|
|
18
|
-
Your prompt
|
|
18
|
+
Your prompt includes:
|
|
19
19
|
|
|
20
|
-
- **
|
|
21
|
-
- **Tests requiring this mock**: List of tests with their expected behaviors
|
|
20
|
+
- **Tests requiring mocks**: List with mock_type and expected behavior for each
|
|
22
21
|
- **Phase info**: Current phase being tested
|
|
22
|
+
- **Mocked files so far**: Files already edited in previous batches (avoid conflicts)
|
|
23
23
|
</context_you_receive>
|
|
24
24
|
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
cat .planning/PROJECT.md 2>/dev/null | head -50
|
|
29
|
-
```
|
|
25
|
+
<references>
|
|
26
|
+
@~/.claude/mindsystem/references/mock-patterns.md
|
|
27
|
+
</references>
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**2. Verify with config files**
|
|
34
|
-
```bash
|
|
35
|
-
# Flutter/Dart
|
|
36
|
-
ls pubspec.yaml 2>/dev/null
|
|
29
|
+
<process>
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
ls package.json 2>/dev/null && grep -E '"react"|"next"' package.json
|
|
40
|
-
|
|
41
|
-
# React Native
|
|
42
|
-
ls package.json 2>/dev/null && grep '"react-native"' package.json
|
|
43
|
-
|
|
44
|
-
# Vue
|
|
45
|
-
ls package.json 2>/dev/null && grep '"vue"' package.json
|
|
46
|
-
```
|
|
31
|
+
**1. Identify service methods**
|
|
47
32
|
|
|
48
|
-
|
|
49
|
-
- Flutter: `pubspec.yaml` exists
|
|
50
|
-
- React/Next.js: `package.json` with react/next dependency
|
|
51
|
-
- React Native: `package.json` with react-native dependency
|
|
52
|
-
- Vue: `package.json` with vue dependency
|
|
53
|
-
- Other: Generate generic pattern with clear adaptation notes
|
|
54
|
-
</framework_detection>
|
|
33
|
+
For each test, identify the service/repository method that provides the data being tested. Use Grep to find fetch calls, API methods, or data access points related to the test's expected behavior.
|
|
55
34
|
|
|
56
|
-
|
|
57
|
-
**Philosophy:** Mocks are temporary scaffolding. They should:
|
|
58
|
-
- Be contained in as few files as possible (ideally 1 override file)
|
|
59
|
-
- Have minimal hooks in production code (single if-check)
|
|
60
|
-
- Be easy to completely remove (delete file + remove hooks)
|
|
35
|
+
**2. Read and edit each method**
|
|
61
36
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
1. **Create override file** - Single file with all mock flags and data
|
|
65
|
-
2. **Add minimal hooks** - If-check at service/repository layer
|
|
66
|
-
3. **Provide toggle instructions** - How to enable/disable each state
|
|
67
|
-
|
|
68
|
-
**Override file location conventions:**
|
|
69
|
-
- Flutter: `lib/test_overrides.dart`
|
|
70
|
-
- React/Next.js: `src/testOverrides.ts` or `lib/testOverrides.ts`
|
|
71
|
-
- React Native: `src/testOverrides.ts`
|
|
72
|
-
- Vue: `src/testOverrides.ts`
|
|
73
|
-
</mock_pattern>
|
|
74
|
-
|
|
75
|
-
<generation_process>
|
|
76
|
-
**1. Analyze tests to determine mock requirements**
|
|
77
|
-
|
|
78
|
-
For each test, identify:
|
|
79
|
-
- What state needs to be simulated
|
|
80
|
-
- What service/API call needs to be intercepted
|
|
81
|
-
- What data should be returned
|
|
82
|
-
|
|
83
|
-
**2. Create override file**
|
|
37
|
+
For each method, add a hardcoded return/throw BEFORE the real implementation:
|
|
84
38
|
|
|
85
39
|
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# Flags
|
|
89
|
-
forcePremiumUser = false
|
|
90
|
-
forceErrorState = false
|
|
91
|
-
forceEmptyResponse = false
|
|
92
|
-
forceLoadingState = false
|
|
40
|
+
// MOCK: {description} — revert after UAT
|
|
41
|
+
{hardcoded return value or throw}
|
|
93
42
|
|
|
94
|
-
|
|
95
|
-
mockErrorMessage = "Simulated error for testing"
|
|
96
|
-
mockPremiumUserData = { ... }
|
|
97
|
-
|
|
98
|
-
# Reset function
|
|
99
|
-
resetAllOverrides() { ... }
|
|
43
|
+
// Real implementation below...
|
|
100
44
|
```
|
|
101
45
|
|
|
102
|
-
**
|
|
46
|
+
**Patterns by mock_type:**
|
|
103
47
|
|
|
104
|
-
|
|
105
|
-
|
|
48
|
+
| mock_type | Edit pattern |
|
|
49
|
+
|-----------|-------------|
|
|
50
|
+
| `error_state` | `throw Exception('{error message}');` before real call |
|
|
51
|
+
| `empty_response` | `return [];` or `return null;` before real call |
|
|
52
|
+
| `premium_user` | `return {hardcoded user object with premium fields};` |
|
|
53
|
+
| `external_data` | `return {hardcoded data matching expected schema};` |
|
|
54
|
+
| `loading_state` | `await {5s delay};` before real call |
|
|
55
|
+
| `transient_state` | Delay or never-resolve — read `mock-patterns.md` transient_state_patterns |
|
|
56
|
+
| `offline` | `throw {network error};` before real call |
|
|
106
57
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (testOverrides.forcePremiumUser) {
|
|
111
|
-
return testOverrides.mockPremiumUserData
|
|
112
|
-
}
|
|
113
|
-
// ... real implementation
|
|
114
|
-
}
|
|
115
|
-
```
|
|
58
|
+
**3. For transient_state mocks:** Read `mock-patterns.md` for delay injection and never-resolve strategies. Choose based on whether the test is verifying the transition or the loading UI appearance.
|
|
59
|
+
|
|
60
|
+
**4. Track all changes**
|
|
116
61
|
|
|
117
|
-
|
|
62
|
+
Maintain a list of every file edited and what was changed.
|
|
118
63
|
|
|
119
|
-
|
|
120
|
-
1. Which file to edit
|
|
121
|
-
2. Which flag to set
|
|
122
|
-
3. How to apply (hot reload, restart, etc.)
|
|
123
|
-
4. How to verify mock is active
|
|
124
|
-
</generation_process>
|
|
64
|
+
</process>
|
|
125
65
|
|
|
126
66
|
<return_format>
|
|
127
67
|
```markdown
|
|
128
|
-
##
|
|
129
|
-
|
|
130
|
-
**Framework detected:** {Flutter | React | etc.}
|
|
131
|
-
**Mock type:** {the mock_type requested}
|
|
132
|
-
|
|
133
|
-
### Files Created
|
|
134
|
-
|
|
135
|
-
**{path/to/override_file}**
|
|
136
|
-
- Purpose: Central mock control
|
|
137
|
-
- Flags: {list of flags added}
|
|
68
|
+
## Mocks Applied
|
|
138
69
|
|
|
139
|
-
### Files
|
|
70
|
+
### Files Edited
|
|
140
71
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
72
|
+
| File | Method | Mock Type | Change |
|
|
73
|
+
|------|--------|-----------|--------|
|
|
74
|
+
| `{path}` | `{methodName}` | {type} | {brief description} |
|
|
144
75
|
|
|
145
|
-
###
|
|
76
|
+
### Cleanup
|
|
146
77
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
4. Verify: {what user should see to confirm mock is active}
|
|
152
|
-
|
|
153
|
-
**To enable {mock_state_2}:**
|
|
154
|
-
...
|
|
155
|
-
|
|
156
|
-
### Reset
|
|
157
|
-
|
|
158
|
-
To disable all mocks:
|
|
159
|
-
1. Set all flags to `false` in `{override_file}`
|
|
160
|
-
2. {Hot reload / Restart}
|
|
78
|
+
To revert all mocks:
|
|
79
|
+
```bash
|
|
80
|
+
git checkout -- {space-separated list of files}
|
|
81
|
+
```
|
|
161
82
|
|
|
162
|
-
|
|
83
|
+
### Mocked Files List
|
|
84
|
+
{JSON array of file paths for UAT.md frontmatter}
|
|
163
85
|
```
|
|
164
86
|
</return_format>
|
|
165
87
|
|
|
166
88
|
<constraints>
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
89
|
+
- Edit existing methods only — do not create new files
|
|
90
|
+
- Add mock code BEFORE the real implementation (early return pattern)
|
|
91
|
+
- Mark every edit with `// MOCK: {description} — revert after UAT`
|
|
92
|
+
- Do not modify test files — this is for manual UAT, not automated tests
|
|
93
|
+
- Do not create override files or toggle flags — inline hardcoding only
|
|
94
|
+
- Keep mock data minimal but realistic enough for UI rendering
|
|
173
95
|
</constraints>
|
|
174
|
-
|
|
175
|
-
<success_criteria>
|
|
176
|
-
- [ ] Framework correctly detected
|
|
177
|
-
- [ ] Override file created with appropriate flags
|
|
178
|
-
- [ ] Minimal hooks added to production code (if needed)
|
|
179
|
-
- [ ] Clear toggle instructions for each mock state
|
|
180
|
-
- [ ] Reset instructions provided
|
|
181
|
-
- [ ] All files written to disk (not just returned as content)
|
|
182
|
-
</success_criteria>
|
|
@@ -43,9 +43,9 @@ Phase: $ARGUMENTS (optional)
|
|
|
43
43
|
4. **Extract testable deliverables** from summaries
|
|
44
44
|
5. **Classify tests by mock requirements** — Use SUMMARY.md mock_hints when available; classify inline with keyword heuristics when absent. Confirm data availability with user before batching.
|
|
45
45
|
6. **Group into batches** — By mock type, max 4 per batch, no-mock tests first
|
|
46
|
-
- If any tests require mocks: Read `~/.claude/mindsystem/references/mock-patterns.md`
|
|
46
|
+
- If any tests require transient_state mocks: Read `~/.claude/mindsystem/references/mock-patterns.md` for delay strategies
|
|
47
47
|
7. **For each batch:**
|
|
48
|
-
- If mock needed:
|
|
48
|
+
- If mock needed: Apply inline mocks (1-4 direct edits, 5+ via ms-mock-generator subagent), tell user to hot reload
|
|
49
49
|
- Present tests via AskUserQuestion (Pass / Can't test / Skip / Other)
|
|
50
50
|
- Process results, update UAT.md
|
|
51
51
|
- **For each issue found:**
|
|
@@ -54,10 +54,10 @@ Phase: $ARGUMENTS (optional)
|
|
|
54
54
|
- If complex: Spawn ms-verify-fixer subagent
|
|
55
55
|
- 2 retries on failed re-test, then offer options
|
|
56
56
|
8. **On batch transition:**
|
|
57
|
-
- If new mock_type:
|
|
57
|
+
- If new mock_type: Revert old mocks (`git checkout -- <mocked_files>`), apply new ones
|
|
58
58
|
- If same mock_type: Keep mocks active
|
|
59
59
|
9. **On completion:**
|
|
60
|
-
-
|
|
60
|
+
- Revert all mocks (`git checkout -- <mocked_files>`)
|
|
61
61
|
- Generate UAT fixes patch
|
|
62
62
|
- Restore user's pre-existing work (if stashed)
|
|
63
63
|
- Commit UAT.md, present summary
|
|
@@ -77,7 +77,7 @@ Phase: $ARGUMENTS (optional)
|
|
|
77
77
|
- Don't run automated tests — this is manual user validation
|
|
78
78
|
- Don't skip investigation — always try 2-3 tool calls before escalating
|
|
79
79
|
- Don't fix complex issues inline — spawn fixer subagent for multi-file or architectural changes
|
|
80
|
-
- Don't commit mock code —
|
|
80
|
+
- Don't commit mock code — stash mocked files before fixing, restore after
|
|
81
81
|
- Don't re-present skipped tests — assumptions stand
|
|
82
82
|
</anti_patterns>
|
|
83
83
|
|
|
@@ -85,14 +85,14 @@ Phase: $ARGUMENTS (optional)
|
|
|
85
85
|
- [ ] Dirty tree handled at start (stash/commit/abort)
|
|
86
86
|
- [ ] Tests extracted from SUMMARY.md and classified
|
|
87
87
|
- [ ] Tests batched by mock requirements
|
|
88
|
-
- [ ] Mocks
|
|
88
|
+
- [ ] Mocks applied inline when needed (1-4 direct, 5+ via subagent)
|
|
89
89
|
- [ ] Tests presented in batches of 4 using AskUserQuestion
|
|
90
90
|
- [ ] Issues investigated with lightweight check first
|
|
91
91
|
- [ ] Simple issues fixed inline with proper commit message
|
|
92
92
|
- [ ] Complex issues escalated to fixer subagent
|
|
93
93
|
- [ ] Failed re-tests get 2 retries then options
|
|
94
94
|
- [ ] Stash conflicts auto-resolved to fix version
|
|
95
|
-
- [ ] Mocks
|
|
95
|
+
- [ ] Mocks reverted on completion (git checkout)
|
|
96
96
|
- [ ] UAT fixes patch generated
|
|
97
97
|
- [ ] User's pre-existing work restored
|
|
98
98
|
- [ ] UAT.md committed with final summary
|
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
<overview>
|
|
2
|
-
Mock patterns for manual UAT testing. Mocks are temporary
|
|
2
|
+
Mock patterns for manual UAT testing. Mocks are temporary inline edits to service methods — hardcoded return values that let you reach testable UI states. They exist only as uncommitted changes, never in commit history.
|
|
3
3
|
</overview>
|
|
4
4
|
|
|
5
|
-
<philosophy>
|
|
6
|
-
**Mocks enable testing states you can't easily reach.**
|
|
7
|
-
|
|
8
|
-
Without mocks, testing "error message display" requires actually triggering server errors. Testing "premium user badge" requires a premium account. Testing "empty list placeholder" requires deleting all data.
|
|
9
|
-
|
|
10
|
-
**With mocks:** Set a flag, hot reload, test the UI state.
|
|
11
|
-
|
|
12
|
-
**Core principles:**
|
|
13
|
-
1. **Temporary** — Mocks are stashed/discarded, never committed
|
|
14
|
-
2. **Minimal** — One override file, minimal production hooks
|
|
15
|
-
3. **Explicit** — Clear flags, clear toggle instructions
|
|
16
|
-
4. **Removable** — Delete file + remove imports = clean
|
|
17
|
-
</philosophy>
|
|
18
|
-
|
|
19
5
|
<classification_framework>
|
|
20
6
|
|
|
21
7
|
**Two-question framework for mock classification:**
|
|
@@ -57,19 +43,161 @@ Domain terms don't map reliably to mock types. "View recipe list" needs external
|
|
|
57
43
|
|
|
58
44
|
</classification_framework>
|
|
59
45
|
|
|
46
|
+
<mock_types>
|
|
47
|
+
|
|
48
|
+
| Mock Type | Enables Testing | Inline Pattern |
|
|
49
|
+
|-----------|-----------------|----------------|
|
|
50
|
+
| `error_state` | Error messages, retry UI, fallback displays | Throw exception before real implementation |
|
|
51
|
+
| `premium_user` | Premium badges, gated features, upgrade prompts | Return mock user object with premium fields |
|
|
52
|
+
| `empty_response` | Empty states, placeholder UI, "no results" | Return empty list/null before real implementation |
|
|
53
|
+
| `loading_state` | Loading spinners, skeleton screens | Add delay before real implementation |
|
|
54
|
+
| `offline` | Offline UI, cached data, sync indicators | Throw network error before real implementation |
|
|
55
|
+
| `transient_state` | Brief async states (loading skeletons, transitions) | Delay or never-resolve strategies (see below) |
|
|
56
|
+
| `external_data` | Features depending on API data that may not exist locally | Return hardcoded data objects |
|
|
57
|
+
|
|
58
|
+
</mock_types>
|
|
59
|
+
|
|
60
|
+
<inline_mock_patterns>
|
|
61
|
+
|
|
62
|
+
**Inline mocks edit service methods directly.** Add hardcoded return values BEFORE the real implementation. Mark with `// MOCK:` comment for cleanup tracking.
|
|
63
|
+
|
|
64
|
+
**Pattern:** Early return with mock comment
|
|
65
|
+
```
|
|
66
|
+
// MOCK: {description} — revert after UAT
|
|
67
|
+
{hardcoded return/throw}
|
|
68
|
+
|
|
69
|
+
// Real implementation below...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**By mock_type:**
|
|
73
|
+
|
|
74
|
+
**error_state** — Throw before real call:
|
|
75
|
+
```dart
|
|
76
|
+
// Before:
|
|
77
|
+
Future<User> login(String email, String password) async {
|
|
78
|
+
final response = await _api.post('/auth/login', data: {'email': email, 'password': password});
|
|
79
|
+
return User.fromJson(response.data);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// After:
|
|
83
|
+
Future<User> login(String email, String password) async {
|
|
84
|
+
// MOCK: force login error — revert after UAT
|
|
85
|
+
throw Exception('Invalid credentials');
|
|
86
|
+
|
|
87
|
+
final response = await _api.post('/auth/login', data: {'email': email, 'password': password});
|
|
88
|
+
return User.fromJson(response.data);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**empty_response** — Return empty collection:
|
|
93
|
+
```dart
|
|
94
|
+
// Before:
|
|
95
|
+
Future<List<Recipe>> getRecipes() async {
|
|
96
|
+
final response = await _api.get('/recipes');
|
|
97
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// After:
|
|
101
|
+
Future<List<Recipe>> getRecipes() async {
|
|
102
|
+
// MOCK: force empty list — revert after UAT
|
|
103
|
+
return [];
|
|
104
|
+
|
|
105
|
+
final response = await _api.get('/recipes');
|
|
106
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**premium_user / external_data** — Return hardcoded object:
|
|
111
|
+
```dart
|
|
112
|
+
// Before:
|
|
113
|
+
Future<User> getCurrentUser() async {
|
|
114
|
+
final response = await _api.get('/user/me');
|
|
115
|
+
return User.fromJson(response.data);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// After:
|
|
119
|
+
Future<User> getCurrentUser() async {
|
|
120
|
+
// MOCK: force premium user — revert after UAT
|
|
121
|
+
return User(id: 'mock-001', name: 'Test User', isPremium: true, tier: 'gold');
|
|
122
|
+
|
|
123
|
+
final response = await _api.get('/user/me');
|
|
124
|
+
return User.fromJson(response.data);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**TypeScript equivalents follow identical pattern** — early return/throw with `// MOCK:` comment before the real implementation.
|
|
129
|
+
|
|
130
|
+
</inline_mock_patterns>
|
|
131
|
+
|
|
132
|
+
<transient_state_patterns>
|
|
133
|
+
|
|
134
|
+
**Transient states are UI states that appear briefly during async operations.** Loading skeletons, shimmer effects, transition animations — they resolve too fast to observe and test manually.
|
|
135
|
+
|
|
136
|
+
**Two strategies:**
|
|
137
|
+
|
|
138
|
+
**1. Extended delay (default):**
|
|
139
|
+
|
|
140
|
+
Add a configurable delay before the real data returns. The transient state stays visible long enough to test.
|
|
141
|
+
|
|
142
|
+
```dart
|
|
143
|
+
// MOCK: extend loading state for testing — revert after UAT
|
|
144
|
+
await Future.delayed(const Duration(seconds: 5));
|
|
145
|
+
|
|
146
|
+
// Real implementation continues...
|
|
147
|
+
final response = await _api.get('/recipes');
|
|
148
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// MOCK: extend loading state for testing — revert after UAT
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
154
|
+
|
|
155
|
+
// Real implementation continues...
|
|
156
|
+
const response = await fetch('/api/recipes');
|
|
157
|
+
return response.json();
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**When to use:** Testing that the loading UI (skeleton, spinner) displays correctly while waiting.
|
|
161
|
+
|
|
162
|
+
**2. Never-resolve:**
|
|
163
|
+
|
|
164
|
+
The async call never completes. The transient state stays permanently visible.
|
|
165
|
+
|
|
166
|
+
```dart
|
|
167
|
+
// MOCK: freeze loading state — revert after UAT
|
|
168
|
+
await Completer<void>().future; // Never completes
|
|
169
|
+
|
|
170
|
+
// Real implementation continues...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// MOCK: freeze loading state — revert after UAT
|
|
175
|
+
await new Promise(() => {}); // Never resolves
|
|
176
|
+
|
|
177
|
+
// Real implementation continues...
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**When to use:** Testing that the loading UI itself is correct (layout, styling, animation) without it disappearing.
|
|
181
|
+
|
|
182
|
+
**Choosing between strategies:**
|
|
183
|
+
- Testing the transition (loading → loaded): Use extended delay (5s default)
|
|
184
|
+
- Testing the loading UI appearance: Use never-resolve
|
|
185
|
+
|
|
186
|
+
</transient_state_patterns>
|
|
187
|
+
|
|
60
188
|
<git_stash_lifecycle>
|
|
61
189
|
|
|
62
190
|
**Why stash?**
|
|
63
191
|
|
|
64
|
-
Fixes must be clean commits (no mock code). But after fixing,
|
|
192
|
+
Fixes must be clean commits (no mock code). But after fixing, mocks need to be restored to re-test. Git stash enables this:
|
|
65
193
|
|
|
66
194
|
```
|
|
67
195
|
┌─────────────────────────────────────────────────────────────┐
|
|
68
196
|
│ Phase 1: Setup │
|
|
69
197
|
├─────────────────────────────────────────────────────────────┤
|
|
70
198
|
│ 1. git stash push -m "pre-verify-work" (if dirty) │
|
|
71
|
-
│ 2.
|
|
72
|
-
│ 3.
|
|
199
|
+
│ 2. Inline mocks applied to service methods (uncommitted) │
|
|
200
|
+
│ 3. Mocked files tracked in UAT.md: mocked_files: [...] │
|
|
73
201
|
└─────────────────────────────────────────────────────────────┘
|
|
74
202
|
│
|
|
75
203
|
▼
|
|
@@ -78,7 +206,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
78
206
|
├─────────────────────────────────────────────────────────────┤
|
|
79
207
|
│ 4. User tests on device with mocks active │
|
|
80
208
|
│ 5. User reports issue │
|
|
81
|
-
│ 6. git stash push -m "mocks-batch-N"
|
|
209
|
+
│ 6. git stash push -m "mocks-batch-N" -- <mocked_files> │
|
|
82
210
|
│ 7. Fixer investigates and commits fix ← Clean commit │
|
|
83
211
|
│ 8. git stash pop ← Restore mocks │
|
|
84
212
|
│ 9. User re-tests specific item │
|
|
@@ -89,7 +217,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
89
217
|
┌─────────────────────────────────────────────────────────────┐
|
|
90
218
|
│ Phase 3: Cleanup │
|
|
91
219
|
├─────────────────────────────────────────────────────────────┤
|
|
92
|
-
│ 11. git
|
|
220
|
+
│ 11. git checkout -- <mocked_files> ← Revert mocks │
|
|
93
221
|
│ 12. Generate UAT fixes patch │
|
|
94
222
|
│ 13. git stash pop (if pre-existing) ← Restore user work │
|
|
95
223
|
└─────────────────────────────────────────────────────────────┘
|
|
@@ -97,7 +225,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
97
225
|
|
|
98
226
|
**Stash naming convention:**
|
|
99
227
|
- `pre-verify-work` — User's original uncommitted work
|
|
100
|
-
- `mocks-batch-N` — Current mock state for batch N
|
|
228
|
+
- `mocks-batch-N` — Current mock state for batch N (stashed only during fix application)
|
|
101
229
|
|
|
102
230
|
</git_stash_lifecycle>
|
|
103
231
|
|
|
@@ -121,222 +249,3 @@ git add <conflicted-file>
|
|
|
121
249
|
**This is rare.** Mocks typically live in data layer, fixes often in UI layer.
|
|
122
250
|
|
|
123
251
|
</conflict_resolution>
|
|
124
|
-
|
|
125
|
-
<flutter_example>
|
|
126
|
-
|
|
127
|
-
**Override file: `lib/test_overrides.dart`**
|
|
128
|
-
|
|
129
|
-
```dart
|
|
130
|
-
// Test Overrides - DELETE THIS FILE BEFORE COMMITTING
|
|
131
|
-
// Used for manual UAT testing only
|
|
132
|
-
|
|
133
|
-
class TestOverrides {
|
|
134
|
-
// === STATE FLAGS ===
|
|
135
|
-
static bool forcePremiumUser = false;
|
|
136
|
-
static bool forceErrorState = false;
|
|
137
|
-
static bool forceEmptyResponse = false;
|
|
138
|
-
static bool forceLoadingState = false;
|
|
139
|
-
static bool forceTransientState = false;
|
|
140
|
-
|
|
141
|
-
// === MOCK DATA ===
|
|
142
|
-
static String mockErrorMessage = 'Simulated error for testing';
|
|
143
|
-
static Duration mockLoadingDelay = const Duration(seconds: 3);
|
|
144
|
-
static Duration mockTransientDelay = const Duration(seconds: 5);
|
|
145
|
-
|
|
146
|
-
static Map<String, dynamic> mockPremiumUser = {
|
|
147
|
-
'id': 'test-user-001',
|
|
148
|
-
'name': 'Test Premium User',
|
|
149
|
-
'isPremium': true,
|
|
150
|
-
'subscriptionTier': 'gold',
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
// === RESET ===
|
|
154
|
-
static void reset() {
|
|
155
|
-
forcePremiumUser = false;
|
|
156
|
-
forceErrorState = false;
|
|
157
|
-
forceEmptyResponse = false;
|
|
158
|
-
forceLoadingState = false;
|
|
159
|
-
forceTransientState = false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**Production hook: `lib/services/user_service.dart`**
|
|
165
|
-
|
|
166
|
-
```dart
|
|
167
|
-
import '../test_overrides.dart';
|
|
168
|
-
|
|
169
|
-
class UserService {
|
|
170
|
-
Future<User> getCurrentUser() async {
|
|
171
|
-
// TEST OVERRIDE - Remove before commit
|
|
172
|
-
if (TestOverrides.forcePremiumUser) {
|
|
173
|
-
return User.fromJson(TestOverrides.mockPremiumUser);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Real implementation
|
|
177
|
-
final response = await _api.get('/user/me');
|
|
178
|
-
return User.fromJson(response.data);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
Future<List<Item>> getItems() async {
|
|
182
|
-
// TEST OVERRIDE - Remove before commit
|
|
183
|
-
if (TestOverrides.forceEmptyResponse) {
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
|
-
if (TestOverrides.forceErrorState) {
|
|
187
|
-
throw Exception(TestOverrides.mockErrorMessage);
|
|
188
|
-
}
|
|
189
|
-
// TEST OVERRIDE - Extend transient state (loading skeleton stays visible)
|
|
190
|
-
if (TestOverrides.forceTransientState) {
|
|
191
|
-
await Future.delayed(TestOverrides.mockTransientDelay);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Real implementation
|
|
195
|
-
final response = await _api.get('/items');
|
|
196
|
-
return (response.data as List).map((j) => Item.fromJson(j)).toList();
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Toggle instructions:**
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
To enable Premium User state:
|
|
205
|
-
1. Open lib/test_overrides.dart
|
|
206
|
-
2. Set TestOverrides.forcePremiumUser = true
|
|
207
|
-
3. Hot reload (r in terminal)
|
|
208
|
-
4. Verify: User profile shows "Premium" badge
|
|
209
|
-
|
|
210
|
-
To enable Error State:
|
|
211
|
-
1. Open lib/test_overrides.dart
|
|
212
|
-
2. Set TestOverrides.forceErrorState = true
|
|
213
|
-
3. Hot reload (r in terminal)
|
|
214
|
-
4. Verify: Error message appears on relevant screens
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
</flutter_example>
|
|
218
|
-
|
|
219
|
-
<react_example>
|
|
220
|
-
|
|
221
|
-
**Override file: `src/testOverrides.ts`**
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
// Test Overrides - DELETE THIS FILE BEFORE COMMITTING
|
|
225
|
-
// Used for manual UAT testing only
|
|
226
|
-
|
|
227
|
-
export const testOverrides = {
|
|
228
|
-
// === STATE FLAGS ===
|
|
229
|
-
forcePremiumUser: false,
|
|
230
|
-
forceErrorState: false,
|
|
231
|
-
forceEmptyResponse: false,
|
|
232
|
-
forceLoadingState: false,
|
|
233
|
-
|
|
234
|
-
// === MOCK DATA ===
|
|
235
|
-
mockErrorMessage: 'Simulated error for testing',
|
|
236
|
-
mockLoadingDelayMs: 3000,
|
|
237
|
-
|
|
238
|
-
mockPremiumUser: {
|
|
239
|
-
id: 'test-user-001',
|
|
240
|
-
name: 'Test Premium User',
|
|
241
|
-
isPremium: true,
|
|
242
|
-
subscriptionTier: 'gold',
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
// === RESET ===
|
|
246
|
-
reset() {
|
|
247
|
-
this.forcePremiumUser = false;
|
|
248
|
-
this.forceErrorState = false;
|
|
249
|
-
this.forceEmptyResponse = false;
|
|
250
|
-
this.forceLoadingState = false;
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**Production hook: `src/services/userService.ts`**
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { testOverrides } from '../testOverrides';
|
|
259
|
-
|
|
260
|
-
export async function getCurrentUser(): Promise<User> {
|
|
261
|
-
// TEST OVERRIDE - Remove before commit
|
|
262
|
-
if (testOverrides.forcePremiumUser) {
|
|
263
|
-
return testOverrides.mockPremiumUser as User;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Real implementation
|
|
267
|
-
const response = await fetch('/api/user/me');
|
|
268
|
-
return response.json();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export async function getItems(): Promise<Item[]> {
|
|
272
|
-
// TEST OVERRIDE - Remove before commit
|
|
273
|
-
if (testOverrides.forceEmptyResponse) {
|
|
274
|
-
return [];
|
|
275
|
-
}
|
|
276
|
-
if (testOverrides.forceErrorState) {
|
|
277
|
-
throw new Error(testOverrides.mockErrorMessage);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Real implementation
|
|
281
|
-
const response = await fetch('/api/items');
|
|
282
|
-
return response.json();
|
|
283
|
-
}
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
**Toggle instructions:**
|
|
287
|
-
|
|
288
|
-
```
|
|
289
|
-
To enable Premium User state:
|
|
290
|
-
1. Open src/testOverrides.ts
|
|
291
|
-
2. Set forcePremiumUser: true
|
|
292
|
-
3. Save file (auto hot reload in dev mode)
|
|
293
|
-
4. Verify: User profile shows "Premium" badge
|
|
294
|
-
|
|
295
|
-
To enable Error State:
|
|
296
|
-
1. Open src/testOverrides.ts
|
|
297
|
-
2. Set forceErrorState: true
|
|
298
|
-
3. Save file (auto hot reload)
|
|
299
|
-
4. Verify: Error message appears on relevant screens
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
</react_example>
|
|
303
|
-
|
|
304
|
-
<best_practices>
|
|
305
|
-
|
|
306
|
-
**Do:**
|
|
307
|
-
- Keep all flags in one file
|
|
308
|
-
- Use descriptive flag names (`forcePremiumUser` not `flag1`)
|
|
309
|
-
- Add comments marking test-only code
|
|
310
|
-
- Provide reset function
|
|
311
|
-
- Document toggle instructions clearly
|
|
312
|
-
|
|
313
|
-
**Don't:**
|
|
314
|
-
- Create complex mock infrastructure
|
|
315
|
-
- Add mocks in UI components (use service layer)
|
|
316
|
-
- Commit mock code (ever)
|
|
317
|
-
- Create multiple override files
|
|
318
|
-
- Add conditional compilation / build flags
|
|
319
|
-
|
|
320
|
-
**Signs you're over-engineering:**
|
|
321
|
-
- More than one override file
|
|
322
|
-
- Mock code in more than 3 production files
|
|
323
|
-
- Complex mock data generators
|
|
324
|
-
- Mocking at multiple layers simultaneously
|
|
325
|
-
|
|
326
|
-
</best_practices>
|
|
327
|
-
|
|
328
|
-
<cleanup>
|
|
329
|
-
|
|
330
|
-
**After UAT complete:**
|
|
331
|
-
|
|
332
|
-
1. `git stash drop` — Removes mock stash permanently
|
|
333
|
-
2. Delete override file if still present
|
|
334
|
-
3. Remove any imports/hooks still in production code
|
|
335
|
-
|
|
336
|
-
**Verification:**
|
|
337
|
-
```bash
|
|
338
|
-
git status # Should show no mock-related files
|
|
339
|
-
grep -r "testOverrides" src/ # Should find nothing (or only the override file itself)
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
</cleanup>
|
|
@@ -14,7 +14,7 @@ source: [list of SUMMARY.md files tested]
|
|
|
14
14
|
started: [ISO timestamp]
|
|
15
15
|
updated: [ISO timestamp]
|
|
16
16
|
current_batch: [N]
|
|
17
|
-
|
|
17
|
+
mocked_files: []
|
|
18
18
|
pre_work_stash: [stash name or null]
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -138,7 +138,7 @@ mock_type: empty_response
|
|
|
138
138
|
- `started`: IMMUTABLE - set on creation
|
|
139
139
|
- `updated`: OVERWRITE - update on every change
|
|
140
140
|
- `current_batch`: OVERWRITE - current batch number
|
|
141
|
-
- `
|
|
141
|
+
- `mocked_files`: OVERWRITE - list of files with inline mocks, or empty array
|
|
142
142
|
- `pre_work_stash`: OVERWRITE - user's pre-existing work stash or null
|
|
143
143
|
|
|
144
144
|
**Progress:**
|
|
@@ -196,23 +196,22 @@ mock_type: empty_response
|
|
|
196
196
|
<mock_lifecycle>
|
|
197
197
|
|
|
198
198
|
**When batch needs mocks:**
|
|
199
|
-
1.
|
|
200
|
-
2.
|
|
201
|
-
3.
|
|
199
|
+
1. Edit service methods inline (hardcoded return values)
|
|
200
|
+
2. Record files in `mocked_files` frontmatter
|
|
201
|
+
3. User hot reloads, testing proceeds
|
|
202
202
|
|
|
203
203
|
**When fix needed:**
|
|
204
|
-
1. `git stash push -m "mocks-batch-N"
|
|
205
|
-
2.
|
|
206
|
-
3.
|
|
207
|
-
4.
|
|
208
|
-
5. Clear `mock_stash` if no conflicts
|
|
204
|
+
1. `git stash push -m "mocks-batch-N" -- <mocked_files>`
|
|
205
|
+
2. Fix applied, committed
|
|
206
|
+
3. `git stash pop` to restore mocks
|
|
207
|
+
4. If conflict: take fix version, remove file from `mocked_files`
|
|
209
208
|
|
|
210
209
|
**On batch transition (different mock_type):**
|
|
211
|
-
1.
|
|
212
|
-
2.
|
|
210
|
+
1. Revert old mocks: `git checkout -- <mocked_files>`
|
|
211
|
+
2. Clear `mocked_files`, apply new inline mocks
|
|
213
212
|
|
|
214
213
|
**On session complete:**
|
|
215
|
-
1.
|
|
214
|
+
1. Revert all mocks: `git checkout -- <mocked_files>`
|
|
216
215
|
2. Restore pre_work_stash if exists
|
|
217
216
|
|
|
218
217
|
</mock_lifecycle>
|
|
@@ -225,8 +224,9 @@ On `/ms:verify-work` with existing UAT.md:
|
|
|
225
224
|
- "complete" → offer to re-run or view results
|
|
226
225
|
- "testing" or "fixing" → resume
|
|
227
226
|
|
|
228
|
-
2. Check `
|
|
229
|
-
- If
|
|
227
|
+
2. Check `mocked_files`:
|
|
228
|
+
- If non-empty, verify mocks still present via `git diff --name-only`
|
|
229
|
+
- If mocks lost, regenerate for current batch
|
|
230
230
|
|
|
231
231
|
3. Check `current_batch`:
|
|
232
232
|
- Resume from that batch
|
|
@@ -262,7 +262,7 @@ source: 04-01-SUMMARY.md, 04-02-SUMMARY.md
|
|
|
262
262
|
started: 2025-01-15T10:30:00Z
|
|
263
263
|
updated: 2025-01-15T11:15:00Z
|
|
264
264
|
current_batch: 2
|
|
265
|
-
|
|
265
|
+
mocked_files: [src/services/auth_service.dart, src/services/api_service.dart]
|
|
266
266
|
pre_work_stash: null
|
|
267
267
|
---
|
|
268
268
|
|
|
@@ -5,7 +5,7 @@ Complete verify-and-fix session: by session end, everything verified, issues fix
|
|
|
5
5
|
</purpose>
|
|
6
6
|
|
|
7
7
|
<execution_context>
|
|
8
|
-
<!-- mock-patterns.md
|
|
8
|
+
<!-- mock-patterns.md loaded on demand for transient_state mocks (see generate_mocks step) -->
|
|
9
9
|
</execution_context>
|
|
10
10
|
|
|
11
11
|
<template>
|
|
@@ -232,7 +232,7 @@ tests:
|
|
|
232
232
|
<step name="create_batches">
|
|
233
233
|
**Group tests into batches:**
|
|
234
234
|
|
|
235
|
-
**If any tests have mock_required=true:** Read `~/.claude/mindsystem/references/mock-patterns.md`
|
|
235
|
+
**If any tests have mock_required=true AND batch includes `transient_state` mocks:** Read `~/.claude/mindsystem/references/mock-patterns.md` for delay/never-resolve strategies.
|
|
236
236
|
|
|
237
237
|
**Rules:**
|
|
238
238
|
1. Group by mock_type (tests needing same mock state go together)
|
|
@@ -311,7 +311,7 @@ source: [list of SUMMARY.md files]
|
|
|
311
311
|
started: [ISO timestamp]
|
|
312
312
|
updated: [ISO timestamp]
|
|
313
313
|
current_batch: 1
|
|
314
|
-
|
|
314
|
+
mocked_files: []
|
|
315
315
|
pre_work_stash: [from dirty tree handling, or null]
|
|
316
316
|
---
|
|
317
317
|
|
|
@@ -378,11 +378,11 @@ Read current batch from UAT.md.
|
|
|
378
378
|
**1. Handle mock generation (if needed):**
|
|
379
379
|
|
|
380
380
|
If `mock_type` is not null AND different from previous batch:
|
|
381
|
-
-
|
|
381
|
+
- Revert old mocks if any (from `mocked_files` in UAT.md frontmatter):
|
|
382
382
|
```bash
|
|
383
|
-
|
|
384
|
-
[ -n "$MOCK_STASH" ] && git stash drop "$MOCK_STASH"
|
|
383
|
+
git checkout -- <mocked_files>
|
|
385
384
|
```
|
|
385
|
+
- Clear `mocked_files` in frontmatter
|
|
386
386
|
- Go to `generate_mocks`
|
|
387
387
|
|
|
388
388
|
If `mock_type` is null or same as previous:
|
|
@@ -394,72 +394,61 @@ Go to `present_tests`
|
|
|
394
394
|
</step>
|
|
395
395
|
|
|
396
396
|
<step name="generate_mocks">
|
|
397
|
-
**Generate mocks for current batch:**
|
|
397
|
+
**Generate mocks for current batch using inline approach:**
|
|
398
398
|
|
|
399
|
-
|
|
400
|
-
```
|
|
401
|
-
## Batch [N]: [Name]
|
|
399
|
+
Count mock-requiring tests in this batch.
|
|
402
400
|
|
|
403
|
-
**
|
|
401
|
+
**Decision logic:**
|
|
404
402
|
|
|
405
|
-
|
|
403
|
+
| Count | Approach |
|
|
404
|
+
|-------|----------|
|
|
405
|
+
| 1-4 | Inline: edit service methods directly in main context |
|
|
406
|
+
| 5+ | Subagent: spawn ms-mock-generator for batch editing |
|
|
406
407
|
|
|
407
|
-
1
|
|
408
|
-
2. I'll set up mocks manually — Skip generation, you handle it
|
|
409
|
-
3. Skip this batch — Log all tests as assumptions
|
|
410
|
-
```
|
|
408
|
+
**Inline approach (1-4 mocks):**
|
|
411
409
|
|
|
412
|
-
|
|
410
|
+
For each test in the batch:
|
|
411
|
+
1. Identify the service/repository method that provides the data
|
|
412
|
+
2. Read the method
|
|
413
|
+
3. Edit to hardcode desired return value BEFORE the real implementation:
|
|
414
|
+
```
|
|
415
|
+
// MOCK: {description} — revert after UAT
|
|
416
|
+
{hardcoded return/throw}
|
|
417
|
+
```
|
|
418
|
+
4. For transient_state mocks: Read `~/.claude/mindsystem/references/mock-patterns.md` for delay/never-resolve strategies
|
|
419
|
+
|
|
420
|
+
**Subagent approach (5+ mocks):**
|
|
413
421
|
|
|
414
|
-
Spawn mock generator:
|
|
415
422
|
```
|
|
416
423
|
Task(
|
|
417
424
|
prompt="""
|
|
418
|
-
Generate mocks for manual UAT testing.
|
|
425
|
+
Generate inline mocks for manual UAT testing.
|
|
419
426
|
|
|
420
|
-
Project: {from PROJECT.md}
|
|
421
427
|
Phase: {phase_name}
|
|
422
|
-
Mock type: {mock_type}
|
|
423
428
|
|
|
424
|
-
Tests requiring
|
|
425
|
-
{test list with expected behaviors}
|
|
429
|
+
Tests requiring mocks:
|
|
430
|
+
{test list with mock_type and expected behaviors}
|
|
426
431
|
|
|
427
|
-
|
|
432
|
+
Mocked files from previous batches (avoid conflicts):
|
|
433
|
+
{mocked_files from UAT.md frontmatter}
|
|
428
434
|
""",
|
|
429
435
|
subagent_type="ms-mock-generator",
|
|
430
436
|
description="Generate {mock_type} mocks"
|
|
431
437
|
)
|
|
432
438
|
```
|
|
433
439
|
|
|
434
|
-
After
|
|
440
|
+
**After mocks applied (both approaches):**
|
|
435
441
|
|
|
436
|
-
1.
|
|
437
|
-
2.
|
|
438
|
-
3.
|
|
442
|
+
1. Record mocked files in UAT.md frontmatter: `mocked_files: [file1.dart, file2.dart, ...]`
|
|
443
|
+
2. Tell user: "Mocks applied. Hot reload to test."
|
|
444
|
+
3. Proceed directly to `present_tests` — no user confirmation needed
|
|
439
445
|
|
|
440
|
-
|
|
441
|
-
questions:
|
|
442
|
-
- question: "I've created the mock files. Have you enabled the mocks and verified they're working?"
|
|
443
|
-
header: "Mocks ready"
|
|
444
|
-
options:
|
|
445
|
-
- label: "Yes, mocks are active"
|
|
446
|
-
description: "I've toggled the flags and hot reloaded"
|
|
447
|
-
- label: "Having trouble"
|
|
448
|
-
description: "Something isn't working with the mocks"
|
|
449
|
-
multiSelect: false
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
**If "I'll set up manually":**
|
|
453
|
-
- Present what mock state is needed
|
|
454
|
-
- Wait for user to confirm ready
|
|
446
|
+
**Skip option:**
|
|
455
447
|
|
|
456
|
-
|
|
457
|
-
-
|
|
458
|
-
- Mark all tests in batch as `skipped` with user's reason
|
|
448
|
+
If user has previously indicated they want to skip mock batches, or if mock generation fails:
|
|
449
|
+
- Mark all tests in batch as `skipped`
|
|
459
450
|
- Append to Assumptions section
|
|
460
451
|
- Proceed to next batch
|
|
461
|
-
|
|
462
|
-
Proceed to `present_tests`.
|
|
463
452
|
</step>
|
|
464
453
|
|
|
465
454
|
<step name="present_tests">
|
|
@@ -574,9 +563,9 @@ For each question:
|
|
|
574
563
|
|
|
575
564
|
**1. Stash mocks (if active):**
|
|
576
565
|
```bash
|
|
577
|
-
git stash push -m "mocks-batch-{N}"
|
|
566
|
+
git stash push -m "mocks-batch-{N}" -- <mocked_files>
|
|
578
567
|
```
|
|
579
|
-
|
|
568
|
+
Use `mocked_files` list from UAT.md frontmatter.
|
|
580
569
|
|
|
581
570
|
**2. Make the fix:**
|
|
582
571
|
- Edit the file(s)
|
|
@@ -605,11 +594,11 @@ git stash pop
|
|
|
605
594
|
|
|
606
595
|
**Handle stash conflict:**
|
|
607
596
|
```bash
|
|
608
|
-
#
|
|
597
|
+
# Conflict means fix touched a mocked file — take the fix version
|
|
609
598
|
git checkout --theirs <conflicted-file>
|
|
610
599
|
git add <conflicted-file>
|
|
611
600
|
```
|
|
612
|
-
|
|
601
|
+
Remove conflicted file from `mocked_files` list in UAT.md (mock no longer needed for that file).
|
|
613
602
|
|
|
614
603
|
**6. Request re-test:**
|
|
615
604
|
```
|
|
@@ -626,7 +615,7 @@ Go to `handle_retest`.
|
|
|
626
615
|
|
|
627
616
|
**1. Stash mocks (if active):**
|
|
628
617
|
```bash
|
|
629
|
-
git stash push -m "mocks-batch-{N}"
|
|
618
|
+
git stash push -m "mocks-batch-{N}" -- <mocked_files>
|
|
630
619
|
```
|
|
631
620
|
|
|
632
621
|
**2. Spawn ms-verify-fixer:**
|
|
@@ -738,13 +727,12 @@ questions:
|
|
|
738
727
|
|
|
739
728
|
Read full UAT file.
|
|
740
729
|
|
|
741
|
-
Check `
|
|
742
|
-
```
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
1. Restore mocks — Continue where we left off
|
|
746
|
-
2. Discard mocks — Start batch fresh
|
|
730
|
+
Check `mocked_files` — if non-empty, verify mocks are still present:
|
|
731
|
+
```bash
|
|
732
|
+
git diff --name-only
|
|
747
733
|
```
|
|
734
|
+
If mocked files have uncommitted changes, mocks are still active — continue.
|
|
735
|
+
If mocked files are clean, mocks were lost — regenerate for current batch.
|
|
748
736
|
|
|
749
737
|
Find current position:
|
|
750
738
|
- current_batch
|
|
@@ -796,12 +784,11 @@ issues: {count}
|
|
|
796
784
|
<step name="complete_session">
|
|
797
785
|
**Complete UAT session:**
|
|
798
786
|
|
|
799
|
-
**1.
|
|
787
|
+
**1. Revert mocks:**
|
|
800
788
|
```bash
|
|
801
|
-
|
|
802
|
-
MOCK_STASH=$(git stash list | grep "mocks-batch" | head -1 | cut -d: -f1)
|
|
803
|
-
[ -n "$MOCK_STASH" ] && git stash drop "$MOCK_STASH"
|
|
789
|
+
git checkout -- <mocked_files>
|
|
804
790
|
```
|
|
791
|
+
Use `mocked_files` list from UAT.md frontmatter. Clear the list after reverting.
|
|
805
792
|
|
|
806
793
|
**2. Generate UAT fixes patch (if fixes were made):**
|
|
807
794
|
```bash
|
|
@@ -818,7 +805,7 @@ PRE_WORK_STASH=$(git stash list | grep "pre-verify-work" | head -1 | cut -d: -f1
|
|
|
818
805
|
|
|
819
806
|
**4. Update UAT.md:**
|
|
820
807
|
- status: complete
|
|
821
|
-
- Clear current_batch,
|
|
808
|
+
- Clear current_batch, mocked_files
|
|
822
809
|
- Final Progress counts
|
|
823
810
|
|
|
824
811
|
**5. Commit UAT.md:**
|
|
@@ -863,7 +850,7 @@ Check if more phases remain in ROADMAP.md:
|
|
|
863
850
|
|---------|------|------|
|
|
864
851
|
| Frontmatter.status | OVERWRITE | Phase transitions |
|
|
865
852
|
| Frontmatter.current_batch | OVERWRITE | Batch transitions |
|
|
866
|
-
| Frontmatter.
|
|
853
|
+
| Frontmatter.mocked_files | OVERWRITE | Mock generation/cleanup |
|
|
867
854
|
| Frontmatter.updated | OVERWRITE | Every write |
|
|
868
855
|
| Progress | OVERWRITE | After each test result |
|
|
869
856
|
| Current Batch | OVERWRITE | Batch transitions |
|
|
@@ -895,7 +882,7 @@ Default: **major** (safe default)
|
|
|
895
882
|
- [ ] Dirty tree handled at start
|
|
896
883
|
- [ ] Tests classified by mock requirements
|
|
897
884
|
- [ ] Batches created respecting dependencies and mock types
|
|
898
|
-
- [ ] Mocks
|
|
885
|
+
- [ ] Mocks applied inline when needed (1-4 direct, 5+ via subagent)
|
|
899
886
|
- [ ] Tests presented in batches of 4
|
|
900
887
|
- [ ] Issues investigated with lightweight check (2-3 calls)
|
|
901
888
|
- [ ] Simple issues fixed inline with proper commit
|
|
@@ -903,7 +890,7 @@ Default: **major** (safe default)
|
|
|
903
890
|
- [ ] Re-test retries (2 max, tracked via retry_count) before offering options
|
|
904
891
|
- [ ] Blocked tests re-presented after blocking issues resolved
|
|
905
892
|
- [ ] Stash conflicts auto-resolved to fix version
|
|
906
|
-
- [ ] Mocks
|
|
893
|
+
- [ ] Mocks reverted on completion (git checkout)
|
|
907
894
|
- [ ] UAT fixes patch generated
|
|
908
895
|
- [ ] User's pre-existing work restored
|
|
909
896
|
- [ ] UAT.md committed with final summary
|
package/package.json
CHANGED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
<purpose>
|
|
2
|
-
Generate framework-specific mock code for manual UAT testing. Creates override files with toggle flags and minimal production hooks.
|
|
3
|
-
|
|
4
|
-
Called by verify-work workflow when a test batch requires mock state.
|
|
5
|
-
</purpose>
|
|
6
|
-
|
|
7
|
-
<philosophy>
|
|
8
|
-
**Mocks are temporary scaffolding.**
|
|
9
|
-
|
|
10
|
-
They exist only as uncommitted changes during testing. They enable reaching UI states that require specific backend conditions (premium user, error states, empty lists, loading states).
|
|
11
|
-
|
|
12
|
-
**Principles:**
|
|
13
|
-
- Minimal footprint: One override file + minimal hooks
|
|
14
|
-
- Easy removal: Delete file, remove imports, done
|
|
15
|
-
- Framework-appropriate: Match project conventions
|
|
16
|
-
- User-controlled: Clear toggle instructions
|
|
17
|
-
</philosophy>
|
|
18
|
-
|
|
19
|
-
<framework_detection>
|
|
20
|
-
|
|
21
|
-
**Step 1: Read PROJECT.md**
|
|
22
|
-
```bash
|
|
23
|
-
cat .planning/PROJECT.md 2>/dev/null | head -50
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
**Step 2: Verify with config files**
|
|
27
|
-
|
|
28
|
-
| Check | Indicates |
|
|
29
|
-
|-------|-----------|
|
|
30
|
-
| `pubspec.yaml` exists | Flutter |
|
|
31
|
-
| `package.json` has `"react"` or `"next"` | React/Next.js |
|
|
32
|
-
| `package.json` has `"react-native"` | React Native |
|
|
33
|
-
| `package.json` has `"vue"` | Vue |
|
|
34
|
-
|
|
35
|
-
**Step 3: Determine file locations**
|
|
36
|
-
|
|
37
|
-
| Framework | Override File | Import Pattern |
|
|
38
|
-
|-----------|---------------|----------------|
|
|
39
|
-
| Flutter | `lib/test_overrides.dart` | `import 'package:{app}/test_overrides.dart';` |
|
|
40
|
-
| React/Next.js | `src/testOverrides.ts` | `import { testOverrides } from '@/testOverrides';` |
|
|
41
|
-
| React Native | `src/testOverrides.ts` | `import { testOverrides } from '../testOverrides';` |
|
|
42
|
-
| Vue | `src/testOverrides.ts` | `import { testOverrides } from '@/testOverrides';` |
|
|
43
|
-
|
|
44
|
-
</framework_detection>
|
|
45
|
-
|
|
46
|
-
<override_file_pattern>
|
|
47
|
-
|
|
48
|
-
**Structure:**
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
// Test Overrides - DELETE THIS FILE BEFORE COMMITTING
|
|
52
|
-
// Used for manual UAT testing only
|
|
53
|
-
|
|
54
|
-
// === STATE FLAGS ===
|
|
55
|
-
// Set to true to enable mock state
|
|
56
|
-
|
|
57
|
-
{flag declarations based on mock_type}
|
|
58
|
-
|
|
59
|
-
// === MOCK DATA ===
|
|
60
|
-
// Returned when flags are true
|
|
61
|
-
|
|
62
|
-
{mock data structures}
|
|
63
|
-
|
|
64
|
-
// === RESET ===
|
|
65
|
-
// Call to disable all overrides
|
|
66
|
-
|
|
67
|
-
{reset function}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**Flag naming convention:**
|
|
71
|
-
- `force{State}` for boolean flags (e.g., `forcePremiumUser`, `forceErrorState`)
|
|
72
|
-
- `mock{DataType}` for mock data (e.g., `mockUserData`, `mockErrorMessage`)
|
|
73
|
-
|
|
74
|
-
</override_file_pattern>
|
|
75
|
-
|
|
76
|
-
<production_hook_pattern>
|
|
77
|
-
|
|
78
|
-
**Minimal hooks at service/repository layer:**
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
// Check override BEFORE real implementation
|
|
82
|
-
if (testOverrides.force{State}) {
|
|
83
|
-
return testOverrides.mock{Data};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Real implementation continues here...
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
**Placement:**
|
|
90
|
-
- In services/repositories, not UI components
|
|
91
|
-
- At the data fetch point, not the render point
|
|
92
|
-
- Single if-check, no complex branching
|
|
93
|
-
|
|
94
|
-
**Marking:**
|
|
95
|
-
```
|
|
96
|
-
// TEST OVERRIDE - Remove before commit
|
|
97
|
-
if (testOverrides.forceError) {
|
|
98
|
-
throw testOverrides.mockError;
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
</production_hook_pattern>
|
|
103
|
-
|
|
104
|
-
<mock_types>
|
|
105
|
-
|
|
106
|
-
Common mock types and what they enable:
|
|
107
|
-
|
|
108
|
-
| Mock Type | Enables Testing | Typical Flags |
|
|
109
|
-
|-----------|-----------------|---------------|
|
|
110
|
-
| `error_state` | Error messages, retry UI, fallback displays | `forceError`, `mockErrorMessage` |
|
|
111
|
-
| `premium_user` | Premium badges, gated features, upgrade prompts | `forcePremium`, `mockPremiumData` |
|
|
112
|
-
| `empty_response` | Empty states, placeholder UI, "no results" | `forceEmpty` |
|
|
113
|
-
| `loading_state` | Loading spinners, skeleton screens | `forceLoading`, `mockLoadingDelay` |
|
|
114
|
-
| `offline` | Offline UI, cached data, sync indicators | `forceOffline` |
|
|
115
|
-
| `transient_state` | Brief async states (loading skeletons, transitions) | `forceTransient`, `mockTransientDelay` |
|
|
116
|
-
| `external_data` | Features depending on API data that may not exist locally | `forceMockData`, `mockDataSet` |
|
|
117
|
-
|
|
118
|
-
</mock_types>
|
|
119
|
-
|
|
120
|
-
<transient_state_patterns>
|
|
121
|
-
|
|
122
|
-
**Transient states are UI states that appear briefly during async operations.** Loading skeletons, shimmer effects, transition animations — they resolve too fast to observe and test manually.
|
|
123
|
-
|
|
124
|
-
**Two mock strategies:**
|
|
125
|
-
|
|
126
|
-
**1. Extended delay strategy (default):**
|
|
127
|
-
|
|
128
|
-
Add a configurable delay before the real data returns. The transient state stays visible long enough to test.
|
|
129
|
-
|
|
130
|
-
```dart
|
|
131
|
-
// Flutter — Completer-based delay
|
|
132
|
-
Future<List<Recipe>> getRecipes() async {
|
|
133
|
-
// TEST OVERRIDE - Extend loading state for testing
|
|
134
|
-
if (TestOverrides.forceTransientState) {
|
|
135
|
-
await Future.delayed(TestOverrides.mockTransientDelay); // default 5s
|
|
136
|
-
}
|
|
137
|
-
// Real implementation continues...
|
|
138
|
-
final response = await _api.get('/recipes');
|
|
139
|
-
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// React/Next.js — Promise delay
|
|
145
|
-
async function getRecipes(): Promise<Recipe[]> {
|
|
146
|
-
// TEST OVERRIDE - Extend loading state for testing
|
|
147
|
-
if (testOverrides.forceTransientState) {
|
|
148
|
-
await new Promise(resolve => setTimeout(resolve, testOverrides.mockTransientDelayMs));
|
|
149
|
-
}
|
|
150
|
-
// Real implementation continues...
|
|
151
|
-
const response = await fetch('/api/recipes');
|
|
152
|
-
return response.json();
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**When to use:** Testing that the loading UI (skeleton, spinner) displays correctly while waiting.
|
|
157
|
-
|
|
158
|
-
**2. Never-resolve strategy:**
|
|
159
|
-
|
|
160
|
-
The async call never completes. The transient state stays permanently visible.
|
|
161
|
-
|
|
162
|
-
```dart
|
|
163
|
-
// Flutter — Completer that never completes
|
|
164
|
-
Future<List<Recipe>> getRecipes() async {
|
|
165
|
-
// TEST OVERRIDE - Never resolve, keep loading state visible
|
|
166
|
-
if (TestOverrides.forceTransientState && TestOverrides.mockTransientDelay == Duration.zero) {
|
|
167
|
-
await Completer<void>().future; // Never completes
|
|
168
|
-
}
|
|
169
|
-
// Real implementation continues...
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
// JS — Promise that never resolves
|
|
175
|
-
async function getRecipes(): Promise<Recipe[]> {
|
|
176
|
-
// TEST OVERRIDE - Never resolve, keep loading state visible
|
|
177
|
-
if (testOverrides.forceTransientState && testOverrides.mockTransientDelayMs === 0) {
|
|
178
|
-
await new Promise(() => {}); // Never resolves
|
|
179
|
-
}
|
|
180
|
-
// Real implementation continues...
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**When to use:** Testing that the loading UI itself is correct (layout, styling, animation) without it disappearing.
|
|
185
|
-
|
|
186
|
-
**Choosing between strategies:**
|
|
187
|
-
- Testing the transition (loading → loaded): Use extended delay (5s default)
|
|
188
|
-
- Testing the loading UI appearance: Use never-resolve (set delay to 0)
|
|
189
|
-
|
|
190
|
-
</transient_state_patterns>
|
|
191
|
-
|
|
192
|
-
<toggle_instructions_template>
|
|
193
|
-
|
|
194
|
-
**Format for each mock state:**
|
|
195
|
-
|
|
196
|
-
```markdown
|
|
197
|
-
**To enable {state_name}:**
|
|
198
|
-
1. Open `{override_file_path}`
|
|
199
|
-
2. Set `{flag_name} = true`
|
|
200
|
-
3. {Hot reload command or restart instruction}
|
|
201
|
-
4. Verify: {What user should see to confirm mock is active}
|
|
202
|
-
|
|
203
|
-
**To disable:**
|
|
204
|
-
1. Set `{flag_name} = false`
|
|
205
|
-
2. {Hot reload / restart}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**Framework-specific apply instructions:**
|
|
209
|
-
|
|
210
|
-
| Framework | Apply Changes |
|
|
211
|
-
|-----------|---------------|
|
|
212
|
-
| Flutter | Hot reload (r in terminal) or hot restart (R) |
|
|
213
|
-
| React/Next.js (dev) | Auto hot reload on save |
|
|
214
|
-
| React Native | Shake device → Reload, or `r` in Metro |
|
|
215
|
-
| Vue (dev) | Auto hot reload on save |
|
|
216
|
-
|
|
217
|
-
</toggle_instructions_template>
|
|
218
|
-
|
|
219
|
-
<spawn_mock_generator>
|
|
220
|
-
|
|
221
|
-
When verify-work needs mocks:
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
Task(
|
|
225
|
-
prompt="""
|
|
226
|
-
You are generating test mocks for manual UI verification.
|
|
227
|
-
|
|
228
|
-
## Context
|
|
229
|
-
|
|
230
|
-
Project type: {detected_framework}
|
|
231
|
-
Phase: {phase_name}
|
|
232
|
-
Mock type needed: {mock_type}
|
|
233
|
-
|
|
234
|
-
## Tests requiring this mock
|
|
235
|
-
|
|
236
|
-
{test_list_with_expected_behavior}
|
|
237
|
-
|
|
238
|
-
## Requirements
|
|
239
|
-
|
|
240
|
-
1. Create override file at standard location for this framework
|
|
241
|
-
2. Add minimal hooks to relevant services (if needed)
|
|
242
|
-
3. Provide clear toggle instructions
|
|
243
|
-
4. Write all files to disk
|
|
244
|
-
|
|
245
|
-
Follow the patterns from @~/.claude/mindsystem/workflows/generate-mocks.md
|
|
246
|
-
""",
|
|
247
|
-
subagent_type="ms-mock-generator",
|
|
248
|
-
description="Generate {mock_type} mocks"
|
|
249
|
-
)
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
</spawn_mock_generator>
|
|
253
|
-
|
|
254
|
-
<success_criteria>
|
|
255
|
-
- [ ] Framework correctly detected
|
|
256
|
-
- [ ] Override file created at standard location
|
|
257
|
-
- [ ] Minimal hooks added (only if needed)
|
|
258
|
-
- [ ] Toggle instructions clear and complete
|
|
259
|
-
- [ ] Files written to disk (uncommitted)
|
|
260
|
-
- [ ] Easy to remove (clear cleanup path)
|
|
261
|
-
</success_criteria>
|