javascript - How to mock the imports of an ES6 module? -


i have following es6 modules:

network.js

export function getdatafromserver() {   return ... } 

widget.js

import { getdatafromserver } 'network.js';  export class widget() {   constructor() {     getdatafromserver("dataforwidget")     .then(data => this.render(data));   }    render() {     ...   } } 

i'm looking way test widget mock instance of getdatafromserver. if used separate <script>s instead of es6 modules, in karma, write test like:

describe("widget", function() {   it("should stuff", function() {     let getdatafromserver = spyon(window, "getdatafromserver").andreturn("mockdata")     let widget = new widget();     expect(getdatafromserver).tohavebeencalledwith("dataforwidget");     expect(otherstuff).tohavehappened();   }); }); 

however, if i'm testing es6 modules individually outside of browser (like mocha + babel), write like:

import { widget } 'widget.js';  describe("widget", function() {   it("should stuff", function() {     let getdatafromserver = spyon(?????) // how mock?     .andreturn("mockdata")     let widget = new widget();     expect(getdatafromserver).tohavebeencalledwith("dataforwidget");     expect(otherstuff).tohavehappened();   }); }); 

okay, getdatafromserver not available in window (well, there's no window @ all), , don't know way inject stuff directly widget.js's own scope.

so go here?

  1. is there way access scope of widget.js, or @ least replace imports own code?
  2. if not, how can make widget testable?

stuff considered:

a. manual dependency injection.

remove imports widget.js , expect caller provide deps.

export class widget() {   constructor(deps) {     deps.getdatafromserver("dataforwidget")     .then(data => this.render(data));   } } 

i'm uncomfortable messing widget's public interface , exposing implementation details. no go.


b. expose imports allow mocking them.

something like:

import { getdatafromserver } 'network.js';  export let deps = {   getdatafromserver };  export class widget() {   constructor() {     deps.getdatafromserver("dataforwidget")     .then(data => this.render(data));   } } 

then:

import { widget, deps } 'widget.js';  describe("widget", function() {   it("should stuff", function() {     let getdatafromserver = spyon(deps.getdatafromserver)  // !       .andreturn("mockdata");     let widget = new widget();     expect(getdatafromserver).tohavebeencalledwith("dataforwidget");     expect(otherstuff).tohavehappened();   }); }); 

this less invasive requires me write lot of boilerplate each module, , there's still risk of me using getdatafromserver instead of deps.getdatafromserver time. i'm uneasy it, that's best idea far.

i've started employing import * obj style within tests, imports exports module properties of object can mocked. find lot cleaner using rewire or proxyquire or similar technique. i've done when needing mock redux actions, example. here's might use example above:

import * network 'network.js';  describe("widget", function() {   it("should stuff", function() {     let getdatafromserver = spyon(network, "getdatafromserver").andreturn("mockdata")     let widget = new widget();     expect(getdatafromserver).tohavebeencalledwith("dataforwidget");     expect(otherstuff).tohavehappened();   }); }); 

if function happens default export, import * network './network' produce {default: getdatafromserver} , can mock network.default.


Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -