• Stars
    star
    666
  • Rank 67,706 (Top 2 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 6 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

@jackfranklin/test-data-bot

npm version

IMPORTANT: @jackfranklin/test-data-bot is the new version of this package, written in TypeScript and initially released as version 1.0.0.

The old package, test-data-bot (not scoped to my username on npm) was last released as 0.8.0 and is not being updated any more. It is recommended to upgrade to 1.0.0, which has some breaking changes documented below.

If you want to find the old documentation for 0.8.0, you can do so via an old README on GitHub.

Motivation and usage

test-data-bot was inspired by Factory Bot, a Ruby library that makes it really easy to generate fake yet realistic looking data for your unit tests.

Rather than creating random objects each time you want to test something in your system you can instead use a factory that can create fake data. This keeps your tests consistent and means that they always use data that replicates the real thing. If your tests work off objects close to the real thing they are more useful and there's a higher chance of them finding bugs.

Rather than the term factory, test-data-bot uses builder.

test-data-bot makes no assumptions about frameworks or libraries, and can be used with any test runner too. test-data-bot is written in TypeScript, so if you use that you'll get nice type safety (see the TypeScript section of this README) but you can use it in JavaScript with no problems.

npm install --save-dev @jackfranklin/test-data-bot
yarn add --dev @jackfranklin/test-data-bot

Creating your first builder

We use the build function to create a builder. You give a builder an object of fields you want to define:

const { build } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: 'jack',
  },
});

const user = userBuilder.one();
console.log(user);
// => { name: 'jack'}

While the examples in this README use require, you can also use import {build} from '@jackfranklin/test-data-bot'.

Once you've created a builder, you can call the one method it returns to generate an instance of that object - in this case, a user.

const user = userBuilder.one();

You can also call the builder directly to get a single instance - userBuilder(). v2.1 of test-data-bot shipped with the one() method and that is now the recommended way of constructing these objects.

It would be boring though if each user had the same name - so test-data-bot lets you generate data via some API methods:

Incrementing IDs with sequence

Often you will be creating objects that have an ID that comes from a database, so you need to guarantee that it's unique. You can use sequence, which increments every time it's called:

const { build, sequence } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    id: sequence(),
  },
});

const userOne = userBuilder.one();
const userTwo = userBuilder.one();

// userOne.id === 1
// userTwo.id === 2

If you need more control, you can pass sequence a function that will be called with the number. This is useful to ensure completely unique emails, for example:

const { build, sequence } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    email: sequence(x => `jack${x}@gmail.com`),
  },
});

const userOne = userBuilder.one();
const userTwo = userBuilder.one();

// userOne.email === [email protected]
// userTwo.email === [email protected]

You can use the reset method to reset the counter used internally when generating a sequence:

const { build, sequence } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    id: sequence(),
  },
});

const userOne = userBuilder.one();
const userTwo = userBuilder.one();
userBuilder.reset();
const userThree = userBuilder.one();
const userFour = userBuilder.one();

// userOne.id === 1
// userTwo.id === 2
// userThree.id === 1 <- the sequence has been reset here
// userFour.id === 2

Randomly picking between an option with oneOf

If you want an object to have a random value, picked from a list you control, you can use oneOf:

const { build, oneOf } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: oneOf('alice', 'bob', 'charlie'),
  },
});

bool

If you need something to be either true or false, you can use bool:

const { build, bool } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    isAdmin: bool(),
  },
});

perBuild

test-data-bot lets you declare a field to always be a particular value:

const { build, perBuild } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: 'jack',
    details: {},
  },
});

A user generated from this builder will always be the same data. However, if you generate two users using the builder above, they will have exactly the same object for the details key:

const userOne = userBuilder.one();
const userTwo = userBuilder.one();

userOne.details === userTwo.details; // true

If you want to generate a unique object every time, you can use perBuild which takes a function and executes it when a builder is built:

const { build, perBuild } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: 'jack',
    details: perBuild(() => {
      return {};
    }),
  },
});

const userOne = userBuilder.one();
const userTwo = userBuilder.one();

