How to generate multiple reports with mocha? - node.js

I want to have the following reports:
coverage
spec
xunit
all running in a single mocha execution from my grunt
Currently - I have to run the tests 3 times, each time to generate a different report(!).
So I use grunt-mocha-test with 2 configuration where only the reporter is different (once xunit-file and once spec).
And then I have grunt-mocha-istanbul that runs the tests yet again,and generates the coverage report.
I tried using
{
options: {
reporters : ['xunit-file', 'spec']
}
}
for grunt-mocha-test at least to bring it down to 2, but that doesn't work as well.
reading grunt-mocha-istanbul documentation, i can't seem to find any info about reporter configuration.
How can I resolve this?

Maybe this can help:
https://github.com/glenjamin/mocha-multi
AFAIK this is not supported in Mocha yet, but it is on its way:
https://github.com/mochajs/mocha/pull/1360
Hope this helps,
György

I ran into the same problem recently, and found nothing after looking around SO as well as GH issues. It seems that topic of officially supporting multiple reporters are getting postponed over and over.
Having said that having a custom solution is quite easy, assuming the reporters you want to combine already exist. What I did is to create a small and naive custom reporter, and used the reporter in .mocharc.js config.
// junit-spec-reporter.js
const mocha = require("mocha");
const JUnit = require("mocha-junit-reporter");
const Spec = mocha.reporters.Spec;
const Base = mocha.reporters.Base;
function JunitSpecReporter(runner, options) {
Base.call(this, runner, options);
this._junitReporter = new JUnit(runner, options);
this._specReporter = new Spec(runner, options);
return this;
}
JunitSpecReporter.prototype.__proto__ = Base.prototype;
module.exports = JunitSpecReporter;
// .mocharc.js
module.exports = {
reporter: './junit-spec-reporter.js',
reporterOptions: {
mochaFile: './tests-results/results.xml'
}
};
The example above shows how to use both spec and junit reporter.
More info on custom reporter: https://mochajs.org/api/tutorial-custom-reporter.html
Note that this is just a proof of concept and can be made prettier and more robust using more generic approach (and TypeScript).
Update 14.9.2021
I have created a utility package for this: https://www.npmjs.com/package/#netatwork/mocha-utils

For simultaneously reporting for spec and x-unit, there's also an NPM package called spec-xunit-file.
In grunt:
grunt.initConfig({
mochaTest: {
test: {
options: {
reporter: 'spec-xunit-file',
...
},
...
}
}
...
});

Related

How do you find the filename and path of a running test in Jest

