1

I'm trying to test some data through a REST API. The data is stored as an array in the project.

I want the data to be "restored" every time a test suites runs, so that i know the amount of data in the array.

But when im testing the post. The element that is inserted is there in the next test suite, even though i start and stop the server before each test.

app.js requires the user array, so by stopping and starting the server, i thought i would be clean before every test, but it doesn't

Thansk .

 global.test = true;

    // Test server setup
    var app = require('../app');
    var testPort = 9999;
    var testServer;

    // Dependencies
    var should = require('should');
    var request = require('request');

    var baseUrl = 'http://localhost:9999/api';

    describe('RESTApi : GET Methods', function () {
        //Start the Server before the TESTS
        beforeEach(function (done) {

            testServer = app.listen(testPort, function () {
                console.log("Server is listening on: " + testPort);
                done();
            })
                .on('error', function (err) {
                    console.log(err);
                });
        });

        afterEach(function () {  //Stop server after the test
            testServer.close(function () {
                console.log("closing server");
            });
        });

     TEST here           

    });

    describe('RESTApi : POST Methods', function () {
        //Start the Server before the TESTS
        before(function (done) {

            testServer = app.listen(testPort, function () {
                console.log("Server is listening on: " + testPort);
                done();
            })
                .on('error', function (err) {
                    console.log(err);
                });
        });

        after(function () {  //Stop server after the test
            testServer.close(function () {
                console.log("closing server");
            });
        });

       TEST here

    });

------ App.js ----- I know the REST api should be in its own folder. :)

var path = require('path');
        var bodyParser = require('body-parser');

        //For testing to delete the cached user array
        delete require.cache[require.resolve('./users')];

        var users = require('./users');
        var express = require('express');

        function findUser(users, email) {
            var result = users.filter(function(u) {
                return u.email === email;
            });
            if(result.length >= 1) {
                return result[0];
            }
            return undefined;
        }

        var app = express();

        app.use(bodyParser.json());
        app.use(bodyParser.urlencoded({ extended: false }));


        app.get("/api/users", function(req, res) {
            res.send(users);
        });

        app.get("/api/users/:email", function(req, res) {
            var user = findUser(users, req.params.email);
            if(!user) {
                return res.status(404).send({error: "user not found"});
            }
            res.send(user);
        });

        app.post("/api/users", function(req, res) {
            var user = req.body;
            if(findUser(users, user.email)) {
                return res.status(400).send({error: "user exist"});
            }
            users.push(user);
            res.send(user);
        });

        app.put("/api/users/:email", function(req, res) {
            var user = req.body;
            if(!findUser(users, req.params.email)) {
                return res.status(404).send({error: "user not found"});
            }
            if(!user) {
                return res.status(404).send({error: "no user provided"});
            }
            for(var i = 0; i < users.length; i += 1) {
                if(users[i].email === user.email) {
                    users[i].password = user.password;
                    break;
                }
            }
            res.send(user);
        });

        app.delete("/api/users/:email", function(req, res) {
            var user = findUser(users, req.params.email);
            if(!user) {
                return res.status(404).send({error: "user not found"});
            }
            for(var i = 0; i < users.length; i++) {
                if(users[i].email === req.params.email) {
                    users.splice(i, 1);
                    break;
                }
            }
            res.send(user);
        });

        app.all('*', function(req, res) {
            res.status(500).send(req.url + " not a valid");
        });

        if(global.activeTest === undefined){
            app.listen(3000, function() {
                console.log("Rest API started, listen on port 3000");
            });
        }

        module.exports = app;
msDefua
  • 13
  • 3
  • Can you show `app.js`? – JME Jun 01 '15 at 22:26
  • Sure, its added. I tried removing the cashed data and that worked. But if there is a better way let me know :) – msDefua Jun 03 '15 at 16:57
  • Thanks for adding the `app.js` code. Removing the cached required users really worked? It doesn't make sense to me, but I can't argue with you if you actually tried/tested it. I was going to propose a different solution involving refactoring the code that initialized the `user` var in to a function and exposing it so that you can "re-initialize" it before each test. I'll post my proposed solution shortly. – JME Jun 03 '15 at 23:04

2 Answers2

0

It looks like app.listen() is asynchronous, so your tests continue to run regardless of whether the server is stopped. I would put your tests inside the callback parameter.

beautifulcoder
  • 10,832
  • 3
  • 19
  • 29
0

My solution (as I mentioned in my comment above) would be to refactor the code that initializes the users var into a separate function, that can be called before each test.

var path = require('path');
var bodyParser = require('body-parser');
var express = require('express');
var clone = require('clone'); // <-- add `clone` as a dependency

var users;
function initUsers() {
  users = clone(require('./users'));
}

// ... the rest if your code, initializing express/adding route handlers

app.listen(3000, function() {
  console.log("Rest API started, listen on port 3000");
});

module.exports = exports = app;
exports.initUsers = initUsers;

Using this as my sample data in users.js:

module.exports = [
  { email: 'email0', password: 'password0' },
  { email: 'email1', password: 'password1' },
  { email: 'email2', password: 'password2' },
  { email: 'email3', password: 'password3' },
  { email: 'email4', password: 'password4' },
  { email: 'email5', password: 'password5' },
  { email: 'email6', password: 'password6' },
  { email: 'email7', password: 'password7' },
  { email: 'email8', password: 'password8' },
  { email: 'email9', password: 'password9' }
];

I was able to successfully test by calling initUsers() before each test, as follows:

var app = require('../app');
var initUsers = require('../app').initUsers;

var should = require('should');
var request = require('request');

var baseUrl = 'http://localhost:3000/api';

describe('RESTApi', function() {

  describe('GET Methods', function () {

    beforeEach(function() {
      initUsers();
    });

    it('should get all users initially', function(done) {
      request(baseUrl + '/users', function(err, res) {
        var data = JSON.parse(res.body);
        data.length.should.equal(10);
        done();
      });
    });

    it('should remove user', function(done) {
      request.del(baseUrl + '/users/email1', function(err, res) {
        var data = JSON.parse(res.body);
        data.email.should.equal('email1');
        data.password.should.equal('password1');

        request(baseUrl + '/users', function(err, res) {
          var data = JSON.parse(res.body);
          data.length.should.equal(9);
          done();
        });

      });
    });

    it('should get all users again', function(done) {
      request(baseUrl + '/users', function(err, res) {
        var data = JSON.parse(res.body);
        data.length.should.equal(10);
        done();
      });
    });

  });

});

As you can see, I wrote three tests.

  1. get all users (verifying the initial count is 10)
  2. removing a user (verifying the count is now 9)
  3. get all users (verifying count is now 10 again)

These are, by no means, exhaustive tests, but they verify that users is being properly initialized before every test.

JME
  • 3,592
  • 17
  • 24
  • Just what i was looking for, thanks alot!. In your version of app.js you use module.exports = exports = app; What the difference between that and module.exports = app; – msDefua Jun 04 '15 at 16:47
  • Your welcome. The `module.exports`/`exports` issue is beyond the scope of this question. If you want the technical difference check out the [NodeJS doc](https://nodejs.org/api/modules.html#modules_module_exports). Also, the question has already be asked/answered in stackoverflow, see [here](http://stackoverflow.com/questions/7137397/module-exports-vs-exports-in-node-js). – JME Jun 04 '15 at 21:50