How to see output of `console.log` when running Jasmine tests - node.js

I've developed a Node.js module and I'm using Jasmine to write unit tests for it. The module uses console.log to print out some information as it executes when called with a verbose argument set to true.
Let's say the module looks like this:
foo.js
function foo(arg1, verbose){
var output = "Hello " + arg1;
if(verbose)console.log("Returning %s", output);
return output;
}
module.exports = foo;
Let's say my test looks like this:
foo-spec.js
const foo = require("path/to/foo")
describe("Foo suite", () => {
it( "Expect foo to greet", () => {
expect(foo("World", true)).toBe("Hello World");
});
});
I run my tests by typing jasmine in the terminal:
$ jasmine
Everything works well except I'd like to see the verbose output.
$ jasmine
Returning Hello World
Is there a way to make Jasmine do this?

Ok, I've sort of found a workaround for this. Spying on console.log somehow patched it.
foo-spec.js
const foo = require("path/to/foo")
describe("Foo suite", () => {
it( "Expect foo to greet", () => {
//This makes the log visible again from the command line.
spyOn(console, 'log').and.callThrough();
expect(foo("World", true)).toBe("Hello World");
});
});
Not sure why, but spyOn is making the logs visible again. Even though I'm not really doing anything with it, except invoking callThrough. My best guess is that by doing this, console.log is actually being called from the Jasmine process.

Related

Does Rewire set the current running module variables as well as the specified module variables?

So, I was doing some testing with Rewire with Mocha, and I noticed behavior that seems odd to me. using myModule.__set__() seems to actually set the specified variable in the the specified module (myModule), AND in the global scope of the current module (the one that ran the __set__()). For example:
This code runs after running mocha test:
Test.js:
var rewire = require("rewire")
var sinon = require("sinon")
var test2 = rewire("./test2.js")
var expect = require("chai").expect
var spy = sinon.spy()
describe("test", function () {
beforeEach(function () {
test2.__set__("console", { log: spy })
})
it("test should be equal to 3", function () {
test2.test1()
console.log("testing5")
expect(spy.callCount).to.equal(3)
})
})
Test2.js:
module.exports = {
test1() {
console.log("test")
console.log("test")
console.log("test")
}
}
Here, I would expect "testing5" to actually be logged to the console, but the 3 "test"s to just be recorded in the spy, and the callCount to be equal to 3. This is not what is happening however. The "testing5" is not being logged, but is being recorded to that sinon spy, and the test is failing, because the callCount is 4, and not 3. To me this doesn't seem like this would be intended. Is there something I'm doing wrong?

Jest cannot test commander help function