I am using Jest for testing. How do I access the filename or file path of the current test being run?
I need a conditional statement that runs different lines of code based on whether it is a unit test file or integration test file.
Here is an example of what I am trying to achieve:
beforeAll(() => {
if (integration_test_file){
// run this this code
} else if (unit_test_file){
// run this code instead
}
})
This information is available in Jest environment. This is the case for custom environment:
const Environment = require('jest-environment-node'); // or jest-environment-jsdom
module.exports = class MyEnvironment extends Environment {
constructor(config, context) {
super(config, context);
this.testPath = context.testPath;
}
async setup() {
await super.setup();
this.global.IS_INTEGRATION = /match integration/.test(this.testPath);
}
}
The environment is instantiated for each test suite, testPath contains full path to current test file.
IS_INTEGRATION global variable will be available in setupFilesAfterEnv and tests themselves. In case the code needs to be evaluated for all tests, it may belong to environment setup and teardown methods.
You can access the name of the file path of the test being ran in jest via its global variables.
the file path can be found under the global variable
jasmine.testPath
or
global.jasmine.testPath
this answer only applies if you're using jest with its default test runner "jasmine" or "jasmine2". results will differ based on the test runner you use. see
https://jestjs.io/docs/en/configuration#testrunner-string
__dirname works a treat (ref: https://www.geeksforgeeks.org/how-to-get-the-path-of-current-script-using-node-js/)

Configure ESLint RuleTester to use Typescript Parser

I am trying to write some custom ESLint rules for my typescript based project. In my project I am using eslint/typescript for linting.
I have already written a custom eslint plugin which validates a custom rule. Now I want to write the unit tests for that custom rule. My test file looks like this:
/**
* #fileoverview This rule verifies that logic can only depend on other logic
* #author Dayem Siddiqui
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const typescriptParser = require('#typescript-eslint/parser')
var rule = require("../../../lib/rules/logic-dependency"),
RuleTester = require("eslint").RuleTester;
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
typescriptParser.parseForESLint()
var ruleTester = new RuleTester({ parserOptions: {} });
ruleTester.run("logic-dependency", rule, {
valid: [
`class DeleteLogic {
}
class CreateLogic {
constructor(private deleteLogic: DeleteLogic) {}
}`
],
invalid: [
{
code: `class ExternalClient {
}
class UpdateLogic {
constructor(private externalClient: ExternalClient) {}
}`,
errors: [
{
message: "Logic cannot have a dependency on client",
type: "MethodDefinition"
}
]
}
]
});
Right now my tests a failing because by default eslint only understand plain Javascript code. I understand that I need to somehow configure it to use a custom parser that allows it to understand/parse typescript code. However I am unable to find a good example online on how to do that
The RuleTester constructor takes eslint's parser options that allow for configuring the parser itself. So pass it in like this and Bob's your uncle:
const ruleTester = new RuleTester({
parser: '#typescript-eslint/parser',
});
typescript-eslint's own rule tests (e.g. this one) use exactly this.
(Was searching for an answer to this question and kept up ending here, so I posted the solution I found here in the hope it'll be useful.)
eslint 6.0+
Incorporating #Sonata's comment:
Eslint 6.0+ requires an absolute path to the parser (see 6.0 migration guide):
const ruleTester = new RuleTester({
parser: require.resolve('#typescript-eslint/parser'),
});
Use a package such as the typescript-eslint/parser. I can't provide much more than a link in this case. If you need help using it, let me know.

Protractor Cucumber JUnit XML report

I wish to create JUnit style XML reports from Protractor - Cucumber tests so that they can be used by CI.
Is there any detailed step on how this can be achieved?
Got the protractor-cucumber-junit npm library from below link but the documentation is not elaborate.
https://www.npmjs.com/package/protractor-cucumber-junit
Also the page points to a better plugin called 'cucumberjs-junitxml'. The documentation for this is given at
https://github.com/sonyschan/cucumberjs-junitxml
This too is not very helpful.
Questions:
What are the elaborate steps to be followed after installing the plugins to get the final XML?
What changes need to be done in the protractor config file or any other place within the project?
In order to generate the cucumber junit xml, first you need to generate cucumber json report:
1) Create a separate js file you can give it any name it would be better if you put this in hooks.js with all your before & after hooks
var Cucumber = require('cucumber'); // npm install --save cucumber
var fs = require('fs');
var hooks = function () {
var outputDir = './Reports/';
var JsonFormatter = Cucumber.Listener.JsonFormatter();
JsonFormatter.log = function (string) {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir);
}
var targetJson = outputDir + 'cucumber_report.json';
fs.writeFile(targetJson, string, function (err) {
if (err) {
console.log('Failed to save cucumber test results to json file.');
console.log(err);
}
});
};
this.registerListener(JsonFormatter);
}
module.exports = hooks;
This would create cucumber_report.json file in Reports folder in your current directory.
2) You can consume this json report with the cucumber-junit library https://www.npmjs.com/package/cucumber-junit or one of the libraries you mentioned above , all are similar & follow the simple instructions & then simply run the below command
$ cat ./Reports/cucumber_report.json | ./node_modules/.bin/cucumber-junit > cucumber_report.xml
It would generate the cucumber_report.xml file.

Code Coverage for Istanbul Wrong when using Sandbox in Nodeunit

I have written a bunch of tests using nodeunit to test my code. In doing so I wanted to mock out modules being required by the code under test. Instead of changing the code to make it more easily testable with mocks, inversion of control, when it wasn't needed, I instead used nodeunits sandbox function.
Example
var nodeunit = require("nodeunit");
export.MyTest = {
test1(test) {
var fakeGlobals = {
require: function(filename) {
if (filename == "CoolUtil.js") {
return { doit: function wasCool() { return true; } };
} else {
return require(filename);
}
}
};
var testSubject = nodeunit.utils.sandbox("ModuleUnderTest.js", fakeGlobals);
test.equals(42, testSubject.doSomethingCoolUsingCoolUtil(), "Worked");
test.done();
}
}
Istanbul is giving me the wrong coverage report numbers. I tried using the flag --post-require-hook which is said to be used with RequireJS, which I'm fine with switching to but haven't learned yet.
test/node_modules/.bin/istanbul cover --v --hook-run-in-context --root test/node_modules/.bin/nodeunit -- --reporter junit --output target/results/unit_tests test
Has anybody been successful with nodeunit, istanbul and using the sandbox feature in nodeunit?

Can Blanket.js work with Jasmine tests if the tests themselves are loaded with RequireJS?

We've been using Jasmine and RequireJS successfully together for unit testing, and are now looking to add code coverage, and I've been investigating Blanket.js for that purpose. I know that it nominally supports Jasmine and RequireJS, and I'm able to successfully use the "jasmine-requirejs" runner on GitHub, but this runner is using a slightly different approach than our model -- namely, it loads the test specs using a script tag in runner.html, whereas our approach has been to load the specs through RequireJS, like the following (which is the callback for a requirejs call in our runner):
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.TrivialReporter();
var jUnitReporter = new jasmine.JUnitXmlReporter('../JasmineTests/');
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.addReporter(jUnitReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
var specs = [];
specs.push('spec/models/MyModel');
specs.push('spec/views/MyModelView');
$(function () {
require(specs, function () {
jasmineEnv.execute();
});
});
This approach works fine for simply doing unit testing, if I don't have blanket or jasmine-blanket as dependencies for the function above. If I add them (with require.config paths and shim), I can verify that they're successfully fetched, but all that appears to happen is that I get jasmine-blanket's overload of jasmine.getEnv().execute, which simply prints "waiting for blanket..." to the console. Nothing is triggering the tests themselves to be run anymore.
I do know that in our approach there's no way to provide the usual data-cover attributes, since RequireJS is doing the script loading rather than script tags, but I would have expected in this case that Blanket would at least calculate coverage for everything, not nothing. Is there a non-attribute-based way to specify the coverage pattern, and is there something else I need to do to trigger the actual test execution once jasmine-blanket is in the mix? Can Blanket be made to work with RequireJS loading the test specs?
I have gotten this working by requiring blanket-jasmine then setting the options
require.config({
paths: {
'jasmine': '...',
'jasmine-html': '...',
'blanket-jasmine': '...',
},
shim: {
'jasmine': {
exports: 'jasmine'
},
'jasmine-html': {
exports: 'jasmine',
deps: ['jasmine']
},
'blanket-jasmine': {
exports: 'blanket',
deps: ['jasmine']
}
}
});
require([
'blanket-jasmine',
'jasmine-html',
], function (blanket, jasmine) {
blanket.options('filter', '...'); // data-cover-only
blanket.options('branchTracking', true); // one of the data-cover-flags
require(['myspec'], function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 250;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
jasmineEnv.addReporter(new jasmine.BlanketReporter());
jasmineEnv.currentRunner().execute();
});
});
The key lines are the addition of the BlanketReporter and the currentRunner execute. Blanket jasmine adapter overrides jasmine.execute with a no-op that just logs a line, because it needs to halt the execution until it is ready to begin after it has instrumented the code.
Typically the BlanketReport and currentRunner execute would be done by the blanket jasmine adapter but if you load blanket-jasmine itself in require, the event for starting blanket test runner will not get fired as subscribes to the window.load event (which by the point blanket-jasmine is loaded has already fired) therefore we need to add the report and execute the "currentRunner" as it would usually execute itself.
This should probably be raised as a bug, but for now this workaround works well.

Resources