重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
test-specialist by ailabs-393/ai-labs-claude-skills
npx skills add https://github.com/ailabs-393/ai-labs-claude-skills --skill test-specialist将系统化的测试方法和调试技术应用于 JavaScript/TypeScript 应用程序。此技能提供全面的测试策略、错误分析框架以及用于识别覆盖率差距和未测试代码的自动化工具。
编写涵盖单元测试、集成测试和端到端场景的全面测试。
使用 AAA 模式(准备-执行-断言)构建测试:
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);
});
});
});
关键原则:
测试组件如何协同工作,包括数据库、API 和服务交互:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
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);
});
});
使用 Playwright 或 Cypress 等工具测试完整的用户工作流程:
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');
});
应用结构化的调试方法来识别和修复问题。
复现:可靠地复现错误
隔离:缩小问题范围
根本原因分析:确定根本原因
修复实现:实施解决方案
验证:确保完整性
竞态条件:
// Test concurrent operations
test('handles concurrent updates correctly', async () => {
const promises = Array.from({ length: 100 }, () =>
incrementExpenseCount()
);
await Promise.all(promises);
expect(getExpenseCount()).toBe(100);
});
空值/未定义错误:
// Test null safety
test.each([null, undefined, '', 0, false])
('handles invalid input: %p', (input) => {
expect(() => processExpense(input)).toThrow('Invalid expense');
});
差一错误:
// 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);
});
});
在问题演变成错误之前主动识别它们。
测试常见的安全问题:
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 = '<script>alert("xss")</script>';
const expense = createExpense({ description: xss });
expect(expense.description).not.toContain('<script>');
});
test('requires authentication for expense operations', async () => {
await request(app)
.post('/api/expenses')
.send({ amount: 50 })
.expect(401);
});
});
测试性能问题:
test('processes large expense list efficiently', () => {
const largeList = Array.from({ length: 10000 }, (_, i) => ({
amount: i,
category: 'test'
}));
const start = performance.now();
const total = calculateTotal(largeList);
const duration = performance.now() - start;
expect(duration).toBeLessThan(100); // Should complete in <100ms
expect(total).toBe(49995000);
});
使用参数化测试来捕获边界情况:
test.each([
// [input, expected, description]
[[10, 20, 30], 60, 'normal positive values'],
[[0, 0, 0], 0, 'all zeros'],
[[-10, 20, -5], 5, 'mixed positive and negative'],
[[0.1, 0.2], 0.3, 'decimal precision'],
[[Number.MAX_SAFE_INTEGER], Number.MAX_SAFE_INTEGER, 'large numbers'],
])('calculateTotal(%p) = %p (%s)', (amounts, expected, description) => {
const expenses = amounts.map(amount => ({ amount, category: 'test' }));
expect(calculateTotal(expenses)).toBeCloseTo(expected);
});
使用自动化工具识别测试覆盖率的差距。
运行提供的脚本以识别没有测试的源文件:
python3 scripts/find_untested_code.py src
该脚本将:
解释:
生成覆盖率后运行覆盖率分析脚本:
# Generate coverage (using Jest example)
npm test -- --coverage
# Analyze coverage gaps
python3 scripts/analyze_coverage.py coverage/coverage-final.json
该脚本识别:
覆盖率目标:
确保测试保持价值且易于维护。
DRY(不要重复自己):
// Extract common setup
function createTestExpense(overrides = {}) {
return {
amount: 50,
category: 'food',
description: 'Test expense',
date: new Date('2024-01-01'),
...overrides
};
}
test('filters by category', () => {
const expenses = [
createTestExpense({ category: 'food' }),
createTestExpense({ category: 'transport' }),
];
// ...
});
清晰的测试数据:
// Bad: Magic numbers
expect(calculateDiscount(100, 0.15)).toBe(85);
// Good: Named constants
const ORIGINAL_PRICE = 100;
const DISCOUNT_RATE = 0.15;
const EXPECTED_PRICE = 85;
expect(calculateDiscount(ORIGINAL_PRICE, DISCOUNT_RATE)).toBe(EXPECTED_PRICE);
避免测试相互依赖:
// Bad: Tests depend on execution order
let sharedState;
test('test 1', () => {
sharedState = { value: 1 };
});
test('test 2', () => {
expect(sharedState.value).toBe(1); // Depends on test 1
});
// Good: Independent tests
test('test 1', () => {
const state = { value: 1 };
expect(state.value).toBe(1);
});
test('test 2', () => {
const state = { value: 1 };
expect(state.value).toBe(1);
});
遵循此决策树来确定测试方法:
添加新功能?
修复错误?
提高测试覆盖率?
find_untested_code.py 以识别差距analyze_coverage.py分析代码质量?
单元/集成测试:
端到端测试:
覆盖率:
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run specific test file
npm test -- ExpenseCalculator.test.ts
# Run in watch mode
npm test -- --watch
# Run E2E tests
npm run test:e2e
有关详细模式和技巧,请参阅:
references/testing_patterns.md - 全面的测试模式、最佳实践和代码示例references/bug_analysis.md - 深入的错误分析框架、常见错误模式和调试技巧这些参考资料包含大量示例和高级技巧。在以下情况下加载它们:
分析 Jest/Istanbul 覆盖率报告以识别差距:
python3 scripts/analyze_coverage.py [coverage-file]
如果未指定,则自动查找常见的覆盖率文件位置。
输出:
查找没有相应测试文件的源文件:
python3 scripts/find_untested_code.py [src-dir] [--pattern test|spec]
输出:
每周安装数
50
代码仓库
GitHub 星标数
322
首次出现
2026年1月23日
安全审计
安装于
opencode41
codex39
gemini-cli35
cursor33
claude-code31
github-copilot31
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.
Write comprehensive tests covering unit, integration, and end-to-end scenarios.
Structure tests using the AAA pattern (Arrange-Act-Assert):
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 how components work together, including database, API, and service interactions:
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);
});
});
Test complete user workflows using tools like Playwright or Cypress:
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');
});
Apply structured debugging methodology to identify and fix issues.
Reproduction : Reliably reproduce the bug
Isolation : Narrow down the problem
Root Cause Analysis : Determine underlying cause
Fix Implementation : Implement solution
Validation : Ensure completeness
Race Conditions:
// 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:
// Test null safety
test.each([null, undefined, '', 0, false])
('handles invalid input: %p', (input) => {
expect(() => processExpense(input)).toThrow('Invalid expense');
});
Off-by-One Errors:
// 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);
});
});
Proactively identify issues before they become bugs.
Test for common security issues:
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 = '<script>alert("xss")</script>';
const expense = createExpense({ description: xss });
expect(expense.description).not.toContain('<script>');
});
test('requires authentication for expense operations', async () => {
await request(app)
.post('/api/expenses')
.send({ amount: 50 })
.expect(401);
});
});
Test for performance problems:
test('processes large expense list efficiently', () => {
const largeList = Array.from({ length: 10000 }, (_, i) => ({
amount: i,
category: 'test'
}));
const start = performance.now();
const total = calculateTotal(largeList);
const duration = performance.now() - start;
expect(duration).toBeLessThan(100); // Should complete in <100ms
expect(total).toBe(49995000);
});
Use parameterized tests to catch edge cases:
test.each([
// [input, expected, description]
[[10, 20, 30], 60, 'normal positive values'],
[[0, 0, 0], 0, 'all zeros'],
[[-10, 20, -5], 5, 'mixed positive and negative'],
[[0.1, 0.2], 0.3, 'decimal precision'],
[[Number.MAX_SAFE_INTEGER], Number.MAX_SAFE_INTEGER, 'large numbers'],
])('calculateTotal(%p) = %p (%s)', (amounts, expected, description) => {
const expenses = amounts.map(amount => ({ amount, category: 'test' }));
expect(calculateTotal(expenses)).toBeCloseTo(expected);
});
Use automated tools to identify gaps in test coverage.
Run the provided script to identify source files without tests:
python3 scripts/find_untested_code.py src
The script will:
Interpretation:
Run the coverage analysis script after generating coverage:
# Generate coverage (using Jest example)
npm test -- --coverage
# Analyze coverage gaps
python3 scripts/analyze_coverage.py coverage/coverage-final.json
The script identifies:
Coverage targets:
Ensure tests remain valuable and maintainable.
DRY (Don't Repeat Yourself):
// Extract common setup
function createTestExpense(overrides = {}) {
return {
amount: 50,
category: 'food',
description: 'Test expense',
date: new Date('2024-01-01'),
...overrides
};
}
test('filters by category', () => {
const expenses = [
createTestExpense({ category: 'food' }),
createTestExpense({ category: 'transport' }),
];
// ...
});
Clear test data:
// Bad: Magic numbers
expect(calculateDiscount(100, 0.15)).toBe(85);
// Good: Named constants
const ORIGINAL_PRICE = 100;
const DISCOUNT_RATE = 0.15;
const EXPECTED_PRICE = 85;
expect(calculateDiscount(ORIGINAL_PRICE, DISCOUNT_RATE)).toBe(EXPECTED_PRICE);
Avoid test interdependence:
// Bad: Tests depend on execution order
let sharedState;
test('test 1', () => {
sharedState = { value: 1 };
});
test('test 2', () => {
expect(sharedState.value).toBe(1); // Depends on test 1
});
// Good: Independent tests
test('test 1', () => {
const state = { value: 1 };
expect(state.value).toBe(1);
});
test('test 2', () => {
const state = { value: 1 };
expect(state.value).toBe(1);
});
Follow this decision tree to determine the testing approach:
Adding new functionality?
Fixing a bug?
Improving test coverage?
find_untested_code.py to identify gapsanalyze_coverage.py on coverage reportsAnalyzing code quality?
Unit/Integration Testing:
E2E Testing:
Coverage:
# Run all tests
npm test
# Run with coverage
npm test -- --coverage
# Run specific test file
npm test -- ExpenseCalculator.test.ts
# Run in watch mode
npm test -- --watch
# Run E2E tests
npm run test:e2e
For detailed patterns and techniques, refer to:
references/testing_patterns.md - Comprehensive testing patterns, best practices, and code examplesreferences/bug_analysis.md - In-depth bug analysis framework, common bug patterns, and debugging techniquesThese references contain extensive examples and advanced techniques. Load them when:
Analyze Jest/Istanbul coverage reports to identify gaps:
python3 scripts/analyze_coverage.py [coverage-file]
Automatically finds common coverage file locations if not specified.
Output:
Find source files without corresponding test files:
python3 scripts/find_untested_code.py [src-dir] [--pattern test|spec]
Output:
Weekly Installs
50
Repository
GitHub Stars
322
First Seen
Jan 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode41
codex39
gemini-cli35
cursor33
claude-code31
github-copilot31
Vue 3 调试指南:解决响应式、计算属性与监听器常见错误
12,200 周安装