userOne.details === userTwo.details; // false

This approach also lets you use any additional libraries, say if you wanted to use a library to generate fake data:

const myFakeLibrary = require('whatever-library-you-want');
const { build, perBuild } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: perBuild(() => myFakeLibrary.randomName()),
  },
});

Overrides per-build

You'll often need to generate a random object but control one of the values directly for the purpose of testing. When you call a builder you can pass in overrides which will override the builder defaults:

const { build, fake, sequence } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    id: sequence(),
    name: fake(f => f.name.findName()),
  },
});

const user = userBuilder.one({
  overrides: {
    id: 1,
    name: 'jack',
  },
});

// user.id === 1
// user.name === 'jack'

If you need to edit the object directly, you can pass in a map function when you call the builder. This will be called after test-data-bot has generated the fake object, and lets you directly change its properties.

const { build, sequence } = require('@jackfranklin/test-data-bot');

const userBuilder = build('User', {
  fields: {
    id: sequence(),
    name: 'jack',
  },
});

const user = userBuilder.one({
  map: user => {
    user.name = user.name.toUpperCase();
    return user;
  },
});

Using overrides and map lets you easily customise a specific object that a builder has created.

Creating multiple instances

If you want to create multiple instances of a builder at once, you can use the many method on the builder:

const userBuilder = build({
  fields: {
    name: 'jack',
  },
});

const users = userBuilder.many(20); // Creates an array of 20 users.

If you want to pass in any build time configuration, you can pass in a second argument which takes the exact same configuration as calling userBuilder() directly:

const userBuilder = build({
  fields: {
    name: 'jack',
  },
});

const users = userBuilder.many(20, {
  overrides: {
    name: 'bob'
  }
}); // Creates an array of 20 users, each called "bob"!

Mapping over all the created objects with postBuild

If you need to transform an object in a way that test-data-bot doesn't support out the box, you can pass a postBuild function when creating a builder. This builder will run every time you create an object from it.

const { build, fake } = require('@jackfranklin/test-data-bot');

const userBuilder = build({
  fields: {
    name: fake(f => f.name.findName()),
  },
  postBuild: user => {
    user.name = user.name.toUpperCase();
    return user;
  },
});

const user = userBuilder.one();
// user.name will be uppercase

Traits (new in v1.3)

Traits let you define a set of overrides for a factory that can easily be re-applied. Let's imagine you've got a users factory where users can be admins:

interface User {
  name: string;
  admin: boolean;
}

const userBuilder = build<User>({
  fields: {
    name: 'jack',
    admin: false,
  },
  traits: {
    admin: {
      overrides: { admin: true },
    },
  },
});

Notice that we've defined the admin trait here. You don't need to do this; you could easily override the admin field each time:

const adminUser = userBuilder.one({ overrides: { admin: true } });

But imagine that the field changes, or the way you represent admins changes. Or imagine setting an admin is not just one field but a few fields that need to change. Maybe an admin's email address always has to be a certain domain. We can define that behaviour once as a trait:

const userBuilder = build<User>({
  fields: {
    name: 'jack',
    admin: false,
  },
  traits: {
    admin: {
      overrides: { admin: true },
    },
  },
});

And now building an admin user is easy:

const admin = userBuilder.one({ traits: 'admin' });

You can define and use multiple traits when building an object. Be aware that if two traits override the same value, the one passed in last wins:

// any properties defined in other-trait will override any that admin sets
const admin = userBuilder.one({ traits: ['admin', 'other-trait'] });

TypeScript support

test-data-bot is written in TypeScript and ships with the types generated so if you're using TypeScript you will get some nice type support out the box.

The builders are generic, so you can describe to test-data-bot exactly what object you're creating:

interface User {
  id: number;
  name: string;
}

const userBuilder = build<User>('User', {
  fields: {
    id: sequence(),
    name: perBuild(() => yourCustomFakerLibary().name)
  },
});

const users = userBuilder.one();

You should get TypeScript errors if the builder doesn't satisfy the interface you've given it.

What happened to Faker / the fake generator?

