An automatic mock data generator for mongoose using schema definition.
npm install fakingoose
const {
factory
} = require('fakingoose');
const entityFactory = factory(model, options);
- model <Schema> or <Model>: Mongoose model or schema.
- options <? Object>: Generation options are optional. The factory would generate data for all fields based on the schema alone. For cases where there is a need for custom values, options can be used to define custom values or data generation setting per field.
- options.<propertyName>.value <mixed>: A static value for each generated mock object.
- options.<propertyName>.value: <function> a function for generating a dynamic value per item. This function receives the mock object as first argument.
- options.<propertyName>.skip <boolean>: When set to
true
would skip the field. - options.<propertyName>.type <string>: The sub-type for this field type. For example <String> schema type supports
email
,firsname
andlastname
. options.\<propertyName\>.populateWithSchema
: Uses a schema to generate mocks of related modelsoptions.\<propertyName\>.populateWithFactory
: Uses another factory to generate mocks of related models. This options provides more flexibility thanpopulateWithSchema
, taking advantage of custom behaviours of factory via Factory options.options.\<propertyName\>.size
<int>: (Array values only) When specified, will ensure that said array field has given number of elements. By default, this is set to 2.
const mongoose = require('mongoose');
const {
factory
} = require('fakingoose');
const {
Schema
} = mongoose;
const authorSchema = new Schema({
id: Schema.Types.ObjectId,
title: {
type: String,
enum: ['Mr', 'Mrs', 'Dr']
},
fullname: String,
username: String,
email: String,
favoriteQuote: String,
});
const blogSchema = new Schema({
title: String,
author: authorSchema,
body: String,
comments: [{
body: String,
date: Date
}],
date: {
type: Date,
default: Date.now
},
hidden: Boolean,
meta: {
votes: {
type: Number,
min: 0
},
favs: {
type: Number,
min: 0
}
}
});
const options = {
author: {
email: {
type: 'email',
},
username: {
value: (object) => {
return object.fullname.toLowerCase().replace(/\s/g, '.');
}
},
favoriteQuote: {
skip: true
}
},
};
const blogFactory = factory(blogSchema, options);
const mock = blogFactory.generate({
author: {
fullname: 'John Doe'
}
});
sample output
{
"title":"8tnkcjplr",
"author":{
"id":"5d513f762a48134adb1868d7",
"title":"Dr",
"fullname":"John Doe",
"username":"john.doe",
"email":"re@sisuki.mc",
"_id":"5d513f762a48134adb1868d8"
},
"body":"ebjwad6*keskl",
"comments":[
{
"body":"d$*t9y3",
"date":"2019-08-12T10:29:10.193Z",
"_id":"5d513f762a48134adb1868d9"
},
{
"body":"jv5o[",
"date":"2019-08-12T10:29:10.193Z",
"_id":"5d513f762a48134adb1868da"
}
],
"hidden":false,
"meta":{"votes":-3419053502758912,"favs":3323094479405056},
"_id":"5d513f762a48134adb1868db"
}
To define options for nested a property use the nested property path (property names sperated by a dot). Example:
const options = {
"meta.votes": {
value: 0
}, // set value for 'votes' property under meta
"meta.favs": {
skip: true
} // skip value for 'favs' property under meta
}
Multiple nested properties can be skipped from parent property. Example:
const accountSchema = new mongoose.Schema({
user: {
generalInfo: {
firstName: String,
lastName: String,
age: Number
},
address: {
postCode: String,
street: String
}
}
});
const accountFactory = factory(accountSchema, options);
To generate mocks without an address define options as below you have to override the default factory's options:
const options = {
'user.address': {
skip: true
}
}
or
const options = {
user: {
address: {
skip: true
}
}
}
then
const mockObject = accountFactory.generate({}, options);
When generating ObjectId values, you can choose to Stringify the generated ObjectId by using the tostring
option. By default this options is true
, so all generated ObjectIds would be converted to a String. Set tostring
to false to disable this behaviour.
Example: In the snippet below all ObjectIds generated are not stringified.
const friendSchema = new Schema({
id: Schema.Types.ObjectId,
friendIds: [{
type: Schema.Types.ObjectId
}],
bestFriend: {
id: Schema.Types.ObjectId
}
});
const amigoFactory = factory(friendSchema, {
id: {
tostring: false
},
friendIds: {
tostring: false
},
'bestFriend.id': {
tostring: false
}
});
To disable stringification globally use factory.setGlobalObjectIdOptions
.
Example:
const friendSchema = new Schema({
id: Schema.Types.ObjectId,
friendIds: [{
type: Schema.Types.ObjectId
}],
bestFriend: {
id: Schema.Types.ObjectId
}
});
const amigoFactory = factory(friendSchema).setGlobalObjectIdOptions({
tostring: false
});
Generating mocks for related models (Populate)
Mongoose provides an API for automatically replacing the specified paths in the document with document(s) from other collection(s). This package provides a similar functionality when generating mocks.
An example: In the snippet below we have two schemas, activitySchema
& personSchema
.
const activitySchema = new mongoose.Schema({
name: String,
value: String,
});
const personSchema = new mongoose.Schema({
email: String,
name: {
type: String,
},
activities: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'activity'
}],
});
When generating mock data from the personSchema
we should get the sample below
{
email: 'l7@eiwtef%(pzitx',
name: 'ym](ht7ucas*',
activities: ['60f1e810a8b8ac392c3869b7', '60f1e810a8b8ac392c3869b8'],
_id: '60f1e810a8b8ac392c3869b9'
}
In some cases we might want to receive activity data instead of activity ID in the activities
property, so we have a structure like below.
{
email: ')5b2[dj@@)p91(',
name: 'qo[jk!',
activities: [{
name: '7^*8h^@!zp^!*hqwn',
value: ']55f$hmva',
_id: '60f1e51dead56f35c7ed4f62'
},
{
name: 'r!cv!k!p#vqfqt4a9k',
value: '$@6k!z&oflj6',
_id: '60f1e51dead56f35c7ed4f63'
}
],
_id: '60f1e51dead56f35c7ed4f64'
}
Let's look at two seperate ways we can achieve this:
-
options.\<propertyName\>.populateWithSchema
: Uses a schema to generate mocks of related models. -
options.\<propertyName\>.populateWithFactory
: Uses another factory to generate mocks of related models. This options provides more flexibility thanpopulateWithSchema
, taking advantage of custom behaviors of factory via Factory options.
const activityFactory = mocker(activitySchema)
const personFactory = mocker(personSchema, {
activities: {
populateWithFactory: activityFactory
}
})
const mock = personFactory.generate()
const myFactory = mocker(schema, {
activities: {
populateWithSchema: activitySchema
}
})
const mock = myFactory.generate()
Generating decimal (Decimal128) values
When generating decimal values, you can choose to Stringify the generated number by using the tostring
option. By default this options is true
, so all generated numbers would be converted to a String. Set tostring
to false to disable this behaviour.
Example: In the snippet below all numbers generated are not stringified.
const productSchema = new Schema({
price: Schema.Types.Decimal128
});
const productFactory = factory(productSchema, {
price: {
tostring: false
}
});
When generating array values, you can specify a size
parameter to ensure the array field has that many elements. By default, this is set to 2.
Example: Each new user will now have 10 new statuses to start.
const userSchema = new mongoose.Schema({
email: String,
name: {
type: String,
},
activities: [{
type: String,
}],
});
const userFactory = factory(userSchema, {
activities: {
size: 10
}
});
To disable stringification globally use factory.setGlobalDecimal128Options
.
Example:
const productSchema = new Schema({
price: Schema.Types.Decimal128
});
const productFactory = factory(productSchema).setGlobalDecimal128Options({
tostring: false
});
I some cases we want to override options that we used to initialise a factory. These options can be overridden in the generate()
method of the factory.
const schema = new Schema({
updated: {
type: Date,
default: Date.now
},
title: String,
content: String,
});
const options = {
updated: {
skip: true
}
};
const myFactory = mocker(schema, options);
const mockWithoutUpdated = myFactory.generate({}); // here use options used to initilize the factory. We skip the "updated: field
const mockWithoutTitle = myFactory.generate({}, { // here use custom options. We skip the "title: field
title: {
skip: true
}
});
- String
- Array
- Number
- Decimal128
- ObjectId
- Boolean
- Mixed
- Buffer
- Embedded
- Date
- Map
Version | Supported |
---|---|
7.x | ✅ |
6.x | ✅ |
5.x | ✅ |
4.x | ✅ |