DIRECTcut
DIRECTcut

Reputation: 170

Express + Mocha + Chai Error: Server is not listening

I'm writing a simple TypeScript Express app that would get info about YouTube videos. Here is the router (mounted to /api):

import express from 'express';
import ytdl    from 'ytdl-core';
import bodyParser from 'body-parser';

const router = express.Router();

router.post('/info', bodyParser.json(), async (req, res, next) => {
    const videoID = req.body.videoID

    if (!ytdl.validateID(videoID)) {
        const error = new Error('Invalid video ID')
        res.status(400).json({error: error.toString()}).send;
        next();
    } else {
        const videoFormats = await (await ytdl.getInfo(videoID)).formats;
        res.setHeader('Content-type', 'application/json');
        res.send(videoFormats);
    } 
});

export default router;

Today I've attempted to write my first tests with Mocha + Chai. The api/info endpoint expects POST, grabs videoID from the body and responds with JSON. Here are my tests for the endpoint so far.

import app from '../index'  
import chaiHttp from 'chai-http'
import chai from 'chai'

chai.use(chaiHttp);

const expect = chai.expect;
const get    = chai.request(app).get;
const post   = chai.request(app).post;

describe('API', () => {
    describe('POST /api/info', () => {
        it('given videoID of a publically available video, responds with 200 OK and JSON that contains an array of objects',  async () => {
            const res = await post('/api/info')
                                .send({"videoID": "OrxmtDw4pVI"});

            expect(res).to.have.status(200);
            expect(res.body).to.be.an('array');            
        }).timeout(5000);

        it('given an invalid videoID, responds with 400 and an Error', async () => {
            const res = await post('/api/info')
                                .send({"videoID": "qwerty"});

            expect(res).to.have.status(400);
        });
    });
});

The test results are as follows:

API
    POST /api/info
      √ given videoID of a publically available video, responds with 200 OK and JSON that contains an array of objects (1028ms)
      1) given an invalid videoID, responds with 400 and an Error


  1 passing (1s)
  1 failing

  1) API
       POST /api/info
         given an invalid videoID, responds with 400 and an Error:
     Error: Server is not listening
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] test: `mocha -r ts-node/register src/**/*.spec.ts --exit`
npm ERR! Exit status 1

As you can see, the second test fails due to the Server is not listening error. It doesn't happen if I skip the first test.

I used Postman to test this endpoint with this data manually and found no issues that would cause server crashes, no errors are thrown.

I launch tests with the npm run test command, here is the script from package.json:

"scripts": {
    "test": "mocha -r ts-node/register src/**/*.spec.ts --exit"

I suspect there is something wrong with the test suite itself, but I am unable to pinpoint a solution. What am I missing here?

Upvotes: 1

Views: 910

Answers (1)

DIRECTcut
DIRECTcut

Reputation: 170

I think I found it.

Seems like my tests did contain a mistake and not an obvious one for a beginner like myself.

You don't want to get get and post shortcuts like so:

const get    = chai.request(app).get;
const post   = chai.request(app).post;

I think the actual mistake is that I invoked request() here. Instead, should've just grabbed a shortcut for chai.request:

const request = chai.request;

Tests work fine now. Test file now looks as follows.

import server from '../index'  
import chaiHttp from 'chai-http'
import chai from 'chai'

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

describe('API', () => {
    
    describe('POST /api/info', () => {
        it('given videoID of a publically available video, responds with 200 and JSON that contains an array of objects',  async () => {
            const res = await request(server)
                                .post('/api/info')
                                .send({"videoID": "OrxmtDw4pVI"});

            expect(res).to.have.status(200);
            expect(res.body).to.be.an('array');            
        });

        it('given an invalid videoID, responds with 400 and an Error', async () => {
            const res = await request(server)
                                .post('/api/info')
                                .send({"videoID": "qwerty"});

            expect(res).to.have.status(400);
            expect(res.body.error).to.include('Error');
        });
    });
});

Upvotes: 2

Related Questions