@martinffx/atelier 1.4.0 → 3.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.
- package/CHANGELOG.md +38 -0
- package/README.md +95 -220
- package/agents/architect.md +6 -6
- package/agents/oracle.md +1 -1
- package/agents/{recon.md → sentinel.md} +3 -3
- package/dist/atelier.js +167 -26
- package/package.json +2 -1
- package/skills/atelier-orchestrator/SKILL.md +180 -0
- package/skills/atelier-setup/SKILL.md +80 -0
- package/skills/code-review/SKILL.md +2 -2
- package/skills/code-review/references/reviewers.md +3 -3
- package/skills/code-review/references/rq.md +9 -9
- package/skills/code-subagents/SKILL.md +44 -75
- package/skills/code-subagents/references/batch-reviewer-prompt.md +44 -0
- package/skills/code-subagents/references/implementor-prompt.md +10 -11
- package/skills/spec-brainstorm/SKILL.md +21 -16
- package/skills/spec-finish/SKILL.md +14 -14
- package/skills/spec-implement/SKILL.md +42 -42
- package/skills/spec-plan/SKILL.md +72 -26
- package/skills/spec-plan/references/plan_template.md +77 -0
- package/skills/code-subagents/references/code-quality-reviewer-prompt.md +0 -48
- package/skills/code-subagents/references/spec-reviewer-prompt.md +0 -62
- package/skills/python-architecture/SKILL.md +0 -148
- package/skills/python-architecture/references/data-modeling.md +0 -558
- package/skills/python-architecture/references/ddd.md +0 -569
- package/skills/python-architecture/references/functional-core.md +0 -337
- package/skills/python-build-tools/SKILL.md +0 -153
- package/skills/python-build-tools/references/basedpyright.md +0 -321
- package/skills/python-build-tools/references/ruff.md +0 -225
- package/skills/python-build-tools/references/uv.md +0 -257
- package/skills/python-fastapi/SKILL.md +0 -184
- package/skills/python-fastapi/references/api-design.md +0 -563
- package/skills/python-fastapi/references/dependencies.md +0 -479
- package/skills/python-fastapi/references/middleware.md +0 -475
- package/skills/python-fastapi/references/validation.md +0 -497
- package/skills/python-modern-python/SKILL.md +0 -201
- package/skills/python-modern-python/references/async.md +0 -76
- package/skills/python-modern-python/references/pattern-matching.md +0 -89
- package/skills/python-modern-python/references/typing.md +0 -96
- package/skills/python-monorepo/SKILL.md +0 -146
- package/skills/python-monorepo/references/docker.md +0 -515
- package/skills/python-monorepo/references/namespace-packages.md +0 -426
- package/skills/python-monorepo/references/workspace-config.md +0 -341
- package/skills/python-sqlalchemy/SKILL.md +0 -119
- package/skills/python-sqlalchemy/references/async.md +0 -51
- package/skills/python-sqlalchemy/references/models.md +0 -67
- package/skills/python-sqlalchemy/references/queries.md +0 -57
- package/skills/python-temporal/SKILL.md +0 -128
- package/skills/python-temporal/references/patterns.md +0 -87
- package/skills/python-temporal/references/testing.md +0 -54
- package/skills/python-testing/SKILL.md +0 -161
- package/skills/python-testing/references/boundaries.md +0 -449
- package/skills/python-testing/references/mocking.md +0 -449
- package/skills/python-testing/references/pytest.md +0 -524
- package/skills/spec-orchestrator/SKILL.md +0 -145
- package/skills/typescript-api-design/SKILL.md +0 -396
- package/skills/typescript-api-design/references/error-responses.md +0 -469
- package/skills/typescript-build-tools/SKILL.md +0 -447
- package/skills/typescript-build-tools/references/biome.md +0 -436
- package/skills/typescript-build-tools/references/bun.md +0 -432
- package/skills/typescript-build-tools/references/turborepo.md +0 -426
- package/skills/typescript-build-tools/references/vitest.md +0 -518
- package/skills/typescript-drizzle-orm/SKILL.md +0 -398
- package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
- package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
- package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
- package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
- package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
- package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
- package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
- package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
- package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
- package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
- package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
- package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
- package/skills/typescript-effect-ts/SKILL.md +0 -341
- package/skills/typescript-effect-ts/references/core.md +0 -412
- package/skills/typescript-effect-ts/references/error-handling.md +0 -468
- package/skills/typescript-effect-ts/references/resources.md +0 -476
- package/skills/typescript-effect-ts/references/schema.md +0 -536
- package/skills/typescript-effect-ts/references/services.md +0 -461
- package/skills/typescript-fastify/SKILL.md +0 -405
- package/skills/typescript-fastify/references/plugins.md +0 -329
- package/skills/typescript-fastify/references/typeid.md +0 -315
- package/skills/typescript-functional-patterns/SKILL.md +0 -402
- package/skills/typescript-functional-patterns/references/adts.md +0 -497
- package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
- package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
- package/skills/typescript-functional-patterns/references/option-result.md +0 -585
- package/skills/typescript-testing/SKILL.md +0 -353
- package/skills/typescript-testing/references/mocking.md +0 -675
- package/skills/typescript-testing/references/msw.md +0 -852
- package/skills/typescript-testing/references/snapshot-testing.md +0 -774
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: typescript-testing
|
|
3
|
-
description: TypeScript testing patterns with Vitest and MSW. Use when writing unit tests, mocking APIs, creating typed mocks for dependency injection, or using snapshot testing.
|
|
4
|
-
user-invocable: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# TypeScript Testing Patterns
|
|
8
|
-
|
|
9
|
-
Comprehensive testing patterns using Vitest for unit testing, MSW for API mocking, and snapshot testing for complex object validation.
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
### Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Core testing dependencies
|
|
17
|
-
bun add -d vitest @vitest/ui
|
|
18
|
-
|
|
19
|
-
# MSW for API mocking
|
|
20
|
-
bun add -d msw
|
|
21
|
-
|
|
22
|
-
# Optional: coverage reporting
|
|
23
|
-
bun add -d @vitest/coverage-v8
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Basic Test Structure
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
30
|
-
|
|
31
|
-
describe('UserService', () => {
|
|
32
|
-
beforeEach(() => {
|
|
33
|
-
vi.clearAllMocks()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('creates user with valid data', async () => {
|
|
37
|
-
const result = await userService.create({ name: 'Alice' })
|
|
38
|
-
expect(result).toMatchObject({ name: 'Alice' })
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Typed Mock Objects
|
|
44
|
-
|
|
45
|
-
Create type-safe mocks for dependency injection using `vi.mocked()`:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
import { vi } from 'vitest'
|
|
49
|
-
import type { UserRepository } from './user-repository'
|
|
50
|
-
|
|
51
|
-
// Mock the entire module
|
|
52
|
-
vi.mock('./user-repository')
|
|
53
|
-
|
|
54
|
-
// Get typed mock instance
|
|
55
|
-
const mockUserRepo = vi.mocked<UserRepository>({
|
|
56
|
-
findById: vi.fn(),
|
|
57
|
-
save: vi.fn(),
|
|
58
|
-
delete: vi.fn(),
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
// Type-safe mock return values
|
|
62
|
-
mockUserRepo.findById.mockResolvedValue({
|
|
63
|
-
id: '123',
|
|
64
|
-
name: 'Alice',
|
|
65
|
-
email: 'alice@example.com',
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// Assertions with full type safety
|
|
69
|
-
expect(mockUserRepo.findById).toHaveBeenCalledWith('123')
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Mock Return Values
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// Single return value
|
|
76
|
-
mockRepo.findById.mockResolvedValue(user)
|
|
77
|
-
|
|
78
|
-
// Multiple calls, different returns
|
|
79
|
-
mockRepo.findById
|
|
80
|
-
.mockResolvedValueOnce(null)
|
|
81
|
-
.mockResolvedValueOnce(user)
|
|
82
|
-
|
|
83
|
-
// Conditional logic
|
|
84
|
-
mockRepo.findById.mockImplementation(async (id) => {
|
|
85
|
-
if (id === '123') return user
|
|
86
|
-
return null
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
// Throw errors
|
|
90
|
-
mockRepo.save.mockRejectedValue(new Error('Database error'))
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Spy on Real Implementations
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
import { vi } from 'vitest'
|
|
97
|
-
import { emailService } from './email-service'
|
|
98
|
-
|
|
99
|
-
// Spy on method without replacing it
|
|
100
|
-
vi.spyOn(emailService, 'send')
|
|
101
|
-
|
|
102
|
-
// Call real implementation
|
|
103
|
-
await emailService.send({ to: 'alice@example.com', subject: 'Test' })
|
|
104
|
-
|
|
105
|
-
// Assert it was called
|
|
106
|
-
expect(emailService.send).toHaveBeenCalledOnce()
|
|
107
|
-
|
|
108
|
-
// Temporarily override return value
|
|
109
|
-
emailService.send.mockResolvedValueOnce({ messageId: 'test-123' })
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
See [references/mocking.md](./references/mocking.md) for comprehensive mocking patterns including module mocks, class mocks, stateful handlers, and dependency injection.
|
|
113
|
-
|
|
114
|
-
## API Mocking with MSW
|
|
115
|
-
|
|
116
|
-
Mock HTTP requests at the network level for integration tests:
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { http, HttpResponse } from 'msw'
|
|
120
|
-
import { setupServer } from 'msw/node'
|
|
121
|
-
import { afterAll, afterEach, beforeAll } from 'vitest'
|
|
122
|
-
|
|
123
|
-
// Define handlers
|
|
124
|
-
const handlers = [
|
|
125
|
-
http.get('/api/users/:id', ({ params }) => {
|
|
126
|
-
return HttpResponse.json({
|
|
127
|
-
id: params.id,
|
|
128
|
-
name: 'Alice',
|
|
129
|
-
email: 'alice@example.com',
|
|
130
|
-
})
|
|
131
|
-
}),
|
|
132
|
-
|
|
133
|
-
http.post('/api/users', async ({ request }) => {
|
|
134
|
-
const body = await request.json()
|
|
135
|
-
return HttpResponse.json({ id: '123', ...body }, { status: 201 })
|
|
136
|
-
}),
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
// Setup server
|
|
140
|
-
const server = setupServer(...handlers)
|
|
141
|
-
|
|
142
|
-
beforeAll(() => server.listen())
|
|
143
|
-
afterEach(() => server.resetHandlers())
|
|
144
|
-
afterAll(() => server.close())
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
See [references/msw.md](./references/msw.md) for advanced MSW patterns including error simulation, delays, and per-test overrides.
|
|
148
|
-
|
|
149
|
-
## Snapshot Testing
|
|
150
|
-
|
|
151
|
-
Validate complex objects and output without manual assertions:
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
import { it, expect } from 'vitest'
|
|
155
|
-
|
|
156
|
-
it('generates correct user profile', () => {
|
|
157
|
-
const profile = generateUserProfile(user)
|
|
158
|
-
|
|
159
|
-
// Snapshot entire object
|
|
160
|
-
expect(profile).toMatchSnapshot()
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
// Handle dynamic values (dates, IDs)
|
|
164
|
-
it('creates order with timestamp', () => {
|
|
165
|
-
const order = createOrder(items)
|
|
166
|
-
|
|
167
|
-
expect(order).toMatchSnapshot({
|
|
168
|
-
id: expect.any(String),
|
|
169
|
-
createdAt: expect.any(Date),
|
|
170
|
-
})
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
// Inline snapshots for small objects
|
|
174
|
-
it('formats error message', () => {
|
|
175
|
-
const error = formatError(new Error('Failed'))
|
|
176
|
-
expect(error).toMatchInlineSnapshot(`
|
|
177
|
-
{
|
|
178
|
-
"message": "Failed",
|
|
179
|
-
"code": "UNKNOWN_ERROR",
|
|
180
|
-
}
|
|
181
|
-
`)
|
|
182
|
-
})
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
See [references/snapshot-testing.md](./references/snapshot-testing.md) for snapshot maintenance, custom serializers, and best practices.
|
|
186
|
-
|
|
187
|
-
## Testing Async Code
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
// Promises
|
|
191
|
-
it('loads user data', async () => {
|
|
192
|
-
const user = await userService.findById('123')
|
|
193
|
-
expect(user).toBeDefined()
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
// Callbacks
|
|
197
|
-
it('calls callback on completion', () => {
|
|
198
|
-
return new Promise<void>((resolve) => {
|
|
199
|
-
processData(data, (result) => {
|
|
200
|
-
expect(result).toBe(expected)
|
|
201
|
-
resolve()
|
|
202
|
-
})
|
|
203
|
-
})
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
// Timers
|
|
207
|
-
it('retries after delay', async () => {
|
|
208
|
-
vi.useFakeTimers()
|
|
209
|
-
|
|
210
|
-
const promise = retryOperation()
|
|
211
|
-
vi.advanceTimersByTime(1000)
|
|
212
|
-
|
|
213
|
-
const result = await promise
|
|
214
|
-
expect(result).toBe('success')
|
|
215
|
-
|
|
216
|
-
vi.useRealTimers()
|
|
217
|
-
})
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Test Organization
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
// Group related tests
|
|
224
|
-
describe('UserService', () => {
|
|
225
|
-
describe('create', () => {
|
|
226
|
-
it('succeeds with valid data', () => {})
|
|
227
|
-
it('throws on duplicate email', () => {})
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
describe('update', () => {
|
|
231
|
-
it('updates existing user', () => {})
|
|
232
|
-
it('throws on not found', () => {})
|
|
233
|
-
})
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
// Shared setup
|
|
237
|
-
describe('authenticated requests', () => {
|
|
238
|
-
beforeEach(() => {
|
|
239
|
-
mockAuth.isAuthenticated.mockReturnValue(true)
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('allows user creation', () => {})
|
|
243
|
-
it('allows user deletion', () => {})
|
|
244
|
-
})
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Guidelines
|
|
248
|
-
|
|
249
|
-
1. **Test behavior, not implementation** - Focus on what the code does, not how it does it
|
|
250
|
-
2. **One assertion per test when possible** - Makes failures clearer and tests more focused
|
|
251
|
-
3. **Use typed mocks** - `vi.mocked<T>()` provides type safety for mock setup and assertions
|
|
252
|
-
4. **Mock at boundaries** - Mock external dependencies (APIs, databases), not internal functions
|
|
253
|
-
5. **Use MSW for API tests** - Mock at the network level for realistic integration tests
|
|
254
|
-
6. **Snapshots for complex output** - Use snapshots for large objects, explicit assertions for critical values
|
|
255
|
-
7. **Property matchers for dynamic values** - Handle dates, IDs, timestamps with `expect.any()`
|
|
256
|
-
8. **Clear test names** - Describe the scenario and expected outcome: "creates user with valid data"
|
|
257
|
-
9. **Setup/teardown for state** - Use `beforeEach`/`afterEach` to ensure test isolation
|
|
258
|
-
10. **Async/await over callbacks** - Prefer `async`/`await` for cleaner async test code
|
|
259
|
-
11. **Fake timers for time-based code** - Use `vi.useFakeTimers()` to control time in tests
|
|
260
|
-
12. **Test error cases** - Verify error handling with `expect().rejects.toThrow()`
|
|
261
|
-
|
|
262
|
-
## Related Skills
|
|
263
|
-
|
|
264
|
-
- **build-tools** - Vitest configuration, test scripts, coverage setup
|
|
265
|
-
- **api-design** - Testing REST API contracts and error responses
|
|
266
|
-
- **fastify** - Testing Fastify routes and plugins
|
|
267
|
-
- **drizzle-orm** - Testing database queries (use MSW or in-memory DB)
|
|
268
|
-
- **dynamodb-toolbox** - Testing DynamoDB entities and queries
|
|
269
|
-
|
|
270
|
-
## Common Patterns
|
|
271
|
-
|
|
272
|
-
### Testing with Dependency Injection
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
class UserService {
|
|
276
|
-
constructor(
|
|
277
|
-
private repo: UserRepository,
|
|
278
|
-
private email: EmailService,
|
|
279
|
-
) {}
|
|
280
|
-
|
|
281
|
-
async create(data: CreateUserInput) {
|
|
282
|
-
const user = await this.repo.save(data)
|
|
283
|
-
await this.email.sendWelcome(user.email)
|
|
284
|
-
return user
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Test with mocks
|
|
289
|
-
it('sends welcome email on create', async () => {
|
|
290
|
-
const mockRepo = vi.mocked<UserRepository>({
|
|
291
|
-
save: vi.fn().mockResolvedValue(savedUser),
|
|
292
|
-
})
|
|
293
|
-
const mockEmail = vi.mocked<EmailService>({
|
|
294
|
-
sendWelcome: vi.fn().mockResolvedValue(undefined),
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
const service = new UserService(mockRepo, mockEmail)
|
|
298
|
-
await service.create(userData)
|
|
299
|
-
|
|
300
|
-
expect(mockEmail.sendWelcome).toHaveBeenCalledWith('alice@example.com')
|
|
301
|
-
})
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Testing Error Boundaries
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
it('handles repository errors gracefully', async () => {
|
|
308
|
-
mockRepo.save.mockRejectedValue(new Error('Database error'))
|
|
309
|
-
|
|
310
|
-
await expect(
|
|
311
|
-
service.create(userData)
|
|
312
|
-
).rejects.toThrow('Failed to create user')
|
|
313
|
-
|
|
314
|
-
// Verify cleanup or rollback occurred
|
|
315
|
-
expect(mockEmail.sendWelcome).not.toHaveBeenCalled()
|
|
316
|
-
})
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Testing Race Conditions
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
it('handles concurrent requests correctly', async () => {
|
|
323
|
-
const promises = [
|
|
324
|
-
service.processOrder(order1),
|
|
325
|
-
service.processOrder(order2),
|
|
326
|
-
service.processOrder(order3),
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
const results = await Promise.all(promises)
|
|
330
|
-
|
|
331
|
-
expect(results).toHaveLength(3)
|
|
332
|
-
expect(new Set(results.map(r => r.id)).size).toBe(3)
|
|
333
|
-
})
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
## Debugging Tests
|
|
337
|
-
|
|
338
|
-
```bash
|
|
339
|
-
# Run single test file
|
|
340
|
-
vitest run path/to/test.spec.ts
|
|
341
|
-
|
|
342
|
-
# Run tests matching pattern
|
|
343
|
-
vitest run -t "creates user"
|
|
344
|
-
|
|
345
|
-
# Watch mode for TDD
|
|
346
|
-
vitest watch
|
|
347
|
-
|
|
348
|
-
# UI mode for debugging
|
|
349
|
-
vitest --ui
|
|
350
|
-
|
|
351
|
-
# Coverage report
|
|
352
|
-
vitest run --coverage
|
|
353
|
-
```
|