Why are the nightmare.js examples not working? - node.js

var Nightmare = require('nightmare');
var expect = require('chai').expect; // jshint ignore:line
describe('test yahoo search results', function() {
it('should find the nightmare github link first', function*() {
var nightmare = Nightmare()
var breadcrumb = yield nightmare
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit')
.wait('.url.breadcrumb')
.evaluate(function () {
return document.querySelector('.url.breadcrumb').innerText;
});
expect(breadcrumb).to.equal('github.com');
});
});
Why does this test always evaluate to true?
This test evaluates to true even if I change the comparison value. If I add a console.log before the expect, it does not print, which makes me thing the test is never being evaluated and that a null response is true for chai. I am running node v4.2.2, and the latest versions of nightmare and expect. I run the test from the terminal using mocha index.js (the name of this file).

function* and yield is a ES2015 feature called Generators.
There's a additional note after the example on the README:
Please note that the examples are using the mocha-generators package for Mocha, which enables the support for generators.
So you need to install the package and add this to your code:
require('mocha-generators').install();

Related

"Write after end": how to imitate gulp-watch with watchify?

The following Gulp task does almost what I want.
const gulp = require('gulp');
const browserify = require('browserify');
const vinylStream = require('vinyl-source-stream');
const vinylBuffer = require('vinyl-buffer');
const watchify = require('watchify');
const glob = require('glob');
const jasmineBrowser = require('gulp-jasmine-browser');
gulp.task('test', function() {
let testBundler = browserify({
entries: glob.sync('src/**/*-test.js'),
cache: {},
packageCache: {},
}).plugin(watchify);
function updateSpecs() {
return testBundler.bundle()
.pipe(vinylStream(jsBundleName))
.pipe(vinylBuffer())
.pipe(jasmineBrowser.specRunner({console: true}))
.pipe(jasmineBrowser.headless({driver: 'phantomjs'}));
}
testBundler.on('update', updateSpecs);
updateSpecs();
});
It bundles all my Jasmine specs using Browserify and has them tested through gulp-jasmine-browser. It also watches all specs and all modules that they depend on and re-runs the tests if any of these modules changes.
The only ugly bit, which I'd really like to see solved, is that a new PhantomJS instance and a new Jasmine server are created every time updateSpecs is run. I was hoping to avoid that with code like the following:
gulp.task('test', function() {
let testBundler = browserify({
entries: glob.sync('src/**/*-test.js'),
cache: {},
packageCache: {},
}).plugin(watchify);
// persist the Jasmine server and PhantomJS browser
let testServer = jasmineBrowser.headless({driver: 'phantomjs'});
function updateSpecs() {
return testBundler.bundle()
.pipe(vinylStream(jsBundleName))
.pipe(vinylBuffer())
.pipe(jasmineBrowser.specRunner({console: true}))
.pipe(testServer);
}
testBundler.on('update', updateSpecs);
updateSpecs();
});
Alas, this doesn't work. Right after starting the task, all tests run fine, but the next time updateSpecs is called, I get a write after end error and the task exits with status 1. This error originates from the readable-stream Node module.
As I understand it, the end event during the first run of updateSpecs leaves testServer in a state in which it doesn't accept any new inputs. Unfortunately, the Node.js streams documentation isn't very clear on how to remedy this.
I have tried breaking the pipe chain at a different place, but I got the same result, which seems to indicate this is universal behaviour for streams. I also tried stopping the end event from propagating by inserting a through-stream that didn't re-emit that event, but this prevented the tests from being run at all. Finally, I tried returning the testServer stream from the task; this stopped the error, but although the updateSpecs function gets called every time the sources change, the tests are only being run the first time the task starts. This time, the testServer simply seems to ignore the new input.
The gulp-jasmine-browser documentation suggests that the following code would work:
var watch = require('gulp-watch');
gulp.task('test', function() {
var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
return gulp.src(filesForTest)
.pipe(watch(filesForTest))
.pipe(jasmineBrowser.specRunner())
.pipe(jasmineBrowser.server());
});
And it goes on to suggest that you can also make this work with Browserify, but this isn't illustrated. Apparently, gulp-watch does something which causes the follow-up pipes to accept updated inputs later. How can I imitate this behaviour with watchify?
GitHub issue
As it turns out, it is a hard rule in Node.js that you cannot write after the end event. In addition, jasmineBrowser.specRunner(), .server() and .headless() must receive the end signal in order to actually test anything. This restriction is inherited from the official Jasmine test runner.
The example with gulp-watch from the README doesn't actually work, either, for the same reason. In order to make it work, one would have to do something similar to the working version of my watchify code in the question:
gulp.task('test', function() {
var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
function runTests() {
return gulp.src(filesForTest)
.pipe(jasmineBrowser.specRunner())
.pipe(jasmineBrowser.server());
}
watch(filesForTest).on('add change unlink', runTests);
});
(I didn't test it, but something very close to this should work.)
So whatever watching mechanism you're using, you'll always need to call .specRunner() and .server() again for every cycle. The good news is that apparently, the Jasmine server will be reused if you explicitly pass a port number:
.pipe(jasmineBrowser.server({port: 8080}));
this also applies to .headless().

Expect and should use the Promise object instead of the resolved result

I have the following setup for my unit testing:
const mocha = require('mocha')
var chai = require('chai')
var chaiAsPromised = require('chai-as-promised')
chai.use(chaiAsPromised)
var expect = chai.expect
chai.should()
describe('chain test', function() {
it('should be a string', function() {
return Promise.resolve('string').should.to.be.a('string');
});
});
But when I run mocha, then the result is:
1) chain test should be a string:
AssertionError: expected {} to be a string
So it seems as if the test is done against the Promise object itself and not against the resolved result.
According to chai-as-promised: Installation and Setup the setup is correct.
And the test is created the same way as described in chai-as-promised: How to Use.
I have tested both the expect(promise). and the promise.should syntax. Does anyone know what the problem could be?
The used versions of node and the modules are:
node v4.6.1
chai 3.5.0
chai-as-promised 6.0.0
mocha 3.2.0
I found the mistake.
The problem is that the correct syntax is not .should.to.be but has to be .should.eventually.be

