test-writer
为概念文档页面的所有代码示例生成全面的Vitest测试,验证代码准确性。
npx skills add leonardomso/33-js-concepts --skill test-writerBefore / After 效果对比
1 组技术文档中的代码示例缺乏自动化测试,可能存在错误或与实际不符,读者难以信任,且每次修改后都需要手动验证。
使用test-writer为文档代码示例自动生成Vitest测试,确保代码的准确性和可靠性,提高文档质量,减少手动验证的工作量。
description SKILL.md
test-writer
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: Identify the expected output (from console.log comments or documented behavior) Convert to expect assertions Add source line reference in comments 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 import { describe, it, expect } from 'vitest' For DOM tests or tests needing mocks: import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' DOM Test File Header /** * @vitest-environment jsdom / import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' Describe Block Organization Match the structure of the documentation: 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 // 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: // ============================================================ // 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: console.log(typeof "hello") // "string" console.log(typeof 42) // "number" Test: // 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: 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: // 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: function greet(name) { return "Hello, " + name + "!" } console.log(greet("Alice")) // "Hello, Alice!" Test: // 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: // This throws an error! const obj = null console.log(obj.property) // TypeError: Cannot read property of null Test: // 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: function divide(a, b) { if (b === 0) throw new Error("Cannot divide by zero") return a / b } Test: // 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: async function fetchUser(id) { const response = await fetch(/api/users/${id}) return response.json() } Test: // 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: const promise = new Promise((resolve) => { resolve("done") }) promise.then(result => console.log(result)) // "done" Test: // 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: const promise = new Promise((resolve, reject) => { reject(new Error("Something went wrong")) }) Test: // 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: console.log(0.1 + 0.2) // 0.30000000000000004 console.log(0.1 + 0.2 === 0.3) // false Test: // 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: const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) console.log(doubled) // [2, 4, 6, 8, 10] Test: // 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 }) Pattern 11: Object Mutation Testing Documentation: const obj = { a: 1 } obj.b = 2 console.log(obj) // { a: 1, b: 2 } Test: // From lines XX-YY: Object mutation it('should allow adding properties to objects', () => { const obj = { a: 1 } obj.b = 2 expect(obj).toEqual({ a: 1, b: 2 }) }) Pattern 12: Closure Testing Documentation: function counter() { let count = 0 return function() { count++ return count } } const increment = counter() console.log(increment()) // 1 console.log(increment()) // 2 console.log(increment()) // 3 Test: // From lines XX-YY: Closure counter example it('should maintain state across calls via closure', () => { function counter() { let count = 0 return function() { count++ return count } } const increment = counter() expect(increment()).toBe(1) expect(increment()).toBe(2) expect(increment()).toBe(3) }) it('should create independent counters', () => { function counter() { let count = 0 return function() { count++ return count } } const counter1 = counter() const counter2 = counter() expect(counter1()).toBe(1) expect(counter1()).toBe(2) expect(counter2()).toBe(1) // Independent }) Pattern 13: DOM Event Testing Documentation: const button = document.getElementById('myButton') button.addEventListener('click', function(event) { console.log('Button clicked!') console.log(event.type) // "click" }) Test (in .dom.test.js file): /* * @vitest-environment jsdom / import { describe, it, expect, beforeEach, afterEach } from 'vitest' describe('DOM Event Handlers', () => { let button beforeEach(() => { button = document.createElement('button') button.id = 'myButton' document.body.appendChild(button) }) afterEach(() => { document.body.innerHTML = '' }) // From lines XX-YY: Button click event it('should fire click event handler', () => { const output = [] button.addEventListener('click', function(event) { output.push('Button clicked!') output.push(event.type) }) button.click() expect(output).toEqual(['Button clicked!', 'click']) }) }) Pattern 14: DOM Manipulation Testing Documentation: const div = document.createElement('div') div.textContent = 'Hello' div.classList.add('greeting') document.body.appendChild(div) Test: // From lines XX-YY: Creating and appending elements it('should create element with text and class', () => { const div = document.createElement('div') div.textContent = 'Hello' div.classList.add('greeting') document.body.appendChild(div) const element = document.querySelector('.greeting') expect(element).not.toBeNull() expect(element.textContent).toBe('Hello') expect(element.classList.contains('greeting')).toBe(true) }) Pattern 15: Timer Testing Documentation: console.log('First') setTimeout(() => console.log('Second'), 0) console.log('Third') // Output: First, Third, Second Test: // From lines XX-YY: setTimeout execution order it('should execute setTimeout callback after synchronous code', async () => { const output = [] output.push('First') setTimeout(() => output.push('Second'), 0) output.push('Third') // Wait for setTimeout to execute await new Promise(resolve => setTimeout(resolve, 10)) expect(output).toEqual(['First', 'Third', 'Second']) }) Pattern 16: Strict Mode Behavior Documentation: // In strict mode, this throws "use strict" x = 10 // ReferenceError: x is not defined Test: // From lines XX-YY: Strict mode variable declaration it('should throw ReferenceError in strict mode for undeclared variables', () => { // Vitest runs in strict mode by default expect(() => { // Using eval to test strict mode behavior "use strict" eval('undeclaredVar = 10') }).toThrow() }) Complete Test File Template import { describe, it, expect } from 'vitest' describe('[Concept Name]', () => { // ============================================================ // [FIRST SECTION NAME FROM DOCUMENTATION] // From [concept].mdx lines XX-YY // ============================================================ describe('[First Section]', () => { // From lines XX-YY: [Brief description of example] it('should [expected behavior]', () => { // Code from documentation expect(result).toBe(expected) }) // From lines XX-YY: [Brief description of next example] it('should [another expected behavior]', () => { // Code from documentation expect(result).toEqual(expected) }) }) // ============================================================ // [SECOND SECTION NAME FROM DOCUMENTATION] // From [concept].mdx lines XX-YY // ============================================================ describe('[Second Section]', () => { // From lines XX-YY: [Description] it('should [behavior]', () => { // Test }) }) // ============================================================ // EDGE CASES AND COMMON MISTAKES // From [concept].mdx lines XX-YY // ============================================================ describe('Edge Cases', () => { // From lines XX-YY: [Edge case description] it('should handle [edge case]', () => { // Test }) }) describe('Common Mistakes', () => { // From lines XX-YY: Wrong way example it('should demonstrate the incorrect behavior', () => { // Test showing why the "wrong" way fails }) // From lines XX-YY: Correct way example it('should demonstrate the correct behavior', () => { // Test showing the right approach }) }) }) Complete DOM Test File Template /* * @vitest-environment jsdom / import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' // ============================================================ // DOM EXAMPLES FROM [CONCEPT NAME] // From [concept].mdx lines XX-YY // ============================================================ describe('[Concept Name] - DOM', () => { // Shared setup let container beforeEach(() => { // Create a fresh container for each test container = document.createElement('div') container.id = 'test-container' document.body.appendChild(container) }) afterEach(() => { // Clean up after each test document.body.innerHTML = '' vi.restoreAllMocks() }) // ============================================================ // [SECTION NAME] // From lines XX-YY // ============================================================ describe('[Section Name]', () => { // From lines XX-YY: [Example description] it('should [expected DOM behavior]', () => { // Setup const element = document.createElement('div') container.appendChild(element) // Action element.textContent = 'Hello' // Assert expect(element.textContent).toBe('Hello') }) }) // ============================================================ // EVENT HANDLING // From lines XX-YY // ============================================================ describe('Event Handling', () => { // From lines XX-YY: Click event example it('should handle click events', () => { const button = document.createElement('button') container.appendChild(button) let clicked = false button.addEventListener('click', () => { clicked = true }) button.click() expect(clicked).toBe(true) }) }) }) Running Tests # Run all tests npm test # Run tests for specific concept npm test -- tests/fundamentals/primitive-types/ # Run tests for specific file npm test -- tests/fundamentals/primitive-types/primitive-types.test.js # Run DOM tests only npm test -- tests/fundamentals/primitive-types/primitive-types.dom.test.js # Run with watch mode npm run test:watch # Run with coverage npm run test:coverage # Run with verbose output npm test -- --reporter=verbose Quality Checklist Completeness All testable code examples have corresponding tests Tests organized by documentation sections Source line references included in comments (From lines XX-YY) DOM tests in separate .dom.test.js file Edge cases and error examples tested Correctness Tests verify the actual documented behavior Output comments in docs match test expectations Async tests properly use async/await Error tests use correct toThrow pattern Floating point comparisons use toBeCloseTo Object comparisons use toEqual (not toBe) Convention Uses explicit imports from vitest Follows describe/it nesting pattern Test names start with "should" Proper file naming ({concept}.test.js) DOM tests have jsdom environment directive Verification All tests pass: npm test -- tests/{category}/{concept}/ No skipped tests without documented reason No false positives (tests that pass for wrong reasons) Test Report Template Use this template to document test coverage for a concept page. # Test Coverage Report: [Concept Name] Concept Page: /docs/concepts/[slug].mdx Test File: /tests/{category}/{concept}/{concept}.test.js DOM Test File: /tests/{category}/{concept}/{concept}.dom.test.js (if applicable) Date: YYYY-MM-DD Author: [Name/Claude] ## Summary | Metric | Count | |--------|-------| | Total Code Examples in Doc | XX | | Testable Examples | XX | | Tests Written | XX | | DOM Tests Written | XX | | Skipped (with reason) | XX | ## Tests by Section | Section | Line Range | Examples | Tests | Status | |---------|------------|----------|-------|--------| | [Section 1] | XX-YY | X | X | ✅ | | [Section 2] | XX-YY | X | X | ✅ | | [Section 3] | XX-YY | X | X | ⚠️ (1 skipped) | ## Skipped Examples | Line | Example Description | Reason | |------|---------------------|--------| | XX | ASCII diagram of call stack | Conceptual, not executable | | YY | Browser fetch example | Requires network, mocked instead | ## Test Execution bash npm test -- tests/{category}/{concept}/ Result: ✅ XX passing | ❌ X failing | ⏭️ X skipped Notes [Any special considerations, mock requirements, or issues encountered] --- ## Common Issues and Solutions ### Issue: Test passes but shouldn't **Problem:** Test expectations don't match documentation output **Solution:** Double-check the expected value matches the `console.log` comment exactly javascript // Documentation says: console.log(result) // [1, 2, 3] // Make sure test uses: expect(result).toEqual([1, 2, 3]) // NOT toBe for arrays Issue: Async test times out Problem: Async test never resolves Solution: Ensure all promises are awaited and async function is marked // Bad it('should fetch data', () => { const data = fetchData() // Missing await! expect(data).toBeDefined() }) // Good it('should fetch data', async () => { const data = await fetchData() expect(data).toBeDefined() }) Issue: DOM test fails with "document is not defined" Problem: Missing jsdom environment Solution: Add environment directive at top of file /* * @vitest-environment jsdom */ Issue: Test isolation problems Problem: Tests affect each other Solution: Use beforeEach/afterEach for cleanup afterEach(() => { document.body.innerHTML = '' vi.restoreAllMocks() }) Summary When writing tests for a concept page: Extract all code examples from the documentation Categorize as testable, DOM, error, or conceptual Create test file in correct location with proper naming Convert each example to test using appropriate pattern Reference source lines in comments for traceability Run tests to verify all pass Document coverage using the report template Remember: Tests serve two purposes: Verify documentation is accurate Catch regressions if code examples are updated Every testable code example in the documentation should have a corresponding test. If an example can't be tested, document why.Weekly Installs229Repositoryleonardomso/33-…conceptsGitHub Stars66.3KFirst SeenJan 20, 2026Security AuditsGen Agent Trust HubPassSocketPassSnykPassInstalled onopencode128github-copilot126gemini-cli125claude-code124codex116cursor109
forum用户评价 (0)
发表评价
暂无评价,来写第一条吧
统计数据
用户评分
为此 Skill 评分