visit our site

Mocking ES6 module import with and without Dependency Injection

In Development, Front End, Testing

by Sergii Boiko by January 10, 2017

ES6 module system is a great addition to JavaScript language, but sometimes it’s at odds with writing tests, because you need to mock imported function.

Usual solution is to use Dependency Injection akin to what is used in Angular.JS. You need to wrap the whole module into some function and explicitly pass required dependencies. While such approach works fine, it mangles code and adds an additional layer of indirection.

There are two alternative approaches. One is by using mocking library, which is simpler. Another one is more complex and uses Dependency Injection, but in a way, which does not cause big changes to initial code. Using mocking library works fine at the moment, because ES6 modules are transpiled into ES5 objects. But it could not work with real ES6 modules and then Dependency Injection way can be handy.

Mocking with Sinon.JS

Let’s consider feature.js module, which looks like this:

feature.js imports fetchData function from backend.js. The goal is to mock fetchData call in feature.js when writing functional tests. In our example, we will use Sinon.JS, but Jasmine can be used as well.

So, the main trick here is to import the whole module:

and stub/mock required call:

Mocking with Dependency Injection

To manually mock the function, the simplest way would be to reassign fetchData to some mock-function, but imported bindings are read-only. So, we need to make a little trick:

Now, instead of directly using fetchData from backend.js we imported it as originalFetchData. Our local variable fetchData can be reassigned to anything we want. By default it is bound to originalFetchData. To mock it we need to call mock and pass a mocked version. In case we need to unmock, just call mock with no params.

An example of usage in test:

Mocking Module

There is a slight variation of this approach, if we need to mock a set of calls from one module:

Here we import the whole module and cherry-pick required calls. The rest is the same as before, but we need to pass an object with mocked calls into mock.

* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • Hi Sergii, thanks for the article… I’d like to clarify one small thing, that is, what you call “Manual Mocking Solution” and “Mocking Module” are actually variants of Dependency Injection. Maybe you’d want to change the title of the article to “Mocking ES6 module import without IoC frameworks”?

    • Sergii Boiko

      Hi Pavel, thank you for the suggestion. I’ll update the article and the naming to be more precise.

      • okay, by the way, thank you very much for introducing me to SinonJS and using it to mocking dependencies injected via ES6 modules! I think that this approach is actually preferable for JS, because this approach takes advantage of caching module imports and as such offers a mocking strategy that’s kind of embedded in the language itself.

Signup for our weekly newsletter

Want to get more of Railsware blog?

RSS Feed

We're always ready to help!

Contact us