Skip to content

Jest from Facebook: Automagical mocking for tests if you’re into that sort of thing

Recently, I messed with Jest, a new testing tool from Facebook’s open source machine to see what’s up about it (thanks for the poke, Linda!)

Unfortunately their “getting started” has more in common with my favorite “how programming textbooks are” comic than I’d like, as the getting started example simply shows how to write a unit test and nothing about how Jest is a special unicorn and why it’s useful.

Jest is a layer on top of Jasmine that Facebook uses in their projects, notably for the testing of React applications. The layer itself is really thin, but it does provide automatic mocking, ‘finds tests’ (because you conveniently put them in the __tests__ folder), and also some mocks for time that could come in handy, but I suspect other mocking libraries have other options.

I made a very simple project to explore automatic mocking, the chief magic point of Jest. It takes that simple sum.js example of a unit test, adds a dependency, and writes a few tests to see how that all shakes out.

Given a module with a dependency:

var thing = require('./thing.js');
function sum(x, y) {
  thing();
  return x + y;
}

module.exports = sum;

And a basic test:

describe('sum', function() {
  it('adds numbers', function() {
    var sum = require('../sum.js');
    var thing = require ('../thing.js');
    expect(sum(1, 2)).toBe(3);
  });
});

That test will fail with Jest out of the box. Why? Jest hooks onto the require() call and automatically mocks it into a simple empty function (foo() {}), unless you turn off automatic mocking. For this test, we want to explicitly prevent Jest from mocking the sum library:

jest.dontMock('../sum.js');
describe('sum', function() {
  it('adds numbers', function() {
    var sum = require('../sum.js');
    var thing = require ('../thing.js');
    expect(sum(1, 2)).toBe(3);
  });
});

All green. If I write a test to see if thing is mocked:

it('mocks thing', function() {
  var thing = require('../thing.js');
  expect(thing()).toBe(undefined);
});

That passes. However, just to note, setting mocking/non-mocking status appears to be global in a file. That makes sense modularly, because you generally wouldn’t mock an external file and test it in the same file.

it('does not mock it when I ask nicely', function() {
  jest.dontMock('../thing.js');
  var thing = require('../thing.js');
  expect(thing()).toBe(2);
});

it('mocks it only in the scope of the argument (this fails)', function() {
  var thing = require('../thing.js');
  expect(thing()).toBe(undefined);
});

If you want to check out the sample project yourself, and mess with the automagical mocking, it’s over here. The reasoning behind Jest’s raison d’etre is pretty well covered in their piece on CommonJS at the moment, where they generally state their preference for a require system over an Angular-style dependency injection.

Overall, I’m not very impressed, it’s nothing special compared to running Jasmine + your favorite flavor of test runner (… Karma?), and auto-magic mocking was never something I’ve desperately needed (aside from the fact that the “mocks” are really not so much mocks than glorified stubs, as they don’t have an expected behavior … but that’s for another time). Seems like a case of open sourcing something useful for their workflow, so glad to see it shared, but I don’t see it useful in an everyday context.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.