Node.js Mocha Testing Restful API Endpoints and Code Coverage - javascript

I've been really enjoying Istanbul and experimenting with other Node.js coverage libraries as well, but I have an issue. Nearly all of my unit tests are HTTP calls to my API like so:
it('should update the customer', function (done) {
superagent.put('http://myapp:3000/api/customer')
.send(updatedData)
.end(function (res) {
var customer = res.body;
expect(res.statusCode).to.equal(200);
expect(customer.name).to.equal(updatedData.name);
done();
});
});
As opposed to actually requiring the customers.js file and calling updateCustomer directly. Testing the endpoint makes much more sense to me, as it not only tests updateCustomer, but also the routes, controllers, and everything else involved.
This works fine, but the problem is that I can't seem to see a way for any code coverage tool to recognize these tests. Is there any way for Istanbul or anything else to recognize these Mocha tests? If not, what is the convention? How do you test endpoints and still use code coverage tools?

The issue is that you're using superagent, whereas you should be using supertest to write unit tests. If you use supertest, istanbul will correctly track code coverage.
Some sample code to get you started:
'use strict';
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
var config = require('../../config/config');
var request = require('supertest');
var app = require('../../config/express')();
describe('Test API', function () {
describe('test()', function() {
it('should test', function(done) {
request(app)
.get('/test')
.query({test: 123})
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res){
expect(err).to.equal(null);
expect(res.body).to.equal('whatever');
done();
});
});
it('should return 400', function(done) {
request(app)
.get('/test/error')
.query({})
.expect('Content-Type', /json/)
.expect(400, done);
});
});
});

Related

Autotests with webpack-dev-server

I'm quite confused with topic.
I develop a some kind of lazy module assembler using webpack-dev-server. It finally works but sometimes we need more assurance. That's why I need some tests. The task is to make them a kind of autotests.
For now the code of server start looks like this (I omit excessive params).
import webpack from "webpack";
import webpackConfig from "../webpack.config.js";
import webpackCompileConfig from "../webpack-compiler.config.mjs";
import WebpackDevServer from "webpack-dev-server";
webpack(webpackConfig(mode, dirname, masterPath)).run(function(err) {
if (err) throw err;
const compileOpt = {
// pack of compiler options
};
const compiler = webpack(webpackCompileConfig(compileOpt));
const server = new WebpackDevServer(compiler, {
// pack of server options
});
server.listen(port, "0.0.0.0", err => {
if (err) throw err;
console.log(`Starting root server on 0.0.0.0:${port}`);
});
});
It starts and works properly: gets some file requests, bundles necessary modules with webpack and sends them to requester.Simple test I want to start with are to check are there files after assembling or not.
Supposed logic is:
Run some command inside this project, e.g. npm run test
It starts server and sends a pack of requests with different logic I want to test (parallel, simultaneous requests etc.)
It tests file existence and send me results in console or smth. of that sort
The problem is my very little expirience in any kind of testing so I'll appreciate your help.
===The way I use it now (spoiler: manually)
The only thing the Internet helps me about.
Server starts as usual
There is another fully off-site test module (code below)
Run mocha
See listed test results
test-server.js
var chai = require("chai");
var chaiHttp = require("chai-http");
const should = chai.should();
chai.use(chaiHttp);
describe("Test file existence", function() {
it("units", done => {
chai
.request("http://localhost:9000")
.get("/units/awesome-project/index.js")
.end((err, res) => {
res.should.have.status(200);
done();
});
});
// another 'it()'s to test other files
});
Yes, it works. But I want more automatisation. Just
Run server
Send requests
Get test results
I'm ready for dialog.
Well.. just sad that nobody ask.
Anyway I've found the answer by myself. And I even wonder how it was freaking easy. It seems that all I need is written here: https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically
So the final result is similar to this:
import fs from "fs";
import path from "path";
import Mocha from "mocha";
const mocha = new Mocha();
const testDir = `${config.dirname}/test/tests`;
fs.readdirSync(testDir)
.filter(file => file.match(/\.js$/))
.forEach(file => {
mocha.addFile(path.join(testDir, file));
});
// somewhere before the devserver start
const runner = mocha.timeout(30000).run();
runner.on("end", () => {
process.exit();
});
I found it at the day I posted this question but there was a hope for someone else to answer (to compare solutions).
Best regards,
Nick Rimer

Sinon Spy and Stub function through actual http request

I have a function which is called from an API. I can stub it using sinon if I directly call it in my test for example foo.bar(); But if I call it through a test that makes an http request to that function it doesn't get stubbed. Any ideas?
You need to be able to start your application from the tests, and you should structure you application in a way that you can inject the dependencies that you want to control.
In the code below I have tried showing how you can use link seams (using proxyquire) to control the dependencies, but you could also use direct dependency injection to your app (say, pass it in to the start() method) as an alternative.
The code below is instructive, not necessarily working, so it skips setting up http listeners properly, etc. That is left as an exercise for the reader ;)
app.js
const myModule = require('./my-module');
if (require.main === module) {
/// starting from the cli
start({});
}
module.exports = {
start(){
app.get(`/`, (req, res) => {
myModule.foo(req.data).then(res.send).catch(res.send);
});
});
stop(){
app.stop(); // somehow kill the http listener and shutdown
}
}
test.js
const stub = sinon.stub();
const myApp = proxyquire('../app.js',{'./my-module': {foo: stub } });
before(()=> {
myApp.start();
});
it('should call a sinon stub', (done) => {
request('localhost:3000/')
.then( result = > expect(stub.called).to.equal(true) )
.then(done, done);
});