With jest I'm not able to test commander module functions that result in process exit.
For example, if I pass the --help option or an invalid parameter like -x (see below) process.exit or process.stdout.write are not called as they should looking at the commander sources.
import {Command} from "commander";
let mockExit: jest.SpyInstance;
let mockStdout: jest.SpyInstance;
beforeAll(() => {
mockExit = jest.spyOn(process, "exit").mockImplementation();
mockStdout = jest.spyOn(process.stdout, "write").mockImplementation();
});
afterAll(() => {
mockExit.mockRestore();
mockStdout.mockRestore();
});
test("Ask for help", () => {
// Setup
const save = JSON.parse(JSON.stringify(process.argv));
process.argv = ["--help"]; // Same setting it to "-x"
const program = new Command();
program
.option("-v, --verbose [level]", "verbose level")
.parse(process.argv);
expect(mockExit).toBeCalled();
// expect(mockStdout).toBeCalled();
// Cleanup
process.argv = save;
});
What is strange is that, from the behavior of other tests, process.argv is not restored after this one.
Tests are in typescript and passed through ts-jest.
Any ideas?
Thanks!
I suggest you use .exitOverride(), which is the approach Commander uses in its own tests. This means early "termination" is via a throw rather than exit.
https://github.com/tj/commander.js#override-exit-handling
The first problem though (from comments) is the arguments. Commander expects the parse arguments follow the conventions of node with argv[0] is the application and argv[1] is the script being run, with user parameters after that.
So instead of:
argsToParse = ["--help"];
something like:
argsToParse = ['node", "dummy.js", "--help"];
(No need to modify process.argv as such.)

Cannot run Mocha tests with phantomjs-node

I'm trying to use phantomjs-node with mocha to run some tests
var phantom = require('phantom');
phantom.create().then(function(ph) {
ph.createPage().then(function(page) {
page.open('http://localhost:8900').then(function(status) {
console.log(status);
if ( status === "success" ) {
page.injectJs("../node_modules/mocha/mocha.js");
page.injectJs("../node_modules/chai/chai.js");
//inject your test reporter
page.injectJs("testMocha/reporter.js");
//inject your tests
tests.forEach(function(test) {
page.injectJs(test);
})
page.property('evaluate').then(function() {
window.mocha.run();
});
}else{
ph.exit();
}
});
});
});
I run the file with
node myFile.js
But when I run the file nothing shows up in the console, none of my tests are run, and the script hangs.
If I do it without phantomjs-node I'm able to run and display my tests, launching the file with
phantomjs myFile.js
but I need phantomjs-node to do other things needed for my tests. How can I mocha with phantomjs-node?
The solution to my problem was that first i needed to start the evaluate this way :
page.evaluate(function() {
I thought i had to do page.property('evaluate').then(function() { cause i was using phantomjs-node but that's not the case
And second the reason i couldn't see my tests results from mocha is because in my reporter file i was displaying the result with callPhantom :
window.callPhantom({ message: args.join(" ") });
But with phantomjs-node this doesn't seem to work so instead just do a simple console.log
console.log( args.join(" ") );
An exemple of the reporter i use and a great tutorial on how to use phantomJS and mocha together can be found there :
http://doublenegative.com/phantomjs-mocha-and-chai-for-functional-testing/

NodeJS - Requiring module returns empty array

Writing the simplest module we could, we write into hello.js:
var hello = function(){
console.log('hello');
};
exports = hello; \\ Doesn't work on Amazon EC2 Ubuntu Instance nor Windows Powershell
I run Node and require the module
var hello = require('./hello');
hello;
and an empty array {} gets returned when I'm supposed to get [Function].
I tried replacing exports with module.exports, but this doesn't work on my Windows Powershell. It does work on my Amazon EC2 Ubuntu Instance, so why doesn't exports work? Has the API changed? And what could possibly be happening with Powershell that neither of these work?
I know Windows isn't the most desirable development environment, but I can't get my head around such a simple mishap.
EDIT
exporting with ES6 is a little nicer
export const hello = function(){
console.log('hello');
};
importing will look like
import {hello} from './file';
Original answer
You'll want to use module.exports
var hello = function(){
console.log('hello');
};
module.exports = hello;
If just exporting one thing, I'll usually do it all in one line
var hello = module.exports = function() {
console.log('hello');
};
Extras
If you use a named function, in the event an error occurs in your code, your stack trace will look a lot nicer. Here's the way I would write it
// use a named function ↓
var hello = module.exports = function hello() {
console.log("hello");
};
Now instead of showing anonymous for the function name in the stack trace, it will show you hello. This makes finding bugs so much easier.
I use this pattern everywhere so that I can debug code easily. Here's another example
// event listeners ↓
mystream.on("end", function onEnd() {
console.log("mystream ended");
};
// callbacks ↓
Pokemon.where({name: "Metapod"}, function pokemonWhere(err, result) {
// do stuff
});
If you want to export multiple things, you can use exports directly, but you must provide a key
// lib/foobar.js
exports.foo = function foo() {
console.log("hello foo!");
};
exports.bar = function bar() {
console.log("hello bar!");
};
Now when you use that file
var foobar = require("./lib/foobar");
foobar.foo(); // hello foo!
foobar.bar(); // hello bar!
As a final bonus, I'll show you how you can rewrite that foobar.js by exporting a single object but still getting the same behavior
// lib/foobar.js
module.exports = {
foo: function foo() {
console.log("hello foo!");
},
bar: function bar() {
console.log("hello bar!");
}
};
// works the same as before!
This allows you to write modules in whichever way is best suited for that particular module. Yay!
The reason exports is not working is because of the reference conflict. The top variable in each file is module which has a property module.exports. When the module is loaded new variable is created in the background. Something like this happens:
var exports = module.exports;
Obviously exports is a reference to module.exports, but doing
exports = function(){};
forces exports variable to point at function object - it does not change module.exports. It's like doing:
var TEST = { foo: 1 };
var foo = TEST.foo;
foo = "bar";
console.log(TEST.foo);
// 1
Common practice is to do:
module.exports = exports = function() { ... };
I have no idea why it doesn't work under Windows Powershell. To be honest I'm not even sure what that is. :) Can't you just use native command prompt?

Mocha and ZombieJS

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;
});

Resources