I'm working on getting Expresso set up and some tests running. I followed along with a tutorial on node tuts and have 4 tests running, and passing. Now I'm trying to get a code coverage output to show up when I run the tests, like the docs show. However, I'm sort of lost.
My super basic learning example tests are in a file called test.js in a folder called test:
var Account = require('../lib/account');
require('should');
module.exports = {
"initial balance should be 0" : function(){
var account = Account.create();
account.should.have.property('balance');
account.balance.should.be.eql(0);
},
"crediting account should increase the balance" : function(){
var account = Account.create();
account.credit(10);
account.balance.should.be.eql(10);
},
"debiting account should decrease the balance" : function(){
var account = Account.create();
account.debit(5);
account.balance.should.be.eql(-5);
},
"transferring from account a to b b should decrease from a and increase b": function(){
var accountA = Account.create();
var accountB = Account.create();
accountA.credit(100);
accountA.transfer(accountB, 25);
accountA.balance.should.be.eql(75);
accountB.balance.should.be.eql(25);
}
}
And the code itself is in lib/account.js:
var Account = function(){
this.balance = 0;
}
module.exports.create = function(){
return new Account();
}
Account.prototype.credit = function(amt){
this.balance += amt;
}
Account.prototype.debit = function(amt){
this.balance -= amt;
}
Account.prototype.transfer = function(acct, amt){
this.debit(amt);
acct.credit(amt);
}
Account.prototype.empty = function(acct){
this.debit(this.balance);
}
When I run expresso from the command line, I get:
$ expresso
100% 4 tests
Likewise, if I run expresso with a -c flag or a variety of other options, I get the same output. I'd like to get the code coverage output shown in the docs. I've also run the command $ node-jscoverage lib lib-cov, and the lib-cov folder has things in it now..
What am I missing?
Best result I've found so far was to edit paths on test run:
This is run_tests.sh
#! /bin/bash
rm -Rf ./app-cov
node_modules/expresso/deps/jscoverage/node-jscoverage app/ app-cov
NODE_PATH=$NODE_PATH:/usr/local/lib/node:/usr/local/lib/node_modules:./mmf_node_modules:./app-cov node_modules/expresso/bin/expresso -c
Related
Mocha can be invoked from a script and it has a useful JSON reporter, but how can one access that reported structure from the invoking script? Redirecting stdout worked:
var Mocha = require('mocha');
var stats = {};
var oldWrite = process.stdout.write;
process.stdout.write = function(txt) {
stats = JSON.parse(txt).stats; // write invoked in one gulp.
};
new Mocha().
addFile("test/toyTest").
reporter("json", {stats: stats}).
run(function (failures) {
process.on('exit', function () {
process.stdout.write = oldWrite;
console.log("percentage: " + stats.passes/(stats.passes+stats.failures));
process.exit(failures > 0 ? 1 : 0);
});
});
but I'd have expected a more direct solution.
According to the code, the answer was "you can't":
process.stdout.write(JSON.stringify(obj, null, 2));
Since the my solution above is somewhat less than obvious, I created a pull request to add a reporter option to pass in a target object:
var Mocha = require('mocha');
var report = {};
new Mocha().
addFile("test/toyTest").
reporter("json", {"output-object": report}).
run(function (failures) {
process.on('exit', function () {
var s = report.stats;
console.log("percentage: " + s.passes/(s.passes+s.failures));
process.exit(failures > 0 ? 1 : 0);
});
});
which saves capturing process.stdout.write as well as the needless serialization and deserialization of the report structure. I also added a command line to set the output file so you can run:
mocha -R json --reporter-options output-file=rpt.json
An alternative solution is to create your own reporter like it has been suggested in the documentation. I simply copied the json reporter in node_modules/mocha/lib/reporters/json.js to new file in my project folder companyReporter.js and replaced this line
Ln 69: process.stdout.write(JSON.stringify(obj, null, 2));
With
Ln 69: process.send(obj);
It was also necessary to update the paths to the requires on line 9 and 10 of myReporter.js. I prefer this way because I'm not messing with process.stdout.write.
The last change to the code was updating the reporter path:
var Mocha = require('mocha');
process.on('message', function (message) {
const test = message.toString('utf8').replace(/\n$/,'');
new Mocha().
addFile(test).
reporter(__dirname + '/path/to/myReporter.js').
run(function(failures) {
process.exit(failures > 0 ? 1 : 0);
});
});
I think every spec files first load by mocha and mocha runs them at least describe part if "it"s wasn't selected with "only".
// Lines before first "it" will run for every spec files
// even if I don't mark them with ".only" word
var db = require("../../node/server/db"),
should = require('should')
...;
describe("main describe...", function () {
var user = {},
apiRootUrl = "http://127.0.0.1:3000";
user.nameSurname = "Cem Topkaya";
kullanici = schema.AJV.validate(schema_name, user);
describe("child describe", function () {
it(....)
it.only(....)
it(....)
}
}
I want to run only one spec file not others. Is there any way to prevent this?
If you give to Mocha the full path of your test file, it will just load that file and no other file:
$ mocha path/to/test.js
I have a following simple function:
var moment = require('moment-timezone');
exports.splitIntoDays = function(from,to) {
var timeIntervals = [];
var interval = {};
var start = moment(from);
var end = moment(to);
if(start.isAfter(end)) {
throw new Error('From date ('+from+') is after To date ('+to+').Enter a valid date range.');
}
var initial = start;
console.log("Before loop"+initial.format("YYYY/MM/DD-HH:mm:ss")+" "+initial.diff(end,'hours'));
while(end.diff(initial,'hours') > 24) {
timeIntervals.push({"from" : initial.format("YYYY/MM/DD-HH:mm:ss"), "to" : initial.add(24,'hours').format("YYYY/MM/DD-HH:mm:ss")});
initial = initial.add(1,'hours');
}
timeIntervals.push({"from" : initial.format("YYYY/MM/DD-HH:mm:ss"), "to" : end.format("YYYY/MM/DD-HH:mm:ss")});
console.info(JSON.stringify(timeIntervals));
return timeIntervals;
}
So, if I call it, splitIntoDays('2014/09/13-10:00:00','2014/09/14-09:00:00'),
I get the following response:
[ { from: '2014/09/13-10:00:00', to: '2014/09/14-09:00:00' } ]
I wrote the following test using Mocha and Chai:
var expect = require("chai").expect;
var utils = require("../Utils.js");
describe("Utils", function(){
describe("#splitIntoDays()", function(){
var timeIntervals = [];
var results = utils.splitIntoDays('2014/09/13-10:00:00','2014/09/14-09:00:00');
timeIntervals.push({ "from": '2014/09/13-10:00:00', "to": '2014/09/14-09:00:00' });
expect(results).to.equal(timeIntervals);
});
});
But, this one fails. Can you please help me in pointing out a mistake?
You need to wrap your test in an it call and you need to use deep.equal. For instance:
it("equal", function () {
expect(results).to.deep.equal(timeIntervals);
});
equal by itself will check that the objects are strictly equal with ===. Start Node on your computer and type [] === [] at the prompt. You'll get the result false. This is because you have two Array objects and a strict equality check will fail if the objects are not the same instance.
The it call is necessary because this is how you tell Mocha "here's a test for you to run". The describe calls declare test suites but do not themselves declare any tests.
I'm just starting out with JsTestDriver and I've created very simple demo code to see if I have configured my environment correctly. However about 40-50% of the time I'm getting the following error when Firefox is launched (via JsTestDriver) "Firefox Closed Unexpectedly While Starting".
This error does not occur if I use Chrome.
My environment consists of:
VirtualBox 4.1.18 running Ubuntu 10.04.4 LTS 32bit
Firefox 13.0.1
JsTestDriver-1.3.4.b
openjdk-6-jre-headless
I'm executing:
java -jar /home/developer/bin/JsTestDriver.jar --port 9876 --browser /usr/bin/firefox --tests all --testOutput results
My JsTestDriver config is:
server: http://localhost:9876
load:
- src/*.js
test:
- test/*.js
timeout: 10
The source code (code under test) is:
Person = function()
{
this.firstName = "";
this.lastName = "";
this.fullName = function()
{
if((this.firstName != "") && (this.lastName != ""))
{
return this.lastName + ", " + this.firstName;
}
var name = this.firstName + " " + this.lastName;
return name.trim();
}
};
The test code (JsTestDriver based code) is:
PersonTest = TestCase("PersonTest");
PersonTest.prototype.testFullName = function()
{
fixture = new Person();
fixture.firstName = "John";
fixture.lastName = "Doe";
assertEquals("Doe, John", fixture.fullName());
};
PersonTest.prototype.testFullName_FirstNameOnly = function()
{
fixture = new Person();
fixture.firstName = "John";
assertEquals("John", fixture.fullName());
};
PersonTest.prototype.testFullName_LastNameOnly = function()
{
fixture = new Person();
fixture.lastName = "Doe"
assertEquals("Doe", fixture.fullName());
};
Thanks!
Your problem may be in that you're spinning up your server opening your browser every time you run your tests. I think a less error prone solution would be to start your server and have it capture some browsers, and then leave it running. Then you can run your tests against that server as needed. Our solution at work involves three virtual machines running IE7,IE8,IE9,Firefox, and Chrome all the time, and our Maven build process runs our javascript unit tests at every build. Also, make sure that you always use the '--reset' argument as well. It will keep your browsers fresh. I wrote a post that shows how to integrate QUnit, Requirejs, and code coverage with JSTD that is independent of Maven: js-test-driver+qunit+coverage+requirejs. Hope it helps.
I'm starting a nodejs project and would like to do BDD with Mocha and Zombiejs. Unfortunately I'm new to just about every buzzword in that sentence. I can get Mocha and Zombiejs running tests fine, but I can't seem to integrate the two - is it possible to use Mocha to run Zombiejs tests, and if so, how would that look?
Just looking for "hello world" to get me started, but a tutorial/example would be even better.
Thanks!
Assuming you already have installed mocha, zombie and expect.js according to instructions, this should work for you:
// Put below in a file in your *test* folder, ie: test/sampletest.js:
var expect = require('expect.js'),
Browser = require('zombie'),
browser = new Browser();
describe('Loads pages', function(){
it('Google.com', function(done){
browser.visit("http://www.google.com", function () {
expect(browser.text("title")).to.equal('Google');
done();
});
});
});
Then you should be able to run the mocha command from your root application folder:
# mocha -R spec
Loads pages
✓ Google.com (873ms)
✔ 1 tests complete (876ms)
Note: If your tests keep failing due to timeouts, it helps to increase mocha's timeout setting a bit by using the -t argument. Check out mocha's documentation for complete details.
I wrote a lengthy reply to this question explaining important gotchas about asynchronous tests, good practices ('before()', 'after()', TDD, ...), and illustrated by a real world example.
http://redotheweb.com/2013/01/15/functional-testing-for-nodejs-using-mocha-and-zombie-js.html
if you want to use cucumber-js for your acceptance tests and mocha for your "unit" tests for a page, you can use cuked-zombie (sorry for the advertising).
Install it like described in the readme on github, but place your world config in a file called world-config.js
`/* globals __dirname */
var os = require('os');
var path = require('path');
module.exports = {
cli: null,
domain: 'addorange-macbook': 'my-testing-domain.com',
debug: false
};
Then use mocha with zombie in your unit tests like this:
var chai = require('chai'), expect = chai.expect;
var cukedZombie = require('cuked-zombie');
describe('Apopintments', function() {
describe('ArrangeFormModel', function() {
before(function(done) { // execute once
var that = this;
cukedZombie.infectWorld(this, require('../world-config'));
this.world = new this.World(done);
// this inherits the whole world api to your test
_.merge(this, this.world);
});
describe("display", function() {
before(function(done) { // executed once before all tests are run in the discribe display block
var test = this;
this.browser.authenticate().basic('maxmustermann', 'Ux394Ki');
this.visitPage('/someurl', function() {
test.helper = function() {
};
done();
});
});
it("something on the /someurl page is returned", function() {
expect(this.browser.html()).not.to.be.empty;
});