typescript - En Jest, ¿cómo simulo un módulo externo SOLO en una prueba específica?
Estoy usando Jest con TypeScript (usando ts-jest). Este es mi sujeto de prueba que usa la biblioteca dotenv:
import * as dotenv from 'dotenv';
export class TestSubject {
public function test() {
console.log(dotenv); // Here I debug if I'm using a mock or not
}
}
Me gustaría simular la biblioteca dotenv solo para una prueba específica, pero estoy atascado.
Aquí está mi conjunto de pruebas:
import { TestSubject } from './test-subject';
import * as dotenv from 'dotenv';
jest.mock('dotenv'); // place it here, otherwise it doesn't work
describe('Suite 1', () => {
it('test 1', () => {
// I want to use the mock here... and it works
const subject = new TestSubject();
subject.test(); // shows that I'm using the mock
});
it('test 2', () => {
// I don't want the mock here
jest.dontMock('dotenv'); // doesn't work
jest.unmock('dotenv'); // doesn't work
const subject = new TestSubject();
subject.test(); // shows that I'm still using the mock!!!
});
});
Como puedes ver, la llamada jest.mock('dotenv') debe colocarse fuera de describe, de lo contrario, no funciona.
Estoy tratando de no usar el mock en test 2, pero no funciona: console.log muestra que estoy usando el mock.
Respuesta #1
Una mejora a la solución de @slideshowp2.
Con jest.domock necesitas llamar a require después al módulo (como aquí), pero el resultado de require tiene el tipo any y perdemos la seguridad de tipos. así que puedes usar las importaciones dinámicas de TypeScript.
Ejemplo de código completo:
import * as summer from './exampleModule';
describe('mock vs no-mock', () => {
beforeEach(() => {
jest.resetModules();
});
it('NO-MOCKED', async () => {
console.log(summer.sum(1, 1));
expect(summer.sum(1, 1)).toBe(2);
});
it('MOCKED', async () => {
jest.doMock('./exampleModule');
const summer = await import('./exampleModule');
const mockedSummer = mocked(summer, true);
mockedSummer.sum.mockImplementation((a, b) => a + b + 1);
console.log(summer.sum(1, 1));
expect(summer.sum(1, 1)).toBe(3);
});
it('NO-MOCKED', async () => {
console.log(summer.sum(1, 1));
expect(summer.sum(1, 1)).toBe(2);
});
});
Respuesta #2
Aquí está la solución:
index.ts, el archivo será probado:
import * as dotenv from 'dotenv';
export class TestSubject {
public test() {
console.log(dotenv);
}
}
Prueba unitaria:
describe('TestSubject', () => {
beforeEach(() => {
jest.resetModules();
});
it('should mock dotenv', () => {
jest.doMock('dotenv');
const dotenv = require('dotenv');
const { TestSubject } = require('./');
const subject = new TestSubject();
subject.test();
expect(jest.isMockFunction(dotenv.config)).toBeTruthy();
});
it('should not mock dotenv', () => {
jest.unmock('dotenv');
const dotenv = require('dotenv');
const { TestSubject } = require('./');
const subject = new TestSubject();
subject.test();
expect(jest.isMockFunction(dotenv.config)).toBeFalsy();
});
});
Resultado de la prueba unitaria:
PASS src/stackoverflow/56446543/index.spec.ts
TestSubject
✓ should mock dotenv (2111ms)
✓ should not mock dotenv (2ms)
console.log src/stackoverflow/56446543/index.ts:5
{ config:
{ [Function: config]
_isMockFunction: true,
getMockImplementation: [Function],
mock: [Getter/Setter],
mockClear: [Function],
mockReset: [Function],
mockRestore: [Function],
mockReturnValueOnce: [Function],
mockResolvedValueOnce: [Function],
mockRejectedValueOnce: [Function],
mockReturnValue: [Function],
mockResolvedValue: [Function],
mockRejectedValue: [Function],
mockImplementationOnce: [Function],
mockImplementation: [Function],
mockReturnThis: [Function],
mockName: [Function],
getMockName: [Function] },
parse:
{ [Function: parse]
_isMockFunction: true,
getMockImplementation: [Function],
mock: [Getter/Setter],
mockClear: [Function],
mockReset: [Function],
mockRestore: [Function],
mockReturnValueOnce: [Function],
mockResolvedValueOnce: [Function],
mockRejectedValueOnce: [Function],
mockReturnValue: [Function],
mockResolvedValue: [Function],
mockRejectedValue: [Function],
mockImplementationOnce: [Function],
mockImplementation: [Function],
mockReturnThis: [Function],
mockName: [Function],
getMockName: [Function] },
default:
{ config:
{ [Function: config]
_isMockFunction: true,
getMockImplementation: [Function],
mock: [Getter/Setter],
mockClear: [Function],
mockReset: [Function],
mockRestore: [Function],
mockReturnValueOnce: [Function],
mockResolvedValueOnce: [Function],
mockRejectedValueOnce: [Function],
mockReturnValue: [Function],
mockResolvedValue: [Function],
mockRejectedValue: [Function],
mockImplementationOnce: [Function],
mockImplementation: [Function],
mockReturnThis: [Function],
mockName: [Function],
getMockName: [Function] },
parse:
{ [Function: parse]
_isMockFunction: true,
getMockImplementation: [Function],
mock: [Getter/Setter],
mockClear: [Function],
mockReset: [Function],
mockRestore: [Function],
mockReturnValueOnce: [Function],
mockResolvedValueOnce: [Function],
mockRejectedValueOnce: [Function],
mockReturnValue: [Function],
mockResolvedValue: [Function],
mockRejectedValue: [Function],
mockImplementationOnce: [Function],
mockImplementation: [Function],
mockReturnThis: [Function],
mockName: [Function],
getMockName: [Function] } } }
console.log src/stackoverflow/56446543/index.ts:5
{ config: [Function: config],
parse: [Function: parse],
default: { config: [Function: config], parse: [Function: parse] } }
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.394s, estimated 4s
Como puedes ver, el módulo dotenv está simulado para el primer caso de prueba y no está simulado para el segundo caso de prueba.
Puedes encontrar la demostración completa aquí: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56446543
