I'm trying to mock method inquirer.prompt in a unit testing, which has several questions (in the example I put only two examples).
return prompt([
{
type: 'input',
name: 'name1',
message: 'Question 1?',
filter: (fieldValue: string) => fieldValue.trim(),
validate: (fieldValue: string) => showValidationResults(fieldValue, validateFieldIsNotEmpty),
},
{
type: 'input',
name: 'name2',
message: 'Question 2?',
validate: (fieldValue: string) => showValidationResults(fieldValue, validateFieldIsNotEmpty),
},
...
]);
I need to reach a certain unit test coverage so I want to check that the filter and validate functions are being correctly called.
I am only finding solutions that suggest to extract those functions to their own method and then call them directly from the unit test, but this is not a good solution for me because the unit test doesn't still know if the lines of filter and validate are being called, makes the code less clean.
Also, I would prefer not to call private methods directly from the unit test instead of calling the main method of the class.
Is there a way that I could mock prompt so I can inject the answers to the questions and then check that the filter and validate portions are executed?
Inspired by the comment of @jonrsharpe I came out with the following solution:
const mockValidateFieldIsNotEmpty = jest.fn();
const mockPrompt = jest.fn();
import ExecutionEnvironmentContext from '../../../../ExecutionEnvironmentContext';
import ClassToTest from '../ClassToTest';
jest.mock('../../../../validation/InteractiveAnswersValidator', () => {
const ActualInteractiveAnswersValidator = jest.requireActual('../../../../validation/InteractiveAnswersValidator');
return {
...ActualInteractiveAnswersValidator,
validateFieldHasNoSpaces: mockValidateFieldHasNoSpaces,
};
});
jest.mock('inquirer', () => {
return {
Separator: jest.fn(),
prompt: mockPrompt,
};
});
describe('Class to test', () => {
it('should call filter and validate methods of inquirer prompt', async () => {
const expectedErrorMessages = ['errorMessage'];
mockValidateFieldIsNotEmpty.mockReturnValue({ result: true });
mockPrompt.mockImplementation((opt: { type: string; name: string; message: string; filter?: any; validate?: any }[]) => {
const choice = opt[0];
expect(opt[0]).toHaveProperty('filter');
expect(opt[0]).toHaveProperty('validate');
expect(opt[1]).toHaveProperty('validate');
expect(opt[0].filter(' mockMessage ')).toEqual('mockMessage');
expect(opt[0].validate(' mockMessage ')).toEqual(true);
expect(opt[1].validate('mockMessage')).toEqual(true);
});
await ClassToTest.callToFunction({ });
});
});
This way, I'm calling the methods registered inside filter, checking their results. It may not give the biggest testing value but at least I'm reaching 100% coverage in these methods.