Unit test for node js

I am new to nodejs, and need to write unit test for a node project. I try to learn mocha and there are two questions:
when I write unit test for function A, in A it also use function B, so how can I mock an output for B?
how can I unit test these endpoints in app.js. like app.get, app.put.
can someone give me some suggestions or simple examples?
Can someone also give me some advice on writing unit test for nodejs, thanks so much.
Thanks so much everyone.
Answering Q1,
If the output of b method is used in a metheod, then you can make the test of b method first.
Otherwise you can prepare result of b in before section of your test method and use it in a method.
It depends on your approach of testing.
Answering Q2 -
You can use superagent for sending get or post request ...
Some code examples ...
require('should');
var assert = require("assert");
var request = require('superagent');
var expect = require('expect.js');
then,
describe('yourapp', function(){
before(function(){
// function start
start your server code
// function end
})
describe('server', function(){
describe('some-description', function(){
it('should return json in response', function(done){
request.post('http path')
.send(JSON.parse("your json"))
.end(function(res){
expect(res).to.exist;
expect(res.status).to.equal(200);
expect(res.text).to.contain('ok');
done();
});
})
});
})
after(function(){
//stop your server
})
});
Here done is an important aspect in a unit testing component for asynchronous method testing.
Some reference -
superagent
this blog post
Hope this will help you,
Thanks
Answering Q1,
If the funcitons in different modules,
You can use a mock tool : fremock
Using freemock You can do this:
your code
//function a exports in the module named mA
function a(){
return "1";
}
//function a exports in the module named mB
function b(){
a();
}
test code
var freemock = require('freemock');
freemock.start()
var mock_b = freemock.getMock('mB');
mock_b.setMethod({
"a":{
willReturn:"1"
}
})
freemock.end();
Some advice:
Mocha is good test framework for node.js .
For example,
Assert tool: should.js
Code coverage tool:istanbul
...
Mocha combines all this tools;
Here is a demo using Mocha:
your code(filename:mA.js)
//in the module named mA
function a(){
return true;
}
test code(filename:testmA.js)
var should = require('should');
beforeEach(function(){
//do something before testing
});
afterEach(function(){
//do something after testing
});
describe("test",function(){
describe("test1",function(){
it("if true",function(){
var mA = require('./mA');
var result = mA.a();
should.ok(result);
});
it("if false",function(){
//other test
});
});
describe("test2",function(){
it("test2-1",function(){
//other test
})
})
})
We should need run.js to start the test:
//run.js
var Mocha = require('mocha');
var mocha = new Mocha;
mocha.addFile(__dirname+'/test/testmA.js')
mocha.run();
The project dir tree is:
|- run.js
|
|- mA.js
|
|- test - testMA.js
Finally
Run this command:
istanbul cover run.js
Hope you enjoy!
I am recently involved in a node project where I have to run unit tests.
Eventually I wrote a small script runner for karma using NW.JS
This allowed me to access all node modules and run my tests on the server itself. I uploaded this project to github, Narma.
Right now it was only tested on a Mac

