Como zombar das importações de um módulo ES6?

Eu tenho os seguintes módulos ES6:

network.js

export function getDataFromServer() {
  return ...
}

widget.js

import { getDataFromServer } from 'network.js';

export class Widget() {
  constructor() {
    getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }

  render() {
    ...
  }
}

Estou procurando uma maneira de testar o Widget com uma instância simulada degetDataFromServer. Se eu usasse separado<script>s em vez dos módulos ES6, como no Karma, eu poderia escrever meu teste como:

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(window, "getDataFromServer").andReturn("mockData")
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

No entanto, se estiver testando os módulos ES6 individualmente fora de um navegador (como no Mocha + babel), escreveria algo como:

import { Widget } from 'widget.js';

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(?????) // How to mock?
    .andReturn("mockData")
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

Ok, mas agoragetDataFromServer não está disponível emwindow (bem, não háwindow ) e não sei como injetar coisas diretamente nowidget.jspróprio escopo.

Então, para onde eu vou daqui?Existe uma maneira de acessar o escopo dewidget.js, ou pelo menos substituir suas importações por meu próprio código?Caso contrário, como posso fazerWidget testável?Coisas que eu considerei:uma. Injeção de dependência manual.

Remova todas as importações dewidget.js e espere que o chamador forneça os deps.

export class Widget() {
  constructor(deps) {
    deps.getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }
}

Fico muito desconfortável ao atrapalhar a interface pública do Widget dessa maneira e expor os detalhes da implementação. Não vá.

b. Exponha as importações para permitir zombar delas.

Algo como:

import { getDataFromServer } from 'network.js';

export let deps = {
  getDataFromServer
};

export class Widget() {
  constructor() {
    deps.getDataFromServer("dataForWidget")
    .then(data => this.render(data));
  }
}

então:

import { Widget, deps } from 'widget.js';

describe("widget", function() {
  it("should do stuff", function() {
    let getDataFromServer = spyOn(deps.getDataFromServer)  // !
      .andReturn("mockData");
    let widget = new Widget();
    expect(getDataFromServer).toHaveBeenCalledWith("dataForWidget");
    expect(otherStuff).toHaveHappened();
  });
});

Isso é menos invasivo, mas exige que eu escreva um monte de clichê para cada módulo, e ainda há o risco de eu usargetDataFromServer ao invés dedeps.getDataFromServer o tempo todo. Estou desconfortável com isso, mas essa é a minha melhor ideia até agora.

questionAnswers(5)

yourAnswerToTheQuestion