3

After looking into the questions:

  1. Async setup of environment with Jest
  2. window/document not defined in import
  3. Configure Jest global tests setup with .ts file (TypeScript)
  4. About app.listen() callback
  5. How to write a Jest configuration file
  6. NodeJS: How to get the server's port?
  7. https://alligator.io/nodejs/serving-static-files-in-express/
  8. Promisify server.listen
  9. Unexpected token import in custom node environment
  10. How to access class properties of Jest Test Environment inside child test?
  11. Cannot create custom TestEnvironment in Jest
  12. globalSetup is executed in different context than tests
  13. global beforeAll
  14. How to test url change with Jest
  15. Specify window.location for each test file for Jest
  16. window.location.href can't be changed in tests
  17. global beforeAll
  18. How do I test a single file using Jest?
  19. https://basarat.gitbook.io/typescript/intro-1/jest

I was able to do this:

package.json

{
  "name": "my-project",
  "jest": {
    "testEnvironment": "./testEnvironment.js",
  }
}

testEnvironment.js

const express = require('express');
// const NodeEnvironment = require('jest-environment-node'); // for server node apps
const NodeEnvironment = require('jest-environment-jsdom'); // for browser js apps

class ExpressEnvironment extends NodeEnvironment {
  constructor(config, context) {
    super(config, context);
  }

  async setup() {
    await super.setup();
    const app = express();

    this.global.server = app.listen(0, "127.0.0.1", () => {
        console.log(`Running express server on '${JSON.stringify(server.address())}'...`);

        how to make setup() wait until app.listen callback is finished, 
        i.e., the server has properly started.

    });
    app.use(express.static('../testfiles'));
  }

  async teardown() {
    this.global.server.close();
    await super.teardown();
  }

  runScript(script) {
    return super.runScript(script);
  }
}

module.exports = ExpressEnvironment;

How to make setup() wait until app.listen() callback is finished, i.e., the server has properly started?

Before, when I was using beforeAll(), my code was working fine because I could use the done() async callback passed by beforeAll():

const express = require('express');
const app = express();
var server;

beforeAll(async (done) => {
    server = app.listen(0, "127.0.0.1", () => {
        console.log(`Running express server on '${JSON.stringify(server.address())}'...`);
        done();
    });
    app.use(express.static('../testfiles'));
});

afterAll(() => {
    server.close();
});

How would be the equivalent to the beforeAll done() callback on the NodeEnvironment setup() function?

Evandro Coan
  • 8,560
  • 11
  • 83
  • 144

2 Answers2

2

You can do this by awaiting the listen even, wrapping it in a promise, and calling the promise resolve as the callback to the server listen

  const app = express();
  let server;
  await new Promise(resolve => server = app.listen(0, "127.0.0.1", resolve));
  this.global.server = server;

You could also put a custom callback that will just call the promise resolver as the third argument to the app.listen() and it should run that code then call resolve if you need some sort of diagnostics.

Evandro Coan
  • 8,560
  • 11
  • 83
  • 144
Robert Mennell
  • 1,954
  • 11
  • 24
0

Extending Robert Mennell answer:

You could also put a custom callback that will just call the promise resolver as the third argument to the app.listen() and it should run that code then call resolve if you need some sort of diagnostics.

let server;
const app = express();

await new Promise(function(resolve) {
    server = app.listen(0, "127.0.0.1", function() {
        console.log(`Running express server on '${JSON.stringify(server.address())}'...`);
        resolve();
    });
});
this.global.server = server;

Then, you can access the this.global.server in your tests files to get the server port/address: Is it possible to create an Express.js server in my Jest test suite?

Evandro Coan
  • 8,560
  • 11
  • 83
  • 144