¿Cómo burlarse de las importaciones de un módulo ES6?

Tengo los siguientes 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() {
    ...
  }
}

Estoy buscando una manera de probar Widget con una instancia simulada degetDataFromServer. Si usara por separado<script>s en lugar de módulos ES6, como en Karma, podría escribir mi prueba 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();
  });
});

Sin embargo, si estoy probando módulos ES6 individualmente fuera de un navegador (como con Mocha + babel), escribiría 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 pero ahoragetDataFromServer no está disponible enwindow (bueno, no haywindow en absoluto), y no sé cómo inyectar cosas directamente enwidget.jspropio alcance.

Entonces, ¿a dónde voy desde aquí?¿Hay alguna manera de acceder al alcance dewidget.js, o al menos reemplazar sus importaciones con mi propio código?Si no, ¿cómo puedo hacerWidget comprobable?Cosas que consideré:a. Inyección manual de dependencias.

Eliminar todas las importaciones dewidget.js y esperar que la persona que llama proporcione los departamentos.

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

Me incomoda mucho estropear la interfaz pública de Widget como esta y exponer los detalles de implementación. No vayas.

si. Exponer las importaciones para permitir burlarse de ellos.

Algo como:

import { getDataFromServer } from 'network.js';

export let deps = {
  getDataFromServer
};

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

entonces:

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();
  });
});

Esto es menos invasivo pero requiere que escriba una gran cantidad de repeticiones para cada módulo, y todavía existe el riesgo de que usegetDataFromServer en lugar dedeps.getDataFromServer todo el tiempo. Estoy inquieto al respecto, pero esa es mi mejor idea hasta ahora.

Respuestas a la pregunta(5)

Su respuesta a la pregunta