Prior to v2.0.0 of this library, we shipped built-in support for using Faker.js to generate data. It was removed because it was a big dependency to ship to all users, even those who don't use faker. If you want to use it you can, in combination with the perBuild builder:

import {build, perBuild} from '@jackfranklin/test-data-bot';

// This can be any fake data library you like.
import fake from 'faker';

const userBuilder = build({
  // Within perBuild, call your faker library directly.
  name: perBuild(() => fake().name())
})

More Repositories

1

gulp-load-plugins

Automatically load in gulp plugins
JavaScript
756
star
2

dotfiles

My dotfiles for my dev environment, compromising of tmux, vim, zsh and git.
Lua
235
star
3

jQuery-Form-Validator

Got bored of using other ones, so made my own
JavaScript
233
star
4

pulldown

The minimal JavaScript package manager.
JavaScript
175
star
5

demopack

A prepackaged Webpack for easy frontend demos.
JavaScript
172
star
6

remote-data-js

Dealing with remote data and all its states properly in JavaScript applications.
JavaScript
149
star
7

universal-react-example

An example Universal ReactJS application
JavaScript
144
star
8

the-refactoring-tales

HTML
138
star
9

tilvim

TIL Vim: Short posts on Vim tips and tricks
HTML
89
star
10

tweet-parser

Parsing tweets into lists of entities.
JavaScript
76
star
11

react-css-modules-webpack

React + Webpack Dev Server + Hot Reloading + CSS Modules
JavaScript
72
star
12

jspm-es6-react-example

JavaScript
69
star
13

fetch-factory

Easy JS objects for talking to your APIs
JavaScript
67
star
14

jspm-dev-builder

Incremental development builds with jspm
JavaScript
66
star
15

elmplayground

An Elm blog, written in Elm, about Elm.
Elm
63
star
16

react-remote-data

JavaScript
57
star
17

so-fetch

TypeScript
57
star
18

html-dist

A tool for editing HTML files to add new scripts
JavaScript
47
star
19

javascriptplayground.com

HTML
39
star
20

react-hot-load-webpack-boilerplate

JavaScript
37
star
21

doccy

Generate Markdown documentation from JavaScript
JavaScript
31
star
22

elm-for-js-developers-talk

Elm
30
star
23

vue2-demo-proj

JavaScript
28
star
24

react-training-workshop

Code, notes and more for a day long React workshop.
JavaScript
27
star
25

todo-react-testing

A silly small React TODO app used in a blog post about testing React apps.
JavaScript
25
star
26

rollup-plugin-markdown

JavaScript
23
star
27

react-no-webpack-required

Using React without Babel & Webpack
JavaScript
22
star
28

do-you-even-elm

How much Elm do you do?
Elm
21
star
29

node-todo

A Node.js & Express.js todo app
JavaScript
19
star
30

vscode-go-to-file

TypeScript
18
star
31

svg-to-elm

TypeScript
17
star
32

Forrst-API-jQuery-Wrapper

A jQuery wrapper for the Forrst API. As the Forrst API grows, so will this.
JavaScript
17
star
33

elm-boilerplate

Starting point for Elm-Lang projects
JavaScript
17
star
34

interactive-es6

Learn ES6 in your browser in an app built in ES6.
JavaScript
16
star
35

responsiveImages

Responsive Images in JavaScript!
CoffeeScript
16
star
36

jspm-es6-example

JavaScript
16
star
37

doubler

Simple doubles for JS testing
JavaScript
14
star
38

react-ast-viewer

An Abstract Syntax Tree browser, written in React
JavaScript
14
star
39

pure-react-forms

JavaScript
14
star
40

JavaScript-Playground--Simple-jQuery-PubSub

Code for the blog post on JavaScriptPlayground.com on a simple jQuery PubSub
JavaScript
13
star
41

cannon-blog

A ReactJS blogging engine
JavaScript
13
star
42

jspm-es6-angular-example

JavaScript
13
star
43

totesy

My own TODO app
JavaScript
12
star
44

elm-game-of-life

Building Conway's Game of Life in Elm
Elm
12
star
45

JS-Regex

