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

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

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

Running javascript e2e tests on a local appium server

I'm wanting to run e2e tests written in javascript with mocha on an Appium server instance running a local android emulator. The app on test is an apk originally written in react-native.
On Windows I have the server up and running with an Android Studio emulator through using the Appium desktop app. The server all looks good and has the apk of the native app I want to test working fine. I also have a basic describe/assert test written in mocha that I want to apply to the app.
My question is what do I need to include (presumably in the test file) to make the tests actually test the emulator application? I'm finding the documentation pretty confusing and the sample code seems pretty specific to a different use case.
Many thanks for your help!
There are at least 2 good js client libraries to use for Appium based project: webdriverio and wd. Personally, I'm using the second one so I can advice you how write tests with it and mocha:
my test file looks like this:
'use strict'
require(path.resolve('hooks', 'hooks'))
describe('Suite name', function () {
before('Start new auction', async function () {
//do before all the tests in this file, e.g. generate test data
})
after('Cancel auction', async function () {
//do after all the tests in this file, e.g. remove test data
})
it('test1', async () => {
// test steps and checks are here
})
it('test2', async () => {
// test steps and checks are here
})
it('test3', async () => {
// test steps and checks are here
})
})
where hooks.js contains global before/after for all the tests:
const hooks = {}
before(async () => {
// before all the tests, e.g. start Appium session
})
after(async () => {
// after all the tests, e.g. close session
})
beforeEach(async () => {
// before each test, e.g. restart app
})
afterEach(async function () {
// e.g. take screenshot if test failed
})
module.exports = hooks
I'm not saying its the best practice of designing tests, but its one of multiple ways.
Cool so I managed to get it working to a degree. I was checking through the Appium console logs as I was trying to run stuff and noticed that the session id was missing from my requests. All that was needed was to attach the driver using the session id. My code looks a bit like this:
"use strict";
var wd = require("wd")
var assert = require("assert")
var serverConfig = {
host: "localhost",
port: 4723,
}
var driver = wd.remote(serverConfig)
driver.attach("0864a299-dd7a-4b2d-b3a0-e66226817761", function() {
it("should be true", function() {
const action = new wd.TouchAction()
action
.press({x: 210, y: 130})
.wait(3000)
.release()
driver.performTouchAction(action)
assert.equal(true, true)
})
})
The equals true assert is just there as a placeholder sanity check. The only problem with this currently is that I'm copy-pasting the alpha-numeric session id inside the attach method each time I restart the Appium server so I need to find a way to automate that.

Mock backend in nightwatch.js tests

In my Vue.js app I'm using nightwatch to test my app. I have the following spec:
module.exports = {
'wrong email or password': function (browser) {
const devServer = browser.globals.devServerURL
var nock = require('nock');
var couchdb = nock('http://localhost:3000/')
.get('api/v1/login')
.reply(401, {
error: 'dupa'
});
browser
.url(devServer + '/login')
.setValue('input[type=email]', 'email#example.com')
.setValue('input[type=password]', 'password')
.click('.login')
.assert.containsText('#app', 'Niepoprawny email lub hasło.')
.end()
}
}
In my test I'm trying to use https://github.com/node-nock/nock. But unfortunately this not mocks any requests. What I'm doing wrong?
Nock replaces the HTTP mechanism in the browser environment in which it is run.
Since you're running it in your test, which isn't running in the browser, the browser environment is unchanged.
There are several things you could do, but that depends on what you're trying to achieve:
You could write a fake server and have it listen at port 3000 and answer any way you like.
You could configure your application to use a different mechanism according to configuration, and have it load a Nock 'strategy' in the test.
If you have other tests checking the UI, you could replace this test with unit tests and integration tests for the functions that do the actual requests.
To write a fake, you just need a simple server that returns the answer you want. Here's an example with express.js:
const express = require('express')
const app = express()
app.get('/api/v1/login', function (req, res) {
res.send('Some response')
})
app.listen(3000, function () {
console.log('server listening on port 3000')
})

Is it possible to make Mocha wait for a Promise to resolve, which sets up the Express app?

I am working on an older Express app and upgrading it to use a remote secrets storage service. Inside the app entry point I have something like:
getSecrets.then(secrets => {
...
const app = express();
// configure app...
// start server...
});
Previously this was a synchronous operation and there was a module.exports = app which was required later in a required Mocha module.
Now when the tests run, of course this doesn't work. I have attempted to export the Promise and tried to make some tests wait for it, but not having much luck.
Does anyone have any recommendations on this? I don't really find anything out there quite like this.
The root issue is that the tests require the app to be set up so that require can do HTTP requests against the routes.
Is there some way to make Mocha wait for the Promise to resolve if I returned the app?
This app uses Gulp.
var $ = require('gulp-load-plugins')();
var _ = require('lodash');
var gulp = require('gulp-help')(require('gulp'));
var config = require('../config.js').mocha;
// TODO: gulp-order is required to deal with some of the order-dependent
// tests
gulp.task(
'mocha',
'Runs mocha with NODE_ENV = env.NODE_ENV || \'test\'',
function() {
var mochaOptions = _.extend({}, config.options, {
NODE_ENV: process.env.NODE_ENV || 'test',
});
return gulp.src(config.src)
.pipe($.order(config.src))
.pipe($.cached('mocha'))
.pipe($.spawnMocha(mochaOptions));
}
);
The app is set to a global inside the config file.
Simple answer: Set up a separate app for Mocha to test with using the same routes/config defaults.

Node.js Mocha Testing Restful API Endpoints and Code Coverage

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

Categories