Broma: ¿cómo simular la consola cuando es utilizada por una biblioteca de terceros?

84

Estoy tratando de simular el error console.warn / error pero no puedo. Utilizo una biblioteca de terceros que llama a console.warn dentro de ella. Necesito probar si se llamó o no. En mi caso de prueba, estaba intentando stub console.warn pero no ayudó. Después de eso, estaba tratando de simular la consola manualmente, pero tampoco funcionó.

console.warn = jest.fn();
testSchema('/app/components/Users/UserItem/UserItemContainer.js');
expect(console.warn).toBeCalled();

no funcionó

console.warn = jest.fn();
testSchema('/app/components/Users/UserItem/UserItemContainer.js');
console.warn('error');
expect(console.warn).toBeCalled();

funcionó. Pero sigo viendo console.warn node_modules/babel-relay-plugin/lib/getBabelRelayPlugin.js:138en la terminal. ¿Alguien puede ayudarme?

Errorpro
fuente

Respuestas:

144

Tienes que usar globalpara acceder a objetos en el contexto global

global.console = {warn: jest.fn()}
expect(console.warn).toBeCalled()

o uso jest.spyOnagregado en19.0.0

jest.spyOn(global.console, 'warn')
Andreas Köberle
fuente
2
Sí chicos, funciona. Pero una cosa es que debe requerir la biblioteca después de declarar global.console. Lo hice mal. Requería mi lib y después de eso se declaró global. Gracias.
Errorpro
2
Es interesante cómo esto no está documentado en ninguna parte del sitio web de Jest. Estoy buscando y no encuentro nada que explique esto.
Leonardo
2
con mecanografiado: error TS2322: Escriba '{advertir: Mock <{}>; } 'no se puede asignar al tipo' Consola '.
Gerard Brull
8
solo para que todos estén al tanto. global.console = {...}se suprime el error, mientras que jest.spyOn(...)no lo hará. Tú decides si quieres eliminar los errores o no en tus pruebas.
a11smiles
38
Prefiero jest.spyOn(...)porque es más fácil de limpiar y estoy usando TypeScript, pero también quería suprimir errores en la salida como menciona @ a11smiles. Así que usé lo jest.spyOn(global.console, "warn").mockImplementation(() => {})que evita que el espía llame al subyacenteconsole.warn
djskinner
73

Utilice jest.spyOn()y spy.mockRestore().

const spy = jest.spyOn(console, 'warn').mockImplementation();
...
spy.mockRestore();

La respuesta aceptada no restaura el original console.warn()y "comprometerá" las otras pruebas dentro del mismo archivo (si console.warn()se usa dentro de las otras pruebas o el código que se está probando).

Para su información, si lo usa console.warn = jest.fn()en un archivo de prueba, no afectará a otros archivos de prueba (por ejemplo, console.warn volverá a su valor original en los otros archivos de prueba).

Consejo: puede llamar al spy.mockRestore()interior afterEach()/ afterAll()para asegurarse de que incluso si una prueba falla, no comprometerá las otras pruebas del mismo archivo (por ejemplo, garantiza que las pruebas dentro del mismo archivo estén completamente aisladas).

Ejemplo completo:

const spy = jest.spyOn(console, 'warn').mockImplementation();
console.warn('message1'); // Won't be displayed (mocked)
console.warn('message2'); // Won't be displayed (mocked)
expect(console.warn).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledTimes(2); // Another syntax
expect(console.warn).toHaveBeenLastCalledWith('message2');
expect(spy).toHaveBeenLastCalledWith('message2'); // Another syntax
expect(spy.mock.calls).toEqual([['message1'], ['message2']]);
expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);
spy.mockRestore(); // IMPORTANT
//console.warn.mockRestore(); // Another syntax

console.warn('message3'); // Will be displayed (not mocked anymore)
expect(spy).toHaveBeenCalledTimes(0); // Not counting anymore
expect(spy.mock.calls).toEqual([]);
//expect(console.warn.mock.calls).toEqual([]); // Crash

No puedes escribir

console.warn = jest.fn().mockImplementation();
... 
console.warn.mockRestore();

porque no restaurará el original console.warn().

/! \ mockImplementationOnce()Aún necesitará llamar a spy.mockRestore():

// /!\
const spy = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
console.warn('message1'); // Won't be displayed (mocked)
expect(console.warn).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(1); // Another syntax
expect(console.warn).toHaveBeenLastCalledWith('message1');
expect(spy).toHaveBeenLastCalledWith('message1'); // Another syntax
expect(spy.mock.calls).toEqual([['message1']]);
expect(console.warn.mock.calls).toEqual([['message1']]);

console.warn('message2'); // Will be displayed (not mocked anymore)
// /!\
expect(console.warn).toHaveBeenCalledTimes(2); // BAD => still counting
expect(spy.mock.calls).toEqual([['message1'], ['message2']]);
expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);

spy.mockRestore(); // IMPORTANT
//console.warn.mockRestore(); // Another syntax
console.warn('message3'); // Will be displayed (not mocked anymore)
expect(spy).toHaveBeenCalledTimes(0); // Not counting anymore
expect(spy.mock.calls).toEqual([]);
//expect(console.warn.mock.calls).toEqual([]); // Crash

También puedes escribir:

const assert = console.assert;
console.assert = jest.fn();
...
console.assert = assert;
tanguy_k
fuente