Javascript class getter setter shows Uncovered Line under unit test - javascript

I have following javascript class and writing unit test using mocha and sinon. When I run test case I see uncovered lines for 'return this._agentId;' and 'this._agentId = value;'.I am not sure how to cover these lines under test.I am using Istanbul test coverage tool to see coverage.
// Agentmessage.js
class AgentMessage {
constructor(agentId, message) {
this._agentId = agentId;
this._message = message;
}
get agentId() {
return this._agentId;
}
set agentId(value) {
this._agentId = value;
}
}
module.exports = AgentMessage;
// Agentmessage.test.js
'use strict';
const chai=require('chai');
const sinon=require('sinon');
var chaiAsPromised=require('chai-as-promised');
chai.use(chaiAsPromised).should();
const expect = chai.expect;
const agentMessage = require('../src/model/agentMessage');
describe('agentMessage test',function() {
let sandbox;
let agentMessageObj;
beforeEach(() => {
agentMessageObj = new agentMessage('agentId', 'message');
sandbox=sinon.sandbox.create();
});
afterEach(() => {
sandbox.restore();
});
it('agentMessage set agentId Test',() => {
agentMessageObj.agentId = 'agentId';
expect(agentMessageObj.agentId).to.deep.equal('agentId');
});
it('agentMessage get agentId Test',() => {
expect(agentMessageObj.agentId).to.equal('agentId');
});
});

I am not seeing the same issue you are. I get 100% coverage.
You say istanbul but you are in fact using the nyc package correct? I think you'll find that the instanbul project suggests you use the nyc runner if you are not already.
Consider refreshing your environment if you are able.
rm -rf .nyc_output && rm -rf coverage && rm -rf node_modules
npm i --save-dev nyc mocha chai
If that does not clear things up, consider removing things, temporarily at least, that you are not using in these particular tests. sinon and chai-as-promised for example. Isolate the code. See if there are some conflicts there.
Try this similar code. I get full coverage.
./node_modules/.bin/nyc --reporter html ./node_modules/.bin/mocha test.js
test.js
const { expect } = require('chai')
const AgentMessage = require('./index');
describe('agentMessage test', function () {
let agentMessage;
beforeEach(function () {
agentMessage = new AgentMessage('agentId01', 'message02');
});
it('agentMessage set agentId Test', async function () {
agentMessage.agentId = 'agentId02';
expect(agentMessage.agentId).to.deep.equal('agentId02');
});
});
If after all of that, if it is still a problem, if you're using a more advanced configuration of nyc/istanbul, start stripping away that configuration and using default properties. See if you find the sweet/troubled part.

Related

How do I test the code in a "if (require.main === module)" section of a Node.js script using Jest?

I have written a function like this:
const myFunction = () => {
return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
console.log(myFunction());
}
and this is my test:
const { myFunction } = require('../myFunction');
describe('test', () => {
it('should return the text', () => {
expect(myFunction()).toMatch('text');
});
});
According to code coverage tools, every line in the code is covered except for this line line:
console.log(myFunction());
Based on comments, I think maybe the reality is that this line cannot be tested, so I'm updating my question:
How can I:
Test this line with Jest, understanding that it may not actually tick the "covered" box, but so I can literally test it. Because not every one of my files has such trivial code in that block. Sometimes I do want to test it for real.
Cause the coverage statistic to show the file as 100% covered? Not because I am pedantic, but I like using the coverage report to find things I need to add tests for, and having dozens of "false negatives" in my report makes that more difficult.
Based on a suggestion in the comments, I found that I can use a child_process exec call within the test to test the output from the command line like this:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const { myFunction } = require('../myFunction');
describe('test', () => {
it('should return the text', () => {
expect(myFunction()).toBe('text');
});
it('should return the text when called via command line too', async () => {
const { stdout } = await exec('node myFunction', {
encoding: 'utf8',
});
expect(stdout).toBe('text\n');
});
});
Further comments pointed out that without exporting that section of code, Jest can never see it, and hence, never test it, meaning it will never show as "covered". Therefore, once I am satisfied that it is "tested well enough" I can exclude it form my report by adding /* istanbul ignore next */ before the offending line like this:
const myFunction = () => {
return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
/* istanbul ignore next */
console.log(myFunction());
}
As explained here, Node.js require wraps script contents with wrapper code specified in Module.wrapper and evaluates it with vm.runInThisContext. This can be implemented in a test. It can be something like:
let Module = require('module');
...
jest.resetModules();
jest.spyOn(console, 'log');
let myModPath = require.resolve('../myFunction');
let wrapper = Module.wrap(fs.readFileSync(myModPath));
let compiledWrapper = vm.runInThisContext(wrapper, {});
let mockModule = new Module(myModPath);
let mockExport = mockModule.exports;
let mockRequire = Module.createRequire(myModPath);
mockRequire.main = mockModule;
wrapper(mockExport, mockRequire, mockModule, path.basename(myModPath), path.dirname(myModPath));
expect(console.log).toBeCalledWith('test');

