Adding test IDs to unit tests for reporting - javascript

I'm using mocha and trying to build a testing system which reports tests individually. The goal is to have traceability between tests defined in the requirements for the project and unit tests. So, for example, the test 'Must be able to create new widgets' is in the requirements database with id of '43', I want the unit test which tests that criteria to report something like Test 43, Must be able to create new widgets, pass, and then update the corresponding db entry (another service could be responsible for this).
Can this be done in mocha? The only thing I've found so far is to replace text in the it() function with the test id, and use the json reporter to process the results afterwards (but then I don't get the text for what is being tested, unless I combine them and do some kind of parsing). Note: not all tests would have an id.
Here's an example of the kind of functionality I'm hoping for
describe("Widget" function() {
it("should allow creation of widgets", function() {
this.id = 43;
result = widget.create();
expect.result.to.exist;
});
});
And then either a hook, like
afterEach(function(test) {
if (test.hasOwnProperty('id')) {
report(test.result);
}
});
Or a custom reporter, or an adapter of some sort.
runner.on('test end', function(test) {
console.log(test.id); //doesn't exist, but i want it to
report(test);
});

This depends on your assertion library.
With Chai, you havethe optional field for text.
assert.should.exist(result, 'expect Result to exist (Id 43)');
With Jasmine, you can add the test reference to your it():
describe("Widget" function() {
it("should allow creation of widgets (Id 43)", function() {
To use the Mocha custom reporters you could try to define one in your test suite.
module.exports = MyReporter;
function MyReporter(runner) {
var passes = 0;
var failures = 0;
runner.on('pass', function(test){
passes++;
console.log('pass: %s', test.fullTitle());
});
runner.on('fail', function(test, err){
failures++;
console.log('fail: %s -- error: %s', test.fullTitle(), err.message);
});
runner.on('end', function(){
console.log('end: %d/%d', passes, passes + failures);
process.exit(failures);
});
}
There are really 2 suggestions here. The first is the simplest, and is to simply add your id to the description of the it() and then that will show you what has passed and failed. That would be the quickest way to reach your goal.
However, if you wanted to have the fancier method, and could test to ensure things are set, then you could use the custom reporter, which would allow you to fail a test if the ID was not set.

What I wanted and what exists were so close! I was able to solve this using the ctx property of the test in the reporter, e.g. test.ctx.id
test.js
describe("Widget" function() {
it("should allow creation of widgets", function() {
this.id = 43;
result = widget.create();
expect.result.to.exist;
});
});
reporter.js
runner.on('test end', function(test) {
console.log(test.ctx.id);
report(test);
});

Related

Mocha Unit Test with Jquery Submit

I'm working on creating a Mocha unit test based on solution code that was given to me by someone else. (The goal here is to create an online code assessment for students that will be run against my unit test). It's a simple exercise and will not be extensible at all in the future.
I want to get the return value from a jQuery on-submit event and use that for my test case but am unsure how I can do that given the solution code that was given to me to work from.
I've gone through the document here (https://gist.github.com/soheilhy/867f76feea7cab4f8a84) but my particular case is different since we are using jQuery's on document ready and the on-submit.
I've also tried to do something like "export.validate = function(){}" to match an example from the docs but everything I've tried I either get that Mocha doesn't know the function, or Mocha doesn't know the boolean variable references.
solutionCode.js
$(document).ready(function() {
$("#form-submit").on("submit", function () {
var xValid = true;
var yValid = true;
//...Bunch of logic here that could change the boolean values...
return xValid && yValid;
});
});
And here is my Mocha test file.js
this.jsdom = require('jsdom-global')()
global.$ = global.jQuery = require('jquery');
var assert = require('assert');
var work = require('path/to/solutionCode.js');
describe('Validate Form', function() {
it('Form is valid', function(done) {
//Not sure how to get the return value here to do my assertion...
done();
});
});
If the value of both booleans in the return are True, the test should pass, otherwise it should fail.

How to increase the code coverage using istanbul in node.js

I am using Istanbul for code coverage, but i m getting very low coverage percentage particularly in Models file.
Consider the following is the model file:
ModelA.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var app = require('../server')
var db = require('../db/dbConnection');
var config = require('../configs/config')
const Schema1 = new Schema({ 'configurations': [] });
exports.save = function (aa, data, callback) {
var logMeta = {
file: 'models/modelA',
function: 'save',
data: {},
error: {}
}
if (!aa) {
return callback('aa is required')
}
global.logs[aa].log('info', 'AA: ' + aa, logMeta);
db.connectDatabase(aa, function(error, mongoDB){
if(error){
logMeta.data['error'] = error
global.logs[aa].log('error', 'error', logMeta);
return callback(error)
}
const ModelA = mongoDB.model('bbb', cccc);
ModelA.findOneAndUpdate({}, data, {upsert: true, new: true, runValidators: true}, function(error ,result){
if (error) {
logMeta.data['error'] = error
global.logs[aa].log('error', 'error', logMeta);
}
else {
logMeta.data = {}
logMeta.data['result'] = JSON.parse(JSON.stringify(result))
global.logs[aa].log('info', 'result', logMeta);
}
callback(error, result);
});
})
}
TestA.js:
var should = require('should'),
sinon = require('sinon'),
ModelA= require("../models/ModelA");
describe('Model test', function () {
it('Should save Model', function (done) {
var todoMock = sinon.mock(new ModelA({'configurations': []}));
var todo = todoMock.object;
todoMock
.expects('save')
.yields(null, 'SAVED');
todo.save(function(err, result) {
todoMock.verify();
todoMock.restore();
should.equal('SAVED', result, "Test fails due to unexpected result")
done();
});
});
});
But i am getting codecoverage percentage 20. SO how can i increase the percentage:
ALso:
1.Whether i have to mock the db.connectDatabase if yews how can i acheive that?
Whether i have to use TestDb to run all my UnitTest? Or i have to assert??
Code Coverage will work for Unit Test or integration test???
Please share your ideas. Thanks
I have been using Istanbul to 100% code cover most of my client/server projects so I might have the answers you are looking for.
How does it work
Whenever you require some local file, this gets wrapped all over the place to understand if every of its parts is reached by your code.
Not only the required file is tainted, your running test is too.
However, while it's easy to code cover the running test file, mocked classes and their code might never be executed.
todoMock.expects('save')
Accordingly to Sinon documentation:
Overrides todo. save with a mock function and returns it.
If Istanbul tainted the real save method, anything within that scope won't ever be reached so that you are actually testing that mock works, not that your real code does.
This should answer your question: Code Coverage will work for Unit Test or integration test ???
The answer is that it covers the code, which is the only thing you're interested from a code cover perspective. Covering Sinon JS is nobody goal.
No need to assert ... but
Once you've understood how Istanbul works, it follows up naturally to understand that it doesn't matter if you assert or not, all it matters is that you reach the code for real and execute it.
Asserting is just your guard against failures, not a mechanism interesting per se in any Istanbul test. When your assertion fails, your test does too, so it's good for you to know that things didn't work and there's no need to keep testing the rest of the code (early failure, faster fixes).
Whether you have to mock the db.connectDatabase
Yes, at least for the code you posted. You can assign db as generic object mock to the global context and expect methods to be called but also you can simplify your life writing this:
function createDB(err1, err2) {
return {
connectDatabase(aa, callback) {
callback(err1, {
model(name, value) {
return {
findOneAndUpdate($0, $1, $3, fn) {
fn(err2, {any: 'object'});
}
};
}
});
}
};
}
global.db = createDB(null, null);
This code in your test file can be used to create a global db that behaves differently accordingly with the amount of errors you pass along, giving you the ability to run the same test file various times with different expectations.
How to run the same test more than once
Once your test is completed, delete require.cache[require.resolve('../test/file')] and then require('../test/file') again.
Do this as many times as you need.
When there are conditional features detection
I usually run the test various times deleting global constructors in case these are patched with a fallback. I also usually store them to be able to put 'em back later on.
When the code is obvious but shouldn't be reached
In case you have if (err) process.exit(1); you rarely want to reach that part of the code. There are various comments understood by Istanbul that would help you skip parts of the test like /* istanbul ignore if */ or ignore else, or even the generic ignore next.
Please consider thinking twice if it's just you being lazy, or that part can really, safely, be skipped ... I got bitten a couple of times with a badly handled error, which is a disaster since when it happens is when you need the most your code to keep running and/or giving you all the info you need.
What is being covered?
Maybe you know this already but the coverage/lcov-report/index.html file, that you can open right away with any browser, will show you all the parts that aren't covered by your tests.

How do I access information about the currently running test case from the beforeEach function?

Using Protractor 5.1.2 and Jasmine2 for describing test cases, how does one get the current testcase/spec being run in the beforeEach method?
I would like to do some different setup based on which test case I'm running. I do not want to put these tests in different spec files with repeating code except for the little bit I want to change in the setup.
Example of what I'm looking for:
...
beforeEach(() => {
if(currentSpec/TestCase.name == "thisName") {
// Do a particular login specific to testcase.name
} else {
// Do a default login
}
});
...
My research into this brought up much older solutions (2+ years) that are very out of date and seem to keep saying that accessing the currently running testcase/spec is something they (protractor) try to keep hidden. I feel like wanting to do particular setup for a particular test case in a suite of test cases is not a unique thing. I could just be using the wrong search terms.
I am not sure how to do what you want with beforeEach(). But, I think you can get the same effect by using a helper file. This will allow you to setup a common file that any spec can reference so you can use a common set of functions. To set this up, you will:
Create a central file (I call mine util.js)
const helper = function(){
this.exampleFunction = function(num){
return num; //insert function here
}
this.exampleFunction2 = function(elem){
elem.click() //insert function here
}
}
Inside your spec.js file you will do:
const help = require('path/to/util.js');
const util = new help();
describe('Example with util',function(){
it('Should use util to click an element',function(){
let elem = $('div.yourItem');
util.exampleFunction2(elem);
});
});
You can then call these functions from any spec file. You would then be able to seperate your tests into seperate spec files, but have a common set of functions for the parts that are the same.
Another way to do this, without creating separate files is to just use a local function.
Example spec.js file:
describe('Should use functions',function(){
afterEach(function(){
$('button.logout').click();
)};
it('Should run test as user 1',function(){
$('#Username').sendKeys('User1');
$('#Password').sendKeys('Password1');
$('button.login).click();
doStuff();
)};
it('Should run test as user 2',function(){
$('#Username').sendKeys('User2');
$('#Password').sendKeys('Password2');
$('button.login').click();
doStuff();
)};
function doStuff(){
$('div.thing1').click();
$('div.thing2').click();
)};
)};
As per comments for multiple describes:
describe('Test with user 1',function(){
beforeEach(function(){
//login as user 1
});
it('Should do a thing',function(){
//does the thing as user 1
});
});
describe('Test with user 2',function(){
beforeEach(function(){
//login as user 2
});
it('Should do another thing',function(){
//does the other thing as user 2
});
});
The whole point of beforeEach is that it is the same for each test.
If you want to do different things, then they belong in the specific test.
Write a helper function and call it from the specific test if you want to have common functionality that does slightly different things depending on an argument.

Is there a way to get current Mocha instance and edit options at runtime?

Let's say you have a simple mocha test:
describe("Suite", function(){
it("test",function(doneCallback){
// here be tests
});
});
In this test I can change the timeout by adding this.timeout(VALUE); anywhere within the describe function.
However, besides the timeout value, there are plenty of other Mocha options that can be exclusively declared either from the command line or from a mocha.opts file that lives in the test folder (./test/mocha.opts).
What I want is to change some of these options at run-time (for example, the reporter) and not in command line / mocha.opts file.
From my research of what's possible, I found that there is an article explaining how you can use mocha programmatically, which would allow changing these options at run-time, but you need to create the Mocha instance yourself, whereas in an ordinary test one doesn't have direct access to the Mocha instance.
So, is there a way to get the Mocha instance from an existent test and change some of these options like reporter at run-time during a test?
I would like to have an option that doesn't require to modify the source code of Mocha in any way (I suppose I could tamper with the Mocha instance to implement a way to get an instance directly in the Mocha constructor).
The best way that you can achieve that is by using Mocha as per the wiki link that you have already referenced, which is using Mocha programmatically.
So to your inquiry on changing the reporter parameter here is a brief example that would do what you want, in order to run the tests against a theoretically already existing file named test-file-a.js that contains your tests:
var Mocha = require('mocha'),
mocha = new Mocha(),
path = require('path');
mocha.addFile(path.join(__dirname, 'test-file-a.js'));
mocha
.reporter('list')
.run();
Besides that there are plenty other options that you can use and also there are some listeners for events, like test that you may want to do something during a test, for example:
mocha
.reporter('list')
.ui('tdd')
.bail()
.timeout(10000)
.run()
.on('test', function(test) {
if (test.title === 'some title that you want here') {
//do something
}
});
Please note that you can define the options per each Mocha instance that will run again a test suite, but not during the runtime of a test suite, so for example if you start your tests for test-file-a.js with the option reporter('list') as above you cannot change it while the tests are running to something else, like you may do for example with the timeout option where you can do this.timeout().
So you would have to instantiate a new Mocha instance as the examples above with different options each time.
No, you cannot. without changing the code.
In short, mocha is created in a scope you cannot access from tests. Without going in details, the objects provided in your scope cannot change the options you want. (You cannot do this: link)
But there is a way to define your own reporter and customize the output for each test:
Create a file called MyCustomReporter.js:
'use strict';
module.exports = MyCustomReporter;
function MyCustomReporter (runner) {
runner.on('start', function () {
var reporter = this.suite.suites["0"].reporter;
process.stdout.write('\n');
});
runner.on('pending', function () {
process.stdout.write('\n ');
});
runner.on('pass', function (test) {
var reporter = this.suite.useReporter;
if(reporter == 'do this') {
}
else if(reporter == 'do that'){
}
process.stdout.write('\n ');
process.stdout.write('passed');
});
runner.on('fail', function () {
var reporter = this.suite.useReporter;
process.stdout.write('\n ');
process.stdout.write('failed ');
});
runner.on('end', function () {
console.log();
});
}
When you run mocha, pass the path of MyCustomReporter.js as reporter parameter(without .js), eg:
mocha --reporter "/home/user/path/to/MyCustomReporter"
The default mocha script actually tries to require a reporter file if it is not found in the default ones(under lib/reporters), github link
Finally, in your tests, you can pass some parameters to customize the output of your reporter:
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
this.parent.reporter = 'do this';
it('should return -1 when the value is not present', function() {
this.runnable().parent.useReporter = 'do this';
assert.equal([1,2,3].indexOf(4), -1);
});
});
});

