dasJulian
dasJulian

Reputation: 577

Chai & Mocha: Tests stop express server from listening

I wrote tests using chai. Here are just three example tests:

(In reality, there are more tests, please check out the repl linked)

File: tests/2_functional-tests.js

const chaiHttp = require('chai-http');
const chai = require('chai');
const assert = chai.assert;
const app = require('../app');

chai.use(chaiHttp);
const request = chai.request;

let id1;
let id2;

suite('Functional Tests', function() {
  test("Create an issue with every field: POST request to /api/issues/{project}", async () => {
    const res = await request(app)
    .post("/api/issues/testproject")
    .set('content-type', 'application/x-www-form-urlencoded')
    .send({
      issue_title: "Test issue",
      issue_text: "Test issue text",
      created_by: "Chai func test nr 1",
      assigned_to: "nobody :P",
      status_text: "didn't even start"
    });
    assert.equal(res.status, 200);
    let responseObj = JSON.parse(res.res.text);
    assert.equal(responseObj.issue_title, "Test issue");
    assert.equal(responseObj.issue_text, "Test issue text");
    assert.equal(responseObj.created_by, "Chai func test nr 1");
    assert.equal(responseObj.assigned_to, "nobody :P");
    assert.equal(responseObj.status_text, "didn't even start");
    assert.isTrue(responseObj.open);

        id1 = responseObj._id;     
  });

  test("Create an issue with missing required fields: POST request to /api/issues/{project}", async () => {
    const res = await request(app)
      .post("/api/issues/testproject")
      .set('content-type', 'application/x-www-form-urlencoded')
      .send({
        issue_title: "Test issue 3", //no issue_text
        created_by: "Chai func test nr 3"
      });
    assert.equal(res.status, 200);
    let responseObj = JSON.parse(res.res.text);
    assert.equal(responseObj.error, "required field(s) missing")
  });

  test("View issues on a project with multiple filters: GET request to /api/issues/{project}", async () => {
    const res = await request(app)
      .get("/api/issues/testproject?open=true&created_by=Chai+func+test+nr+1")

    assert.equal(res.status, 200);
    let responseObj = JSON.parse(res.res.text);

    assert.equal(responseObj.length, 1);
    assert.equal(responseObj[0].issue_text, "Test issue text");
    assert.equal(responseObj[0].status_text, "didn't even start");
    assert.equal(responseObj[0].created_by, "Chai func test nr 1");
    assert.equal(responseObj[0].open, true);
  });
});

These tests work all as expected. I don't get any errors. Nonetheless, these tests stop my express server from listening.

Here I am listening and then starting the test runner: (in the server.js file)

const listener = app.listen(process.env.PORT || 3000, function () {
  console.log('Your app is listening on port ' + listener.address().port);
  if (process.env.NODE_ENV === 'test') {
    console.log('Running Tests...');
    setTimeout(function () {
      try {
        runner.run();
      } catch (e) {
        console.log('Tests are not valid:');
        console.error(e);
      }
    }, 5000);
  }
});

When I start the server, it listens and all routes are available. However, after the test runner starts, the server stops listening and the routes stop working. But interestingly, if I remove the tests and run just the empty suite, like this:

const chaiHttp = require('chai-http');
const chai = require('chai');
const assert = chai.assert;
const app = require('../app');

chai.use(chaiHttp);
const request = chai.request;

let id1;
let id2;

suite('Functional Tests', function() {
});

...everything works fine and the server keeps listening.

The runner.run is in the test-runner.js file the emitter.run function.

const analyser = require('./assertion-analyser');
const EventEmitter = require('events').EventEmitter;

const Mocha = require('mocha'),
    fs = require('fs'),
    path = require('path');

const mocha = new Mocha();
let testDir = './tests'


// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file){
    // Only keep the .js files
    return file.substr(-3) === '.js';

}).forEach(function(file){
    mocha.addFile(
        path.join(testDir, file)
    );
});

let emitter = new EventEmitter();
emitter.run = function() {

  let tests = [];
  let context = "";
  let separator = ' -> ';
  // Run the tests.
  try {
  let runner = mocha.ui('tdd').run()
    .on('test end', function(test) {
        // remove comments
        let body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
        // collapse spaces
        body = body.replace(/\s+/g,' ');
        let obj = {
          title: test.title,
          context: context.slice(0, -separator.length),
          state: test.state,
          // body: body,
          assertions: analyser(body)
        };
        tests.push(obj);
    })
    .on('end', function() {
        emitter.report = tests;
        emitter.emit('done', tests)
    })
    .on('suite', function(s) {
      context += (s.title + separator);

    })
    .on('suite end', function(s) {
      context = context.slice(0, -(s.title.length + separator.length))
    })
  } catch(e) {
    throw(e);
  }
};

module.exports = emitter;

This is a project of the freecodecamp.org curriculum, and the test-runner.js is just from the starter project, so I didn't touch it and I don't think there is anything wrong with it.

What could be the problem? Could it be that something is severely wrong with the code structure?

Here is a link to the project on replit - Feel free to fork

- Before tests:

Image of server listening, tests have not yet executed

- After tests:

Image of tests passing, server not listening

Upvotes: 0

Views: 664

Answers (2)

stavrogyn
stavrogyn

Reputation: 79

This is replit's bag. It couses by .end method of chai.http: the server get dropped after test's running.

You could use following trick: add in your suite after chai's hook which will open your server after last test and will not end it.

after(function() {
  chai.request(server)
    .post('/api/translate')
    .send({
      text: "Paracetamol takes up to an hour to work.",
      locale: "british-to-american"
    })
});

Upvotes: 1

dasJulian
dasJulian

Reputation: 577

Looks like this is a problem of replit, everything works seamlessly if I download the files and run the server locally.

These tests were perhaps just too difficult to handle for the replit free tier server. But if I wait (5-10 minutes), the server will start listening again.

Unfortunately, I've made some edits to the link in the question, so maybe you won't be able to reproduce the error now. (these edits somehow reduced the waiting time heavily)

However, here is an older version of the project, which still has the error, but it has a different structure. Just in case anyone wants to take a look.

Upvotes: 0

Related Questions