Migrating from Jazzer.js
Vitiate is a coverage-guided fuzzer built as a native Vitest plugin. Fuzz tests run alongside unit tests in the same runner with no separate toolchain required. See the Quickstart for prerequisites and installation.
Update Dependencies
Section titled “Update Dependencies”Remove Jazzer.js packages and Jest dependencies (if they were only used for fuzzing):
npm uninstall @jazzer.js/core @jazzer.js/jest-runner jest ts-jest @types/jestInstall Vitiate:
npm install --save-dev vitiateIf your fuzz targets use FuzzedDataProvider for structured inputs, also install:
npm install --save-dev @vitiate/fuzzed-data-providerThen clean up leftover configuration:
- Remove any
overridesorresolutionsblocks inpackage.jsonthat were added for Jazzer.js - Delete
jest.config.fuzz.js(or whatever Jest config was used for fuzzing) - Delete
fuzz/globals.d.tsor similar type declaration files forit.fuzz - Remove any custom npm scripts that wrap
jest --config jest.config.fuzz.jsornpx jazzer
Configure Vitest
Section titled “Configure Vitest”Create or update vitest.config.ts with the Vitiate plugin:
import { defineConfig } from "vitest/config";import { vitiatePlugin } from "@vitiate/core/plugin";
export default defineConfig({ plugins: [vitiatePlugin()], test: { projects: [ { extends: true, test: { name: "unit", include: ["test/**/*.test.ts"] } }, { extends: true, test: { name: "fuzz", include: ["test/**/*.fuzz.ts"] } }, ], },});The projects split keeps unit and fuzz tests in separate Vitest projects so they can have different configurations. Adjust the include globs to match your directory structure.
See Plugin Options for the full configuration reference.
Convert Fuzz Tests
Section titled “Convert Fuzz Tests”Test structure
Section titled “Test structure”Jazzer.js uses Jest’s describe/it.fuzz pattern. Vitiate uses a standalone fuzz() function:
Jazzer.js:
import "@jazzer.js/jest-runner";import { parse } from "../src/parser.js";
describe("parser", () => { it.fuzz("does not crash", (data: Buffer) => { parse(data.toString()); });});Vitiate:
import { fuzz } from "@vitiate/core";import { parse } from "../src/parser.js";
fuzz("parser does not crash", (data: Buffer) => { parse(data.toString());});Key differences:
- No
describewrapper needed -fuzz()is a top-level call - No
import "@jazzer.js/jest-runner"- the plugin handles registration - The test name is the first argument to
fuzz()(combine thedescribeandit.fuzznames if needed)
Error handling
Section titled “Error handling”In both Jazzer.js and Vitiate, a fuzz target signals a bug by throwing. The standard pattern is to catch expected errors and let unexpected ones propagate:
fuzz("parse rejects gracefully", (data: Buffer) => { try { parse(data.toString()); } catch (error) { if (error instanceof ParseError) { return; // Expected - parser rejected invalid input } throw error; // Unexpected error - this is a bug }});Any assertion approach works: throw, Node’s built-in assert, or third-party assertion libraries. Vitiate does not prescribe a specific assertion helper.
Replacing Jest assertions
Section titled “Replacing Jest assertions”Vitest’s expect is API-compatible with Jest’s, so most assertion code works unchanged. Just update the import:
import { expect } from "vitest";Modifiers
Section titled “Modifiers”| Jazzer.js | Vitiate |
|---|---|
it.fuzz.skip(...) | fuzz.skip(...) |
it.fuzz.only(...) | fuzz.only(...) |
| - | fuzz.todo("name") |
See fuzz() API for the complete API reference.
Migrate FuzzedDataProvider
Section titled “Migrate FuzzedDataProvider”The import path changes but the API is compatible - both follow the same LLVM FuzzedDataProvider design:
Jazzer.js:
import { FuzzedDataProvider } from "@jazzer.js/core";Vitiate:
import { FuzzedDataProvider } from "@vitiate/fuzzed-data-provider";See FuzzedDataProvider Reference for the full API.
Map Bug Detectors
Section titled “Map Bug Detectors”Jazzer.js uses kebab-case names; Vitiate uses camelCase. Vitiate also adds detectors that Jazzer.js does not have.
| Jazzer.js name | Vitiate name | Tier | Default |
|---|---|---|---|
command-injection | commandInjection | 1 | On |
path-traversal | pathTraversal | 1 | On |
| - | unsafeEval | 1 | On |
prototype-pollution | prototypePollution | 2 | Off |
| - | redos | 2 | Off |
| - | ssrf | 2 | Off |
Tier 1 detectors are enabled by default. Tier 2 detectors must be explicitly enabled because they hook sensitive APIs and may produce false positives.
If your Jazzer.js config disabled specific detectors, translate the names to camelCase in your Vitiate configuration. See Vulnerability Detectors for usage and Detectors Reference for the full configuration API.
Migrate Corpus and Crash Artifacts
Section titled “Migrate Corpus and Crash Artifacts”Initialize the directory structure
Section titled “Initialize the directory structure”Run npx vitiate init to create seed directories for all discovered fuzz tests:
npx vitiate initThis creates .vitiate/testdata/<hashdir>/seeds/ directories based on your fuzz test names.
Copy existing artifacts
Section titled “Copy existing artifacts”If you have crash regressions or seed inputs from Jazzer.js, copy them into the new structure:
# Copy crash regressionscp old-crashes/* .vitiate/testdata/<hashdir>/crashes/
# Copy seed inputscp old-seeds/* .vitiate/testdata/<hashdir>/seeds/The <hashdir> is a hash-based directory name shown by npx vitiate init. Each test gets its own directory. Timeout artifacts go in the sibling timeouts/ directory.
Update .gitignore
Section titled “Update .gitignore”# Vitiate cached corpus (regenerated by the fuzzer).vitiate/corpus/
# SWC WASM plugin compilation cache (created by Vitiate's instrumentation).swc/The .swc/ directory contains platform-specific compiled WASM plugin artifacts that SWC creates during instrumentation. It is safe to delete and will be recreated on the next run. Jazzer.js does not create this directory since it uses a different instrumentation approach.
Commit .vitiate/testdata/ to version control - it contains your crash regressions and seed inputs.
Clean up old artifacts
Section titled “Clean up old artifacts”Remove Jazzer.js corpus directories once migration is verified:
.cifuzz-corpus/(Jazzer.js default corpus directory)- Any custom corpus or crash directories from your old Jest config
- Old
jest.config.fuzz.jsreferences in CI scripts
See Corpus and Regression Testing for details on how Vitiate manages inputs.
Update Package Scripts
Section titled “Update Package Scripts”| Old (Jazzer.js) | New (Vitiate) |
|---|---|
jest --config jest.config.fuzz.js | npx vitiate regression |
npx jazzer target.fuzz.ts | npx vitiate fuzz |
npx jazzer -m=regression target.fuzz.ts | npx vitiate regression |
npx jazzer target.fuzz.ts -- -max_total_time=300 | npx vitiate fuzz --fuzz-time 300 |
See CLI Flags for the complete command reference.
Update CI
Section titled “Update CI”Regression tests (every PR)
Section titled “Regression tests (every PR)”Before:
- run: npx jest --config jest.config.fuzz.jsAfter:
- run: npx vitiate regressionNightly fuzzing
Section titled “Nightly fuzzing”Before:
- run: npx jazzer target.fuzz.ts -- -max_total_time=3600After:
- run: npx vitiate fuzz --fuzz-time 3600Update crash artifact paths in any CI steps that upload or archive them - Vitiate stores crashes under .vitiate/testdata/<hashdir>/crashes/ instead of Jazzer.js’s flat output directory.
See CI Fuzzing for complete GitHub Actions examples including corpus caching and crash artifact upload.
Verify the Migration
Section titled “Verify the Migration”- Install dependencies:
npm cicompletes without errors - Unit tests pass:
npx vitest run(regression mode runs fuzz tests against any existing corpus) - Regression tests pass:
npx vitiate regressionreplays all committed crash artifacts and seeds - Smoke fuzz:
npx vitiate fuzz --fuzz-time 30runs for 30 seconds without errors