kogosoftwarellc / open-api

A Monorepo of various packages to power OpenAPI in node
MIT License
892 stars 235 forks source link

Unable to test with Jest #765

Open hggaguilera opened 3 years ago

hggaguilera commented 3 years ago

I been trying to write some test with using using OpenAPI 2.0, I'm using this library to add the paths via the controllers but I always get a 404 response back from the tests,

Here is my openapi.json

{
  "swagger": "2.0",
  "info": {
    "version": "0.0.1",
    "title": "Restaurant",
    "description": "API for Restaurant Platform"
  },
  "host": "localhost:9000",
  "basePath": "/api/v1",
  "schemes": ["http", "https"],
  "securityDefinitions": {
    "Bearer": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header"
    }
  },
  "consumes": ["application/json"],
  "produces": ["application/json"],
  "paths": {},
  "definitions": {
    "Message": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string"
        }
      }
    }
  }
}

this is my controller message.js

const get = [
  (req, res) => {
    res.status(200).json({ message: 'Hello World!!!' });
  },
];

get.apiDoc = {
  operationId: 'getMessage',
  summary: 'Get the api message.',
  description: 'Returns the hello world message.',
  tags: ['Message'],
  responses: {
    200: {
      description: 'The hello world message',
      schema: {
        $ref: '#/definitions/Message',
      },
    },
  },
};

module.exports = {
  get,
};

and here is my app.js config

import 'dotenv/config';
import logger from 'morgan';
import path from 'path';
import { initialize } from 'express-openapi';
import express from 'express';
import passport from 'passport';
import cors from 'cors';
import authMiddleware from './middlewares/auth';
import { connect } from '../mappings';
import openapi from './openapi.json';

/**
 * Connecting to the Database
 */
connect.then();

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(logger('dev'));
app.use(passport.initialize());
app.use(authMiddleware);

/**
 * Initialize the openapi
 * @param app                        - The express app instance
 * @param {Object}  apiDoc           - The js/json file with our base api declaration
 * @param {String}  paths            - The path to the routes
 * @param {Boolean} validateApiDoc   - Allow validation of the api definition document
 * @param {String}  docsPath         - Endpoint for the api definition BASEURL + /openapi.json
 * @param {Function} errorMiddleware - Custom middleware to manage commons error
 */
 initialize({
  app,
  apiDoc: openapi,
  paths: path.resolve(__dirname, 'controllers/v1'),
  validateApiDoc: true,
  docsPath: '/openapi.json',
  errorMiddleware(err, req, res) {
    logger.error(err, 'error-handler');
    if (!err.status || err.status === 500) return res.status(500).send();
    return res.status(err.status).json(err.errors);
  },
});

export default app;

as for my test I only have the following

import path from 'path';
import jestOpenAPI from 'jest-openapi';
import request from 'supertest';
import app from '../app';

jestOpenAPI(path.join(__dirname, '../openapi.json'));

describe('message', () => {
  it('should make a GET request and satisfy OpenAPI spec', async () => {
    // Make request (supertest used here)
    const res = await request(app).get('/message');
    // Make any assertions as normal
    expect(res.status).toEqual(200);
    // Assert that the HTTP response satisfies the OpenAPI spec
    expect(res).toSatisfyApiSpec();
  });
});

here is the console output.

Screenshot from 2021-09-04 16 53 04

itswoop commented 2 years ago

We have this issue too. Your call to initialize() returns a promise. So that's why you are getting a 404 – the routes aren't yet configured. You can verify this by debugging and inspecting app._router.stack.

However, my problem is that my test just seems to hang when importing my app.js file with an initialize() call. As soon as I comment out initialize() in app.js, I get the same result as OP, 404s.

mwithington commented 1 year ago

bump

mwithington commented 1 year ago

Hey checkout jest-light-runner @itswoop & @hggonzalez we found that adding in a block to our pkg.json with the following code:


    "runner": "jest-light-runner"
  }```

  also run an npm install for https://www.npmjs.com/package/jest-light-runner
`npm i jest-light-runner` we are on Node 16.17 and everything is working for us.
jiuyun01 commented 1 year ago

Might be related.

I got an issue with OAS 3.0. Jest returns the following error:

Test suite failed to run

A jest worker process (pid=46310) was terminated by another process: signal=SIGSEGV, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (node_modules/jest-worker/build/workers/ChildProcessWorker.js:366:23)

The error will go away if I comment out initialize() in app.js.

jiuyun01 commented 1 year ago

The Jest crash has something to do with the following two configuration fields:

  await initialize({
    ...
    routesGlob: "**/*.{ts,js}",
    routesIndexFileRegExp: /(?:index)?\.[tj]s$/,
    ...
  });

If I comment them out to use default one, it seems not able to generate path correctly (got 404 instead of 200):

  ● GET /v2/todos › should return 200 for todos get request

    expect(received).toEqual(expected) // deep equality

    Expected: 200
    Received: 404

      110 |   it('should return 200 for todos get request', async () => {
      111 |     const res = await req.get('/v2/todos');
      112 |     expect(res.statusCode).toEqual(200);

Update: the reason why it got 404, because paths isn't populated since the following test case is passing:

describe('Get /v2/api-docs', () => {
  it('should return 200 for api docs request', async () => {
    const res = await req.get('/v2/api-docs');
    expect(res.statusCode).toEqual(200);
    //prove supertest not working with express-openapi since paths not populated
    expect(res.body.paths).toEqual({});      
  });
});
jiuyun01 commented 1 year ago

@mwithington: It is working with jest-light-runner as suggested by you against js files instead the ones ts-jest transformed from ts files.

So it appears to be typescript related problem when working express-open-api and supertest together.