feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
244
skills/vitest/references/core-hooks.md
Normal file
244
skills/vitest/references/core-hooks.md
Normal file
@@ -0,0 +1,244 @@
|
||||
---
|
||||
name: lifecycle-hooks
|
||||
description: beforeEach, afterEach, beforeAll, afterAll, and around hooks
|
||||
---
|
||||
|
||||
# Lifecycle Hooks
|
||||
|
||||
## Basic Hooks
|
||||
|
||||
```ts
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, test } from 'vitest'
|
||||
|
||||
beforeAll(async () => {
|
||||
// Runs once before all tests in file/suite
|
||||
await setupDatabase()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
// Runs once after all tests in file/suite
|
||||
await teardownDatabase()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
// Runs before each test
|
||||
await clearTestData()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// Runs after each test
|
||||
await cleanupMocks()
|
||||
})
|
||||
```
|
||||
|
||||
## Cleanup Return Pattern
|
||||
|
||||
Return cleanup function from `before*` hooks:
|
||||
|
||||
```ts
|
||||
beforeAll(async () => {
|
||||
const server = await startServer()
|
||||
|
||||
// Returned function runs as afterAll
|
||||
return async () => {
|
||||
await server.close()
|
||||
}
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
const connection = await connect()
|
||||
|
||||
// Runs as afterEach
|
||||
return () => connection.close()
|
||||
})
|
||||
```
|
||||
|
||||
## Scoped Hooks
|
||||
|
||||
Hooks apply to current suite and nested suites:
|
||||
|
||||
```ts
|
||||
describe('outer', () => {
|
||||
beforeEach(() => console.log('outer before'))
|
||||
|
||||
test('test 1', () => {}) // outer before → test
|
||||
|
||||
describe('inner', () => {
|
||||
beforeEach(() => console.log('inner before'))
|
||||
|
||||
test('test 2', () => {}) // outer before → inner before → test
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Hook Timeout
|
||||
|
||||
```ts
|
||||
beforeAll(async () => {
|
||||
await slowSetup()
|
||||
}, 30_000) // 30 second timeout
|
||||
```
|
||||
|
||||
## Around Hooks
|
||||
|
||||
Wrap tests with setup/teardown context:
|
||||
|
||||
```ts
|
||||
import { aroundEach, test } from 'vitest'
|
||||
|
||||
// Wrap each test in database transaction
|
||||
aroundEach(async (runTest) => {
|
||||
await db.beginTransaction()
|
||||
await runTest() // Must be called!
|
||||
await db.rollback()
|
||||
})
|
||||
|
||||
test('insert user', async () => {
|
||||
await db.insert({ name: 'Alice' })
|
||||
// Automatically rolled back after test
|
||||
})
|
||||
```
|
||||
|
||||
### aroundAll
|
||||
|
||||
Wrap entire suite:
|
||||
|
||||
```ts
|
||||
import { aroundAll, test } from 'vitest'
|
||||
|
||||
aroundAll(async (runSuite) => {
|
||||
console.log('before all tests')
|
||||
await runSuite() // Must be called!
|
||||
console.log('after all tests')
|
||||
})
|
||||
```
|
||||
|
||||
### Multiple Around Hooks
|
||||
|
||||
Nested like onion layers:
|
||||
|
||||
```ts
|
||||
aroundEach(async (runTest) => {
|
||||
console.log('outer before')
|
||||
await runTest()
|
||||
console.log('outer after')
|
||||
})
|
||||
|
||||
aroundEach(async (runTest) => {
|
||||
console.log('inner before')
|
||||
await runTest()
|
||||
console.log('inner after')
|
||||
})
|
||||
|
||||
// Order: outer before → inner before → test → inner after → outer after
|
||||
```
|
||||
|
||||
## Test Hooks
|
||||
|
||||
Inside test body:
|
||||
|
||||
```ts
|
||||
import { onTestFailed, onTestFinished, test } from 'vitest'
|
||||
|
||||
test('with cleanup', () => {
|
||||
const db = connect()
|
||||
|
||||
// Runs after test finishes (pass or fail)
|
||||
onTestFinished(() => db.close())
|
||||
|
||||
// Only runs if test fails
|
||||
onTestFailed(({ task }) => {
|
||||
console.log('Failed:', task.result?.errors)
|
||||
})
|
||||
|
||||
db.query('SELECT * FROM users')
|
||||
})
|
||||
```
|
||||
|
||||
### Reusable Cleanup Pattern
|
||||
|
||||
```ts
|
||||
function useTestDb() {
|
||||
const db = connect()
|
||||
onTestFinished(() => db.close())
|
||||
return db
|
||||
}
|
||||
|
||||
test('query users', () => {
|
||||
const db = useTestDb()
|
||||
expect(db.query('SELECT * FROM users')).toBeDefined()
|
||||
})
|
||||
|
||||
test('query orders', () => {
|
||||
const db = useTestDb() // Fresh connection, auto-closed
|
||||
expect(db.query('SELECT * FROM orders')).toBeDefined()
|
||||
})
|
||||
```
|
||||
|
||||
## Concurrent Test Hooks
|
||||
|
||||
For concurrent tests, use context's hooks:
|
||||
|
||||
```ts
|
||||
test.concurrent('concurrent', ({ onTestFinished }) => {
|
||||
const resource = allocate()
|
||||
onTestFinished(() => resource.release())
|
||||
})
|
||||
```
|
||||
|
||||
## Extended Test Hooks
|
||||
|
||||
With `test.extend`, hooks are type-aware:
|
||||
|
||||
```ts
|
||||
const test = base.extend<{ db: Database }>({
|
||||
db: async ({}, use) => {
|
||||
const db = await createDb()
|
||||
await use(db)
|
||||
await db.close()
|
||||
},
|
||||
})
|
||||
|
||||
// These hooks know about `db` fixture
|
||||
test.beforeEach(({ db }) => {
|
||||
db.seed()
|
||||
})
|
||||
|
||||
test.afterEach(({ db }) => {
|
||||
db.clear()
|
||||
})
|
||||
```
|
||||
|
||||
## Hook Execution Order
|
||||
|
||||
Default order (stack):
|
||||
1. `beforeAll` (in order)
|
||||
2. `beforeEach` (in order)
|
||||
3. Test
|
||||
4. `afterEach` (reverse order)
|
||||
5. `afterAll` (reverse order)
|
||||
|
||||
Configure with `sequence.hooks`:
|
||||
|
||||
```ts
|
||||
defineConfig({
|
||||
test: {
|
||||
sequence: {
|
||||
hooks: 'list', // 'stack' (default), 'list', 'parallel'
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Key Points
|
||||
|
||||
- Hooks are not called during type checking
|
||||
- Return cleanup function from `before*` to avoid `after*` duplication
|
||||
- `aroundEach`/`aroundAll` must call `runTest()`/`runSuite()`
|
||||
- `onTestFinished` always runs, even if test fails
|
||||
- Use context hooks for concurrent tests
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://vitest.dev/api/hooks.html
|
||||
-->
|
||||
Reference in New Issue
Block a user