--- name: test-specialist description: This skill should be used when writing test cases, fixing bugs, analyzing code for potential issues, or improving test coverage for JavaScript/TypeScript applications. Use this for unit tests, integration tests, end-to-end tests, debugging runtime errors, logic bugs, performance issues, security vulnerabilities, and systematic code analysis. --- # Test Specialist ## Overview Apply systematic testing methodologies and debugging techniques to JavaScript/TypeScript applications. This skill provides comprehensive testing strategies, bug analysis frameworks, and automated tools for identifying coverage gaps and untested code. ## Core Capabilities ### 1. Writing Test Cases Write comprehensive tests covering unit, integration, and end-to-end scenarios. #### Unit Testing Approach Structure tests using the AAA pattern (Arrange-Act-Assert): ```typescript describe('ExpenseCalculator', () => { describe('calculateTotal', () => { test('sums expense amounts correctly', () => { // Arrange const expenses = [ { amount: 100, category: 'food' }, { amount: 50, category: 'transport' }, { amount: 25, category: 'entertainment' } ]; // Act const total = calculateTotal(expenses); // Assert expect(total).toBe(175); }); test('handles empty expense list', () => { expect(calculateTotal([])).toBe(0); }); test('handles negative amounts', () => { const expenses = [ { amount: 100, category: 'food' }, { amount: -50, category: 'refund' } ]; expect(calculateTotal(expenses)).toBe(50); }); }); }); ``` **Key principles:** - Test one behavior per test - Cover happy path, edge cases, and error conditions - Use descriptive test names that explain the scenario - Keep tests independent and isolated #### Integration Testing Approach Test how components work together, including database, API, and service interactions: ```typescript describe('ExpenseAPI Integration', () => { beforeAll(async () => { await database.connect(TEST_DB_URL); }); afterAll(async () => { await database.disconnect(); }); beforeEach(async () => { await database.clear(); await seedTestData(); }); test('POST /expenses creates expense and updates total', async () => { const response = await request(app) .post('/api/expenses') .send({ amount: 50, category: 'food', description: 'Lunch' }) .expect(201); expect(response.body).toMatchObject({ id: expect.any(Number), amount: 50, category: 'food' }); // Verify database state const total = await getTotalExpenses(); expect(total).toBe(50); }); }); ``` #### End-to-End Testing Approach Test complete user workflows using tools like Playwright or Cypress: ```typescript test('user can track expense from start to finish', async ({ page }) => { // Navigate to app await page.goto('/'); // Add new expense await page.click('[data-testid="add-expense-btn"]'); await page.fill('[data-testid="amount"]', '50.00'); await page.selectOption('[data-testid="category"]', 'food'); await page.fill('[data-testid="description"]', 'Lunch'); await page.click('[data-testid="submit"]'); // Verify expense appears in list await expect(page.locator('[data-testid="expense-item"]')).toContainText('Lunch'); await expect(page.locator('[data-testid="total"]')).toContainText('$50.00'); }); ``` ### 2. Systematic Bug Analysis Apply structured debugging methodology to identify and fix issues. #### Five-Step Analysis Process 1. **Reproduction**: Reliably reproduce the bug - Document exact steps to trigger - Identify required environment/state - Note expected vs actual behavior 2. **Isolation**: Narrow down the problem - Binary search through code path - Create minimal reproduction case - Remove unrelated dependencies 3. **Root Cause Analysis**: Determine underlying cause - Trace execution flow - Check assumptions and preconditions - Review recent changes (git blame) 4. **Fix Implementation**: Implement solution - Write failing test first (TDD) - Implement the fix - Verify test passes 5. **Validation**: Ensure completeness - Run full test suite - Test edge cases - Verify no regressions #### Common Bug Patterns **Race Conditions:** ```typescript // Test concurrent operations test('handles concurrent updates correctly', async () => { const promises = Array.from({ length: 100 }, () => incrementExpenseCount() ); await Promise.all(promises); expect(getExpenseCount()).toBe(100); }); ``` **Null/Undefined Errors:** ```typescript // Test null safety test.each([null, undefined, '', 0, false]) ('handles invalid input: %p', (input) => { expect(() => processExpense(input)).toThrow('Invalid expense'); }); ``` **Off-by-One Errors:** ```typescript // Test boundaries explicitly describe('pagination', () => { test('handles empty list', () => { expect(paginate([], 1, 10)).toEqual([]); }); test('handles single item', () => { expect(paginate([item], 1, 10)).toEqual([item]); }); test('handles last page with partial items', () => { const items = Array.from({ length: 25 }, (_, i) => i); expect(paginate(items, 3, 10)).toHaveLength(5); }); }); ``` ### 3. Identifying Potential Issues Proactively identify issues before they become bugs. #### Security Vulnerabilities Test for common security issues: ```typescript describe('security', () => { test('prevents SQL injection', async () => { const malicious = "'; DROP TABLE expenses; --"; await expect( searchExpenses(malicious) ).resolves.not.toThrow(); }); test('sanitizes XSS in descriptions', () => { const xss = ''; const expense = createExpense({ description: xss }); expect(expense.description).not.toContain('