# TypeScript/JavaScript Mutation Testing
**Status:** โ
Production Ready (v2.144.0+)
**Languages:** TypeScript, JavaScript (ES6+, JSX, TSX)
**Quality:** 80%+ mutation score achievable
---
## Overview
PMAT provides **AST-based mutation testing** for TypeScript and JavaScript projects, helping you validate test suite quality by introducing controlled bugs (mutations) and checking if your tests catch them.
**Key Benefits:**
- ๐ฏ Quantify test quality with mutation scores
- ๐ Identify gaps in test coverage
- โก Fast generation (14ms for 67 mutants)
- ๐งฌ 5 mutation operators covering common bug patterns
- ๐ Works with jest, vitest, and mocha
---
## Quick Start
### 1. Install Dependencies
```bash
cd fixtures/typescript
npm install # Install vitest/jest
```
### 2. Run Mutation Testing
```bash
# From project root
cargo run --example typescript_mutation_workflow --features typescript-ast
# Or build the example first
cargo build --example typescript_mutation_workflow --features typescript-ast
./target/debug/examples/typescript_mutation_workflow
```
### 3. View Results
```
๐งฌ TypeScript Mutation Testing Workflow
๐ Reading source file: fixtures/typescript/calculator.ts
Size: 1,776 bytes
๐ง Generating mutants...
Generated: 67 mutants
Time: 14ms
โ
Running baseline tests...
Baseline tests passed โ
๐งช Testing mutants (67 total)...
[Progress updates...]
๐ Mutation Testing Results
Total Mutants: 67
Killed: 54 (80%)
Survived: 13 (19%)
Timeout/Error: 0
๐ฏ Mutation Score: 80% โ
EXCELLENT!
```
---
## Mutation Operators
### 1. Arithmetic Operator Replacement (AOR)
**Replaces:** `+`, `-`, `*`, `/`, `%`
```typescript
// Original
function add(a: number, b: number) {
return a + b;
}
// Mutants
return a - b; // + โ -
return a * b; // + โ *
return a / b; // + โ /
```
**Tests should fail** when arithmetic operators are changed.
### 2. Strict Equality Mutation
**Replaces:** `===`, `!==` with `==`, `!=`
```typescript
// Original
if (value === 0) {
return true;
}
// Mutants
if (value == 0) { // === โ == (type coercion!)
if (value !== 0) { // === โ !== (negation)
```
**Tests should fail** when type-safe equality is weakened.
### 3. Optional Chaining Mutation
**Replaces:** `?.` with `.`
```typescript
// Original
return obj?.nested?.value;
// Mutant
return obj.nested.value; // ?. โ . (will throw if null!)
```
**Tests should fail** when null safety is removed.
### 4. Nullish Coalescing Mutation
**Replaces:** `??` with `||`
```typescript
// Original
return value ?? defaultValue;
// Mutant
**Tests should fail** when nullish behavior changes.
### 5. Async/Await Mutation
**Removes:** `async` and `await` keywords
```typescript
// Original
async function fetchValue(): Promise<number> {
return await Promise.resolve(42);
}
// Mutants
function fetchValue(): Promise<number> { // Remove async
return Promise.resolve(42); // Remove await
}
```
**Tests should fail** when Promise handling is broken.
---
## Understanding Mutation Scores
### Score Interpretation
| **90-100%** | Excellent | Maintain current quality |
| **80-89%** | Good | Minor improvements needed |
| **70-79%** | Acceptable | Add targeted tests |
| **60-69%** | Weak | Significant gaps exist |
| **< 60%** | Poor | Major test suite overhaul needed |
### What Mutation Scores Tell You
**High Score (80%+):**
- โ
Tests catch most bugs
- โ
Good coverage of edge cases
- โ
Type safety validated
- โ
Error conditions tested
**Low Score (<70%):**
- โ Tests miss common bug patterns
- โ Weak edge case coverage
- โ Type coercion not tested
- โ Happy path bias
---
## Surviving Mutants (Test Weaknesses)
Surviving mutants indicate **real gaps** in your test suite:
### Example: Type Coercion Gap
**Mutant:** `===` โ `==` (survives)
```typescript
// Code
if (b === 0) {
throw new Error("Division by zero");
}
// Test (weak!)
expect(() => divide(10, 0)).toThrow();
// Passes even with b == 0 because all inputs are numbers!
// Better test
expect(() => divide(10, "0")).toThrow(); // Would fail with ==
```
### Example: Boundary Condition Gap
**Mutant:** `>` โ `>=` (survives)
```typescript
// Code
return a > b ? a : b;
// Test (weak!)
expect(max(5, 3)).toBe(5);
// Passes even with >= because 5 > 3
// Better test
expect(max(5, 5)).toBe(5); // Would fail with >= edge case
```
### Example: Async Testing Gap
**Mutant:** Remove `await` (survives)
```typescript
// Code
return await Promise.resolve(42);
// Test (weak!)
const result = fetchValue();
expect(result).resolves.toBeDefined();
// Passes even without await (returns Promise)
// Better test
const result = await fetchValue();
expect(typeof result).toBe('number'); // Would fail without await
```
---
## Example Project Structure
```
my-typescript-project/
โโโ src/
โ โโโ calculator.ts # Source code
โ โโโ calculator.test.ts # Tests
โโโ package.json # Test framework config
โโโ tsconfig.json
โโโ node_modules/ # Must run npm install
```
### Minimal package.json
```json
{
"scripts": {
"test": "vitest run"
},
"devDependencies": {
"vitest": "^2.0.0",
"typescript": "^5.0.0"
}
}
```
---
## Advanced Usage
### Parallel Execution (Experimental)
```bash
cargo run --example typescript_mutation_workflow_parallel --features typescript-ast
```
**Benefits:**
- Uses multiple CPU cores
- Potential 8x speedup
- Same mutation score
**Note:** File locking prevents conflicts but serializes file I/O.
### Programmatic Usage
```rust
use pmat::services::mutation::TypeScriptMutationGenerator;
// Generate mutants
let generator = TypeScriptMutationGenerator::with_default_operators();
let mutants = generator.generate_mutants(&source, "test.ts")?;
// Process mutants
for mutant in mutants {
println!("Mutant: {} at line {}", mutant.id, mutant.location.line);
}
```
---
## Limitations & Known Issues
### Current Limitations
1. **Single-file testing** - Multi-file projects not yet supported
2. **npm startup overhead** - Each mutant restarts test framework (~1.8s)
3. **No test selection** - Runs all tests for each mutant
4. **Sequential execution** - No true parallel testing yet
### Workarounds
**Speed up testing:**
```json
{
"scripts": {
"test": "vitest run --reporter=basic" // Minimal output
}
}
```
**Reduce mutants:**
- Focus on critical files
- Use smaller test suites during development
- Run full mutation testing in CI
### Future Enhancements
- [ ] Multi-file project support
- [ ] Test framework keep-alive (3-4x speedup)
- [ ] Smart test selection (2-5x speedup)
- [ ] Parallel execution (8x speedup)
- [ ] HTML reports
- [ ] CI/CD integration
---
## Troubleshooting
### "No package.json found"
**Problem:** Project root not detected
**Solution:**
```bash
# Ensure package.json exists
cd your-project
npm init -y
npm install --save-dev vitest
# Or specify project root explicitly in code
```
### "Baseline tests failed"
**Problem:** Tests fail on original code
**Solution:**
```bash
# Fix tests first
npm test
# Then run mutation testing
cargo run --example typescript_mutation_workflow
```
### "Test execution timeout"
**Problem:** Tests take too long
**Solution:**
```typescript
// Add timeout in test
test('slow operation', async () => {
// ...
}, 30000); // 30 second timeout
```
### "No mutants generated"
**Problem:** Code doesn't match mutation patterns
**Solution:**
- Ensure code has arithmetic operators (+, -, *, /)
- Check for === comparisons
- Verify TypeScript syntax is valid
---
## Best Practices
### 1. Start with Small Files
```bash
# Good: Single file, focused tests
calculator.ts + calculator.test.ts (67 mutants, 2 minutes)
# Avoid: Large files initially
entire-app.ts (1000+ mutants, 30+ minutes)
```
### 2. Interpret Surviving Mutants
**Don't just aim for 100%** - some mutants are equivalent:
```typescript
// These might be equivalent:
return a > b ? a : b;
return a >= b ? a : b; // Same behavior when a > b
```
Focus on **meaningful survivors** that reveal test gaps.
### 3. Add Tests Iteratively
```typescript
// 1. Run mutation testing
// 2. Identify surviving mutants
// 3. Add tests to kill them
// 4. Re-run to verify
// Example: Add type coercion test
test('strict equality with type coercion', () => {
expect(isEqual(0, "0")).toBe(false); // Kills === โ == mutant
});
```
### 4. Use in CI/CD
```yaml
# .github/workflows/mutation-testing.yml
name: Mutation Testing
on: [pull_request]
jobs:
mutation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cargo run --example typescript_mutation_workflow
- run: |
# Fail if mutation score < 70%
if [ $MUTATION_SCORE -lt 70 ]; then exit 1; fi
```
---
## Performance Expectations
### Typical Performance
| 10 | ~18s | ~2s |
| 50 | ~90s | ~7s |
| 100 | ~180s | ~12s |
| 500 | ~900s (15min) | ~60s |
**Note:** Times assume ~1.8s per mutant (current) or ~0.12s (optimized)
### Scaling Recommendations
**Small projects (<50 mutants):** Run on every commit
**Medium projects (50-200 mutants):** Run on PRs
**Large projects (200+ mutants):** Run nightly or on main branch
---
## Related Documentation
- [Complete Implementation Summary](../tickets/PMAT-7010-COMPLETE-SUMMARY.md)
- [REFACTOR Phase Day 1](../tickets/PMAT-7010-REFACTOR-DAY1-COMPLETE.md)
- [Performance Optimization Plan](../tickets/PMAT-7010-REFACTOR-DAY2-PLAN.md)
- [Original Specification](../tickets/TICKET-PMAT-7010.md)
---
## Support & Contributing
### Getting Help
1. Check [Troubleshooting](#troubleshooting) section
2. Review examples in the project repository for working code
3. Open issue on GitHub with reproduction steps
### Contributing
Contributions welcome for:
- Additional mutation operators
- Performance optimizations
- Test framework integrations
- Documentation improvements
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
---
## License
MIT OR Apache-2.0 (same as PMAT)
---
**Last Updated:** 2025-10-08
**Version:** 2.144.0
**Status:** Production Ready
**Maintainer:** PMAT Team