¿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.js
propio alcance.
widget.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.