Reuse scenarios by using mocha

Recently I've started to use JS and mocha.
I've wrote some tests already, but now I got to the point when I need to reuse my already written tests.
I've tired to look for "it" / "describe" reusing, but didn't find something useful...
Does anyone have some good example ?
Thanks
Considering that if you only do unit testing, you won't catch errors due to integration problems between your components, you have at some point to test your components together. It would be a shame to dump mocha to run these tests. So you may want to run with mocha a bunch of tests that follow the same general patter but differ in some small respects.
The way I've found around this problem is to create my test functions dynamically. It looks like this:
describe("foo", function () {
function makeTest(paramA, paramB, ...) {
return function () {
// perform the test on the basis of paramA, paramB, ...
};
}
it("test that foo does bar", makeTest("foo_bar.txt", "foo_bar_expected.txt", ...));
it("test what when baz, then toto", makeTest("when_baz_toto.txt", "totoplex.txt", ...));
[...]
});
You can see a real example here.
Note that there is nothing that forces you to have your makeTest function be in the describe scope. If you have a kind of test you think is general enough to be of use to others, you could put it in a module and require it.
Considering each test is only designed to test a single feature/unit, generally you want to avoid reusing your tests. It's best to keep each test self-contained an minimize the dependencies of the test.
That said, if you have something you repeat often in your tests, you can use a beforeEach to keep things more concise
describe("Something", function() {
// declare your reusable var
var something;
// this gets called before each test
beforeEach(function() {
something = new Something();
});
// use the reusable var in each test
it("should say hello", function() {
var msg = something.hello();
assert.equal(msg, "hello");
});
// use it again here...
it("should say bye", function() {
var msg = something.bye();
assert.equal(msg, "bye");
});
});
You can even use an async beforeEach
beforeEach(function(done) {
something = new Something();
// function that takes a while
something.init(123, done);
});

Categories

Resources