mocha unit test - how to clear cached javascript after each test

I'm trying to test a javascript file (let's call it hello.js) using mocha and jsdom. I have several unit tests; each test basically sets up some window properties, calls hello.js, and checks window property values. Tests seem to be running somehow; however, it seems like mocha uses "cached" hello.js after the first test (logging only shows in the first test).
Can someone tell me how I can ensure that I reload hello.js in each test?
const expect = require('chai').expect;
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
var dom = (new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`));
describe('hello', ()=>{
afterEach(()=>{
dom = (new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`));
global.window = {};
document = {};
location = {};
});
it('should test A', ()=> {
global.window = dom.window;
global.window.document.cookie = "test=kiwi";
document = global.window.document;
const hello = require('../public/hello.js');
expect(document.getElementsByTagName('IFRAME').length).to.equal(1);
});
it('should test B', ()=> {
global.window = dom.window;
global.window.document.cookie = "test=apple";
document = global.window.document;
const hello = require('../public/hello.js');
expect(document.getElementsByTagName('IFRAME').length).to.equal(0);
});
});
There's a library that you can pull in to do this for you:
Example:
const resetCache = require('resnap')(); // Capture "clean" cache state
Reference: Resnap
you can use flush-cache
npm i flush-cache --save-dev
beforeEach(function () {
flush()
})

How to have cli-spinner run during ShellJS command exec?

