Manufactory
Manufactory is lightweight JavaScript library for building JavaScript objects for test data.
Installation
Install via npm as a development dependency:
$ npm install manufactory --save-dev
Getting Started
Defining factories
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');
Using factories
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'
Defining Attributes
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
Mixins
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'
Builder
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 Builder
s 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
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'
Factory name
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')
Development
$ npm install
Tests
$ npm test
Test coverage
$ npm run coverage
Linters
$ npm run lint
License
MIT (Product Hunt Inc.)