Tengo la clase FooStorage
que tiene una matriz de objetos Foo
como variable miembro. Al probar FooStorage
, quiero burlarme de la clase Foo
.
Como se describe en Simulacros de clase ES6 , todo lo que necesito en mi caso es un simulacro automático. Pero cuando trato de burlarme de la clase, no parece tener éxito. En cambio, cuando intento restablecer el simulacro con mockClear()
, recibo un mensaje de error.
A continuación se muestra el código y el resultado de broma:
foo.js
class Foo {}; export default Foo;
foostorage.js
import Foo from "./foo.js"; class FooStorage { constructor() { this.storage = []; // Array of Foo objects } } export default FooStorage;
foostorage.test.js
import Foo from "../src/foo.js"; import FooStorage from "../src/foostorage.js"; import { jest } from "@jest/globals"; jest.mock("../src/foo.js"); beforeEach(() => { Foo.mockClear(); }); test("if the Foo constructor hasn`t been called", () => { const storage = new FooStorage(); expect(Foo).not.toHaveBeenCalled(); });
output
if the Foo constructor hasn`t been called TypeError: Foo.mockClear is not a function 7 | 8 | beforeEach(() => { > 9 | Foo.mockClear(); | ^ 10 | }); 11 | 12 | test("if the Foo constructor hasn`t been called", () => { at Object.<anonymous> (test/foostorage.test.js:9:6)
Ya he intentado poner jest.mock("../src/foo.js");
antes import Foo from "../src/foo.js";
pero el problema no se resolvió.
Estoy usando Jest v. 27.0.6
con jest-environment-node v. 27.0.6
y @types/jest v. 27.0.1
.
También uso los argumentos de nodejs --experimental-modules
y --experimental-vm-modules
para poder usar las importaciones de ES6. No uso Babel ni nada más. Simplemente JavaScript.
Se supone que la simulación automática funciona como se explica en la documentación. Si no lo hace y da como resultado dicho error, esto significa que el módulo no fue simulado, por lo que también fallaría con la simulación manual. Esto puede suceder porque un simulacro no se realizó correctamente (diferente caso o extensión en la ruta del módulo), o porque la elevación de jest.mock
no funcionó (más comúnmente debido a una transformación de Babel mal configurada).
La forma en que este código difiere de lo que se muestra en la documentación es que jest
global se usa comúnmente, mientras que aquí es un valor importado, por lo que no es lo mismo que usar jest
global. Esta es una razón obvia y conocida para que la elevación funcione de manera diferente.
Posiblemente se pueda arreglar ordenando las dependencias de una manera que no interfiera con el orden de ejecución esperado:
import { jest } from "@jest/globals"; jest.mock("../src/foo.js"); import Foo from "../src/foo.js"; ...
La elevación de jest.mock
se basa en un hack no documentado y que no cumple con las especificaciones que también depende de la versión de Jest y una configuración específica. No se garantiza que funcione porque se espera que las importaciones de ES superen otras declaraciones por especificaciones, y no hay exclusiones.
Una solución anticuada pero estable es cambiar para require
que sean llamadas regulares a funciones de JavaScript y se evalúen tal cual:
let { jest } = require ("@jest/globals"); jest.mock("../src/foo.js"); let { default: Foo } = require("../src/foo.js"); ...
Y una solución eficiente es deshacerse de la importación de jest
y configurar un entorno de Jest genérico con los globales correspondientes, de modo que jest.mock
pueda izarse como se esperaba, independientemente de la versión de Jest y otras circunstancias.