@haposoft/cafekit 0.3.2 → 0.3.6
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/bin/install.js +29 -23
- package/package.json +1 -1
- package/src/antigravity/workflows/impact-analysis-output-example.md +313 -0
- package/src/antigravity/workflows/impact-analysis.md +735 -0
- package/src/claude/migration-manifest.json +2 -1
- package/src/common/skills/impact-analysis/SKILL.md +271 -0
- package/src/common/skills/impact-analysis/references/change-detection.md +270 -0
- package/src/common/skills/impact-analysis/references/dependency-scouting.md +337 -0
- package/src/common/skills/impact-analysis/references/edge-case-identification.md +439 -0
- package/src/common/skills/impact-analysis/references/industry-techniques.md +695 -0
- package/src/common/skills/impact-analysis/references/practical-techniques-guide.md +753 -0
- package/src/common/skills/impact-analysis/references/project-detection.md +704 -0
- package/src/common/skills/impact-analysis/references/react-native-customization.md +508 -0
- package/src/common/skills/impact-analysis/references/report-template.md +604 -0
- package/src/common/skills/impact-analysis/references/test-scenario-generation.md +459 -0
- package/src/common/skills/impact-analysis/scripts/README.md +476 -0
- package/src/common/skills/impact-analysis/scripts/ast-analyze.js +403 -0
- package/src/common/skills/impact-analysis/scripts/calculate-risk.js +475 -0
- package/src/common/skills/impact-analysis/scripts/find-dependencies.sh +202 -0
- package/src/common/skills/impact-analysis/scripts/run-analysis.sh +312 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# Test Scenario Generation - Tạo Test Scenarios
|
|
2
|
+
|
|
3
|
+
Templates và patterns để tạo comprehensive test scenarios từ impact analysis.
|
|
4
|
+
|
|
5
|
+
## Scenario Templates
|
|
6
|
+
|
|
7
|
+
### Template 1: Happy Path
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
## Test Scenario: {Feature} - Happy Path
|
|
11
|
+
|
|
12
|
+
**Objective:** Verify {feature} works correctly under normal conditions
|
|
13
|
+
|
|
14
|
+
**Preconditions:**
|
|
15
|
+
- {Condition 1}
|
|
16
|
+
- {Condition 2}
|
|
17
|
+
|
|
18
|
+
**Test Steps:**
|
|
19
|
+
1. {Action 1}
|
|
20
|
+
2. {Action 2}
|
|
21
|
+
3. {Action 3}
|
|
22
|
+
|
|
23
|
+
**Expected Results:**
|
|
24
|
+
- {Result 1}
|
|
25
|
+
- {Result 2}
|
|
26
|
+
- {Result 3}
|
|
27
|
+
|
|
28
|
+
**Verification:**
|
|
29
|
+
- [ ] {Check 1}
|
|
30
|
+
- [ ] {Check 2}
|
|
31
|
+
|
|
32
|
+
**Affected Components:**
|
|
33
|
+
- {Component 1}
|
|
34
|
+
- {Component 2}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Example:**
|
|
38
|
+
```markdown
|
|
39
|
+
## Test Scenario: User Login - Happy Path
|
|
40
|
+
|
|
41
|
+
**Objective:** Verify user can login with valid credentials
|
|
42
|
+
|
|
43
|
+
**Preconditions:**
|
|
44
|
+
- User exists in database
|
|
45
|
+
- User account is active
|
|
46
|
+
- Credentials are valid
|
|
47
|
+
|
|
48
|
+
**Test Steps:**
|
|
49
|
+
1. Navigate to /login
|
|
50
|
+
2. Enter email: test@example.com
|
|
51
|
+
3. Enter password: ValidPass123!
|
|
52
|
+
4. Click "Login" button
|
|
53
|
+
5. Wait for redirect
|
|
54
|
+
|
|
55
|
+
**Expected Results:**
|
|
56
|
+
- User redirected to /dashboard
|
|
57
|
+
- Auth token stored in localStorage
|
|
58
|
+
- User profile loaded in header
|
|
59
|
+
- Welcome message displayed
|
|
60
|
+
|
|
61
|
+
**Verification:**
|
|
62
|
+
- [ ] localStorage.getItem('token') returns valid JWT
|
|
63
|
+
- [ ] API call to /api/me succeeds
|
|
64
|
+
- [ ] User name displayed in header
|
|
65
|
+
|
|
66
|
+
**Affected Components:**
|
|
67
|
+
- src/components/LoginForm.tsx
|
|
68
|
+
- src/api/auth.ts
|
|
69
|
+
- src/hooks/useAuth.ts
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Template 2: Error Handling
|
|
73
|
+
|
|
74
|
+
```markdown
|
|
75
|
+
## Test Scenario: {Feature} - Error Case
|
|
76
|
+
|
|
77
|
+
**Objective:** Verify {feature} handles errors gracefully
|
|
78
|
+
|
|
79
|
+
**Preconditions:**
|
|
80
|
+
- {Setup error condition}
|
|
81
|
+
|
|
82
|
+
**Test Steps:**
|
|
83
|
+
1. {Trigger error}
|
|
84
|
+
2. {Observe behavior}
|
|
85
|
+
|
|
86
|
+
**Expected Results:**
|
|
87
|
+
- {Error message shown}
|
|
88
|
+
- {No crash/data loss}
|
|
89
|
+
- {Recovery possible}
|
|
90
|
+
|
|
91
|
+
**Edge Cases:**
|
|
92
|
+
- {Edge case 1}
|
|
93
|
+
- {Edge case 2}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Example:**
|
|
97
|
+
```markdown
|
|
98
|
+
## Test Scenario: User Login - Invalid Credentials
|
|
99
|
+
|
|
100
|
+
**Objective:** Verify login handles invalid credentials correctly
|
|
101
|
+
|
|
102
|
+
**Preconditions:**
|
|
103
|
+
- User exists but password is wrong
|
|
104
|
+
|
|
105
|
+
**Test Steps:**
|
|
106
|
+
1. Navigate to /login
|
|
107
|
+
2. Enter email: test@example.com
|
|
108
|
+
3. Enter password: WrongPassword
|
|
109
|
+
4. Click "Login"
|
|
110
|
+
|
|
111
|
+
**Expected Results:**
|
|
112
|
+
- Error message: "Invalid email or password"
|
|
113
|
+
- No redirect occurs
|
|
114
|
+
- Form remains interactive
|
|
115
|
+
- No token stored
|
|
116
|
+
- Password field cleared
|
|
117
|
+
|
|
118
|
+
**Edge Cases:**
|
|
119
|
+
- Empty email/password
|
|
120
|
+
- SQL injection attempts: ' OR '1'='1
|
|
121
|
+
- Very long password (1000+ chars)
|
|
122
|
+
- Special characters in password
|
|
123
|
+
- Multiple failed attempts (rate limiting)
|
|
124
|
+
|
|
125
|
+
**Verification:**
|
|
126
|
+
- [ ] Error message visible
|
|
127
|
+
- [ ] localStorage.getItem('token') returns null
|
|
128
|
+
- [ ] Login button re-enabled after error
|
|
129
|
+
- [ ] No console errors
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Template 3: Integration Test
|
|
133
|
+
|
|
134
|
+
```markdown
|
|
135
|
+
## Test Scenario: {Feature A} → {Feature B} Integration
|
|
136
|
+
|
|
137
|
+
**Objective:** Verify {feature A} integrates correctly with {feature B}
|
|
138
|
+
|
|
139
|
+
**Preconditions:**
|
|
140
|
+
- {Both features working independently}
|
|
141
|
+
|
|
142
|
+
**Test Steps:**
|
|
143
|
+
1. {Use feature A}
|
|
144
|
+
2. {Transition to feature B}
|
|
145
|
+
3. {Verify data flow}
|
|
146
|
+
|
|
147
|
+
**Expected Results:**
|
|
148
|
+
- {Data passed correctly}
|
|
149
|
+
- {State synchronized}
|
|
150
|
+
- {No data loss}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Example:**
|
|
154
|
+
```markdown
|
|
155
|
+
## Test Scenario: Login → Profile Update Integration
|
|
156
|
+
|
|
157
|
+
**Objective:** Verify auth token works across features
|
|
158
|
+
|
|
159
|
+
**Preconditions:**
|
|
160
|
+
- User logged in successfully
|
|
161
|
+
- Auth token valid
|
|
162
|
+
|
|
163
|
+
**Test Steps:**
|
|
164
|
+
1. Login with valid credentials
|
|
165
|
+
2. Navigate to /profile
|
|
166
|
+
3. Update profile information
|
|
167
|
+
4. Click "Save"
|
|
168
|
+
5. Verify update persisted
|
|
169
|
+
|
|
170
|
+
**Expected Results:**
|
|
171
|
+
- Profile API receives valid auth token
|
|
172
|
+
- Update succeeds with 200 status
|
|
173
|
+
- UI reflects changes immediately
|
|
174
|
+
- Success message displayed
|
|
175
|
+
- Changes persist after page refresh
|
|
176
|
+
|
|
177
|
+
**Edge Cases:**
|
|
178
|
+
- Token expires during update
|
|
179
|
+
- Network failure mid-update
|
|
180
|
+
- Concurrent profile updates
|
|
181
|
+
- Invalid data in update
|
|
182
|
+
|
|
183
|
+
**Verification:**
|
|
184
|
+
- [ ] Authorization header present in API call
|
|
185
|
+
- [ ] Token not expired
|
|
186
|
+
- [ ] Database updated correctly
|
|
187
|
+
- [ ] No race conditions
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Template 4: Regression Test
|
|
191
|
+
|
|
192
|
+
```markdown
|
|
193
|
+
## Test Scenario: {Existing Feature} - Regression Check
|
|
194
|
+
|
|
195
|
+
**Objective:** Verify {existing feature} still works after changes
|
|
196
|
+
|
|
197
|
+
**Preconditions:**
|
|
198
|
+
- {Feature worked before changes}
|
|
199
|
+
|
|
200
|
+
**Test Steps:**
|
|
201
|
+
1. {Original test steps}
|
|
202
|
+
|
|
203
|
+
**Expected Results:**
|
|
204
|
+
- {Same as before changes}
|
|
205
|
+
|
|
206
|
+
**Regression Risks:**
|
|
207
|
+
- {Risk 1}
|
|
208
|
+
- {Risk 2}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Example:**
|
|
212
|
+
```markdown
|
|
213
|
+
## Test Scenario: User Registration - Regression Check
|
|
214
|
+
|
|
215
|
+
**Objective:** Verify registration still works after auth changes
|
|
216
|
+
|
|
217
|
+
**Preconditions:**
|
|
218
|
+
- Registration worked before auth refactor
|
|
219
|
+
|
|
220
|
+
**Test Steps:**
|
|
221
|
+
1. Navigate to /register
|
|
222
|
+
2. Fill registration form
|
|
223
|
+
3. Submit form
|
|
224
|
+
4. Verify account created
|
|
225
|
+
|
|
226
|
+
**Expected Results:**
|
|
227
|
+
- Account created in database
|
|
228
|
+
- Welcome email sent
|
|
229
|
+
- Auto-login after registration
|
|
230
|
+
- Redirect to onboarding
|
|
231
|
+
|
|
232
|
+
**Regression Risks:**
|
|
233
|
+
- Password hashing changed
|
|
234
|
+
- Email validation broken
|
|
235
|
+
- Auto-login token generation
|
|
236
|
+
- Database schema mismatch
|
|
237
|
+
|
|
238
|
+
**Verification:**
|
|
239
|
+
- [ ] User exists in database
|
|
240
|
+
- [ ] Password hashed correctly (bcrypt)
|
|
241
|
+
- [ ] Email sent (check logs)
|
|
242
|
+
- [ ] Token generated and valid
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Scenario Generation Process
|
|
246
|
+
|
|
247
|
+
### Step 1: Analyze Changed Code
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Changed: src/api/auth.ts
|
|
251
|
+
export async function login(email: string, password: string) {
|
|
252
|
+
// NEW: Added rate limiting
|
|
253
|
+
await checkRateLimit(email);
|
|
254
|
+
|
|
255
|
+
const user = await findUser(email);
|
|
256
|
+
if (!user || !await verifyPassword(password, user.hash)) {
|
|
257
|
+
throw new UnauthorizedError();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// NEW: Added refresh token
|
|
261
|
+
const accessToken = generateToken(user);
|
|
262
|
+
const refreshToken = generateRefreshToken(user);
|
|
263
|
+
|
|
264
|
+
return { accessToken, refreshToken };
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Step 2: Identify Test Areas
|
|
269
|
+
|
|
270
|
+
From changes above:
|
|
271
|
+
1. **New feature**: Rate limiting → Test rate limit enforcement
|
|
272
|
+
2. **New feature**: Refresh token → Test token refresh flow
|
|
273
|
+
3. **Existing**: Login logic → Regression test
|
|
274
|
+
4. **Integration**: Frontend using new tokens → Integration test
|
|
275
|
+
|
|
276
|
+
### Step 3: Generate Scenarios
|
|
277
|
+
|
|
278
|
+
```markdown
|
|
279
|
+
## Scenario 1: Rate Limiting (New Feature)
|
|
280
|
+
Test that rate limiting blocks excessive login attempts
|
|
281
|
+
|
|
282
|
+
## Scenario 2: Refresh Token (New Feature)
|
|
283
|
+
Test that refresh token can renew access token
|
|
284
|
+
|
|
285
|
+
## Scenario 3: Login Flow (Regression)
|
|
286
|
+
Test that existing login still works
|
|
287
|
+
|
|
288
|
+
## Scenario 4: Frontend Integration (Integration)
|
|
289
|
+
Test that frontend handles new token structure
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Scenario Prioritization
|
|
293
|
+
|
|
294
|
+
### Priority Matrix
|
|
295
|
+
|
|
296
|
+
| Priority | Criteria | Example |
|
|
297
|
+
|----------|----------|---------|
|
|
298
|
+
| **P0 (Critical)** | Security, data loss, payment | Auth bypass, data deletion |
|
|
299
|
+
| **P1 (High)** | Core functionality, user-facing | Login, checkout, search |
|
|
300
|
+
| **P2 (Medium)** | Secondary features, edge cases | Profile update, filters |
|
|
301
|
+
| **P3 (Low)** | Nice-to-have, cosmetic | Tooltips, animations |
|
|
302
|
+
|
|
303
|
+
### Risk-Based Prioritization
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
function calculatePriority(scenario) {
|
|
307
|
+
const riskScore =
|
|
308
|
+
(scenario.affectedUsers * 3) +
|
|
309
|
+
(scenario.dataLossRisk * 5) +
|
|
310
|
+
(scenario.securityRisk * 5) +
|
|
311
|
+
(scenario.businessImpact * 2);
|
|
312
|
+
|
|
313
|
+
if (riskScore >= 15) return 'P0';
|
|
314
|
+
if (riskScore >= 10) return 'P1';
|
|
315
|
+
if (riskScore >= 5) return 'P2';
|
|
316
|
+
return 'P3';
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Test Data Preparation
|
|
321
|
+
|
|
322
|
+
### Test User Accounts
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
const testUsers = {
|
|
326
|
+
valid: {
|
|
327
|
+
email: 'test@example.com',
|
|
328
|
+
password: 'ValidPass123!',
|
|
329
|
+
role: 'user'
|
|
330
|
+
},
|
|
331
|
+
admin: {
|
|
332
|
+
email: 'admin@example.com',
|
|
333
|
+
password: 'AdminPass123!',
|
|
334
|
+
role: 'admin'
|
|
335
|
+
},
|
|
336
|
+
inactive: {
|
|
337
|
+
email: 'inactive@example.com',
|
|
338
|
+
password: 'Pass123!',
|
|
339
|
+
status: 'inactive'
|
|
340
|
+
},
|
|
341
|
+
deleted: {
|
|
342
|
+
email: 'deleted@example.com',
|
|
343
|
+
deleted: true
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Edge Case Data
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
const edgeCaseInputs = {
|
|
352
|
+
emails: [
|
|
353
|
+
'', // Empty
|
|
354
|
+
'invalid', // No @
|
|
355
|
+
'test@', // No domain
|
|
356
|
+
'@example.com', // No local
|
|
357
|
+
'a'.repeat(300) + '@test.com', // Too long
|
|
358
|
+
'test+tag@example.com', // Plus addressing
|
|
359
|
+
'test@subdomain.example.com', // Subdomain
|
|
360
|
+
],
|
|
361
|
+
passwords: [
|
|
362
|
+
'', // Empty
|
|
363
|
+
'short', // Too short
|
|
364
|
+
'a'.repeat(1000), // Too long
|
|
365
|
+
'NoNumbers!', // Missing numbers
|
|
366
|
+
'nonumbers123', // Missing special
|
|
367
|
+
'12345678', // Only numbers
|
|
368
|
+
'password', // Common password
|
|
369
|
+
]
|
|
370
|
+
};
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Automated Scenario Generation
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
// generate-scenarios.ts
|
|
377
|
+
function generateScenarios(changedFiles: string[]) {
|
|
378
|
+
const scenarios = [];
|
|
379
|
+
|
|
380
|
+
for (const file of changedFiles) {
|
|
381
|
+
// Happy path
|
|
382
|
+
scenarios.push({
|
|
383
|
+
type: 'happy-path',
|
|
384
|
+
file,
|
|
385
|
+
priority: 'P1'
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
// Error handling
|
|
389
|
+
scenarios.push({
|
|
390
|
+
type: 'error-handling',
|
|
391
|
+
file,
|
|
392
|
+
priority: 'P1'
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Edge cases
|
|
396
|
+
const edgeCases = detectEdgeCases(file);
|
|
397
|
+
for (const edge of edgeCases) {
|
|
398
|
+
scenarios.push({
|
|
399
|
+
type: 'edge-case',
|
|
400
|
+
file,
|
|
401
|
+
case: edge,
|
|
402
|
+
priority: 'P2'
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Regression
|
|
407
|
+
const dependencies = findDependencies(file);
|
|
408
|
+
for (const dep of dependencies) {
|
|
409
|
+
scenarios.push({
|
|
410
|
+
type: 'regression',
|
|
411
|
+
file: dep,
|
|
412
|
+
changedFile: file,
|
|
413
|
+
priority: 'P2'
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return scenarios;
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Output Format
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"scenarios": [
|
|
427
|
+
{
|
|
428
|
+
"id": "TS-001",
|
|
429
|
+
"title": "User Login - Happy Path",
|
|
430
|
+
"type": "happy-path",
|
|
431
|
+
"priority": "P1",
|
|
432
|
+
"estimatedTime": "5 min",
|
|
433
|
+
"automated": false,
|
|
434
|
+
"steps": [...],
|
|
435
|
+
"expectedResults": [...],
|
|
436
|
+
"affectedComponents": [...]
|
|
437
|
+
}
|
|
438
|
+
],
|
|
439
|
+
"summary": {
|
|
440
|
+
"total": 15,
|
|
441
|
+
"byPriority": { "P0": 2, "P1": 5, "P2": 6, "P3": 2 },
|
|
442
|
+
"byType": { "happy-path": 4, "error": 4, "integration": 3, "regression": 4 },
|
|
443
|
+
"estimatedTime": "2 hours"
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Integration with Test Execution
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
# Generate scenarios
|
|
452
|
+
node generate-scenarios.js > test-scenarios.json
|
|
453
|
+
|
|
454
|
+
# Execute automated tests
|
|
455
|
+
npm test -- --scenarios=test-scenarios.json
|
|
456
|
+
|
|
457
|
+
# Manual test checklist
|
|
458
|
+
cat test-scenarios.json | jq '.scenarios[] | select(.automated == false)'
|
|
459
|
+
```
|