Chance.js vs Faker.js: Choosing a Random Data Library for Tests
When you need to generate random test data in JavaScript, two libraries dominate the conversation: Faker.js and Chance.js. Faker is the more popular choice, but Chance.js has a distinct design philosophy that makes it better suited to certain use cases — particularly when you need weighted randomness, custom probability distributions, or a simpler API surface with fewer dependencies.
This guide covers the Chance.js API in depth, compares it against Faker.js on the dimensions that matter for testing, and gives you a decision framework for choosing between them.
What Is Chance.js?
Chance.js is a minimalist random data generator. Unlike Faker, which is organized around real-world data categories (names, addresses, commerce), Chance focuses on probabilistic generation — it gives you tools to control how data is distributed, not just what categories it belongs to.
npm install chance
npm install --save-dev @types/chance # TypeScript typesimport Chance from 'chance';
const chance = new Chance();
chance.name() // "Harold Higgins"
chance.email() // "veho@tohu.com"
chance.integer({ min: 1, max: 100 }) // 47
chance.bool() // true or falseChance is instantiated as an object rather than used as a module-level singleton. This makes it easy to create multiple instances with different seeds in the same test file.
Core API Overview
Person Data
const chance = new Chance();
chance.name() // "Bernice Payne"
chance.name({ middle: true }) // "Carol Ann Stevens"
chance.first() // "Roberto"
chance.last() // "Yamamoto"
chance.prefix() // "Mr." / "Dr." / "Mrs."
chance.suffix() // "Jr." / "PhD"
chance.age({ type: 'adult' }) // integer 18–65
chance.age({ type: 'child' }) // integer 1–12
chance.birthday() // Date object
chance.ssn() // "078-05-1120" (test SSN)Internet and Contact
chance.email() // "jujuj@vuf.edu"
chance.email({ domain: 'example.com' }) // "abc@example.com"
chance.url() // "https://sub.example.org/path"
chance.ip() // "192.168.1.42"
chance.ipv6() // full IPv6 address
chance.twitter() // "@username"
chance.domain() // "example.net"Numbers and Strings
chance.integer({ min: 0, max: 1000 }) // 742
chance.floating({ min: 0, max: 1, fixed: 4 }) // 0.3847
chance.natural() // non-negative integer
chance.string({ length: 8 }) // "aBcDeFgH"
chance.string({ pool: 'abcdefghijklmnop' }) // restricted charset
chance.character({ alpha: true }) // single letter
chance.word() // "lorem"
chance.sentence() // "Lorem ipsum..."
chance.paragraph() // multiple sentencesPicking and Collections
chance.pick(['red', 'green', 'blue']) // one random element
chance.pickset(['a', 'b', 'c', 'd'], 2) // ['c', 'a'] — two unique
chance.shuffle(['a', 'b', 'c']) // shuffled copy
chance.unique(chance.color, 5) // 5 unique colorsSeeding for Reproducible Tests
Like Faker, Chance supports seeding to make random output deterministic:
const chance = new Chance(42);
chance.name(); // always "Harriet Payne" with seed 42
// Or seed after construction
const chance2 = new Chance();
chance2.seed = 12345;Unlike Faker, each Chance instance has its own seed. This means you can run tests in parallel with different seeds without global state conflicts:
// Two independent random streams, no interference
const userChance = new Chance(100);
const orderChance = new Chance(200);
const user = { name: userChance.name(), email: userChance.email() };
const order = { id: orderChance.guid(), amount: orderChance.dollar() };Weighted Randomness — Chance's Killer Feature
The feature that sets Chance apart from Faker is weighted(). It lets you pick from a set of values with non-uniform probabilities:
const chance = new Chance();
// 70% free, 25% premium, 5% enterprise
const plan = chance.weighted(
['free', 'premium', 'enterprise'],
[70, 25, 5]
);
// Simulate realistic order status distribution
const status = chance.weighted(
['pending', 'processing', 'shipped', 'delivered', 'cancelled'],
[10, 15, 20, 50, 5]
);This is invaluable for generating test datasets that reflect real-world distributions. If 90% of your users are on the free plan, a random dataset with equal distribution doesn't test the realistic load on your billing logic. Weighted randomness fixes that.
Practical Use: Generating Realistic Test Datasets
function buildTestUserSet(count: number) {
const chance = new Chance(999);
return Array.from({ length: count }, () => ({
id: chance.guid(),
name: chance.name(),
email: chance.email(),
plan: chance.weighted(['free', 'pro', 'enterprise'], [75, 20, 5]),
isVerified: chance.weighted([true, false], [85, 15]),
country: chance.weighted(['US', 'GB', 'DE', 'other'], [40, 15, 10, 35]),
}));
}This produces a dataset that exercises your analytics, billing, and localization code paths in roughly realistic proportions.
Custom Generators with mixin
Chance allows you to extend the instance with domain-specific generators:
const chance = new Chance();
chance.mixin({
productSku(): string {
return `SKU-${this.string({ length: 4, pool: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' })}-${this.natural({ min: 1000, max: 9999 })}`;
},
testUser(overrides = {}) {
return {
id: this.guid(),
name: this.name(),
email: this.email({ domain: 'testcorp.internal' }),
role: this.pick(['admin', 'editor', 'viewer']),
...overrides,
};
},
apiErrorCode(): number {
return this.pick([400, 401, 403, 404, 422, 500, 503]);
},
});
// Now available on the instance
chance.productSku(); // "SKU-TXPZ-4821"
chance.testUser({ role: 'admin' });
chance.apiErrorCode(); // 422TypeScript users will want to augment the Chance.Chance interface, but the runtime behavior works immediately after mixin.
Faker.js vs Chance.js: Feature Comparison
| Feature | Faker.js | Chance.js |
|---|---|---|
| Data categories | 60+ (commerce, finance, vehicle, music, etc.) | ~30 (core personal/internet data) |
| Locale support | 60+ locales | English-centric (some locale helpers) |
| Weighted randomness | Not built-in | chance.weighted() — first-class |
| Custom generators | Factory pattern (external) | mixin() — built into the instance |
| Multiple streams | Singleton (workarounds needed) | Multiple instances natively |
| Package size | ~5 MB unpacked | ~1 MB unpacked |
| TypeScript | Bundled types | @types/chance |
| Maintenance | Active (@faker-js/faker) |
Maintained but slower cadence |
When to Use Chance.js
Choose Chance when:
- You need weighted distributions. Simulating realistic usage patterns, A/B test cohorts, or load distributions that reflect production.
- You need multiple independent random streams. Parallel test generation without shared state.
- You want a minimal dependency. Chance is around 1 MB; Faker is 5 MB. For serverless functions or edge deployments where cold start matters, this is relevant.
- Your custom generator logic is complex. Chance's
mixinkeeps custom generators alongside the instance rather than in separate factory files.
Choose Faker.js when:
- You need locale-specific data. German addresses, Japanese names, French phone number formats.
- You need category breadth. Finance, vehicles, science, music — data types Chance doesn't have.
- Your team is already using it. The ecosystem and documentation are richer.
Using Both Together
Nothing stops you from using both in the same project:
import { faker } from '@faker-js/faker';
import Chance from 'chance';
const chance = new Chance(123);
function buildTestScenario() {
return {
// Faker for locale-specific German data
user: {
name: faker.person.fullName({ sex: 'female' }),
address: faker.location.streetAddress(),
},
// Chance for weighted business logic
subscription: chance.weighted(
['monthly', 'annual'],
[30, 70]
),
// Chance for constrained integers
retryCount: chance.integer({ min: 0, max: 3 }),
};
}The libraries complement each other — Faker for rich realistic data, Chance for probabilistic control.
Seeding Strategy for CI
// testSetup.ts
import Chance from 'chance';
const seed = process.env.TEST_SEED
? parseInt(process.env.TEST_SEED, 10)
: Date.now();
export const chance = new Chance(seed);
// Log seed in CI so failures can be reproduced
if (process.env.CI) {
console.log(`Test seed: ${seed}`);
console.log(`To reproduce: TEST_SEED=${seed} npm test`);
}Summary
Chance.js and Faker.js solve the same core problem — eliminating hard-coded test data — but from different angles. Faker excels at breadth of realistic data across many locales. Chance excels at probabilistic control: weighted picks, multiple independent streams, and composable custom generators via mixin. For most projects, Faker.js is the better default. But when your tests need to simulate realistic usage distributions or you want finer control over randomness, Chance.js fills a gap that Faker doesn't address.