I'm currently trying to make a simple command-line node program that allows for me to easily create a boilerplate for a lot of the React/Redux applications that I make. I'm using ShellJS to execute console commands (I've tried using Node's child_process, too.) The problem is getting cli-spinner to work with executing terminal commands. Here's my code:
#! /usr/bin/env node
var shell = require('shelljs');
var userArgs = process.argv.slice(2);
var folderName = userArgs[0];
var Spinner = require('cli-spinner').Spinner;
var depSpin = new Spinner('Installing dependencies.. %s');
depSpin.setSpinnerString(10);
shell.mkdir(folderName);
shell.cd(folderName);
depSpin.start();
// I expect for the spinner to start here (before the execution of the commands.)
shell.exec('npm init -y', {silent: true});
shell.exec('npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react react-dom react-redux redux webpack', {silent: true});
shell.exec('npm install --save-dev babel-preset-env webpack-dev-server', {silent: true});
depSpin.stop();
// Since ShellJS should run synchronously,
// the spinner should stop right after the last command finishes.
shell.touch('webpack.config.js');
shell.mkdir(['build', 'frontend']);
shell.cd('frontend');
shell.mkdir(['components', 'containers', 'reducers', 'store']);
shell.touch('app.js');
But when running the program, it just hangs without displaying anything while it installs the dependencies. It's the same as when the spinner code wasn't even in there. I've also tried removing the depSpin.stop(), which just makes the program hang forever on the spinner. I have a feeling that this issue is caused by a conflict between cli-spinner and ShellJS both using the terminal.
I was able to accomplish this effect by using child_process's spawn. I had to create a child_process.spawn and run all of the commands concatenated with &&. That freed up the console output to be exclusively the cli-spinner output. I then did an event handler for when the child process exited to stop the spinner.
#! /usr/bin/env node
var shell = require('shelljs');
var userArgs = process.argv.slice(2);
var folderName = userArgs[0];
var Spinner = require('cli-spinner').Spinner;
var depSpin = new Spinner('Installing dependencies.. %s');
var spawn = require('child_process').spawn;
var commandsDep = [
'cd ' + folderName,
'npm init -y',
'npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react react-dom react-redux redux webpack',
'npm install --save-dev babel-preset-env webpack-dev-server'
];
var depChild = spawn(commandsDep.join(' && '), {
shell: true
});
depSpin.setSpinnerString(18);
shell.mkdir(folderName);
shell.cd(folderName);
depSpin.start();
depChild.on('exit', () => {
depSpin.stop();
shell.exec('clear');
console.log('Installing dependencies.. โœ“');
})
shell.touch('webpack.config.js');
shell.mkdir(['build', 'frontend']);
shell.cd('frontend');
shell.mkdir(['components', 'containers', 'reducers', 'store']);
shell.touch('app.js');
shell.cd('containers');
shell.touch(['AppContainer.js', 'Root.js']);
shell.cd('../reducers');
shell.touch('index.js');
shell.cd('../store');
shell.touch('configureStore.js');
Based on Owens' answer I made a helper method myself to run long commands with a spinner inline with normal shelljs commands;
const Spinner = require('cli-spinner').Spinner;
const spinner = new Spinner('installing.. %s');
spinner.setSpinnerString('|/-\\');
var spawn = require('child_process').spawn;
const longCommand = (command, onSuccess) => {
return new Promise((resolve, reject) => {
var process = spawn(command, { shell: true });
spinner.start();
process.on('exit', () => {
spinner.stop();
onSuccess();
resolve();
})
})
}
const npmInstall = async () => {
await longCommand("npm install", () => console.log(`NPM modules installed! ๐Ÿ‘`))
// Other stuff
shell.mkdir('new')
}
npmInstall()

How do I require() from the console using webpack?

