Я пытаюсь издеваться над функцией, которая возвращает другую функцию. Однако я не уверен, как это сделать с помощью шутки. Заранее спасибо.
Модуль нужно было издеваться:
const initGreeter = () =>{
return {
sayHello: (name:string) =>{
console.info(`Hello: ${name}`)
}
}
}
export default initGreeter;
Тестируемый модуль:
import initGreeter from './greeter';
export const greetSomeone = (name:string) =>{
const greeter = initGreeter();
greeter.sayHello(name)
}
Тесты:
import initGreeter from '../../utils/greeter';
import { greetSomeone } from '../../utils/greeterConsumer';
describe('greeterConsumer', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('greeter consumer should call SayHello on greeter', () => {
//TODO:mock greeter here
greetSomeone('sam');
expect(greeter.sayHello.mock.call[0][0]).toBe('sam');
});
it('greeter consumer throws exception', () => {
//TODO:mock greeter here so it throws exception
expect(greetSomeone('sam')).toThrow(Error);
});
});
Обратите внимание, код в обновлениях 1 и 2 является продолжением кода решения от @slideshowp2.
Обновление 2: похоже, если изменить код ниже
jest.mock('./greeter', () => {
return jest.fn(() => mGreeter);
});
к
jest.mock('../../utils/greeter.ts', () => ({
__esModule: true,
default: jest.fn(() => mGreeter)
}));
оно работает.
Есть и другие способы заставить код из @slideshowp2 работать как есть, например, установив «esModuleInterop»: true в tsconfig. Однако я не совсем понимаю, почему это работает в любом случае. Я могу проверить в будущем и обновить здесь.
Обновление 1: после внедрения решения от @slideshowp2
Я получаю ошибку ниже в моем тесте
FAIL src/tests/utils/greeterConsumer.test.ts ● greeterConsumer › потребитель Greeter должен вызвать SayHello на GREETER.
TypeError: greeter_1.default is not a function
2 |
3 | export const greetSomeone = (name:string) =>{
> 4 | const greeter = initGreeter();
| ^
5 | greeter.sayHello(name)
6 | }
at Object.<anonymous>.exports.greetSomeone (src/utils/greeterConsumer.ts:4:21)
at Object.<anonymous> (src/__tests__/utils/greeterConsumer.test.ts:18:5)
Вы можете использовать jest.mock(moduleName, factory, options) для имитации ../../utils/greeter
модуля вручную.
Например.
greeter.ts
:
const initGreeter = () => {
return {
sayHello: (name: string) => {
console.info(`Hello: ${name}`);
},
};
};
export default initGreeter;
greeterConsumer.ts
:
import initGreeter from './greeter';
export const greetSomeone = (name: string) => {
const greeter = initGreeter();
greeter.sayHello(name);
};
greeterConsumer.test.ts
:
import initGreeter from './greeter';
import { greetSomeone } from './greeterConsumer';
const mGreeter = {
sayHello: jest.fn(),
};
jest.mock('./greeter', () => {
return jest.fn(() => mGreeter);
});
describe('greeterConsumer', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('greeter consumer should call SayHello on greeter', () => {
greetSomeone('sam');
expect(initGreeter).toBeCalledTimes(1);
expect(mGreeter.sayHello).toBeCalledWith('sam');
});
it('greeter consumer throws exception', () => {
mGreeter.sayHello.mockImplementationOnce(() => {
throw new Error('oops');
});
expect(() => greetSomeone('sam')).toThrowError('oops');
expect(initGreeter).toBeCalledTimes(1);
expect(mGreeter.sayHello).toBeCalledWith('sam');
});
});
результат модульного теста:
PASS examples/65281989/greeterConsumer.test.ts
greeterConsumer
✓ greeter consumer should call SayHello on greeter (3 ms)
✓ greeter consumer throws exception (10 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
greeterConsumer.ts | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.473 s
исходный код: https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65281989
Похоже, я смог заставить это работать. Пожалуйста, смотрите обновление 2 в OP. Еще раз спасибо за подробный ответ @slideshowp2.
Ошибка: это мера предосторожности для защиты от неинициализированных фиктивных переменных. Если гарантировано, что макет требуется лениво, разрешены имена переменных с префиксом mock
(без учета регистра).
Спасибо @slideshowp2 за подробный ответ. к сожалению, я получаю сообщение об ошибке «TypeError: Greeter_1.default не является функцией» из теста «приветствующий потребитель должен вызвать SayHello для приветствующего». Пожалуйста, смотрите подробности в разделе обновления op. Есть ли какие-то настройки конфигурации для шутки, которые портят это на моей стороне?