Bootstrapping a Mocha test suite

I have numerous tests spread across multiple files in a Node JS application. I'd like to run bootstrap code prior to Mocha's execution of any of the test files. This is so that I can, for example, set globals to be used in each of the actual tests.
Sample bootstrap code
global.chai = require('chai');
global.expect = chai.expect;
global.sinon = require('sinon');
It seems Mocha loads all files under /test alphabetically, so if I name this bootstrap code "bootstrap.js" and everything else with a starting letter after "B" it "works".
Obviously this is fragile and sucky, but I don't want to put this boilerplate requiring of my supporting libraries at the top of every test file.
How do I tell Mocha to load a bootstrap script first, or create something functionally equivalent?
have you tried mocha --require mymodule.js TESTS_DIR
from the documentation
-r, --require
The --require option is useful for libraries such as should.js, so you
may simply --require should instead of manually invoking
require('should') within each test file. Note that this works well for
should as it augments Object.prototype, however if you wish to access
a module's exports you will have to require them, for example var
should = require('should').
you could also write at the top of each test to load the require("./bootstrap.js") and run tests.
I use mocha's flag --delay
If you need to perform asynchronous operations before any of your
suites are run, you may delay the root suite. Simply run Mocha with
the --delay flag. This will provide a special function, run(), in the
global context.
setTimeout(function() {
// do some setup
describe('my suite', function() {
// ...
});
run();
}, 5000);
If prior to running Mocha you want to first run some bootstrap code in a file that uses ECMAScript 2015 Module syntax (i.e. import instead of require)
Create the following files:
./setupBabel.js (to bootstrap Babel transpiler)
require('babel-polyfill');
require('babel-register');
./setupDependencies.js (to bootstrap Chai and Sinon using ES2015 syntax)
import chai from 'chai';
import sinon from 'sinon';
global.expect = chai.expect;
global.sinon = sinon;
./test/codeSpec.js (example Unit Test using Chai, Sinon Stubs, Spies, and ES2015 syntax such as arrow functions, let, and const)
describe('test suite', () => {
it('does not modify immutable constant value', () => {
const myStub = sinon.stub();
const mySpy = sinon.spy(myStub);
myStub.returns({});
let val = 1;
expect(val).to.not.equal(2);
sinon.assert.notCalled(mySpy);
});
});
Run the following in terminal to install relevant NPM packages:
npm install babel-polyfill babel-register chai sinon mocha
Run the test suite with the following terminal command and flags:
mocha --require ./setupBabel.js --require ./setupDependencies.js ./test/codeSpec.js
describe('异步钩子测试', function () {
const lover = {
bodyname: 'yueyue',
girlname: 'fangfang'
}
const test = 'lihang'
beforeEach('每一个测试之前的钩子', function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('通过')
})
})
})
it('方方爱张越', function () {
// 是否等于yueuyue
expect(lover.bodyname).to.equal('yueyue')
// 是否是一个字符串
lover.girlname.should.equal('fangfang')
})
})

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