bbyars / mountebank

Over the wire test doubles
http://www.mbtest.org
MIT License
2k stars 262 forks source link

Mocha test hangs after all tests pass when `imposters` endpoint is called. #757

Open noel-yap opened 6 months ago

noel-yap commented 6 months ago

Expected behaviour

Mocha exits.

Actual behaviour

Mocha hangs after all tests pass.

Steps to reproduce

Contents of server.test.js:

import request from "supertest";

import {server} from "./server.js";

describe("Mountebank API Test", function () {
  before(function (done) {
    console.log("Mountebank starting…");
    server.start(8080)
        .then(() => {
          console.log("Mountebank started");
          done();
        });
  });

  after(function (done) {
    console.log("Mountebank stopping…\n");
    server.stop(() => {
      console.log("Mountebank stopped\n");
      done();
    });
  });

  describe("mountebank port", function () {
    const req = request(config.MB_AUTHORITY);

    it("should return a successful response from Mountebank", function (done) {
      req
          .get("/")
          .expect(200)
          .expect("Content-Type", "application/json; charset=utf-8")
          .end(done);
    });
  });
});

Contents of server.js:

import mb from "mountebank";

import {mbh} from "./mountebank-helper.js";

export const server = {
  mbApp: null,

  start: (port) => {
    return mb.create({
      loglevel: "debug",
      port: port,
    }).then((app) => {
      server.mbApp = app;

      return mbh.postImposter({
        protocol: "http",
      });
    });
  },

  stop: (done) => {
    server.mbApp.close(done);
  }
};

Contents of mountebank-helper.js:

import superagent from "superagent";

export const mbh = {
  postImposter: (body) => {
    return superagent
        .post("http://localhost:8080/imposters")
        .set("Content-Type", "application/json")
        .send(body)
        .then(() => {
          console.log(`Imposter created`);
        }).catch((err) => {
          throw new Error(`Failed to create imposter: ${err}`);
        });
  }
};

Software versions used

OS         :
mountebank : 2.9.1
Installation method : pnpm

Log contents in mb.log when running mb --loglevel debug

{"level":"info","message":"[mb:8080] mountebank v2.9.1 now taking orders - point your browser to http://localhost:8080/ for help","timestamp":"2024-03-02T01:22:05.621Z"}
{"level":"info","message":"[mb:8080] POST /imposters","timestamp":"2024-03-02T01:22:05.633Z"}
{"level":"info","message":"[http:8081] Open for business...","timestamp":"2024-03-02T01:22:05.638Z"}
{"level":"info","message":"[mb:8080] GET /","timestamp":"2024-03-02T01:22:05.644Z"}
{"level":"info","message":"[mb:8080] Adios - see you soon?","timestamp":"2024-03-02T01:22:05.647Z"}
noel-yap commented 6 months ago

The following fixes the problem:

Contents of server.js:

export const server = {
  mbApp: null,

  start: (port) => {
    return mb.create({
      loglevel: "debug",
      port: port,
    }).then((app) => {
      server.mbApp = app;

      return mbh.registerImposter(xifin.getImposter());
    });
  },

  stop: (done) => {
    mbh.deregisterImposters()
        .then(() => {
          server.mbApp.close(done);
        })
  }
};

Contents of mountebank-helper.js:

export const mbh = {
  registerImposter: (body) => {
    return superagent
        .post(`${config.MB_AUTHORITY}/imposters`)
        .set("Content-Type", "application/json")
        .send(body)
        .then(() => {
          console.log(`Imposter "${body.name}" created`);
        }).catch((err) => {
          throw new Error(`Failed to create "${body.name}" imposter: ${err}`);
        });
  },

  deregisterImposters: () => {
    return superagent
        .delete(`${config.MB_AUTHORITY}/imposters`)
        .then(() => {
          console.log("All imposters deregistered")
        }).catch((err) => {
          throw new Error(`Failed to deregister imposters: ${err}`)
        })
  }
};

I do think, though, that it's unexpected that when calling close on the app, it doesn't cleanup all other resources its holding.