memory-journal-mcp 7.0.1 → 7.2.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 (124) hide show
  1. package/README.md +75 -66
  2. package/dist/{chunk-6J4RPJ4I.js → chunk-GR4T3SRW.js} +146 -105
  3. package/dist/{chunk-ARLH46WS.js → chunk-IWKLHSPU.js} +89 -3
  4. package/dist/{chunk-2BJHLTYP.js → chunk-ORV7ZZOE.js} +1086 -86
  5. package/dist/cli.js +30 -4
  6. package/dist/github-integration-2TFMXHIJ.js +1 -0
  7. package/dist/index.d.ts +6 -2
  8. package/dist/index.js +3 -3
  9. package/dist/{tools-FFFGXIKN.js → tools-CXR2FEB2.js} +2 -2
  10. package/package.json +2 -2
  11. package/skills/README.md +77 -0
  12. package/skills/autonomous-dev/SKILL.md +56 -0
  13. package/skills/bin/sync.js +50 -0
  14. package/skills/bun/SKILL.md +156 -0
  15. package/skills/github-commander/SKILL.md +1 -1
  16. package/skills/github-commander/workflows/code-quality-audit.md +7 -5
  17. package/skills/github-commander/workflows/issue-triage.md +13 -4
  18. package/skills/github-commander/workflows/milestone-sprint.md +9 -1
  19. package/skills/github-commander/workflows/perf-audit.md +2 -0
  20. package/skills/github-commander/workflows/pr-review.md +9 -3
  21. package/skills/github-commander/workflows/roadmap-kickoff.md +79 -0
  22. package/skills/github-commander/workflows/security-audit.md +3 -3
  23. package/skills/github-commander/workflows/update-deps.md +2 -2
  24. package/skills/gitlab/SKILL.md +115 -0
  25. package/skills/gitlab/package-lock.json +392 -0
  26. package/skills/gitlab/package.json +14 -0
  27. package/skills/gitlab/scripts/gitlab-client.ts +125 -0
  28. package/skills/gitlab/scripts/gitlab-helper.ts +80 -0
  29. package/skills/golang/SKILL.md +54 -0
  30. package/skills/mysql/SKILL.md +30 -0
  31. package/skills/package.json +48 -0
  32. package/skills/playwright-standard/SKILL.md +58 -0
  33. package/skills/playwright-standard/examples/fixtures.ts +66 -0
  34. package/skills/playwright-standard/examples/type-stubs.d.ts +10 -0
  35. package/skills/playwright-standard/references/advanced-scenarios.md +59 -0
  36. package/skills/playwright-standard/references/infrastructure.md +43 -0
  37. package/skills/postgres/SKILL.md +33 -0
  38. package/skills/react-best-practices/AGENTS.md +2883 -0
  39. package/skills/react-best-practices/README.md +127 -0
  40. package/skills/react-best-practices/SKILL.md +138 -0
  41. package/skills/react-best-practices/metadata.json +17 -0
  42. package/skills/react-best-practices/rules/_sections.md +46 -0
  43. package/skills/react-best-practices/rules/_template.md +28 -0
  44. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  45. package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  46. package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  47. package/skills/react-best-practices/rules/async-api-routes.md +35 -0
  48. package/skills/react-best-practices/rules/async-defer-await.md +80 -0
  49. package/skills/react-best-practices/rules/async-dependencies.md +48 -0
  50. package/skills/react-best-practices/rules/async-parallel.md +24 -0
  51. package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  52. package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  53. package/skills/react-best-practices/rules/bundle-conditional.md +37 -0
  54. package/skills/react-best-practices/rules/bundle-defer-third-party.md +48 -0
  55. package/skills/react-best-practices/rules/bundle-dynamic-imports.md +34 -0
  56. package/skills/react-best-practices/rules/bundle-preload.md +44 -0
  57. package/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  58. package/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  59. package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  60. package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  61. package/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  62. package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  63. package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  64. package/skills/react-best-practices/rules/js-cache-storage.md +68 -0
  65. package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  66. package/skills/react-best-practices/rules/js-early-exit.md +50 -0
  67. package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  68. package/skills/react-best-practices/rules/js-index-maps.md +37 -0
  69. package/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  70. package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  71. package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  72. package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  73. package/skills/react-best-practices/rules/rendering-activity.md +24 -0
  74. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  75. package/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  76. package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  77. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  78. package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +72 -0
  79. package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +26 -0
  80. package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  81. package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  82. package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  83. package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  84. package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  85. package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  86. package/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  87. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  88. package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  89. package/skills/react-best-practices/rules/rerender-memo.md +44 -0
  90. package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  91. package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  92. package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  93. package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  94. package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  95. package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
  96. package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  97. package/skills/react-best-practices/rules/server-cache-react.md +76 -0
  98. package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
  99. package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  100. package/skills/react-best-practices/rules/server-serialization.md +38 -0
  101. package/skills/rust/SKILL.md +86 -0
  102. package/skills/shadcn-ui/SKILL.md +72 -0
  103. package/skills/skill-builder/SKILL.md +457 -0
  104. package/skills/skill-builder/checklist.md +65 -0
  105. package/skills/sqlite/SKILL.md +38 -0
  106. package/skills/typescript/SKILL.md +453 -0
  107. package/skills/typescript/assets/eslint-template.js +102 -0
  108. package/skills/typescript/assets/tsconfig-template.json +45 -0
  109. package/skills/typescript/references/enterprise-patterns.md +531 -0
  110. package/skills/typescript/references/generics.md +493 -0
  111. package/skills/typescript/references/nestjs-integration.md +579 -0
  112. package/skills/typescript/references/react-integration.md +616 -0
  113. package/skills/typescript/references/toolchain.md +547 -0
  114. package/skills/typescript/references/type-system.md +481 -0
  115. package/skills/vitest-standard/SKILL.md +82 -0
  116. package/skills/vitest-standard/examples/service-mock.ts +60 -0
  117. package/skills/vitest-standard/examples/tdd-calculator.ts +41 -0
  118. package/skills/vitest-standard/examples/type-stubs.d.ts +18 -0
  119. package/skills/vitest-standard/references/async-and-errors.md +58 -0
  120. package/skills/vitest-standard/references/coverage-and-config.md +53 -0
  121. package/skills/vitest-standard/references/mocking.md +61 -0
  122. package/skills/vitest-standard/references/tdd-patterns.md +60 -0
  123. package/dist/github-integration-PDRLXKGM.js +0 -1
  124. package/skills/github-commander/workflows/full-audit.md +0 -134
