Manufactory is lightweight JavaScript library for building JavaScript objects for test data.
Install via npm as a development dependency:
$ npm install manufactory --save-dev
While Manufactory doesn't enforce a strict directory structure nor expects
specific naming, we recommend to define your factories in a test/factories
directory. Each factory should match the name of the object that you are
building. For example, if the given factory represents the Post model, we
recommend to define it in test/factories/Post.factory.js.
// test/factories/Post.factory.js
import Factory from 'manufactory';
export default Factory()
.setName('Post')
.attr('title', 'Awesome Post')
.attr('slug', (i) => `awesome-post-${i}`)
.attr('name.first', 'John')
.attr('name.last', 'Doe');
import PostFactory from 'test/factories/Post.factory.js';
// defaults
const post1 = PostFactory();
post1.title // => 'Awesome Post'
post1.name.first // => 'John'
post1.name.last // => 'Doe'
post1.slug // => 'awesome-post-1'
// overriding defaults
const post2 = PostFactory({ title: 'Other title' });
post2.title // => 'Other title'
post2.name.first // => 'John'
post2.name.last // => 'Doe'
post2.slug // => 'awesome-post-2'
Static values:
const PostFactory = Factory()
.attr('title', 'Awesome Post');
PostFactory().title // => 'Awesome Post'
Dynamic values (aka lazy values):
const PostFactory = Factory()
.attr('title', function() {
return 'Awesome Post';
});
PostFactory().title // => 'Awesome Post'
Sequences:
const PostFactory = Factory()
.attr('title', function(i) {
return `Awesome Post ${i}`;
});
PostFactory().title // => 'Awesome Post 1'
PostFactory().title // => 'Awesome Post 2'
Nested objects:
const PostFactory = Factory()
.setName('Post')
.attr('name.first', 'John')
.attr('name.last', 'Doe');
PostFactory().name.first // => 'John'
PostFactory().name.last // => 'Doe'
For more details - visit the pathval project.
Type conversion:
const PostFactory = Factory()
.attr('number', '1', Number)
PostFactory().number // => 1
You can mixin other factories in order to share
builders, attributes and middlewares. Imagine that you have
different types of post. You can define a Base factory
and mix it into its variations:
const SlugFactory = Factory()
.attr('slug', (i) => `slug-${i}`);
const BasePostFactory = Factory()
.attr('title', 'Title');
const PublishedPost = Factory()
.mixin(BasePostFactory)
.mixin(SlugFactory)
.attr('state', 'published');
const TrashedPost = Factory()
.mixin(BasePostFactory)
.mixin(SlugFactory)
.attr('state', 'trashed');
const publishedPost = PublishedPost();
publishedPost.title // => 'Title'
publishedPost.slug // => 'slug-1'
publishedPost.state // => 'published'
const trashedPost = TrashedPost();
trashedPost.title // => 'Title'
trashedPost.slug // => 'slug-2'
trashedPost.state // => 'trashed'
The builder is a function that will be invoked with all
compiled attributes, the name of the factory and the root name.
Each factory can have its own builder. The default builder is Object.
With Builders you can easily modify your factories to be persisted
into a database or cast them to whatever your system expects.
import Immutable from 'immutable';
const PostFactory = Factory()
.setBuilder(Immutable.Map)
.attr('title', 'Awesome Post');
PostFactory().get('title') // => 'Awesome Post'
PostFactory() instanceof Immutable.Map // => true
const DBBuilder = (attrs, name, rootName) => {
// pseudo code
return getModel(name).create(attrs); // returns a Promise
};
const PostFactory = Factory()
.setBuilder(DBBuilder)
.attr('title', 'Awesome Post');
PostFactory().then((factory) => {
// the `factory` is now persisted in the db
});
Middlewares are functions that receive the compiled attributes and can modify them as they wish. It's a great way to share functionality across different projects.
const middleware = (attrs) => {
attrs.title = `Super ${attrs.title}`;
return attrs;
};
const PostFactory = Factory()
.use(middleware)
.attr('title', 'Awesome Post');
PostFactory().title // => 'Super Awesome Post'
Each factory can have its own name. Setting a name is optional and can be useful in situations where you have to specify the name of the object that you are building, so it can be used in the builder later:
const PostFactory = Factory()
.setName('Post')
$ npm install
$ npm test
$ npm run coverage
$ npm run lint
MIT (Product Hunt Inc.)