swagger-express-middleware icon indicating copy to clipboard operation
swagger-express-middleware copied to clipboard

Unit testing swagger-express-middleware with Jest and Supertest

Open mescalito opened this issue 5 years ago • 4 comments

Do you know how to UT a simple endpoint with Jest and Supertest when using swagger-express-middleware?

I want to unit test the very basic swagger-express-middleware walkthrough example: https://apitools.dev/swagger-express-middleware/docs/walkthroughs/walkthrough.html

But the test is not working, what is going on? I look everywhere and found no examples.

/samples/test/user.test.js

"use strict";
const app = require("./sample1.js"); // Link to your server file
const supertest = require("supertest");
const request = supertest(app);

it("gets the test endpoint", async done => {
  const response = await request.get("/pet");

  expect(response.status).toBe(200);
  expect(response.body.message).toBe("pass!");
  done();
});

/samples/package.json

{
  "name": "samples",
  "version": "1.0.0",
  "description": "Samples & Walkthroughs ==",
  "scripts": {
    "start": "node sample1.js",
    "test": "jest",
    "test:watch": "jest --watch"
  },
  "dependencies": {
    "swagger-express-middleware": "^2.0.5"
  },
  "devDependencies": {
    "jest": "^25.1.0",
    "supertest": "^4.0.2"
  },
  "author": "",
  "license": "ISC"
}

/samples/sample1.js

'use strict';

const createMiddleware = require('swagger-express-middleware');
const path = require('path');
const express = require('express');

// Create an Express app
const app = express();

// Initialize Swagger Express Middleware with our Swagger file
let swaggerFile = path.join(__dirname, 'PetStore.yaml');
createMiddleware(swaggerFile, app, (err, middleware) => {

  // Add all the Swagger Express Middleware, or just the ones you need.
  // NOTE: Some of these accept optional options (omitted here for brevity)
  app.use(
    middleware.metadata(),
    middleware.CORS(),
    middleware.files(),
    middleware.parseRequest(),
    middleware.validateRequest(),
    middleware.mock()
  );

  // Start the app
  app.listen(8000, () => {
    console.log('The Swagger Pet Store is now running at http://localhost:8000');
  });
});
module.exports = app;

https://stackoverflow.com/questions/59852732/unit-testing-swagger-express-middleware-with-jest-and-supertest

Thanks!

mescalito avatar Jan 22 '20 04:01 mescalito

createMiddleware is loading the file asynchronously then adding the middleware after your test has run.

Instead I would recommend loading the spec file synchronously (not a performance issue since it happens once at startup) then creating your middleware like

const middleware = createMiddleware(parsedSwaggerSpec, app)

tamlyn avatar Mar 12 '20 12:03 tamlyn

@tamlyn that's easy to tell but hard to do, thanks though!

ncabrera2345 avatar Mar 12 '20 13:03 ncabrera2345

You could create a wrapper method that returns a Promise and resolves when the swagger middleware is ready:

const init = () =>
  new Promise((resolve, reject) =>
    createMiddleware(swaggerFile, app, (err, middleware) => {
      if (err) {
        return reject(err);
      }

      // do work

      return resolve();
    })
  );

ajcrews avatar Apr 09 '20 23:04 ajcrews

So far, I was happy testing other conventional express applications with Jest & Supertest until I got in this very same situation with swagger-middleware-express.

I've solved the way @tamlyn suggested, but it was tricky, and I had to import swagger-parser in the project explicitly. I think it will be helpful a createMiddlewareSync function shipped out of the box.

For those who are still looking for a solution, this is the code.

'use strict'
const path = require('path')
const createMiddleware = require('@apidevtools/swagger-express-middleware')
const SwaggerParser = require('@apidevtools/swagger-parser')
const express = require('express')
const app = express()

const loadSwaggerFile = async (file) => {
  const swaggerFile = path.join(__dirname, file)
  return SwaggerParser.dereference(swaggerFile)  
}

const createSwaggerMiddlewareApp = async () => {
  const parsedSwaggerSpec = await loadSwaggerFile('./api/swagger/swagger.yaml')
  const middleware = createMiddleware(parsedSwaggerSpec, app)
  app.use(
    middleware.metadata(),
    middleware.CORS(),
    middleware.parseRequest(),
    middleware.validateRequest(),  
  )
  return app
}

module.exports = createSwaggerMiddlewareApp


lucallero avatar May 18 '20 22:05 lucallero