How do I require() / import modules from the console? For example, say I've installed the ImmutableJS npm, I'd like to be able to use functions from the module while I'm working in the console.
Here's another more generic way of doing this.
Requiring a module by ID
The current version of WebPack exposes webpackJsonp(...), which can be used to require a module by ID:
function _requireById(id) {
return webpackJsonp([], null, [id]);
}
or in TypeScript
window['_requireById'] =
(id: number): any => window['webpackJsonp'];([], null, [id]);
The ID is visible at the top of the module in the bundled file or in the footer of the original source file served via source maps.
Requiring a module by name
Requiring a module by name is much trickier, as WebPack doesn't appear to keep any reference to the module path once it has processed all the sources. But the following code seems to do the trick in lot of the cases:
/**
* Returns a promise that resolves to the result of a case-sensitive search
* for a module or one of its exports. `makeGlobal` can be set to true
* or to the name of the window property it should be saved as.
* Example usage:
* _requireByName('jQuery', '$');
* _requireByName('Observable', true)ยด;
*/
window['_requireByName'] =
(name: string, makeGlobal?: (string|boolean)): Promise<any> =>
getAllModules()
.then((modules) => {
let returnMember;
let module = _.find<any, any>(modules, (module) => {
if (_.isObject(module.exports) && name in module.exports) {
returnMember = true;
return true;
} else if (_.isFunction(module.exports) &&
module.exports.name === name) {
return true;
}
});
if (module) {
module = returnMember ? module.exports[name] : module.exports;
if (makeGlobal) {
const moduleName = makeGlobal === true ? name : makeGlobal as string;
window[moduleName] = module;
console.log(`Module or module export saved as 'window.${moduleName}':`,
module);
} else {
console.log(`Module or module export 'name' found:`, module);
}
return module;
}
console.warn(`Module or module export '${name}'' could not be found`);
return null;
});
// Returns promise that resolves to all installed modules
function getAllModules() {
return new Promise((resolve) => {
const id = _.uniqueId('fakeModule_');
window['webpackJsonp'](
[],
{[id]: function(module, exports, __webpack_require__) {
resolve(__webpack_require__.c);
}},
[id]
);
});
}
This is quick first shot at this, so it's all up for improvement!
Including this in a module will allow require([modules], function) to be used from a browser
window['require'] = function(modules, callback) {
var modulesToRequire = modules.forEach(function(module) {
switch(module) {
case 'immutable': return require('immutable');
case 'jquery': return require('jquery');
}
})
callback.apply(this, modulesToRequire);
}
Example Usage:
require(['jquery', 'immutable'], function($, immutable) {
// immutable and $ are defined here
});
Note: Each switch-statement option should either be something this module already requires, or provided by ProvidePlugin
Sources:
Based on this answer, which can be used to add an entire folder.
Alternative method from Webpack Docs - which allows something like require.yourModule.function()
I found a way that works, for both WebPack 1 and 2. (as long as the source is non-minified)
Repo: https://github.com/Venryx/webpack-runtime-require
Install
npm install --save webpack-runtime-require
Usage
First, require the module at least once.
import "webpack-runtime-require";
It will then add a Require() function to the window object, for use in the console, or anywhere in your code.
Then just use it, like so:
let React = Require("react");
console.log("Retrieved React.Component: " + React.Component);
It's not very pretty (it uses regexes to search the module wrapper functions) or fast (takes ~50ms the first call, and ~0ms after), but both of these are perfectly fine if it's just for hack-testing in the console.
Technique
The below is a trimmed version of the source to show how it works. (see the repo for the full/latest)
var WebpackData;
webpackJsonp([],
{123456: function(module, exports, __webpack_require__) {
WebpackData = __webpack_require__;
}},
[123456]
);
var allModulesText;
var moduleIDs = {};
function GetIDForModule(name) {
if (allModulesText == null) {
let moduleWrapperFuncs = Object.keys(WebpackData.m).map(moduleID=>WebpackData.m[moduleID]);
allModulesText = moduleWrapperFuncs.map(a=>a.toString()).join("\n\n\n");
// these are examples of before and after webpack's transformation: (which the regex below finds the var-name of)
// require("react-redux-firebase") => var _reactReduxFirebase = __webpack_require__(100);
// require("./Source/MyComponent") => var _MyComponent = __webpack_require__(200);
let regex = /var ([a-zA-Z_]+) = __webpack_require__\(([0-9]+)\)/g;
let matches = [];
let match;
while (match = regex.exec(allModulesText))
matches.push(match);
for (let [_, varName, id] of matches) {
// these are examples of before and after the below regex's transformation:
// _reactReduxFirebase => react-redux-firebase
// _MyComponent => my-component
// _MyComponent_New => my-component-new
// _JSONHelper => json-helper
let moduleName = varName
.replace(/^_/g, "") // remove starting "_"
.replace(new RegExp( // convert chars where:
"([^_])" // is preceded by a non-underscore char
+ "[A-Z]" // is a capital-letter
+ "([^A-Z_])", // is followed by a non-capital-letter, non-underscore char
"g"),
str=>str[0] + "-" + str[1] + str[2] // to: "-" + char
)
.replace(/_/g, "-") // convert all "_" to "-"
.toLowerCase(); // convert all letters to lowercase
moduleIDs[moduleName] = parseInt(id);
}
}
return moduleIDs[name];
}
function Require(name) {
let id = GetIDForModule(name);
return WebpackData.c[id].exports;
}
Being able to use require modules in the console is handy for debugging and code analysis. #psimyn's answer is very specific so you aren't likely to maintain that function with all the modules you might need.
When I need one of my own modules for this purpose, I assign a window property to it so I can get at it e.g window.mymodule = whatever_im_exporting;. I use the same trick to expose a system module if I want to play with it e.g:
myservice.js:
let $ = require('jquery');
let myService = {};
// local functions service props etc...
module.exports = myService;
// todo: remove these window prop assignments when done playing in console
window.$ = $;
window.myService = myService;
It is still a bit of a pain, but digging into the bundles, I can't see any way to conveniently map over modules.
The answer from #Rene Hamburger is good but unfortunately doesn't work anymore (at least with my webpack version). So I updated it:
function getWebpackInternals() {
return new Promise((resolve) => {
const id = 'fakeId' + Math.random();
window['webpackJsonp'].push(["web", {
[id]: function(module, __webpack_exports__, __webpack_require__) {
resolve([module, __webpack_exports__, __webpack_require__])
}
},[[id]]]);
});
}
function getModuleByExportName(moduleName) {
return getWebpackInternals().then(([_, __webpack_exports__, __webpack_require__]) => {
const modules = __webpack_require__.c;
const moduleFound = Object.values(modules).find(module => {
if (module && module.exports && module.exports[moduleName]) return true;
});
if (!moduleFound) {
console.log('couldnt find module ' + moduleName);
return;
}
return moduleFound.exports[moduleName];
})
}
getModuleByExportName('ExportedClassOfModule');
expose-loader is, in my opinion, a more elegant solution:
require("expose-loader?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.
Adding the below code to one of your modules will allow you to load modules by id.
window.require = __webpack_require__;
In the console use the following:
require(34)
You could do something similar as psimyn advised by
adding following code to some module in bundle:
require.ensure([], function () {
window.require = function (module) {
return require(module);
};
});
Use require from console:
require("./app").doSomething();
See more
After making an npm module for this (see my other answer), I did a search on npms.io and seem to have found an existing webpack-plugin available for this purpose.
Repo: https://www.npmjs.com/package/webpack-expose-require-plugin
Install
npm install --save webpack-expose-require-plugin
Usage
Add the plugin to your webpack config, then use at runtime like so:
let MyComponent = require.main("./path/to/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
See package/repo readme page for more info.
EDIT
I tried the plugin out in my own project, but couldn't get it to work; I kept getting the error: Cannot read property 'resource' of undefined. I'll leave it here in case it works for other people, though. (I'm currently using the solution mentioned above instead)
After both making my own npm package for this (see here), as well as finding an existing one (see here), I also found a way to do it in one-line just using the built-in webpack functions.
It uses WebPack "contexts": https://webpack.github.io/docs/context.html
Just add the following line to a file directly in your "Source" folder:
window.Require = require.context("./", true, /\.js$/);
Now you can use it (eg. in the console) like so:
let MyComponent = Require("./Path/To/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
However, one important drawback of this approach, as compared to the two solutions mentioned above, is that it seems to not work for files in the node_modules folder. When the path is adjusted to "../", webpack fails to compile -- at least in my project. (perhaps because the node_modules folder is just so massive)

How do I use gulp with tape?

I'm trying to integrate Gulp with Tape (https://github.com/substack/tape), the NodeJs test harness.
How can I do this? There doesn't seem to be an existing gulp plugin.
I've see this, but it looks really inelegant:
var shell = require('gulp-shell')
gulp.task('exec-tests', shell.task([
'tape test/* | faucet',
]));
gulp.task('autotest', ['exec-tests'], function() {
gulp.watch(['app/**/*.js', 'test/**/*.js'], ['exec-tests']);
});
I've tried this, which looks like it should work:
var tape = require('tape');
var spec = require('tap-spec');
gulp.task('test', function() {
return gulp.src(paths.serverTests, {
read: false
})
.pipe(tape.createStream())
.pipe(spec())
.pipe(process.stdout);
});
but I get a TypeError: Invalid non-string/buffer chunk error
Your "inelegant" answer is the best one. Not every problem can be best solved with streams, and using gulp just as a wrapper is not a sin.
Right, your task won't work because gulp streams are based on vinyl, a virtual file abstraction. I don't really think there's a good way of handling this in gulp, it seems like you should be using the tape API directly. I mean, you could put some gulp task sugar around it if you wish:
var test = require('tape');
var spec = require('tap-spec');
var path = require('path');
var gulp = require('gulp');
var glob = require('glob');
gulp.task('default', function () {
var stream = test.createStream()
.pipe(spec())
.pipe(process.stdout);
glob.sync('path/to/tests/**/*.js').forEach(function (file) {
require(path.resolve(file));
});
return stream;
});
Seems kind of messy to me; not only because we're not using any of gulp's streaming abstractions, but we're not even putting it into a way that could hook into a gulp pipeline afterwards. Furthermore, you can't get gulp's task finished message when using this code either. If anyone knows a way around that then, please, be my guest. :-)
I think I would prefer to use tape on the command line. But, if you want all of your build step tasks in your gulpfile this might be the route to go.
Just use code below and gulp tdd and having TDD :) with tape
const tapNotify = require('tap-notify');
const colorize = require('tap-colorize');
const tape = require('gulp-tape');
const through = require('through2');
gulp.task('test',function(){
process.stdout.write('\x1Bc');
const reporter = through.obj();
reporter.pipe(tapNotify({
passed: {title: 'ok', wait:false},
failed: {title: 'missing',wait:false}
}));
reporter
.pipe(colorize())
.pipe(process.stdout);
return gulp.src('test/**/*.js')
.pipe(tape({
outputStream: through.obj(),
reporter: reporter
}));
});
gulp.task('tdd', function() {
gulp.run('test');
gulp.watch(['app/scripts/**/*.js*', 'test/**/*.js'],['test']);
});
In a GitHub issue for tape jokeyrhyme mentions that gulp tasks can be Promises, and suggests a way to use that for running tape tests. Based upon that advice I've done this:
gulpfile.babel.js:
import glob from "glob";
gulp.task("test", () => {
let module = process.argv[process.argv.length - 1];
return new Promise(resolve => {
// Crude test for 'gulp test' vs. 'gulp test --module mod'
if (module !== "test") {
require(`./js/tape/${module}.js`);
resolve();
return;
}
glob.sync("./js/tape/*.js").forEach(f => require(f)));
resolve();
});
});
Looking at Ben's answer I suspect what I've done isn't very nice though, for one thing I've noticed that failing tests don't result in a non-zero exit code (although I've not tried Ben's approach to validate whether that does).
// npm i --save-dev gulp-tape
// npm i --save-dev faucet (just an example of using a TAP reporter)
import gulp from 'gulp';
import tape from 'gulp-tape';
import faucet from 'faucet';
gulp.task('test:js', () => {
return gulp.src('src/**/*test.js')
.pipe(tape({
reporter: faucet()
}));
});
Here's an example of my solution:
var gulp = require('gulp');
var tape = require('tape');
var File = require('vinyl');
var through = require('through2');
var exec = (require('child_process')).execSync;
function execShell(shcmd, opts) {
var out = '';
try {
out = exec(shcmd, opts);
} catch (e) {
if (e.error) throw e.error;
if (e.stdout) out = e.stdout.toString();
}
return out;
};
gulp.task('testreport', function(){
return gulp.src(
'testing/specs/tape_unit.js', {read: false}
).pipe(
through.obj(function(file, encoding, next) {
try{
// get tape's report
var tapout = execShell(
"./node_modules/.bin/tape " + file.path
);
// show the report in a console with tap-spec
execShell(
"./node_modules/.bin/tap-spec", { input: tapout, stdio: [null, 1, 2] }
);
// make a json report
var jsonout = execShell(
"./node_modules/.bin/tap-json", { input: tapout }
);
// do something with report's object
// or prepare it for something like Bamboo
var report = JSON.parse(jsonout.toString());
// continue the stream with the json report
next(null, new File({
path: 'spec_report.json',
contents: new Buffer(JSON.stringify(report, null, 2))
}));
}catch(err){ next(err) }
})
).pipe(
gulp.dest('testing/reports')
);
});

Categories

Resources