@@ -0,0 +1,481 @@
1
+ # TypeScript Type System Reference
2
+
3
+ > **Load when:** User asks about type annotations, interfaces vs types, unions, intersections, or type system fundamentals.
4
+
5
+ Complete guide to TypeScript's structural type system.
6
+
7
+ ## Contents
8
+
9
+ - [Type Annotations](#type-annotations)
10
+ - [Interfaces vs Type Aliases](#interfaces-vs-type-aliases)
11
+ - [Union and Intersection Types](#union-and-intersection-types)
12
+ - [Literal Types](#literal-types)
13
+ - [Type Guards and Narrowing](#type-guards-and-narrowing)
14
+ - [The satisfies Operator](#the-satisfies-operator)
15
+
16
+ ---
17
+
18
+ ## Type Annotations
19
+
20
+ ### Variable Annotations
21
+
22
+ ```typescript
23
+ // Explicit type annotations
24
+ const name: string = 'Alice'
25
+ const age: number = 30
26
+ const active: boolean = true
27
+
28
+ // Type inference (preferred when obvious)
29
+ const inferredName = 'Bob' // TypeScript infers string
30
+ const inferredAge = 25 // TypeScript infers number
31
+
32
+ // Arrays
33
+ const numbers: number[] = [1, 2, 3]
34
+ const strings: Array<string> = ['a', 'b', 'c']
35
+
36
+ // Tuples (fixed-length arrays with specific types)
37
+ const pair: [string, number] = ['age', 30]
38
+ const triple: [string, number, boolean] = ['name', 1, true]
39
+ ```
40
+
41
+ ### Function Annotations
42
+
43
+ ```typescript
44
+ // Function with typed parameters and return
45
+ function greet(name: string): string {
46
+ return `Hello, ${name}!`
47
+ }
48
+
49
+ // Arrow function
50
+ const add = (a: number, b: number): number => a + b
51
+
52
+ // Optional parameters
53
+ function greetOptional(name: string, greeting?: string): string {
54
+ return `${greeting ?? 'Hello'}, ${name}!`
55
+ }
56
+
57
+ // Default parameters
58
+ function greetDefault(name: string, greeting: string = 'Hello'): string {
59
+ return `${greeting}, ${name}!`
60
+ }
61
+
62
+ // Rest parameters
63
+ function sum(...numbers: number[]): number {
64
+ return numbers.reduce((a, b) => a + b, 0)
65
+ }
66
+
67
+ // Function type alias
68
+ type Comparator<T> = (a: T, b: T) => number
69
+ const numberCompare: Comparator<number> = (a, b) => a - b
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Interfaces vs Type Aliases
75
+
76
+ ### When to Use Interfaces
77
+
78
+ ```typescript
79
+ // Interfaces are ideal for object shapes
80
+ interface User {
81
+ id: string
82
+ name: string
83
+ email: string
84
+ }
85
+
86
+ // Interfaces can be extended
87
+ interface Employee extends User {
88
+ employeeId: string
89
+ department: string
90
+ }
91
+
92
+ // Interfaces can be implemented by classes
93
+ class Manager implements Employee {
94
+ constructor(
95
+ public id: string,
96
+ public name: string,
97
+ public email: string,
98
+ public employeeId: string,
99
+ public department: string
100
+ ) {}
101
+ }
102
+
103
+ // Declaration merging (interfaces only)
104
+ interface Config {
105
+ apiUrl: string
106
+ }
107
+
108
+ interface Config {
109
+ timeout: number
110
+ }
111
+
112
+ // Config now has both apiUrl and timeout
113
+ ```
114
+
115
+ ### When to Use Type Aliases
116
+
117
+ ```typescript
118
+ // Type aliases for unions
119
+ type Status = 'pending' | 'approved' | 'rejected'
120
+
121
+ // Type aliases for complex types
122
+ type Handler = (event: Event) => void
123
+
124
+ // Type aliases for mapped types
125
+ type Nullable<T> = { [K in keyof T]: T[K] | null }
126
+
127
+ // Type aliases for conditional types
128
+ type NonNullable<T> = T extends null | undefined ? never : T
129
+
130
+ // Type aliases for tuples
131
+ type Point = [x: number, y: number]
132
+ type RGB = [red: number, green: number, blue: number]
133
+ ```
134
+
135
+ ### Decision Guide
136
+
137
+ | Use Case | Prefer |
138
+ | ----------------- | ----------- |
139
+ | Object shapes | `interface` |
140
+ | Extending objects | `interface` |
141
+ | Class contracts | `interface` |
142
+ | Union types | `type` |
143
+ | Tuple types | `type` |
144
+ | Mapped types | `type` |
145
+ | Conditional types | `type` |
146
+ | Primitive aliases | `type` |
147
+
148
+ ---
149
+
150
+ ## Union and Intersection Types
151
+
152
+ ### Union Types
153
+
154
+ ```typescript
155
+ // Value can be one of several types
156
+ type StringOrNumber = string | number
157
+
158
+ // Discriminated unions (tagged unions)
159
+ interface Dog {
160
+ kind: 'dog'
161
+ bark(): void
162
+ }
163
+
164
+ interface Cat {
165
+ kind: 'cat'
166
+ meow(): void
167
+ }
168
+
169
+ type Pet = Dog | Cat
170
+
171
+ function speak(pet: Pet): void {
172
+ switch (pet.kind) {
173
+ case 'dog':
174
+ pet.bark()
175
+ break
176
+ case 'cat':
177
+ pet.meow()
178
+ break
179
+ }
180
+ }
181
+ ```
182
+
183
+ ### Intersection Types
184
+
185
+ ```typescript
186
+ // Value must satisfy all types
187
+ interface HasName {
188
+ name: string
189
+ }
190
+
191
+ interface HasAge {
192
+ age: number
193
+ }
194
+
195
+ type Person = HasName & HasAge
196
+
197
+ const person: Person = {
198
+ name: 'Alice',
199
+ age: 30,
200
+ }
201
+
202
+ // Practical: Extending with additional properties
203
+ type WithTimestamp<T> = T & { createdAt: Date; updatedAt: Date }
204
+
205
+ interface Article {
206
+ title: string
207
+ content: string
208
+ }
209
+
210
+ type TimestampedArticle = WithTimestamp<Article>
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Literal Types
216
+
217
+ ### String Literals
218
+
219
+ ```typescript
220
+ // Specific string values
221
+ type Direction = 'north' | 'south' | 'east' | 'west'
222
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
223
+
224
+ function move(direction: Direction): void {
225
+ console.log(`Moving ${direction}`)
226
+ }
227
+
228
+ move('north') // OK
229
+ move('up') // Error: Argument of type '"up"' is not assignable
230
+ ```
231
+
232
+ ### Numeric Literals
233
+
234
+ ```typescript
235
+ type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6
236
+ type BinaryDigit = 0 | 1
237
+
238
+ function roll(): DiceRoll {
239
+ return Math.ceil(Math.random() * 6) as DiceRoll
240
+ }
241
+ ```
242
+
243
+ ### Template Literal Types
244
+
245
+ ```typescript
246
+ // Construct string literal types
247
+ type EventName = 'click' | 'hover' | 'focus'
248
+ type HandlerName = `on${Capitalize<EventName>}`
249
+ // "onClick" | "onHover" | "onFocus"
250
+
251
+ // CSS unit types
252
+ type CSSUnit = 'px' | 'em' | 'rem' | '%'
253
+ type CSSValue = `${number}${CSSUnit}`
254
+
255
+ const width: CSSValue = '100px' // OK
256
+ const height: CSSValue = '50%' // OK
257
+ const bad: CSSValue = '100' // Error
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Type Guards and Narrowing
263
+
264
+ ### Built-in Type Guards
265
+
266
+ ```typescript
267
+ function process(value: string | number | null): string {
268
+ // typeof guard
269
+ if (typeof value === 'string') {
270
+ return value.toUpperCase()
271
+ }
272
+
273
+ // typeof guard for number
274
+ if (typeof value === 'number') {
275
+ return value.toFixed(2)
276
+ }
277
+
278
+ // null/undefined narrowing
279
+ if (value === null) {
280
+ return 'null'
281
+ }
282
+
283
+ // Exhaustiveness check
284
+ const _exhaustive: never = value
285
+ throw new Error(`Unhandled case: ${_exhaustive}`)
286
+ }
287
+ ```
288
+
289
+ ### instanceof Guard
290
+
291
+ ```typescript
292
+ class ApiError extends Error {
293
+ constructor(
294
+ public statusCode: number,
295
+ message: string
296
+ ) {
297
+ super(message)
298
+ }
299
+ }
300
+
301
+ class ValidationError extends Error {
302
+ constructor(public fields: string[]) {
303
+ super('Validation failed')
304
+ }
305
+ }
306
+
307
+ function handleError(error: Error): void {
308
+ if (error instanceof ApiError) {
309
+ console.log(`API Error ${error.statusCode}: ${error.message}`)
310
+ } else if (error instanceof ValidationError) {
311
+ console.log(`Validation Error on fields: ${error.fields.join(', ')}`)
312
+ } else {
313
+ console.log(`Unknown error: ${error.message}`)
314
+ }
315
+ }
316
+ ```
317
+
318
+ ### Custom Type Guards
319
+
320
+ ```typescript
321
+ interface User {
322
+ type: 'user'
323
+ name: string
324
+ }
325
+
326
+ interface Admin {
327
+ type: 'admin'
328
+ name: string
329
+ permissions: string[]
330
+ }
331
+
332
+ type Account = User | Admin
333
+
334
+ // Type predicate: returns boolean but narrows type
335
+ function isAdmin(account: Account): account is Admin {
336
+ return account.type === 'admin'
337
+ }
338
+
339
+ function getPermissions(account: Account): string[] {
340
+ if (isAdmin(account)) {
341
+ return account.permissions // TypeScript knows this is Admin
342
+ }
343
+ return []
344
+ }
345
+ ```
346
+
347
+ ### Assertion Functions
348
+
349
+ ```typescript
350
+ function assertDefined<T>(value: T | undefined, message: string): asserts value is T {
351
+ if (value === undefined) {
352
+ throw new Error(message)
353
+ }
354
+ }
355
+
356
+ function processUser(user: User | undefined): void {
357
+ assertDefined(user, 'User is required')
358
+ // After assertion, user is narrowed to User
359
+ console.log(user.name)
360
+ }
361
+ ```
362
+
363
+ ---
364
+
365
+ ## The satisfies Operator
366
+
367
+ ### Problem: Type Assertions Hide Bugs
368
+
369
+ ```typescript
370
+ // Using 'as' can hide type errors
371
+ const config = {
372
+ port: 3000,
373
+ host: 'localhost',
374
+ } as Record<string, string | number>
375
+
376
+ // No error, but port is now string | number
377
+ const portString = config.port.toFixed(2) // Runtime error if port is string!
378
+ ```
379
+
380
+ ### Solution: satisfies Validates Without Widening
381
+
382
+ ```typescript
383
+ // satisfies checks conformance but preserves literal types
384
+ const config = {
385
+ port: 3000,
386
+ host: 'localhost',
387
+ } satisfies Record<string, string | number>
388
+
389
+ // TypeScript knows port is number, host is string
390
+ config.port.toFixed(2) // OK - port is number
391
+ config.host.toUpperCase() // OK - host is string
392
+ ```
393
+
394
+ ### Practical Use Cases
395
+
396
+ ```typescript
397
+ // Color palette with constrained values
398
+ const palette = {
399
+ primary: '#007bff',
400
+ secondary: '#6c757d',
401
+ success: '#28a745',
402
+ } satisfies Record<string, `#${string}`>
403
+
404
+ // TypeScript knows each property exists and is a hex string
405
+ palette.primary.startsWith('#') // OK
406
+
407
+ // Route configuration
408
+ type RouteConfig = {
409
+ path: string
410
+ method: 'GET' | 'POST'
411
+ handler: () => void
412
+ }
413
+
414
+ const routes = {
415
+ home: { path: '/', method: 'GET', handler: () => {} },
416
+ login: { path: '/login', method: 'POST', handler: () => {} },
417
+ } satisfies Record<string, RouteConfig>
418
+
419
+ // TypeScript preserves literal types for each route
420
+ routes.home.method // "GET" (not "GET" | "POST")
421
+ ```
422
+
423
+ ---
424
+
425
+ ## Special Types
426
+
427
+ ### any vs unknown
428
+
429
+ ```typescript
430
+ // any: Opt out of type checking (avoid)
431
+ let anyValue: any = 'hello'
432
+ anyValue.toFixed(2) // No error, but crashes at runtime
433
+
434
+ // unknown: Type-safe any (prefer)
435
+ let unknownValue: unknown = 'hello'
436
+ unknownValue.toFixed(2) // Error: Object is of type 'unknown'
437
+
438
+ // Must narrow unknown before use
439
+ if (typeof unknownValue === 'string') {
440
+ unknownValue.toUpperCase() // OK after narrowing
441
+ }
442
+ ```
443
+
444
+ ### never
445
+
446
+ ```typescript
447
+ // never: Represents impossible values
448
+ function fail(message: string): never {
449
+ throw new Error(message)
450
+ }
451
+
452
+ // Exhaustiveness checking with never
453
+ type Shape = 'circle' | 'square'
454
+
455
+ function getArea(shape: Shape): number {
456
+ switch (shape) {
457
+ case 'circle':
458
+ return Math.PI
459
+ case 'square':
460
+ return 1
461
+ default:
462
+ // If we add a new shape, this will error
463
+ const _exhaustive: never = shape
464
+ throw new Error(`Unknown shape: ${_exhaustive}`)
465
+ }
466
+ }
467
+ ```
468
+
469
+ ### void vs undefined
470
+
471
+ ```typescript
472
+ // void: Function doesn't return anything meaningful
473
+ function log(message: string): void {
474
+ console.log(message)
475
+ }
476
+
477
+ // undefined: Explicit undefined value
478
+ function findUser(id: string): User | undefined {
479
+ return users.get(id)
480
+ }
481
+ ```
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: vitest-standard
3
+ description: |
4
+ Comprehensive unit testing expertise covering Vitest, test-driven
5
+ development (TDD), mocking strategies, and production-grade best practices.
6
+ Activates for unit testing, Vitest, TDD, Red-Green-Refactor, mocking,
7
+ stubbing, spying, test coverage, and test architecture in TypeScript/Node projects.
8
+ ---
9
+
10
+ # Vitest Standard
11
+
12
+ This skill provides opinionated, production-tested guidance for high-integrity unit testing with Vitest. It emphasizes behavior-driven design, strictly isolated tests, and the TDD lifecycle.
13
+
14
+ ## Golden Rules (Mandatory)
15
+
16
+ 1. **Test Behavior, Not Implementation** — Assert what the code _does_, not how it _looks_ internally.
17
+ 2. **Strict Isolation** — NO shared state between tests. Create new instances in `beforeEach`.
18
+ 3. **Clean Mocks** — Use `vi.clearAllMocks()` in `beforeEach` to prevent call history leaks.
19
+ 4. **No Magic Numbers** — Use descriptive variables for expected values.
20
+ 5. **AAA Pattern** — Every test must follow Arrange-Act-Assert.
21
+ 6. **Async/Await** — Always await promises; use `rejects.toThrow()` for error paths.
22
+ 7. **Deterministic Tests** — No dependence on system time, environment variables, or randomness (mock them).
23
+ 8. **Meaningful Names** — Use `it('should [action] when [condition]')` or Given-When-Then.
24
+ 9. **Mock at Boundaries** — Mock external APIs, databases, and third-party SDKs; test your own logic.
25
+ 10. **Red-Green-Refactor** — Prefer writing tests before code to drive API design.
26
+
27
+ ## Core Patterns
28
+
29
+ ### AAA (Arrange-Act-Assert)
30
+
31
+ ```typescript
32
+ it('should calculate total price', () => {
33
+ // Arrange: Setup data and environment
34
+ const cart = new ShoppingCart()
35
+ cart.addItem({ price: 10, quantity: 2 })
36
+
37
+ // Act: Execute the method being tested
38
+ const total = cart.getTotal()
39
+
40
+ // Assert: Verify the outcome
41
+ expect(total).toBe(20)
42
+ })
43
+ ```
44
+
45
+ ### Mocking Example
46
+
47
+ ```typescript
48
+ import { vi, it, expect } from 'vitest'
49
+
50
+ it('mocks dependencies', () => {
51
+ const mockFn = vi.fn().mockReturnValue(42)
52
+ expect(mockFn()).toBe(42)
53
+ expect(mockFn).toHaveBeenCalledOnce()
54
+ })
55
+ ```
56
+
57
+ ## Quick Reference: Assertions
58
+
59
+ | Assertion | Purpose |
60
+ | :----------------------- | :----------------------------- |
61
+ | `toBe(val)` | Strict equality (`===`) |
62
+ | `toEqual(val)` | Deep equality (objects/arrays) |
63
+ | `toMatchObject(obj)` | Partial match on an object |
64
+ | `toThrow(error?)` | Validates a thrown error |
65
+ | `toHaveBeenCalledWith()` | Verifies mock call arguments |
66
+ | `resolves.toEqual()` | Validates a fulfilled promise |
67
+ | `rejects.toThrow()` | Validates a rejected promise |
68
+
69
+ ---
70
+
71
+ ## Specialized References (Load On-Demand)
72
+
73
+ | Scenario | Reference File |
74
+ | :--------------------------- | :---------------------------------------------------------- |
75
+ | **Mocking & Doubles** | [mocking.md](references/mocking.md) |
76
+ | **Async & Error Handling** | [async-and-errors.md](references/async-and-errors.md) |
77
+ | **Coverage & Configuration** | [coverage-and-config.md](references/coverage-and-config.md) |
78
+ | **TDD Cycle** | [tdd-patterns.md](references/tdd-patterns.md) |
79
+
80
+ ## Example: TDD Calculator
81
+
82
+ See [tdd-calculator.ts](examples/tdd-calculator.ts) for the Red-Green-Refactor workflow.
@@ -0,0 +1,60 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2
+
3
+ // Intercept external module
4
+ vi.mock('./api', () => ({
5
+ fetchUser: vi.fn(),
6
+ updateUser: vi.fn(),
7
+ }))
8
+
9
+ // Mock instance for Dependency Injection
10
+ const mockDb = {
11
+ save: vi.fn().mockResolvedValue({ id: '123' }),
12
+ delete: vi.fn().mockResolvedValue(true),
13
+ }
14
+
15
+ describe('UserService', () => {
16
+ let service: UserService
17
+
18
+ beforeEach(() => {
19
+ service = new UserService(mockDb as any)
20
+ vi.clearAllMocks() // Clear call history between tests
21
+ })
22
+
23
+ afterEach(() => {
24
+ vi.restoreAllMocks() // Restore spies/intercepted methods
25
+ })
26
+
27
+ it('should save user to database', async () => {
28
+ // Arrange
29
+ const user = { name: 'John Doe' }
30
+
31
+ // Act
32
+ const result = await service.saveUser(user)
33
+
34
+ // Assert
35
+ expect(mockDb.save).toHaveBeenCalledOnce()
36
+ expect(mockDb.save).toHaveBeenCalledWith(user)
37
+ expect(result.id).toBe('123')
38
+ })
39
+
40
+ it('should throw error for invalid id', async () => {
41
+ // Arrange
42
+ mockDb.save.mockRejectedValueOnce(new Error('Invalid ID'))
43
+
44
+ // Act & Assert (Async Error Path)
45
+ await expect(service.saveUser({ name: '' })).rejects.toThrow('Invalid ID')
46
+ })
47
+ })
48
+
49
+ class UserService {
50
+ constructor(private db: Database) {}
51
+ async saveUser(user: any) {
52
+ return this.db.save(user)
53
+ }
54
+ }
55
+
56
+ class Database {
57
+ async save(user: any): Promise<any> {
58
+ return { id: '' }
59
+ }
60
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest'
2
+
3
+ // 1. RED: Write a failing test first
4
+ describe('Calculator', () => {
5
+ it('should add numbers', () => {
6
+ const calc = new Calculator()
7
+ expect(calc.add(2, 3)).toBe(5)
8
+ })
9
+
10
+ it('should multiply numbers', () => {
11
+ const calc = new Calculator()
12
+ expect(calc.multiply(2, 3)).toBe(6)
13
+ })
14
+ })
15
+
16
+ // 2. GREEN: Minimal implementations
17
+ class Calculator {
18
+ // Red -> Green -> Refactor cycle
19
+ add(a: number, b: number): number {
20
+ return a + b
21
+ }
22
+
23
+ // Next iteration:
24
+ multiply(a: number, b: number): number {
25
+ return a * b
26
+ }
27
+ }
28
+
29
+ // 3. REFACTOR (Example):
30
+ class ImprovedCalculator {
31
+ // Drive the add method with any number of parameters
32
+ add(...numbers: number[]): number {
33
+ return numbers.reduce((sum, n) => sum + n, 0)
34
+ }
35
+ }
36
+
37
+ // 4. Test the refactored version
38
+ it('should add multiple numbers in ImprovedCalculator', () => {
39
+ const calc = new ImprovedCalculator()
40
+ expect(calc.add(1, 2, 3, 4)).toBe(10)
41
+ })
@@ -0,0 +1,18 @@
1
+ // Type stubs for the Vitest Standard skill examples.
2
+ // This file solves "Cannot find module" errors in the IDE when viewing
3
+ // master reference files outside of a project root.
4
+
5
+ declare module 'vitest' {
6
+ export const describe: any
7
+ export const it: any
8
+ export const expect: any
9
+ export const vi: any
10
+ export const beforeEach: any
11
+ export const afterEach: any
12
+ export const beforeAll: any
13
+ export const afterAll: any
14
+ }
15
+
16
+ declare module 'vitest/config' {
17
+ export const defineConfig: any
18
+ }