I was wondering how to write unit tests for the npm package Inquirer.js, which is a tool to make CLI package more easily. I have read this post but I was't able to make it works.
Here is my code that needs to be tested:
const questions = [
{
type: 'input',
name: 'email',
message: "What's your email ?",
},
{
type: 'password',
name: 'password',
message: 'Enter your password (it will not be saved neither communicate for other purpose than archiving)'
}
];
inquirer.prompt(questions).then(answers => {
const user = create_user(answers.email, answers.password);
let guessing = guess_unix_login(user);
guessing.then(function (user) {
resolve(user);
}).catch(function (message) {
reject(message);
});
} );
...and here is the test, written with Mocha:
describe('#create_from_stdin', function () {
this.timeout(10000);
check_env(['TEST_EXPECTED_UNIX_LOGIN']);
it('should find the unix_login user and create a complete profile from stdin, as a good cli program', function (done) {
const user_expected = {
"login": process.env.TEST_LOGIN,
"pass_or_auth": process.env.TEST_PASS_OR_AUTH,
"unix_login": process.env.TEST_EXPECTED_UNIX_LOGIN
};
let factory = new profiler();
let producing = factory.create();
producing.then(function (result) {
if (JSON.stringify(result) === JSON.stringify(user_expected))
done();
else
done("You have successfully create a user from stdin, but not the one expected by TEST_EXPECTED_UNIX_LOGIN");
}).catch(function (error) {
done(error);
});
});
});
I'd like to fill stdin with the process.env.TEST_LOGIN
(to answer the first Inquirer.js question) and process.env.TEST_PASS_OR_AUTH
(to answer the second Inquirer.js question) to see if the function create a valid profile (with the value unix_login guessed by the method create
of the factory object).
I tried to understand how Inquirer.js unit tests itself, but my understanding of NodeJS isn't good enough. Can you help me with this unit test?
JavaScript Unit Testing is a method where JavaScript test code is written for a web page or web application module. It is then combined with HTML as an inline event handler and executed in the browser to test if all functionalities are working as desired. These unit tests are then organized in the test suite.
A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.
You simply mock or stub any functionality that you don't want to test.
module.js
- simplified example of a module you want to test
const inquirer = require('inquirer')
module.exports = (questions) => {
return inquirer.prompt(questions).then(...)
}
module.test.js
const inquirer = require('inquirer')
const module = require('./module.js')
describe('test user input' () => {
// stub inquirer
let backup;
before(() => {
backup = inquirer.prompt;
inquirer.prompt = (questions) => Promise.resolve({email: 'test'})
})
it('should equal test', () => {
module(...).then(answers => answers.email.should.equal('test'))
})
// restore
after(() => {
inquirer.prompt = backup
})
})
There are libraries to help with mocking/stubbing, like sinon.
Also it was easier to mock inquirer.prompt
in this case because .prompt
was just a property on the main export inquirer
which will refer to the the same object in both module.js
and module.test.js
. For more complicated scenarios there are libraries that can help, like proxyquire. Or you can create your modules in a way that help you switch out the dependencies easily for testing. For example:
module.js
- make it a "factory" function which returns your main function with dependencies injected either automatically (via default arguments) or manually.
module.exports = ({
inquirer = require('inquirer'),
} = {}) => (questions) => {
return inquirer.prompt(questions).then(...)
}
module.test.js
const module = require('./module.js')
describe('test user input' () => {
const inquirer = {prompt: () => Promise.resolve({email: 'test'})};
it('should equal test', () => {
module({inquirer})(...).then(answers => answers.email.should.equal('test'))
})
})
inquirer.js
with jest
testing frameworkinquirer
.prompt
with responsemodule-test.js
import module from './module';
import inquirer from 'inquirer';
jest.mock('inquirer');
describe('Module test', () => {
test('user input', async () => {
expect.assertions(1);
inquirer.prompt = jest.fn().mockResolvedValue({ email: '[email protected]' });
await expect(module()).resolves.toEqual({ email: '[email protected]' });
});
});
(Using ES6 or TypeScript syntax.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With