@pageai/ralph-loop 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/.agent/PROMPT.md +58 -0
  2. package/.agent/STEERING.md +3 -0
  3. package/.agent/logs/LOG.md +13 -0
  4. package/.agent/prd/.gitkeep +0 -0
  5. package/.agent/screenshots/.gitkeep +0 -0
  6. package/.agent/skills/component-refactoring/SKILL.md +247 -0
  7. package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
  8. package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
  9. package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
  10. package/.agent/skills/e2e-tester/SKILL.md +595 -0
  11. package/.agent/skills/frontend-code-review/SKILL.md +73 -0
  12. package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
  13. package/.agent/skills/frontend-code-review/references/performance.md +36 -0
  14. package/.agent/skills/frontend-testing/SKILL.md +316 -0
  15. package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
  16. package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
  17. package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
  18. package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
  19. package/.agent/skills/frontend-testing/references/checklist.md +188 -0
  20. package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
  21. package/.agent/skills/frontend-testing/references/mocking.md +289 -0
  22. package/.agent/skills/frontend-testing/references/workflow.md +265 -0
  23. package/.agent/skills/prd-creator/JSON.md +613 -0
  24. package/.agent/skills/prd-creator/PRD.md +196 -0
  25. package/.agent/skills/prd-creator/SKILL.md +143 -0
  26. package/.agent/skills/skill-creator/SKILL.md +355 -0
  27. package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
  28. package/.agent/skills/skill-creator/references/workflows.md +28 -0
  29. package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
  30. package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
  31. package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
  32. package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
  33. package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  34. package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
  35. package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  36. package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  37. package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
  38. package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  39. package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  40. package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  41. package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  42. package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  43. package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  44. package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  45. package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  46. package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  47. package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
  48. package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  49. package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  50. package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  51. package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  52. package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  53. package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  54. package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  55. package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  56. package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  57. package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  58. package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  59. package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  60. package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  61. package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  62. package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  63. package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  64. package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  65. package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  66. package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  67. package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  68. package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  69. package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  70. package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  71. package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  72. package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  73. package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  74. package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  75. package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
  76. package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
  77. package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  78. package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
  79. package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
  80. package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
  81. package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
  82. package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
  83. package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
  84. package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
  85. package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
  86. package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
  87. package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
  88. package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
  89. package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
  90. package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
  91. package/.agent/tasks/.gitkeep +0 -0
  92. package/.agent/tasks.json +1 -0
  93. package/.claude/agents/code-reviewer.md +172 -0
  94. package/.claude/commands/aw.md +50 -0
  95. package/.claude/hooks/play-sound.js +87 -0
  96. package/.claude/hooks/pre-tool-use.js +40 -0
  97. package/.claude/settings.json +54 -0
  98. package/.claude/settings.local.json +13 -0
  99. package/.mcp.json +31 -0
  100. package/AGENTS.md +44 -0
  101. package/CLAUDE.md +1 -0
  102. package/README.md +236 -0
  103. package/bin/cli.js +156 -0
  104. package/bin/lib/copy.js +149 -0
  105. package/bin/lib/display.js +137 -0
  106. package/package.json +65 -0
  107. package/ralph.sh +333 -0
  108. package/scripts/lib/args.sh +44 -0
  109. package/scripts/lib/cleanup.sh +53 -0
  110. package/scripts/lib/constants.sh +25 -0
  111. package/scripts/lib/display.sh +196 -0
  112. package/scripts/lib/logging.sh +30 -0
  113. package/scripts/lib/notify.sh +41 -0
  114. package/scripts/lib/output.sh +147 -0
  115. package/scripts/lib/preflight.sh +57 -0
  116. package/scripts/lib/preview.sh +77 -0
  117. package/scripts/lib/promise.sh +76 -0
  118. package/scripts/lib/spinner.sh +85 -0
  119. package/scripts/lib/terminal.sh +57 -0
  120. package/scripts/lib/timing.sh +223 -0
