faker
and factory-girl
Say you have defined a mock for your user object:
// user.mock.js
function UserMock() {
this.name = 'john doe';
this.role = 'admin';
}
In order to use it in your unit tests, you would normally inject it as a factory on a mock module:
// user.mock.js
...
angular.module('mocks')
.factory('UserMock', UserMock);
// user.spec.js
...
var UserMock;
beforeEach(module('mocks'));
beforeEach(inject(function(_UserMock_) {
UserMock = _UserMock_;
});
Using the mock in Jasmine
In case you don't understand how to share resources in Angular tests by using dependency injection, here is a short explanation:
angular.module
)ngMock
's global module
function (which is short for angular.mock.module
)Using the same mock in a Protractor test is much easier, but different.
Since Protractor tests run with Node.js and not in the browser, you have to define and use the mock as a Node module:
// user.mock.js
...
module.exports = UserMock;
// login.scenario.js
var UserMock = require('../mocks/user.mock.js');
...
Using the mock in Protractor
Much simpler. Wouldn't it be nice if we could use the same method for unit tests?
Using karma-browserify, we can define and use our mock using the node syntax both in our unit and Protractor tests.
First, install the plugin:
> npm install karma-browserify --save-dev
Change your karma.conf.js
as follows:
frameworks: ['jasmine', 'browserify'],
preprocessors: {
'{specs,mocks}/**/**.browserify.js': ['browserify']
},
browserify: {
debug: true
}
Then apply .browserify.js
suffix to specs and mocks that use module.exports
and require
statements. The reason we do this is so that we precompile only these specs using browserify and not all specs and mocks.
Note: change the {specs, mock}
to wherever your test files reside
The debug
flag will help us debug the tests using source maps.
Now you can use the mock in your unit tests the same way you used it in Protractor:
// user.mock.browserify.js
...
module.exports = UserMock;
// user.spec.browserify.js
UserMock = require('../mocks/user.mock.js');
...
Using the mock the same way
You can now easily use whatever transformers and plugins that Browserify supports. For example, for writing your tests using ES6 (including ES6 module system):
> npm install --save-dev babelify
// karma.conf.js
browserify: {
transform: ['babelify']
}
And then use ES6 inside your mocks / tests:
// user.mock.js
class UserMock {
...
}
export default UserMock;
// user.spec.js
import UserMock from '../mocks/user.mock.js';
There are Node modules that are very helpful for tests & mocks, such as faker. Using them in unit tests is easy, now that we have configured Browserify:
// user.mock.js
var faker = require('faker');
class UserMock() {
constructor() {
this.first_name = faker.name.firstName();
this.role = 'admin';
}
}
Requiring Node modules from inside a test
Browserify is agnostic to the module system you're using. You can use Node's module.exports
with ES6's import
, and vice versa — use ES6's export
with Node's require
:
// these work together:
module.exports = UserMock;
import UserMock from '../mocks/user.mock.js';
// And so do these:
export default UserMock;
var UserMock = require('../mocks/user.mock.js');
// It even works with node modules:
import faker from 'faker';
Browserify is agnostic to the module system
Happy testing :)