- name
- test-writer
- description
- Generate comprehensive Vitest tests for code examples in JavaScript concept documentation pages, following project conventions and referencing source lines
# Skill: Test Writer for Concept Pages
Use this skill to generate comprehensive Vitest tests for all code examples in a concept documentation page. Tests verify that code examples in the documentation are accurate and work as described.
## When to Use
- After writing a new concept page
- When adding new code examples to existing pages
- When updating existing code examples
- To verify documentation accuracy through automated tests
- Before publishing to ensure all examples work correctly
## Test Writing Methodology
Follow these four phases to create comprehensive tests for a concept page.
### Phase 1: Code Example Extraction
Scan the concept page for all code examples and categorize them:
| Category | Characteristics | Action |
|----------|-----------------|--------|
| **Testable** | Has `console.log` with output comments, returns values | Write tests |
| **DOM-specific** | Uses `document`, `window`, DOM APIs, event handlers | Write DOM tests (separate file) |
| **Error examples** | Intentionally throws errors, demonstrates failures | Write tests with `toThrow` |
| **Conceptual** | ASCII diagrams, pseudo-code, incomplete snippets | Skip (document why) |
| **Browser-only** | Uses browser APIs not available in jsdom | Skip or mock |
### Phase 2: Determine Test File Structure
```
tests/
├── fundamentals/ # Concepts 1-6
├── functions-execution/ # Concepts 7-8
├── web-platform/ # Concepts 9-10
├── object-oriented/ # Concepts 11-15
├── functional-programming/ # Concepts 16-19
├── async-javascript/ # Concepts 20-22
├── advanced-topics/ # Concepts 23-31
└── beyond/ # Extended concepts
└── {subcategory}/
```
**File naming:**
- Standard tests: `{concept-name}.test.js`
- DOM tests: `{concept-name}.dom.test.js`
### Phase 3: Convert Examples to Tests
For each testable code example:
1. Identify the expected output (from `console.log` comments or documented behavior)
2. Convert to `expect` assertions
3. Add source line reference in comments
4. Group related tests in `describe` blocks matching documentation sections
### Phase 4: Handle Special Cases
| Case | Solution |
|------|----------|
| Browser-only APIs | Use jsdom environment or skip with note |
| Timing-dependent code | Use `vi.useFakeTimers()` or test the logic, not timing |
| Side effects | Capture output or test mutations |
| Intentional errors | Use `expect(() => {...}).toThrow()` |
| Async code | Use `async/await` with proper assertions |
---
## Project Test Conventions
### Import Pattern
```javascript
import { describe, it, expect } from 'vitest'
```
For DOM tests or tests needing mocks:
```javascript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
```
### DOM Test File Header
```javascript
/**
* @vitest-environment jsdom
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
```
### Describe Block Organization
Match the structure of the documentation:
```javascript
describe('Concept Name', () => {
describe('Section from Documentation', () => {
describe('Subsection if needed', () => {
it('should [specific behavior]', () => {
// Test
})
})
})
})
```
### Test Naming Convention
- Start with "should"
- Be descriptive and specific
- Match the documented behavior
```javascript
// Good
it('should return "object" for typeof null', () => {})
it('should throw TypeError when accessing property of undefined', () => {})
it('should resolve promises in order they were created', () => {})
// Bad
it('test typeof', () => {})
it('works correctly', () => {})
it('null test', () => {})
```
### Source Line References
Always reference the documentation source:
```javascript
// ============================================================
// SECTION NAME FROM DOCUMENTATION
// From {concept}.mdx lines XX-YY
// ============================================================
describe('Section Name', () => {
// From lines 45-52: Basic typeof examples
it('should return correct type strings', () => {
// Test
})
})
```
---
## Test Patterns Reference
### Pattern 1: Basic Value Assertion
**Documentation:**
```javascript
console.log(typeof "hello") // "string"
console.log(typeof 42) // "number"
```
**Test:**
```javascript
// From lines XX-YY: typeof examples
it('should return correct type for primitives', () => {
expect(typeof "hello").toBe("string")
expect(typeof 42).toBe("number")
})
```
---
### Pattern 2: Multiple Related Assertions
**Documentation:**
```javascript
let a = "hello"
let b = "hello"
console.log(a === b) // true
let obj1 = { x: 1 }
let obj2 = { x: 1 }
console.log(obj1 === obj2) // false
```
**Test:**
```javascript
// From lines XX-YY: Primitive vs object comparison
it('should compare primitives by value', () => {
let a = "hello"
let b = "hello"
expect(a === b).toBe(true)
})
it('should compare objects by reference', () => {
let obj1 = { x: 1 }
let obj2 = { x: 1 }
expect(obj1 === obj2).toBe(false)
})
```
---
### Pattern 3: Function Return Values
**Documentation:**
```javascript
function greet(name) {
return "Hello, " + name + "!"
}
console.log(greet("Alice")) // "Hello, Alice!"
```
**Test:**
```javascript
// From lines XX-YY: greet function example
it('should return greeting with name', () => {
function greet(name) {
return "Hello, " + name + "!"
}
expect(greet("Alice")).toBe("Hello, Alice!")
})
```
---
### Pattern 4: Error Testing
**Documentation:**
```javascript
// This throws an error!
const obj = null
console.log(obj.property) // TypeError: Cannot read property of null
```
**Test:**
```javascript
// From lines XX-YY: Accessing property of null
it('should throw TypeError when accessing property of null', () => {
const obj = null
expect(() => {
obj.property
}).toThrow(TypeError)
})
```
---
### Pattern 5: Specific Error Messages
**Documentation:**
```javascript
function divide(a, b) {
if (b === 0) throw new Error("Cannot divide by zero")
return a / b
}
```
**Test:**
```javascript
// From lines XX-YY: divide function with error
it('should throw error when dividing by zero', () => {
function divide(a, b) {
if (b === 0) throw new Error("Cannot divide by zero")
return a / b
}
expect(() => divide(10, 0)).toThrow("Cannot divide by zero")
expect(divide(10, 2)).toBe(5)
})
```
---
### Pattern 6: Async/Await Testing
**Documentation:**
```javascript
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
```
**Test:**
```javascript
// From lines XX-YY: async fetchUser function
it('should fetch user data asynchronously', async () => {
// Mock fetch for testing
global.fetch = vi.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ id: 1, name: 'Alice' })
})
)
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
const user = await fetchUser(1)
expect(user).toEqual({ id: 1, name: 'Alice' })
})
```
---
### Pattern 7: Promise Testing
**Documentation:**
```javascript
const promise = new Promise((resolve) => {
resolve("done")
})
promise.then(result => console.log(result)) // "done"
```
**Test:**
```javascript
// From lines XX-YY: Basic Promise resolution
it('should resolve with correct value', async () => {
const promise = new Promise((resolve) => {
resolve("done")
})
await expect(promise).resolves.toBe("done")
})
```
---
### Pattern 8: Promise Rejection
**Documentation:**
```javascript
const promise = new Promise((resolve, reject) => {
reject(new Error("Something went wrong"))
})
```
**Test:**
```javascript
// From lines XX-YY: Promise rejection
it('should reject with error', async () => {
const promise = new Promise((resolve, reject) => {
reject(new Error("Something went wrong"))
})
await expect(promise).rejects.toThrow("Something went wrong")
})
```
---
### Pattern 9: Floating Point Comparison
**Documentation:**
```javascript
console.log(0.1 + 0.2) // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3) // false
```
**Test:**
```javascript
// From lines XX-YY: Floating point precision
it('should demonstrate floating point imprecision', () => {
expect(0.1 + 0.2).not.toBe(0.3)
expect(0.1 + 0.2).toBeCloseTo(0.3)
expect(0.1 + 0.2 === 0.3).toBe(false)
})
```
---
### Pattern 10: Array Method Testing
**Documentation:**
```javascript
const numbers = [1, 2, 3, 4, 5]
const doubled = numbers.map(n => n * 2)
console.log(doubled) // [2, 4, 6, 8, 10]
```
**Test:**
```javascript
// From lines XX-YY: Array map example
it('should double all numbers in array', () => {
const numbers = [1, 2, 3, 4, 5]
const doubled = numbers.map(n => n * 2)
expect(doubled).toEqual([2, 4, 6, 8, 10])
expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged
})
View on GitHub