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.
npm install create-dataset --save-dev
For instance, to create a company, a user and a profile, one would simply write:
var createDataset = require('create-dataset');
// See next section
require('./create-configuration');
// We define our dataset here
var rawDataset = {
// Leave an empty object, to inherit all default values from some factory
company: {},
// Create a user,
user1: {
// We can also override properties from the default values in the factory
name: "Some name",
// For the company, we'll use the id from the company we just created
company: createDataset.defer("company")
},
// Create another user with default values (and in another company)
user2: {
},
profile: {
user: createDataset.defer("user")
}
};
createDataset(rawDataset, function(err, dataset) {
// At this point, we're all set, one can do
console.log(dataset.user.id);
dataset.company.save();
// etc.
});
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)
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 = {
// Will be matched with 'company' config
startup: {
_model: 'company'
},
// !! Will be matched with `user`, as `user` is defined before `profile` in createDataset.config
userProfile: {
}
}
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); // "lol"
console.log(dataset.company); // [object Object]
});
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));
// which is equivalent to...
before(function(done) {
createDataset(rawDataset, dataset, done);
});
If you need a value that is not known at build time (e.g. the id of an object previously generated), you can specify a function instead of a value. This function takes as parameter the current dataset
(with all previous dependencies already satisfied), for instance:
// We define our dataset here
var rawDataset = {
// Leave an empty object, to inherit all default values from some factory
company: {},
// Create a user,
user1: {
// We can also override properties from the default values in the factory
name: "Some name",
// For the company, we'll use the id from the company we just created
company: function(dataset) {
return company.id;
}
},
};
An helper function createDataset.defer(key)
is provided. It simply returns dataset[key]
.