Chai assertions not executed inside JSDOM Env block

I've just started writing my front-end unit tests with mocha, chai and jsdom. When I try to follow the tutorials based on those - I'm getting passing tests even when I set them to fail. Everything else is setup and works as expected jQuery, setup.js, window etc. The only issue is that my Assertions are not getting executed at all inside the jsdom env block.
This is my test:
var chai = require('chai'),
expect = chai.expect,
jsdom = require('jsdom'),
fs = require('fs'),
jquery = fs.readFileSync('./js/vendor/jquery-3.0.0.min.js', 'utf-8');
describe('UI DOM tests', function () {
it('should fail', function () {
// simple html
var htmlFragment = fs.readFileSync('./test/runner.html');
jsdom.env({
html: htmlFragment,
src: [jquery, '../node_modules/chai/chai.js'],
done: function (err, window) {
var $ = window.$;
expect(true).eql(false); // nothing happens
done();
}
});
expect(true).eql(false); // assert fails as expected
});
});
Any help is greatly appreciated.
it seems you're missing the done argument in your it:
it('should fail', function (done) {
otherwise mocha will think your it is synchronous and finish before your jsdom env is created.

How to unit test an node js express application [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to begin doing unit testing on my node express project. what would be the simplest and easiest way to do this ?
Here are a following links.
Mocha
Mocha is a feature-rich JavaScript test framework running on Node.js
and the browser, making asynchronous testing simple and fun. Mocha
tests run serially, allowing for flexible and accurate reporting,
while mapping uncaught exceptions to the correct test cases.
Karma
The main goal for Karma is to bring a productive testing environment
to developers. The environment being one where they don't have to
set up loads of configurations, but rather a place where developers
can just write the code and get instant feedback from their tests.
Chai
Chai is a BDD / TDD assertion library for node and the browser that
can be delightfully paired with any javascript testing framework.
Jasmine
Jasmine is a Behavior Driven Development testing framework for
JavaScript. It does not rely on browsers, DOM, or any JavaScript
framework. Thus it's suited for websites, Node.js projects, or
anywhere that JavaScript can run.
Blanket
Blanket.js is an easy to install, easy to configure, and easy to use
JavaScript code coverage library that works both in-browser and with
nodejs.
You may also follow the following tutorials
Getting started with Mocha and Chai
Introduction to Jasmine JS
Setting up a project using karma with mocha and chai
Node.js Testing Strategies
Unit Testing with Node.js
Mocha is a pretty solid solution for Node/Express. Their website has a getting started page. A simple example:
var assert = require("assert");
var request = require('supertest');
var express = require('express');
// Module under test
var version = require('version');
describe('server.routes.version', function() {
var app;
beforeEach(function(done) {
app = express();
app.use('/version', version);
done();
});
it('gets the product version', function (done) {
var expected = {
'version': '1.2.3'
}
request(app)
.get('/version')
.expect('Content-Type', /json/)
.expect(200, expected)
.end(function(err, res) {
if (err) throw err;
done();
});
});
});
If you need to mock out a Node module dependency (and eventually you probably will) things get a little more fiddly; I've had some success with a combination of sandboxed-module and sinon:
var assert = require("assert");
var sinon = require('sinon');
var request = require('supertest');
var express = require('express');
describe('server.routes.version', function() {
var app, version, mockConfig;
beforeEach(function(done) {
var mockConfig = sinon.mock({
getVersion: function() {}
});
// Load the tested module within a sandbox
var sandbox = require('sandboxed-module');
version = sandbox.require('../server/routes/version', {
requires: {
'../config': mockConfig
}
});
app = express();
app.use('/version', version);
done();
});
it('gets the product version', function (done) {
mockConfig.expects('getVersion').once().returns('1.2.3');
var expected = {
'version': '1.2.3'
}
request(app)
.get('/version')
.expect('Content-Type', /json/)
.expect(200, expected)
.end(function(err, res) {
mockConfig.verify();
if (err) throw err;
done();
});
});
});

How to test Express Routes that render a view

I am a bit stuck trying to test some Express Routes with SuperTest.
// Mocha test
..
request(app)
.get('/user')
.expect(200)
.end(function(err, res){
if (err) return done(err);
done()
});
...
// Router
app.get('/user', function(req, res){
res.render('user.jade');
});
The router works fine when I test it manually with the browser, and renders the jade template view but when I run the mocha tests it fails with 'Uncaught expected false to be true'. Express logs the request as successful (200), but the test still shows up as failed with the error message.
I have tried to use different code idioms for the SuperTest segment, different jade templates and it only seems to occur the first time I run a test on a router that renders a template. Following tests with GET even on the same router and template succeeeds???
Have tried to find code samples with routers that render a view without success, so perhaps this is an unsupported scenario?
var request = require('supertest');
var app = require('../server').app;
var jade = require('jade');
var should = require('should');
// ...
it('return user template', function(done){
request(app)
.get('/')
.end(function(err, res){
var html = jade.renderFile('./pathToJadeFile/user.jade');
res.text.should.equal(html);
done();
});
});

Categories