@@ -0,0 +1,483 @@
1
+ # 1.10 Snapshot Testing
2
+
3
+ Snapshots capture the output of code and save it for comparison in future test runs. Use them sparingly for appropriate use cases.
4
+
5
+ ## When to Use Snapshots
6
+
7
+ **✅ Good use cases:**
8
+ - Testing complex object structures that rarely change
9
+ - Testing error messages and stack traces
10
+ - Testing serialized output (JSON, XML, HTML)
11
+ - Testing CLI output or formatted text
12
+ - Testing generated code or configurations
13
+
14
+ **❌ Bad use cases:**
15
+ - Testing dynamic data (dates, IDs, random values)
16
+ - Testing simple values (use explicit assertions instead)
17
+ - Testing implementation details
18
+ - Replacing proper assertions for laziness
19
+
20
+ ## Basic Snapshot Testing
21
+
22
+ **✅ Correct: snapshot for complex structure**
23
+ ```ts
24
+ import { describe, it, expect } from 'vitest';
25
+ import { generateConfig } from './config-generator';
26
+
27
+ describe('generateConfig', () => {
28
+ it('should generate correct config structure', () => {
29
+ const config = generateConfig({
30
+ environment: 'production',
31
+ features: ['auth', 'analytics'],
32
+ });
33
+
34
+ expect(config).toMatchSnapshot();
35
+ });
36
+ });
37
+ ```
38
+
39
+ **First run creates snapshot:**
40
+ ```ts
41
+ // __snapshots__/config-generator.test.ts.snap
42
+ exports[`generateConfig > should generate correct config structure 1`] = `
43
+ {
44
+ "analytics": {
45
+ "enabled": true,
46
+ "provider": "google-analytics",
47
+ },
48
+ "auth": {
49
+ "enabled": true,
50
+ "provider": "oauth2",
51
+ "timeout": 3600,
52
+ },
53
+ "environment": "production",
54
+ }
55
+ `;
56
+ ```
57
+
58
+ ## Inline Snapshots
59
+
60
+ For smaller snapshots, use inline snapshots to keep tests self-contained.
61
+
62
+ **✅ Correct: inline snapshot**
63
+ ```ts
64
+ it('should format error message', () => {
65
+ const error = formatError({
66
+ code: 'AUTH_FAILED',
67
+ message: 'Invalid credentials',
68
+ });
69
+
70
+ expect(error).toMatchInlineSnapshot(`
71
+ {
72
+ "code": "AUTH_FAILED",
73
+ "message": "Invalid credentials",
74
+ "timestamp": Any<Date>,
75
+ }
76
+ `);
77
+ });
78
+ ```
79
+
80
+ ## Property Matchers
81
+
82
+ Use property matchers for dynamic values like dates and IDs.
83
+
84
+ **✅ Correct: snapshot with property matchers**
85
+ ```ts
86
+ it('should create user with generated fields', () => {
87
+ const user = createUser({
88
+ name: 'John Doe',
89
+ email: 'john@example.com',
90
+ });
91
+
92
+ expect(user).toMatchSnapshot({
93
+ id: expect.any(String),
94
+ createdAt: expect.any(Date),
95
+ updatedAt: expect.any(Date),
96
+ });
97
+ });
98
+ ```
99
+
100
+ **Snapshot saved:**
101
+ ```ts
102
+ exports[`should create user with generated fields 1`] = `
103
+ {
104
+ "createdAt": Any<Date>,
105
+ "email": "john@example.com",
106
+ "id": Any<String>,
107
+ "name": "John Doe",
108
+ "updatedAt": Any<Date>,
109
+ }
110
+ `;
111
+ ```
112
+
113
+ ## Updating Snapshots
114
+
115
+ Update snapshots when intentional changes occur.
116
+
117
+ ```bash
118
+ # Update all snapshots
119
+ vitest run -u
120
+
121
+ # Update snapshots for specific file
122
+ vitest run user-service.test.ts -u
123
+
124
+ # Interactive update mode
125
+ vitest --ui
126
+ ```
127
+
128
+ **⚠️ Warning: Review changes carefully**
129
+ ```bash
130
+ # Before updating, review what changed
131
+ vitest run
132
+
133
+ # Check git diff to see snapshot changes
134
+ git diff __snapshots__/
135
+
136
+ # Only update if changes are intentional
137
+ vitest run -u
138
+ ```
139
+
140
+ ## Testing React Components
141
+
142
+ Snapshots work well for component output (but prefer visual regression tools for styling).
143
+
144
+ **✅ Correct: component snapshot**
145
+ ```ts
146
+ import { render } from '@testing-library/react';
147
+
148
+ it('should render user profile', () => {
149
+ const { container } = render(
150
+ <UserProfile
151
+ name="John Doe"
152
+ email="john@example.com"
153
+ role="admin"
154
+ />
155
+ );
156
+
157
+ expect(container.firstChild).toMatchSnapshot();
158
+ });
159
+ ```
160
+
161
+ **✅ Better: snapshot with property testing**
162
+ ```ts
163
+ it('should render user profile with all fields', () => {
164
+ const { getByText, getByRole } = render(
165
+ <UserProfile
166
+ name="John Doe"
167
+ email="john@example.com"
168
+ role="admin"
169
+ />
170
+ );
171
+
172
+ // Test specific behaviors
173
+ expect(getByText('John Doe')).toBeInTheDocument();
174
+ expect(getByText('john@example.com')).toBeInTheDocument();
175
+ expect(getByRole('img')).toHaveAttribute('alt', 'John Doe');
176
+
177
+ // Snapshot for full output
178
+ expect(container.firstChild).toMatchSnapshot();
179
+ });
180
+ ```
181
+
182
+ ## Testing Error Messages
183
+
184
+ Snapshots work well for error messages that include context.
185
+
186
+ **✅ Correct: error snapshot**
187
+ ```ts
188
+ it('should throw detailed validation error', () => {
189
+ const invalidData = {
190
+ email: 'invalid-email',
191
+ age: -5,
192
+ name: '',
193
+ };
194
+
195
+ expect(() => validateUser(invalidData)).toThrowErrorMatchingSnapshot();
196
+ });
197
+ ```
198
+
199
+ **Snapshot:**
200
+ ```ts
201
+ exports[`should throw detailed validation error 1`] = `
202
+ [ValidationError: User validation failed:
203
+ - email: Invalid email format
204
+ - age: Age must be between 0 and 150
205
+ - name: Name is required]
206
+ `;
207
+ ```
208
+
209
+ ## Serializers
210
+
211
+ Custom serializers normalize output for consistent snapshots.
212
+
213
+ **✅ Correct: custom serializer for dates**
214
+ ```ts
215
+ import { expect } from 'vitest';
216
+
217
+ expect.addSnapshotSerializer({
218
+ test: (val) => val instanceof Date,
219
+ serialize: (val) => `Date<${val.toISOString()}>`,
220
+ });
221
+
222
+ it('should create order with timestamp', () => {
223
+ const order = createOrder({ items: [] });
224
+
225
+ expect(order).toMatchInlineSnapshot(`
226
+ {
227
+ "createdAt": Date<2024-01-15T10:30:00.000Z>,
228
+ "id": "order-123",
229
+ "items": [],
230
+ }
231
+ `);
232
+ });
233
+ ```
234
+
235
+ ## When NOT to Use Snapshots
236
+
237
+ **❌ Incorrect: snapshot for simple value**
238
+ ```ts
239
+ it('should return user name', () => {
240
+ const name = getUserName(user);
241
+ expect(name).toMatchInlineSnapshot(`"John Doe"`);
242
+ });
243
+ ```
244
+
245
+ **✅ Correct: explicit assertion**
246
+ ```ts
247
+ it('should return user name', () => {
248
+ const name = getUserName(user);
249
+ expect(name).toBe('John Doe');
250
+ });
251
+ ```
252
+
253
+ **❌ Incorrect: snapshot with dynamic data**
254
+ ```ts
255
+ it('should generate report', () => {
256
+ const report = generateReport();
257
+
258
+ // Snapshot will change every run!
259
+ expect(report).toMatchSnapshot();
260
+ });
261
+ ```
262
+
263
+ **✅ Correct: snapshot with matchers**
264
+ ```ts
265
+ it('should generate report', () => {
266
+ const report = generateReport();
267
+
268
+ expect(report).toMatchSnapshot({
269
+ generatedAt: expect.any(Date),
270
+ id: expect.any(String),
271
+ });
272
+ });
273
+ ```
274
+
275
+ ## Testing CLI Output
276
+
277
+ Snapshots work well for command-line output.
278
+
279
+ **✅ Correct: CLI output snapshot**
280
+ ```ts
281
+ it('should display help text', () => {
282
+ const output = cli.getHelpText();
283
+
284
+ expect(output).toMatchInlineSnapshot(`
285
+ "Usage: myapp [options] [command]
286
+
287
+ Options:
288
+ -v, --version Output the version number
289
+ -h, --help Display help for command
290
+
291
+ Commands:
292
+ start [options] Start the application
293
+ stop Stop the application
294
+ status Show application status"
295
+ `);
296
+ });
297
+ ```
298
+
299
+ ## Testing JSON/API Responses
300
+
301
+ **✅ Correct: API response snapshot**
302
+ ```ts
303
+ it('should return user API response', async () => {
304
+ const response = await api.getUser('user-123');
305
+
306
+ expect(response).toMatchSnapshot({
307
+ data: {
308
+ id: expect.any(String),
309
+ createdAt: expect.any(String),
310
+ updatedAt: expect.any(String),
311
+ },
312
+ meta: {
313
+ requestId: expect.any(String),
314
+ timestamp: expect.any(Number),
315
+ },
316
+ });
317
+ });
318
+ ```
319
+
320
+ ## Snapshot Best Practices
321
+
322
+ ### 1. Keep Snapshots Small
323
+
324
+ **❌ Incorrect: massive snapshot**
325
+ ```ts
326
+ it('should render entire page', () => {
327
+ const { container } = render(<App />);
328
+ expect(container).toMatchSnapshot(); // Huge snapshot!
329
+ });
330
+ ```
331
+
332
+ **✅ Correct: focused snapshot**
333
+ ```ts
334
+ it('should render header', () => {
335
+ const { container } = render(<Header user={mockUser} />);
336
+ expect(container).toMatchSnapshot();
337
+ });
338
+
339
+ it('should render navigation', () => {
340
+ const { container } = render(<Navigation items={mockItems} />);
341
+ expect(container).toMatchSnapshot();
342
+ });
343
+ ```
344
+
345
+ ### 2. Name Snapshots Clearly
346
+
347
+ **❌ Incorrect: generic name**
348
+ ```ts
349
+ it('test 1', () => {
350
+ expect(result).toMatchSnapshot();
351
+ });
352
+ ```
353
+
354
+ **✅ Correct: descriptive name**
355
+ ```ts
356
+ it('should format currency with symbol and decimals', () => {
357
+ expect(formatCurrency(1234.56, 'USD')).toMatchInlineSnapshot(`"$1,234.56"`);
358
+ });
359
+ ```
360
+
361
+ ### 3. Review Snapshot Changes
362
+
363
+ Always review snapshot updates in code review.
364
+
365
+ ```bash
366
+ # In CI/CD, ensure snapshots match
367
+ vitest run
368
+
369
+ # Fail if snapshots need updating
370
+ # This prevents accidental updates
371
+ ```
372
+
373
+ **✅ Correct: intentional update**
374
+ ```
375
+ 1. Make code change
376
+ 2. Run tests - see snapshot diff
377
+ 3. Review diff carefully
378
+ 4. Update if intentional: vitest run -u
379
+ 5. Commit updated snapshots
380
+ 6. Explain changes in PR description
381
+ ```
382
+
383
+ ### 4. Combine with Explicit Assertions
384
+
385
+ **✅ Correct: snapshots + assertions**
386
+ ```ts
387
+ it('should generate invoice', () => {
388
+ const invoice = generateInvoice({
389
+ items: [{ name: 'Widget', price: 10, quantity: 2 }],
390
+ tax: 0.08,
391
+ });
392
+
393
+ // Explicit assertions for critical values
394
+ expect(invoice.subtotal).toBe(20);
395
+ expect(invoice.tax).toBe(1.6);
396
+ expect(invoice.total).toBe(21.6);
397
+
398
+ // Snapshot for full structure
399
+ expect(invoice).toMatchSnapshot({
400
+ id: expect.any(String),
401
+ createdAt: expect.any(Date),
402
+ });
403
+ });
404
+ ```
405
+
406
+ ## Snapshot Anti-Patterns
407
+
408
+ **❌ Incorrect: using snapshots as a crutch**
409
+ ```ts
410
+ it('should work', () => {
411
+ // Lazy: just snapshot everything instead of thinking about what to test
412
+ expect(doSomething()).toMatchSnapshot();
413
+ });
414
+ ```
415
+
416
+ **❌ Incorrect: ignoring failing snapshots**
417
+ ```bash
418
+ # Don't blindly update snapshots without understanding why they changed
419
+ vitest run -u # ❌ Without reviewing changes first
420
+ ```
421
+
422
+ **❌ Incorrect: snapshots for test doubles**
423
+ ```ts
424
+ it('should call service', () => {
425
+ const mockService = vi.fn();
426
+ callService(mockService);
427
+
428
+ // Don't snapshot mock calls!
429
+ expect(mockService.mock.calls).toMatchSnapshot();
430
+ });
431
+ ```
432
+
433
+ **✅ Correct: explicit assertions for mocks**
434
+ ```ts
435
+ it('should call service with correct params', () => {
436
+ const mockService = vi.fn();
437
+ callService(mockService);
438
+
439
+ expect(mockService).toHaveBeenCalledWith({
440
+ id: '123',
441
+ action: 'update',
442
+ });
443
+ });
444
+ ```
445
+
446
+ ## Organizing Snapshots
447
+
448
+ Snapshots are stored in `__snapshots__/` directories.
449
+
450
+ ```
451
+ src/
452
+ components/
453
+ button.tsx
454
+ button.test.tsx
455
+ __snapshots__/
456
+ button.test.tsx.snap
457
+ services/
458
+ user-service.ts
459
+ user-service.test.ts
460
+ __snapshots__/
461
+ user-service.test.ts.snap
462
+ ```
463
+
464
+ **✅ Correct: commit snapshots**
465
+ ```bash
466
+ # Always commit snapshot files
467
+ git add src/**/__snapshots__
468
+ git commit -m "Update snapshots after button styling changes"
469
+ ```
470
+
471
+ ## When to Prefer Explicit Assertions
472
+
473
+ Use explicit assertions when:
474
+ - Testing simple values
475
+ - Testing critical business logic
476
+ - Testing behavior, not structure
477
+ - You need clear failure messages
478
+
479
+ Use snapshots when:
480
+ - Testing complex structures
481
+ - Output format matters
482
+ - Regression testing large outputs
483
+ - Maintaining consistency across many similar tests