Create dataset
When writing tests with Node, we often need to create complex objects interdependencies.
Some patterns helps : factories, fixtures... but at the end of the day we still need to spend time managing our dependencies.
This library tries to bring the best of both world: a simple JS object to define the structure, and nothing more. It is framework agnostic and will work for Mongo or SQL objects.
Installation
npm install create-dataset --save-dev
Example use
For instance, to create a company, a user and a profile, one would simply write:
var createDataset = require('create-dataset');
require('./create-configuration');
var rawDataset = {
company: {},
user1: {
name: "Some name",
company: createDataset.defer("company")
},
user2: {
},
profile: {
user: createDataset.defer("user")
}
};
createDataset(rawDataset, function(err, dataset) {
console.log(dataset.user.id);
dataset.company.save();
});
Configuration
Before using this, we need to set the config for objects creation.
You only need to call this once.
var createDataset = require('create-dataset');
createDataset.config = {
company: {
generator: function(data, cb) {
cb(null, CompanyFactory.create(data));
}
},
user: {
dependencies: ['company'],
generator: function(data, cb) {
cb(null, UserFactory.create(data));
}
},
profile: {
dependencies: ['user'],
generator: function(data, cb) {
cb(null, ProfileFactory.create(data));
}
}
};
There is only one mandatory key, generator
, which must indicate how to create an instance from raw data. This can be a call to your factory builder, your ORM or your own custom function. It must return a new item (or an error following node convention).
Other keys:
dependencies
, an array of models to build before building this object. When unspecified, no dependencies are implied. Be careful not to introduce deadlocks here (A needs B and B needs A)
How does it works? And potential caveats
For the sake of simplicity, the key name in your dataset is loosely matched with a model name. For instance, mainCompany
will be matched to company
.
This can be problematic when the name is ambiguous, for instance myUserCompany
. In such a case, the first key to match in your config will be used (in this case, Company
).
If this is not enough, you can add a _model
property to your dataset to force the use of a model:
var rawDataset = {
startup: {
_model: 'company'
},
userProfile: {
}
}
Advanced use
Build over seed object
When calling createDataset
, you may want to build over a pre-existing object.
You may then add a second parameter to createDataset
, specifying the "seed object" on which to build:
var dataset = {
hello: 'lol'
};
var rawDataset = {
company: {}
};
createDataset(rawDataset, dataset, function(err, dataset) {
console.log(dataset.hello);
console.log(dataset.company);
});
Wrap with apply
You may also want to wrap the whole function in a simple function(err){}
, for use with async
or Mongoose's before
. You can simply use .apply
:
var dataset = {
hello: 'lol'
};
var rawDataset = { };
before(createDataset.apply(rawDataset, dataset));
before(function(done) {
createDataset(rawDataset, dataset, done);
});