agentic/code/addons/testing-quality/skills/test-sync/SKILL.md
Detect orphaned tests, obsolete assertions, and test-code misalignment. Use for test suite maintenance, cleanup, and traceability validation.
npx skillsauth add jmagly/aiwg test-syncInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Maintain alignment between test files and source code. Detect orphaned tests (code deleted but tests remain), missing tests, and implementation-coupled tests. Based on UTRefactor research showing automated test maintenance can achieve 89% smell reduction.
| Concept | Source | Reference | |---------|--------|-----------| | Test Refactoring | UTRefactor (ACM 2024) | 89% smell reduction | | Test Smells | Meszaros (2007) | "xUnit Test Patterns" | | Test-Code Traceability | IEEE TSE | Test maintenance research |
| Natural Language | Action | |------------------|--------| | "Find orphaned tests" | Detect tests for deleted code | | "Sync tests with code" | Full alignment analysis | | "Are my tests up to date?" | Test-code sync check | | "Clean up test suite" | Find removable tests | | "Test coverage gaps" | Find missing tests |
Tests that reference deleted or renamed code:
def find_orphaned_tests(project_dir):
"""Find tests for code that no longer exists"""
orphans = []
for test_file in glob(f"{project_dir}/test/**/*.test.ts"):
# Extract tested module from import/path
tested_module = infer_tested_module(test_file)
if not exists(tested_module):
orphans.append({
"test_file": test_file,
"expected_source": tested_module,
"status": "source_deleted"
})
# Check for unused test helpers
for helper in extract_test_helpers(test_file):
if not is_used_in_assertions(test_file, helper):
orphans.append({
"test_file": test_file,
"item": helper,
"status": "unused_helper"
})
return orphans
Source files without corresponding tests:
def find_missing_tests(project_dir):
"""Find source files without tests"""
missing = []
for src_file in glob(f"{project_dir}/src/**/*.ts"):
if is_testable(src_file): # Exclude types, index files
test_file = get_test_path(src_file)
if not exists(test_file):
missing.append({
"source": src_file,
"expected_test": test_file,
"functions": extract_public_functions(src_file),
"priority": assess_priority(src_file)
})
return missing
Tests that test implementation details rather than behavior:
COUPLING_PATTERNS = [
# Testing private methods
(r'\.\_\w+\(', "Tests private method"),
# Testing internal state
(r'\.__\w+', "Accesses internal state"),
# Mocking too deeply
(r'mock.*mock.*mock', "Over-mocking"),
# Testing exact implementation
(r'toHaveBeenCalledWith.*\{.*\{', "Assertion on implementation details"),
]
def find_coupled_tests(test_file):
"""Detect implementation-coupled tests"""
content = read_file(test_file)
issues = []
for pattern, description in COUPLING_PATTERNS:
matches = re.findall(pattern, content)
if matches:
issues.append({
"pattern": pattern,
"description": description,
"count": len(matches),
"risk": "Tests may break on safe refactors"
})
return issues
Verify traceability between tests and source:
def build_test_map(project_dir):
"""Build mapping of tests to source files"""
mapping = {}
for test_file in glob(f"{project_dir}/test/**/*.test.ts"):
source_file = infer_source(test_file)
imports = extract_imports(test_file)
mapping[test_file] = {
"inferred_source": source_file,
"actual_imports": imports,
"coverage": get_coverage_for(test_file),
"alignment": "aligned" if source_file in imports else "misaligned"
}
return mapping
## Test Sync Report
**Project**: my-project
**Analysis Date**: 2024-12-12
**Test Files**: 45
**Source Files**: 78
### Summary
| Category | Count | Action |
|----------|-------|--------|
| Orphaned tests | 3 | Delete |
| Missing tests | 8 | Create |
| Implementation-coupled | 5 | Refactor |
| Aligned | 37 | None |
### Orphaned Tests (Safe to Delete)
#### 1. `test/auth/legacy-login.test.ts`
**Status**: Source deleted
**Original Source**: `src/auth/legacy-login.ts` (deleted in commit abc123)
**Last Modified**: 45 days ago
**Action**: DELETE
```bash
rm test/auth/legacy-login.test.ts
test/utils/string-helpers.test.tsStatus: Function removed
Details: Tests formatCurrency() which was removed
Action: DELETE specific test, keep file
// Remove this test block:
describe('formatCurrency', () => { ... });
src/payment/processor.ts (HIGH PRIORITY)Reason: Payment processing - critical path Public Functions:
processPayment(amount, method) - No testrefundPayment(transactionId) - No testvalidateCard(cardInfo) - No testSuggested Test File: test/payment/processor.test.ts
// Scaffold
describe('PaymentProcessor', () => {
describe('processPayment', () => {
it('should process valid payment');
it('should reject insufficient funds');
it('should handle network errors');
});
describe('refundPayment', () => {
it('should refund valid transaction');
it('should reject invalid transaction');
});
});
test/api/user-service.test.ts:45Issue: Tests private method _validateEmail
Risk: Will break on internal refactoring
Current:
it('should validate email', () => {
expect(service._validateEmail('[email protected]')).toBe(true);
});
Suggested Fix:
it('should reject user with invalid email', () => {
expect(() => service.createUser({ email: 'invalid' }))
.toThrow('Invalid email');
});
| Test File | Source File | Status | |-----------|-------------|--------| | test/auth/login.test.ts | src/auth/login.ts | ✅ Aligned | | test/user/profile.test.ts | src/user/profile.ts | ✅ Aligned | | test/api/old-client.test.ts | (deleted) | ❌ Orphaned | | (missing) | src/payment/processor.ts | ⚠️ Missing |
processor.ts (critical)Add to pre-commit or CI:
- name: Test Sync Check
run: |
npx test-sync --project . --strict
# Fails if orphaned tests or missing critical tests
## Cleanup Actions
### Safe Deletions (Automated)
```bash
# Delete orphaned test files
rm test/auth/legacy-login.test.ts
rm test/utils/old-helpers.test.ts
# Remove orphaned test blocks
sed -i '/describe.*formatCurrency/,/^});$/d' test/utils/string.test.ts
/check-traceability command/project-health-checkRun sync analysis:
python scripts/test_sync.py --project . --output report.md
Remove orphaned tests:
python scripts/cleanup_orphans.py --project . --dry-run
data-ai
Report which research-corpus radar sidecars are overdue for refresh. Computes staleness (days since last refresh vs the cadence window) for every radar, sorted most-overdue-first. Runs via `aiwg corpus radar-status`.
data-ai
Aggregate research-corpus radar sidecars into a corpus or per-cluster freshness report — totals, overdue count, per-cluster / per-GRADE / per-trajectory breakdowns, an overdue table, and per-radar rationale snippets. Runs via `aiwg corpus radar-report`.
testing
Scaffold radar/freshness sidecars for research-corpus REFs. Pulls title/authors from the citation sidecar and GRADE from the analysis doc, defaults the refresh cadence from GRADE and the cluster from a corpus-local map, and stamps documentation/radar/REF-XXX-radar.md. Runs via `aiwg corpus radar-init`.
data-ai
Compute an entity's publication trajectory — per-year paper counts, topic drift, hot-streak detection (≥3 consecutive A-grade years), and career phase. Runs via `aiwg corpus profile-temporal`.