oxfmt deletes a decorator on a rest parameter. This happens with the
default settings, and oxfmt reports no error.
```ts
class C {
m(@Dec() ...args: string[]) {}
}
// before
class C {
m(...args: string[]) {}
}
```
The parser and codegen support these decorators (#18938, #20132), but
the formatter printed only the rest element and its type annotation.
This PR prints the decorators in the same way as for `FormalParameter`.
The new fixture `ts/parameters/rest-decorators.ts` covers single and
multiple decorators, `@(await p)`, a decorator after another parameter,
and long parameter lists. The output matches Prettier 3.9.10 for every
case.
---
AI assistance was used for this change. I reviewed and tested it.
---------
Co-authored-by: leaysgur <6259812+leaysgur@users.noreply.github.com>
Oxc Formatter Tests
This directory contains snapshot-based tests for the oxc_formatter crate.
Overview
The test infrastructure is designed to be simple and flexible:
- File-based testing: Just create
.{js,jsx,ts,tsx,mjs,cjs,mts,cts}files in thefixtures/directory - Hierarchical options: Configure format options via
options.jsonfiles at any directory level - Automatic discovery: Tests are automatically discovered via build script - no manual registration needed
- Nested modules: Directory structure becomes module hierarchy, enabling targeted test execution
- Individual test functions: Each file gets its own test function, visible in
cargo testoutput - Snapshot testing: Uses
instafor snapshot testing with easy review workflow - Co-located snapshots: Snapshots are stored next to test files for easy navigation
Directory Structure
tests/
├── mod.rs # Main test runner
└── fixtures/ # Test input files
├── js/ # JavaScript/JSX tests
│ ├── options.json # Shared options for all js tests
│ ├── arrow-functions.js
│ ├── arrow-functions.js.snap # Snapshot file (includes extension)
│ ├── simple.jsx
│ ├── simple.jsx.snap
│ └── nested/
│ ├── options.json # Overrides parent options
│ ├── example.js
│ └── example.js.snap
└── ts/ # TypeScript/TSX tests
├── generics.ts
└── generics.ts.snap
Adding New Tests
Simple Test (using default options)
Just create a new file in fixtures/js/ or fixtures/ts/:
# Create a new test file
echo "const foo = bar;" > tests/fixtures/js/my-test.js
# The test is automatically discovered - just run tests
cargo test -p oxc_formatter --test mod
The test function is automatically generated by the build script in the module fixtures::js::my_test. The snapshot will be created as tests/fixtures/js/my-test.js.snap next to your test file.
Test with Custom Options
Create an options.json file in the same directory (or parent directory):
[
{
"semi": true,
"singleQuote": false
},
{
"semi": false,
"singleQuote": true,
"printWidth": 120
}
]
Note: Each object in the array is a separate option set. The options are displayed in the snapshot output.
Nested/Organized Tests
Create subdirectories to organize related tests:
mkdir -p tests/fixtures/js/classes
echo "class Foo {}" > tests/fixtures/js/classes/simple.js
The test will inherit options from the nearest options.json file in the directory tree.
Supported Options
The core options (printWidth, tabWidth, useTabs, endOfLine) and the keys apply_option in tests/fixtures/mod.rs maps are supported, any other key fails the test.
Running Tests
Run all tests
cargo test -p oxc_formatter --test mod
Run tests in a specific directory
# Run all tests in the js/comments directory
cargo test -p oxc_formatter fixtures::js::comments
# Run all tests in the js directory (including subdirectories)
cargo test -p oxc_formatter fixtures::js
# Run a specific test file
cargo test -p oxc_formatter fixtures::js::comments::test
Accept new/changed snapshots
cargo insta test --accept -p oxc_formatter --test mod
Accept snapshots for specific tests
# Test names containing `arrow`
cargo insta test --accept -p oxc_formatter --test mod -- arrow
Review snapshots interactively
cargo insta review -p oxc_formatter
How It Works
- Build-time Discovery: The build script (
build.rs) scanstests/fixtures/for all.{js,jsx,ts,tsx,mjs,cjs,mts,cts}files - Module Generation: Directories become nested modules matching the file system structure
- Code Generation: For each file, a test function is generated in the appropriate module
- Example:
fixtures/js/comments/test.js→fixtures::js::comments::test()
- Example:
- Test Execution: Each generated test function calls the shared
test_file()helper - Option Resolution: For each file, walk up the directory tree to find
options.json - Formatting: Format the file with each option set
- Snapshot: Generate a snapshot showing input + all outputs (stored next to test file)
- Comparison: Compare with existing snapshot (if any)
Tips
- Auto-discovery: Just add a
.{js,jsx,ts,tsx,mjs,cjs,mts,cts}file tofixtures/- no need to register it anywhere - Nested Modules: Directories become modules, enabling targeted test execution:
fixtures/js/comments/test.js→cargo test fixtures::js::comments::testfixtures/js/comments/→cargo test fixtures::js::comments(all tests in directory)fixtures/js/→cargo test fixtures::js(all tests including subdirectories)
- Organization: Use subdirectories to group related tests (e.g.,
fixtures/js/arrows/,fixtures/js/classes/) - Shared Options: Put
options.jsonat the directory level to apply to all files in that directory - Override Options: Create
options.jsonin a subdirectory to override parent options - Default Options: If no
options.jsonis found,FormatOptions::default()is used - File Extensions: The source type is detected automatically from the file extension
- Co-located Snapshots: Snapshots are stored next to test files for easy navigation and review
- Rebuilds: The build script automatically rebuilds when files in
tests/fixtures/change