claude-toolkit 0.1.12 → 0.1.18

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.
@@ -0,0 +1,492 @@
1
+ ---
2
+ name: ct-vite-vitest-patterns
3
+ description: Vite build tooling and Vitest unit/integration testing patterns -- config, plugins, mocking, coverage, browser mode, and workspace
4
+ ---
5
+
6
+ # Vite + Vitest Patterns
7
+
8
+ Vite is the build tool; Vitest is its native test runner. They share a unified config -- aliases, plugins, and `define` values work identically in both. This is the primary advantage over separate build/test toolchains.
9
+
10
+ ## Vite Configuration
11
+
12
+ ### Config Structure
13
+
14
+ ```typescript
15
+ import { defineConfig } from 'vite'
16
+
17
+ export default defineConfig({
18
+ base: '/',
19
+ plugins: [],
20
+ envPrefix: 'VITE_',
21
+
22
+ resolve: {
23
+ alias: { '@': '/src' },
24
+ conditions: [],
25
+ },
26
+
27
+ css: {
28
+ transformer: 'postcss', // or 'lightningcss'
29
+ modules: {},
30
+ preprocessorOptions: {},
31
+ },
32
+
33
+ oxc: {}, // Oxc transformer (replaces esbuild in Vite 8)
34
+
35
+ server: {
36
+ port: 5173,
37
+ proxy: {},
38
+ warmup: { clientFiles: [] }, // pre-transform hot files for faster cold starts
39
+ },
40
+
41
+ build: {
42
+ target: 'baseline-widely-available',
43
+ outDir: 'dist',
44
+ sourcemap: false,
45
+ minify: 'oxc', // 'oxc' (default) | 'terser' | false
46
+ rolldownOptions: {}, // Rolldown bundler config (replaces rollupOptions in Vite 8)
47
+ },
48
+
49
+ ssr: {
50
+ target: 'node',
51
+ noExternal: [],
52
+ external: [],
53
+ },
54
+ })
55
+ ```
56
+
57
+ ### Conditional Config
58
+
59
+ ```typescript
60
+ export default defineConfig(({ command, mode, isSsrBuild }) => {
61
+ if (command === 'serve') return { /* dev-specific */ }
62
+ return { /* build-specific */ }
63
+ })
64
+ ```
65
+
66
+ ### Environment Variables
67
+
68
+ Loading order (later overrides earlier): `.env` > `.env.local` > `.env.[mode]` > `.env.[mode].local`.
69
+
70
+ Built-in `import.meta.env`: `MODE`, `BASE_URL`, `PROD`, `DEV`, `SSR`.
71
+
72
+ **Security:** Never put secrets in `VITE_*` variables -- they are embedded in client bundles.
73
+
74
+ TypeScript declarations (`src/vite-env.d.ts`):
75
+
76
+ ```typescript
77
+ /// <reference types="vite/client" />
78
+
79
+ interface ImportMetaEnv {
80
+ readonly VITE_API_URL: string
81
+ }
82
+ interface ImportMeta {
83
+ readonly env: ImportMetaEnv
84
+ }
85
+ ```
86
+
87
+ ### Plugin System
88
+
89
+ ```typescript
90
+ export default defineConfig({
91
+ plugins: [
92
+ solidPlugin(),
93
+ process.env.ANALYZE && visualizer(), // conditional (falsy ignored)
94
+ { ...myPlugin(), enforce: 'pre' }, // before Vite core transforms
95
+ { ...myPlugin(), apply: 'build' }, // build only
96
+ ],
97
+ })
98
+ ```
99
+
100
+ Key hooks (execution order): `config` > `configResolved` > `configureServer` > `transformIndexHtml` > `resolveId` > `load` > `transform` > `handleHotUpdate`.
101
+
102
+ ### Library Mode
103
+
104
+ ```typescript
105
+ import { resolve } from 'node:path'
106
+
107
+ export default defineConfig({
108
+ build: {
109
+ lib: {
110
+ entry: resolve(import.meta.dirname, 'lib/main.ts'),
111
+ name: 'MyLib',
112
+ fileName: 'my-lib',
113
+ formats: ['es', 'cjs'],
114
+ },
115
+ rolldownOptions: {
116
+ external: ['solid-js', 'solid-js/web'], // always externalize peer deps
117
+ },
118
+ },
119
+ })
120
+ ```
121
+
122
+ ### SSR
123
+
124
+ ```json
125
+ {
126
+ "build:client": "vite build --outDir dist/client",
127
+ "build:server": "vite build --outDir dist/server --ssr src/entry-server.ts"
128
+ }
129
+ ```
130
+
131
+ Use `middlewareMode: true` + `appType: 'custom'` for framework SSR integration.
132
+
133
+ ### Build Performance
134
+
135
+ 1. **Avoid barrel files** -- import directly from source modules, not re-export `index.ts`
136
+ 2. **Use explicit extensions** -- `import './Component.tsx'` not `import './Component'`
137
+ 3. **Warm up hot files** -- `server.warmup.clientFiles: ['./src/main.tsx']`
138
+ 4. **Prefer native CSS** -- CSS nesting is supported natively; avoid Sass when possible
139
+ 5. **Narrow resolve.extensions** -- remove extensions you don't use
140
+
141
+ ---
142
+
143
+ ## Vitest Configuration
144
+
145
+ ### Standalone Config
146
+
147
+ ```typescript
148
+ import { defineConfig } from 'vitest/config'
149
+
150
+ export default defineConfig({
151
+ test: {
152
+ include: ['**/*.{test,spec}.{ts,tsx}'],
153
+ environment: 'node', // 'node' | 'jsdom' | 'happy-dom'
154
+ globals: false,
155
+ setupFiles: [],
156
+ testTimeout: 5000,
157
+ pool: 'forks', // 'forks' | 'threads' | 'vmThreads'
158
+
159
+ restoreMocks: true, // auto vi.restoreAllMocks() after each test
160
+ clearMocks: true,
161
+
162
+ coverage: {
163
+ provider: 'v8',
164
+ include: ['src/**/*.{ts,tsx}'],
165
+ exclude: ['**/*.test.*', '**/*.d.ts', 'src/types/**'],
166
+ reporter: ['text', 'html', 'lcov'],
167
+ thresholds: { lines: 80, branches: 80, functions: 80, statements: 80 },
168
+ },
169
+
170
+ snapshotSerializers: [],
171
+ },
172
+ })
173
+ ```
174
+
175
+ ### Integrated with Vite Config
176
+
177
+ ```typescript
178
+ /// <reference types="vitest/config" />
179
+ import { defineConfig } from 'vite'
180
+
181
+ export default defineConfig({
182
+ plugins: [solidPlugin()],
183
+ resolve: { alias: { '@': '/src' } }, // shared: works in both app and tests
184
+ test: {
185
+ environment: 'jsdom',
186
+ setupFiles: ['./tests/setup.ts'],
187
+ },
188
+ })
189
+ ```
190
+
191
+ Vite's `resolve.alias`, `plugins`, and `define` are automatically inherited by Vitest. Never duplicate them.
192
+
193
+ ### Merging Separate Configs
194
+
195
+ ```typescript
196
+ import { defineConfig, mergeConfig } from 'vitest/config'
197
+ import viteConfig from './vite.config'
198
+
199
+ export default mergeConfig(viteConfig, defineConfig({
200
+ test: { environment: 'jsdom' },
201
+ }))
202
+ ```
203
+
204
+ ### Workspace / Projects (Vitest 3+)
205
+
206
+ Use `test.projects` for monorepos or mixed environments:
207
+
208
+ ```typescript
209
+ export default defineConfig({
210
+ test: {
211
+ projects: [
212
+ 'packages/*',
213
+ {
214
+ test: {
215
+ name: 'unit',
216
+ include: ['src/**/*.test.ts'],
217
+ environment: 'node',
218
+ },
219
+ },
220
+ {
221
+ test: {
222
+ name: 'components',
223
+ include: ['src/**/*.test.tsx'],
224
+ environment: 'jsdom',
225
+ },
226
+ },
227
+ ],
228
+ },
229
+ })
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Mocking
235
+
236
+ ### Mock Functions
237
+
238
+ ```typescript
239
+ const fn = vi.fn()
240
+ fn.mockReturnValue(42)
241
+ fn.mockResolvedValue({ data: [] })
242
+ fn.mockImplementation((x) => x * 2)
243
+
244
+ expect(fn).toHaveBeenCalledWith('arg')
245
+ expect(fn).toHaveBeenCalledTimes(1)
246
+ ```
247
+
248
+ ### Module Mocking
249
+
250
+ `vi.mock` is hoisted above imports automatically:
251
+
252
+ ```typescript
253
+ vi.mock('./api', () => ({
254
+ fetchUser: vi.fn().mockResolvedValue({ id: 1, name: 'Test' }),
255
+ }))
256
+
257
+ // Access original implementation inside mock
258
+ vi.mock('./utils', async (importOriginal) => {
259
+ const actual = await importOriginal<typeof import('./utils')>()
260
+ return { ...actual, format: vi.fn() }
261
+ })
262
+ ```
263
+
264
+ **Hoisting caveat:** Variables defined before `vi.mock()` are not accessible inside the factory. Use `vi.hoisted()` for shared variables:
265
+
266
+ ```typescript
267
+ const { mockFetch } = vi.hoisted(() => ({
268
+ mockFetch: vi.fn(),
269
+ }))
270
+
271
+ vi.mock('./api', () => ({ fetch: mockFetch }))
272
+ ```
273
+
274
+ ### Spying
275
+
276
+ ```typescript
277
+ const spy = vi.spyOn(console, 'warn').mockImplementation(() => {})
278
+ expect(spy).toHaveBeenCalledWith('expected warning')
279
+ spy.mockRestore()
280
+ ```
281
+
282
+ ### Timer Mocking
283
+
284
+ ```typescript
285
+ vi.useFakeTimers()
286
+ vi.setSystemTime(new Date('2026-01-01'))
287
+
288
+ setTimeout(callback, 1000)
289
+ vi.advanceTimersByTime(1000)
290
+ expect(callback).toHaveBeenCalled()
291
+
292
+ vi.useRealTimers()
293
+ ```
294
+
295
+ ### Environment Stubs
296
+
297
+ ```typescript
298
+ vi.stubGlobal('__VERSION__', '1.0.0')
299
+ vi.stubEnv('VITE_API_URL', 'http://test.example.com')
300
+
301
+ afterEach(() => {
302
+ vi.unstubAllGlobals()
303
+ vi.unstubAllEnvs()
304
+ })
305
+ ```
306
+
307
+ ---
308
+
309
+ ## Snapshot Testing
310
+
311
+ ```typescript
312
+ // File snapshots (stored in __snapshots__/)
313
+ expect(result).toMatchSnapshot()
314
+
315
+ // Inline snapshots (written into test file by vitest --update)
316
+ expect(result).toMatchInlineSnapshot(`{ "id": 1 }`)
317
+
318
+ // Custom file path
319
+ expect(htmlOutput).toMatchFileSnapshot('./fixtures/expected.html')
320
+ ```
321
+
322
+ Keep inline snapshots under 10-15 lines. Use file snapshots for complex output. Snapshots catch regressions but don't verify correctness -- combine with explicit assertions on critical values.
323
+
324
+ ---
325
+
326
+ ## In-Source Testing
327
+
328
+ ```typescript
329
+ // src/utils/math.ts
330
+ export function add(...args: number[]) {
331
+ return args.reduce((a, b) => a + b, 0)
332
+ }
333
+
334
+ if (import.meta.vitest) {
335
+ const { it, expect } = import.meta.vitest
336
+ it('adds numbers', () => {
337
+ expect(add(1, 2, 3)).toBe(6)
338
+ })
339
+ }
340
+ ```
341
+
342
+ Config:
343
+
344
+ ```typescript
345
+ export default defineConfig({
346
+ test: { includeSource: ['src/**/*.ts'] },
347
+ define: { 'import.meta.vitest': 'undefined' }, // tree-shake from production
348
+ })
349
+ ```
350
+
351
+ Best for small utility functions. Use separate test files for components and integration tests.
352
+
353
+ ---
354
+
355
+ ## Browser Mode (Vitest 4+, Stable)
356
+
357
+ ```typescript
358
+ import { playwright } from '@vitest/browser-playwright'
359
+
360
+ export default defineConfig({
361
+ test: {
362
+ browser: {
363
+ enabled: true,
364
+ provider: playwright(),
365
+ instances: [{ browser: 'chromium' }],
366
+ headless: true,
367
+ },
368
+ },
369
+ })
370
+ ```
371
+
372
+ Providers: `@vitest/browser-playwright` (recommended), `@vitest/browser-webdriverio`.
373
+
374
+ Quick setup: `npx vitest init browser`
375
+
376
+ ### Visual Regression
377
+
378
+ ```typescript
379
+ import { page } from 'vitest/browser'
380
+
381
+ it('matches visual baseline', async () => {
382
+ await page.goto('/component-demo')
383
+ await expect(page.getByRole('button')).toMatchScreenshot()
384
+ })
385
+ ```
386
+
387
+ ### Playwright Traces
388
+
389
+ ```typescript
390
+ browser: {
391
+ provider: playwright({ trace: 'on-first-retry' }),
392
+ // 'off' | 'on' | 'on-first-retry' | 'on-all-retries' | 'retain-on-failure'
393
+ }
394
+ ```
395
+
396
+ ### Browser Mode Limitations
397
+
398
+ - Cannot `vi.spyOn` module exports -- use `vi.mock('./module', { spy: true })` instead
399
+ - Thread-blocking APIs (`alert`, `confirm`, `prompt`) are auto-mocked
400
+ - Uses testing-library selectors: `getByRole`, `getByText`, `getByLabelText`
401
+
402
+ ---
403
+
404
+ ## Coverage
405
+
406
+ Install: `@vitest/coverage-v8` (default, fastest) or `@vitest/coverage-istanbul` (universal).
407
+
408
+ Run: `vitest --coverage`
409
+
410
+ Ignore comments:
411
+
412
+ - V8: `/* v8 ignore next */`
413
+ - Istanbul: `/* istanbul ignore next -- @preserve */`
414
+
415
+ Include `@preserve` to prevent Oxc minifier from stripping comments.
416
+
417
+ ---
418
+
419
+ ## Custom Matchers
420
+
421
+ ```typescript
422
+ import { expect } from 'vitest'
423
+
424
+ expect.extend({
425
+ toBeWithinRange(received: number, floor: number, ceiling: number) {
426
+ const pass = received >= floor && received <= ceiling
427
+ return {
428
+ pass,
429
+ message: () => `expected ${received} to be within [${floor}, ${ceiling}]`,
430
+ }
431
+ },
432
+ })
433
+ ```
434
+
435
+ TypeScript (`vitest.d.ts`):
436
+
437
+ ```typescript
438
+ import 'vitest'
439
+
440
+ declare module 'vitest' {
441
+ interface Matchers<T = any> {
442
+ toBeWithinRange(floor: number, ceiling: number): T
443
+ }
444
+ }
445
+ ```
446
+
447
+ ### Schema Validation (Vitest 4+)
448
+
449
+ ```typescript
450
+ import { z } from 'zod'
451
+
452
+ const UserSchema = z.object({ id: z.number(), name: z.string() })
453
+ expect(response.data).toSatisfy(expect.schemaMatching(UserSchema))
454
+ ```
455
+
456
+ Works with any Standard Schema v1 library (Zod, Valibot, ArkType).
457
+
458
+ ---
459
+
460
+ ## Vite 8 Migration
461
+
462
+ | Old (Vite 7-) | New (Vite 8) | Status |
463
+ |---|---|---|
464
+ | `build.rollupOptions` | `build.rolldownOptions` | Deprecated, compat layer exists |
465
+ | `optimizeDeps.esbuildOptions` | `optimizeDeps.rolldownOptions` | Deprecated |
466
+ | `esbuild` config | `oxc` config | Deprecated |
467
+ | `build.minify: 'esbuild'` | `build.minify: 'oxc'` | New default |
468
+
469
+ The compat layer auto-converts old keys. New code should use the new keys.
470
+
471
+ ---
472
+
473
+ ## Anti-Patterns
474
+
475
+ ### Vite
476
+
477
+ 1. **Barrel file sprawl** -- Re-exporting through `index.ts` forces transforming all modules. Import directly from source.
478
+ 2. **Secrets in VITE_ variables** -- Embedded in client bundles. Use server-only env vars, proxy through API routes.
479
+ 3. **Duplicating resolve config for tests** -- Vitest inherits Vite's aliases and plugins. Don't redeclare.
480
+ 4. **Using `rollupOptions` in Vite 8** -- Works via compat but generates warnings. Use `rolldownOptions`.
481
+ 5. **Not externalizing peer deps in library mode** -- Bundling framework deps causes duplicate instances.
482
+
483
+ ### Vitest
484
+
485
+ 1. **Over-mocking internal modules** -- Mock at boundaries (HTTP, filesystem, external APIs), not internal functions.
486
+ 2. **Forgetting vi.mock is hoisted** -- Variables before `vi.mock()` aren't accessible in the factory. Use `vi.hoisted()`.
487
+ 3. **Not restoring mocks** -- Set `restoreMocks: true` in config. Leaked mocks cause cascading failures.
488
+ 4. **Using jsdom when node suffices** -- jsdom adds overhead. Use workspace projects to split: `node` for logic, `jsdom` for components.
489
+ 5. **Large inline snapshots** -- Over 10-15 lines reduces readability. Use `toMatchFileSnapshot`.
490
+ 6. **Snapshot-only testing** -- Snapshots catch regressions but don't verify correctness. Add explicit assertions.
491
+ 7. **Global jsdom environment** -- Use `test.projects` to run DOM tests in jsdom and logic tests in node.
492
+ 8. **Using `vi.spyOn` in browser mode** -- Use `vi.mock('./module', { spy: true })` instead.
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "ct-vite-vitest-patterns",
3
+ "description": "Vite build tooling and Vitest unit/integration testing patterns",
4
+ "defaultMappings": {
5
+ "vite.config.ts": "ct-vite-vitest-patterns",
6
+ "vitest.config.ts": "ct-vite-vitest-patterns",
7
+ "src/**/*.test.ts": "ct-vite-vitest-patterns",
8
+ "src/**/*.test.tsx": "ct-vite-vitest-patterns",
9
+ "tests": "ct-vite-vitest-patterns"
10
+ },
11
+ "fileExtensions": ["test.ts", "test.tsx", "spec.ts", "spec.tsx"],
12
+ "skillRules": {
13
+ "ct-vite-vitest-patterns": {
14
+ "description": "Vite build config, plugins, env vars, and Vitest testing with mocking, coverage, browser mode, and workspace",
15
+ "priority": 7,
16
+ "triggers": {
17
+ "keywords": [
18
+ "vite",
19
+ "vitest",
20
+ "vi.fn",
21
+ "vi.mock",
22
+ "vi.spyOn",
23
+ "defineConfig",
24
+ "coverage",
25
+ "snapshot",
26
+ "in-source test",
27
+ "browser mode"
28
+ ],
29
+ "keywordPatterns": [
30
+ "\\bvite\\b",
31
+ "\\bvitest\\b",
32
+ "\\bvi\\.fn\\b",
33
+ "\\bvi\\.mock\\b",
34
+ "\\bvi\\.spyOn\\b"
35
+ ],
36
+ "pathPatterns": [
37
+ "**/vite.config.*",
38
+ "**/vitest.config.*",
39
+ "**/*.test.ts",
40
+ "**/*.test.tsx",
41
+ "**/*.spec.ts",
42
+ "**/*.spec.tsx",
43
+ "**/tests/**"
44
+ ],
45
+ "intentPatterns": [
46
+ "(?:create|write|add|run).*(?:test|spec|vitest)",
47
+ "(?:configure|setup).*(?:vite|vitest|coverage)",
48
+ "(?:mock|spy|stub).*(?:function|module|timer)"
49
+ ],
50
+ "contentPatterns": [
51
+ "vitest/config",
52
+ "vi.fn(",
53
+ "vi.mock(",
54
+ "vi.spyOn(",
55
+ "vi.useFakeTimers",
56
+ "toMatchSnapshot",
57
+ "toMatchInlineSnapshot",
58
+ "import.meta.vitest",
59
+ "@vitest/coverage",
60
+ "@vitest/browser"
61
+ ]
62
+ },
63
+ "relatedSkills": ["ct-testing-patterns", "ct-storybook-patterns", "ct-playwright-patterns"]
64
+ }
65
+ }
66
+ }