Faker.js Testing Guide: Generate Realistic Test Data in JavaScript
Faker.js generates realistic fake data for your tests: names, emails, addresses, phone numbers, dates, UUIDs, credit card numbers, and hundreds of other types. Instead of hardcoding test@example.com and John Doe everywhere, you get unique, realistic values every time.
This guide covers Faker.js from installation through advanced usage patterns.
Installation
npm install --save-dev @faker-js/fakerThe current official package is @faker-js/faker. The original faker package was famously deleted in 2022 — always use the @faker-js/faker fork.
Basic Usage
const { faker } = require('@faker-js/faker');
// Person
faker.person.fullName() // 'Johnathan Wuckert'
faker.person.firstName() // 'Elena'
faker.person.lastName() // 'Bernhard'
faker.person.jobTitle() // 'Senior Solutions Consultant'
// Internet
faker.internet.email() // 'janelle_ryan@yahoo.com'
faker.internet.userName() // 'myles_hane74'
faker.internet.url() // 'https://sandy-strategy.biz'
faker.internet.ipv4() // '198.94.47.252'
// Location
faker.location.city() // 'Port Hector'
faker.location.country() // 'France'
faker.location.streetAddress() // '589 Gusikowski Loop'
faker.location.zipCode() // '35457'
// Numbers and IDs
faker.string.uuid() // '2dc5de04-ce20-4d9c-873b-b2bb9e6b77e0'
faker.number.int({ min: 1, max: 100 }) // 42
faker.number.float({ min: 0, max: 1, precision: 0.01 }) // 0.73
// Dates
faker.date.past() // Date object, some time in the past
faker.date.between({ from: '2023-01-01', to: '2024-01-01' })
faker.date.recent({ days: 7 }) // Last 7 daysUsing Faker in Test Factories
The most common use of Faker.js is inside factory functions — functions that create test objects with sensible defaults.
const { faker } = require('@faker-js/faker');
function createUser(overrides = {}) {
return {
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
phone: faker.phone.number(),
role: 'user',
createdAt: faker.date.past(),
isActive: true,
...overrides,
};
}
function createProduct(overrides = {}) {
return {
id: faker.string.uuid(),
name: faker.commerce.productName(),
description: faker.commerce.productDescription(),
price: parseFloat(faker.commerce.price({ min: 1, max: 500 })),
sku: faker.string.alphanumeric(10).toUpperCase(),
stock: faker.number.int({ min: 0, max: 1000 }),
category: faker.commerce.department(),
...overrides,
};
}Tests use these factories and only specify what they care about:
test('users with the admin role can access the dashboard', () => {
const admin = createUser({ role: 'admin' });
expect(canAccessDashboard(admin)).toBe(true);
});
test('products with zero stock are out of stock', () => {
const product = createProduct({ stock: 0 });
expect(product.isOutOfStock).toBe(true);
});Seeding for Reproducibility
By default, Faker generates different values every run. This is usually what you want — but sometimes a test fails and you need to reproduce the exact values.
Faker supports seeding: set a seed number and you always get the same values.
// Reproducible values
faker.seed(12345);
faker.person.fullName() // Always 'Leroy Jenkins' with seed 12345
faker.internet.email() // Always the same email with seed 12345
// Back to random
faker.seed(); // or faker.seed(Date.now())Seeding Strategy in CI
Log the seed at test start, and on failure you can reproduce it:
// jest.setup.js
const seed = process.env.FAKER_SEED
? parseInt(process.env.FAKER_SEED)
: Date.now();
faker.seed(seed);
console.log(`Faker seed: ${seed}`);To reproduce a failure:
FAKER_SEED=1706789234567 npm testLocales
Faker supports 60+ locales. Use this when your app is locale-specific or when you need realistic non-English data.
const { fakerDE, fakerJA, fakerPT_BR } = require('@faker-js/faker');
// German data
fakerDE.person.fullName() // 'Heinz Müller'
fakerDE.location.city() // 'München'
// Japanese data
fakerJA.person.fullName() // '田中 太郎'
fakerJA.location.city() // '大阪市'
// Brazilian Portuguese
fakerPT_BR.person.firstName() // 'João'
fakerPT_BR.location.state() // 'São Paulo'Or configure locale on a specific instance:
const { Faker, de } = require('@faker-js/faker');
const fakerDe = new Faker({ locale: [de] });Available Data Categories
Faker.js has 14 top-level modules. Here are the most useful for testing:
Commerce
faker.commerce.productName() // 'Ergonomic Wooden Table'
faker.commerce.productDescription() // 'The Nagasaki Lander is...'
faker.commerce.price({ min: 1, max: 500, dec: 2 }) // '149.99'
faker.commerce.department() // 'Electronics'
faker.commerce.productAdjective() // 'Refined'
faker.commerce.productMaterial() // 'Concrete'Finance
faker.finance.accountNumber() // '84063934'
faker.finance.amount() // '871.90'
faker.finance.currency() // { code: 'EUR', name: 'Euro', symbol: '€' }
faker.finance.creditCardNumber() // '4111111111111111'
faker.finance.iban() // 'DE89370400440532013000'
faker.finance.transactionType() // 'payment'Company
faker.company.name() // 'Sipes, Kirlin and Sons'
faker.company.buzzNoun() // 'paradigm'
faker.company.catchPhrase() // 'Robust mission-critical toolset'
faker.company.buzzPhrase() // 'scale agile interfaces'System
faker.system.fileName() // 'config.json'
faker.system.filePath() // '/usr/local/var/config.json'
faker.system.mimeType() // 'image/png'
faker.system.fileExt() // 'mp4'
faker.system.semver() // '1.14.2'Lorem
faker.lorem.word() // 'consequatur'
faker.lorem.sentence() // 'Deserunt est officia...'
faker.lorem.paragraph() // Full paragraph
faker.lorem.lines(3) // 3 lines of lorem text
faker.lorem.words(5) // 'voluptas omnis quos eos reprehenderit'Unique Values
When you need guaranteed-unique values across a test run:
const { faker } = require('@faker-js/faker');
// Using the unique helper (deprecated in v9 — use other strategies)
// faker.unique(faker.internet.email)
// Better: use UUIDs for IDs
faker.string.uuid() // Guaranteed globally unique
// Or use a counter
let counter = 0;
const uniqueEmail = () => `user-${++counter}@example.com`;
// Or use faker.helpers.unique for custom generators
const unique = faker.helpers.unique(faker.internet.email);Custom Data with Faker Helpers
Picking from Arrays
const roles = ['admin', 'editor', 'viewer'];
faker.helpers.arrayElement(roles) // picks one
faker.helpers.arrayElements(roles, 2) // picks 2
const permissions = faker.helpers.shuffle(['read', 'write', 'delete']);Weighted Random
faker.helpers.weightedArrayElement([
{ weight: 10, value: 'user' },
{ weight: 3, value: 'editor' },
{ weight: 1, value: 'admin' },
])
// Returns 'user' ~71% of the timefromRegExp
Generate strings matching a pattern:
faker.helpers.fromRegExp(/[A-Z]{2}[0-9]{4}/) // 'AB1234'
faker.helpers.fromRegExp('[0-9]{3}-[0-9]{4}') // '555-1234'mustache
Fill in templates:
faker.helpers.mustache(
'Hello {{name}}, your order {{orderId}} is ready.',
{
name: faker.person.firstName,
orderId: () => faker.string.alphanumeric(8).toUpperCase(),
}
)
// 'Hello Sarah, your order AB12CD34 is ready.'Building a Test Data Layer
For larger codebases, centralize all faker usage in a test/factories directory:
test/
factories/
user.factory.js
order.factory.js
product.factory.js
helpers/
db.js
setup.js// test/factories/user.factory.js
const { faker } = require('@faker-js/faker');
const db = require('../helpers/db');
const UserFactory = {
// In-memory only (for unit tests)
build: (overrides = {}) => ({
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
role: 'user',
isActive: true,
createdAt: new Date(),
...overrides,
}),
// Persisted (for integration tests)
create: async (overrides = {}) => {
const data = UserFactory.build(overrides);
const [user] = await db.query(
'INSERT INTO users (id, email, name, role, is_active, created_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *',
[data.id, data.email, data.name, data.role, data.isActive, data.createdAt]
);
return user;
},
createMany: (n, overrides = {}) =>
Promise.all(Array.from({ length: n }, () => UserFactory.create(overrides))),
};
module.exports = UserFactory;Usage:
const UserFactory = require('../factories/user.factory');
// Unit test
const user = UserFactory.build({ role: 'admin' });
// Integration test
const user = await UserFactory.create({ role: 'admin' });
const users = await UserFactory.createMany(5, { role: 'viewer' });What NOT to Use Faker For
Assertion values
// Wrong — assertion will always fail
const user = UserFactory.build();
expect(user.email).toBe('specific@example.com');
// Right — if you're asserting a specific value, specify it
const user = UserFactory.build({ email: 'specific@example.com' });
expect(user.email).toBe('specific@example.com');Enum fields you're branching on
// Risky — test result depends on which role Faker generates
const user = UserFactory.build();
if (user.role === 'admin') {
// This branch is only hit sometimes
}
// Right — be explicit
const admin = UserFactory.build({ role: 'admin' });
const regularUser = UserFactory.build({ role: 'user' });Dates with business logic
// Risky — faker.date.past() could generate a date that's 5 years ago
// or yesterday, and your logic might only look back 30 days
const user = UserFactory.build({ createdAt: faker.date.past() });
// Right — be specific about date ranges
const recentUser = UserFactory.build({
createdAt: faker.date.recent({ days: 7 }),
});
const oldUser = UserFactory.build({
createdAt: faker.date.past({ years: 2 }),
});Faker.js vs. Alternatives
| Library | Language | Notes |
|---|---|---|
| @faker-js/faker | JavaScript/TypeScript | Most comprehensive JS faker, active community |
| Chance.js | JavaScript | Smaller API, good for simple use cases |
| Rosie | JavaScript | Factory library, works well alongside faker |
| Fishery | TypeScript | TypeScript-first factories, excellent type safety |
| Faker (Python) | Python | Port of Faker.js concepts to Python |
| factory_boy | Python | Django-native factories |
| Bogus | C# | .NET port |
Summary
Faker.js is most valuable when you pair it with the factory pattern:
- Factories define the shape of your test objects
- Faker populates fields that tests don't care about with realistic values
- Tests only specify the fields that drive the behavior under test
The result: tests that are readable, isolated, and resilient to schema changes — because "email" in a test now means "some valid email", not "this specific hardcoded string that will collide with the next parallel test run".