Live JS Regular Expression Testing
JavaScript
12
star
46

prettier-scripts

Some shell scripts for Prettier.
JavaScript
12
star
47

github-proxy

GitHub API but cached and offline-able.
JavaScript
11
star
48

authoring-es6-module-example

JavaScript
10
star
49

node_cli_router

A router for parsing command line flags and arguments in your Node CLI scripts.
JavaScript
9
star
50

wouldlike.js

JavaScript
8
star
51

client-webpack-boilerplate

A teeny client side JS webpack boilerplate to get up and running quickly.
JavaScript
8
star
52

react-fundamentals-2019-workshop

JavaScript
7
star
53

skillswap

Share your skills with others and find people to help you learn new things.
JavaScript
7
star
54

half-stack-webpack

JavaScript
7
star
55

zip-list

TypeScript
7
star
56

testing-react-with-jest

JavaScript
7
star
57

react-introduction-exercises

JavaScript
7
star
58

universal-react-talk

JavaScript
7
star
59

jQuery-UK-2012-Conference-Notes

6
star
60

elm-github-info

Fetching info from GitHub using Elm
Elm
6
star
61

ST2-MDN-Search

Search the MDN from within Sublime Text 2
Python
6
star
62

ng2-jspm-typescript

JavaScript
6
star
63

vim-markdown-writer

Some Vim functions to make writing blog posts in Markdown easier.
Vim Script
6
star
64

introduction-to-elm-workshop

Elm
5
star
65

elm-statey

A state machine library in Elm
Elm
5
star
66

elm-json-decoding

Elm
5
star
67

rollup-plugin-import-glob

JavaScript
5
star
68

advent-of-code-2018

Elm
5
star
69

angular-router-browserify

Angular's router module to be used with browserify.
JavaScript
4
star
70

project_templater

A gem for quickly creating project structures.
Ruby
4
star
71

githubissuebrowser

Browse all issues across your repositories to find something to work on.
Ruby
4
star
72

ecmascript-evaluator

JavaScript
4
star
73

JS-Instagram-Wrapper

JavaScript
4
star
74

HTML5-Placeholder-PolyFill

Adds placeholder functionality to input fields in browsers that don't support HTML5 Placeholders
JavaScript
4
star
75

london-elm-018-talk

JavaScript
4
star
76

jspm-test

Browser test runner for jspm projects
JavaScript
4
star
77

elm-console-log

An easier log function for Elm.
Elm
4
star
78

react-webpack-boilerplate

JavaScript
4
star
79

testing-javascript-workshop

JavaScript
3
star
80

elm-connect-four

Connect 4 written in Elm
Elm
3
star
81

jQuote

3
star
82

epic-fel-es6-today-links

3
star
83

devcastin

Ruby
3
star
84

beginning-react

HTML
3
star
85

jack-sublime-snippets

3
star
86

jQuery-Split-List

Splits lists in half
JavaScript
3
star
87

Base-Template

A starting point for all my development.
JavaScript
3
star
88

reactjs-workshop

Code and notes for a ReactJS workshop
JavaScript
3
star
89

Deck.js---Gamepad-API

Deck.js slideshows controlled with the Gamepad API
JavaScript
3
star
90

jsFrame

Combining a jQuery Plugin with a CSS Grid for lovely coding.
JavaScript
3
star
91

MarkdownTwitter

Automatically linking Twitter mentions in Markdown blog posts
Ruby
2
star
92

jackfranklindotcodotuk

JavaScript
2
star
93

frontendlondonfeb2015-jspm-demo

JavaScript
2
star
94

CoffeePubSub

A very small Pub/Sub implementation in CoffeeScript
CoffeeScript
2
star
95

Back-to-Top-Firefox-Plugin

An easy way to get back to the top of any webpage in Firefox.
JavaScript
2
star
96

util-fns

JavaScript
2
star
97

interactive-react

JavaScript
2
star
98

rash

Ruby hash methods in JavaScript
JavaScript
2
star
99

Big-M-Workshop-Notes

2
star
100

langtons-ant-elm

It's an ant innit.
Elm
2
star