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?
- is there way access scope of
widget.js
, or @ least replace imports own code? - 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
Post a Comment