Test structure
JSSG tests use a simple directory structure where each test case contains two files:- Input files must be named
input.ts(or appropriate extension) - Expected files must be named
expected.ts(or appropriate extension) - File extensions should match your target language (
.ts,.tsx,.js,.jsx)
Command reference
Basic syntax
Language parser to use (e.g., “tsx”, “javascript”, “typescript”).
Path to your transform file (e.g., ”./scripts/codemod.ts”).
Path to test directory (defaults to ”./tests”).
Common options
See all available options in the CLI reference.
Creating effective test cases
1. Start simple:Understanding test results
Exit codes
- 0: All tests passed
- 1: At least one test failed (diffs are printed)
- 2: Error occurred (e.g., syntax error in codemod)
Reading test output
Pro tip: Use
-v flag for detailed output when debugging test failures.Troubleshooting
Language mismatch
Language mismatch
Problem: Tests fail with parsing errors.
Solution: Ensure the
Solution: Ensure the
-l flag matches your source files:Files not found
Files not found
Problem: “No test files found” error.
Solution: Check your directory structure and file names:
Solution: Check your directory structure and file names:
Transform not applied
Transform not applied
Problem: Test passes but no changes were made.
Solution: This is normal if your transform returns
Solution: This is normal if your transform returns
null for unchanged files. If you expect changes:Unexpected diffs
Unexpected diffs
Problem: Test fails with unexpected output.
Solution: Update expected output if changes are intentional:
Solution: Update expected output if changes are intentional:
Codemod syntax errors
Codemod syntax errors
Problem: “Syntax error in codemod” or TypeScript errors.
Solution: Check your transform file:
Solution: Check your transform file:
Workflow integration
Package script
Add to yourpackage.json:
package.json
CI/CD integration
.github/workflows/test.yml
Comparison strictness
Use the--strictness flag to control how expected and actual outputs are compared. This helps tests pass when outputs are semantically equivalent but differ in formatting.
Strictness levels
| Level | Description |
|---|---|
strict | (Default) Exact string equality. Fails on any whitespace or formatting differences. |
cst | Compare Concrete Syntax Trees. Includes all tokens but ignores whitespace content. Preserves ordering. |
ast | Compare Abstract Syntax Trees. Ignores formatting and whitespace, preserves ordering. |
loose | Loose AST comparison. Ignores formatting and ordering of unordered children (e.g., object members, imports). |
What loose comparison ignores
The loose level ignores ordering for semantically unordered constructs:
- Object property ordering:
{a: 1, b: 2}matches{b: 2, a: 1} - Import ordering:
import {a, b} from 'x'matchesimport {b, a} from 'x' - Keyword argument ordering (Python):
func(a=1, b=2)matchesfunc(b=2, a=1) - Interface member ordering: Order of properties in TypeScript interfaces
- Derive attribute ordering (Rust):
#[derive(Debug, Clone)]matches#[derive(Clone, Debug)]
When to use each level
strict: Default. Use when exact output matters (most cases).cst: Use when you want to compare token structure but ignore whitespace content.ast: Use when you want to ignore formatting differences but preserve ordering.loose: Use when your codemod modifies structures where order doesn’t matter semantically.
Supported languages
| Language | Features |
|---|---|
| JavaScript/JSX | Objects, imports, exports |
| TypeScript/TSX | Objects, imports, exports, type definitions, interfaces |
| Python | Dictionaries, imports, keyword arguments, type unions |
| Go | Imports, struct literals (keyed), interface definitions |
| Rust | Struct expressions, derive attributes, use lists, trait bounds |
| JSON | Objects |
Best practices
- Start simple: Begin with basic transformations before complex ones
- Test edge cases: Include empty files, files with comments, and malformed code
- Use descriptive names: Make test cases self-documenting
- Keep tests focused: One transformation per test case
- Validate locally: Always test before publishing
- Use
--strictness loose: When testing transforms that may produce semantically equivalent outputs with different formatting or ordering