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 forma de probar Widget con una instancia simulada de getDataFromServer
. Si usara <script>
s separados 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();
});
});
Está bien, pero ahora getDataFromServer
no está disponible en window
(bueno, no hay ninguno window
), y no sé cómo inyectar cosas directamente en widget.js
el ámbito de aplicación.
Entonces, ¿a dónde voy desde aquí?
- ¿Hay alguna manera de acceder al alcance de
widget.js
, o al menos reemplazar sus importaciones con mi propio código? - Si no, ¿cómo puedo hacer
Widget
comprobable?
Cosas que consideré:
a. Inyección manual de dependencias.
Elimine todas las importaciones widget.js
y espere 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));
}
}
luego:
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 mucho repetitivo para cada módulo, y todavía existe el riesgo de que lo use en getDataFromServer
lugar de deps.getDataFromServer
todo el tiempo. Estoy inquieto al respecto, pero esa es mi mejor idea hasta ahora.
createSpy
( github.com/jasmine/jasmine/blob/… ) con una referencia importada a getDataFromServer del módulo 'network.js'. De modo que, en el archivo de pruebas del widget, importaría getDataFromServer y luego lo haríalet spy = createSpy('getDataFromServer', getDataFromServer)
spyOn
en ese objeto, importado denetwork.js
módulo. Siempre es una referencia al mismo objeto.
Widget
la interfaz pública? Widget
está en mal estado sin deps
. ¿Por qué no hacer explícita la dependencia?