28

I'm using node with TypeScript on my back end and Jest and Supertest as my test framework on my back end.

When I'm trying to test I have the result pass but I get an error at the end. Here's the result:

 PASS  test/controllers/user.controller.test.ts
  Get all users
    ✓ should return status code 200 (25ms)

  console.log node_modules/@overnightjs/logger/lib/Logger.js:173
    [2019-12-05T04:54:26.811Z]: Setting up database ...

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.284s
Ran all test suites.
server/test/controllers/user.controller.test.ts:32
                throw err;
                ^

Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1104:14)
npm ERR! Test failed.  See above for more details.

Here's my test code:

import request from "supertest";
import { AppServer } from '../../config/server';

const server = new AppServer();

describe('Get all users', () => {
  it('should return status code 200', async () => {
    server.startDB();
    const appInstance = server.appInstance;
    const req = request(appInstance);
    req.get('api/v1/users/')
      .expect(200)
      .end((err, res) => {
        if (err) throw err;
      })
  })
})

Here's my server setup. I'm using overnightjs on my back end.

I created a getter to get the Express instance. This is coming from overnight.js.

// this should be the very top, should be called before the controllers
require('dotenv').config();

import 'reflect-metadata';

import { Server } from '@overnightjs/core';
import { Logger } from '@overnightjs/logger';
import { createConnection } from 'typeorm';
import helmet from 'helmet';
import * as bodyParser from 'body-parser';
import * as controllers from '../src/controllers/controller_imports';

export class AppServer extends Server {
  constructor() {
    super(process.env.NODE_ENV === 'development');
    this.app.use(helmet());
    this.app.use(bodyParser.json());
    this.app.use(bodyParser.urlencoded({ extended: true }));
    this.setupControllers();
  }

  get appInstance(): any {
    return this.app;
  }

  private setupControllers(): void {
    const controllerInstances = [];

    // eslint-disable-next-line
    for (const name of Object.keys(controllers)) {
      const Controller = (controllers as any)[name];
      if (typeof Controller === 'function') {
        controllerInstances.push(new Controller());
      }
    }

    /* You can add option router as second argument */
    super.addControllers(controllerInstances);
  }

  private startServer(portNum?: number): void {
    const port = portNum || 8000;
    this.app.listen(port, () => {
      Logger.Info(`Server Running on port: ${port}`);
    });
  }

  /**
   * start Database first then the server
   */
  public async startDB(): Promise<any> {
    Logger.Info('Setting up database ...');
    try {
      await createConnection();
      this.startServer();
      Logger.Info('Database connected');
    } catch (error) {
      Logger.Warn(error);
      return Promise.reject('Server Failed, Restart again...');
    }
  }
}

I read this question - that's why I called the method startDB.

halfer
  • 19,824
  • 17
  • 99
  • 186
aRtoo
  • 1,686
  • 2
  • 18
  • 38

9 Answers9

71

So I figured out and the solution is quite easy. I can't explain why though.

This req.get('api/v1/users/') should be /api/v1/users - you need a leading /.

halfer
  • 19,824
  • 17
  • 99
  • 186
aRtoo
  • 1,686
  • 2
  • 18
  • 38
  • 2
    It makes complete sense that this works. here is why: https://webmasters.stackexchange.com/questions/56840/what-is-the-purpose-of-leading-slash-in-html-urls – Native Coder Oct 13 '20 at 03:18
8

For Frontend...

If you are making use of axios and come across this error, go to the testSetup.js file and add this line

axios.defaults.baseURL = "https://yourbaseurl.com/"

This worked for me. So, typically, this is a baseURL issue.

Kenshinman
  • 679
  • 8
  • 20
  • 1
    Though I wouldn't go into a global file I find this information very useful. Thank you. :) – LSR Jul 28 '20 at 09:15
  • 2
    Thank you, this fixed it for me. Just wanted to add that you need to import `import axios from "axios";` before setting the default baseURL. – Artan M. Jun 01 '21 at 09:07
4

I had this error in my React frontend app tests.

I was using React testing library's findBy* function in my assert:

expect(await screen.findByText('first')).toBeInTheDocument();
expect(await screen.findByText('second')).toBeInTheDocument();
expect(await screen.findByText('third')).toBeInTheDocument();

After I changed it to:

await waitFor(async () => {
  expect(await screen.findByText('first')).toBeInTheDocument();
  expect(await screen.findByText('second')).toBeInTheDocument();
  expect(await screen.findByText('third')).toBeInTheDocument();
});

the error is gone.

I don't know exactly why, but maybe it will help someone

UPDATE: I was mocking fetch incorrectly, so my test called real API and caused that error

I put this line in my setupTests file:

global.fetch = jest.fn()

It mocks fetch for all tests globally. Then, you can mock specific responses right in your tests:

jest.mocked(global.fetch).mockResolvedValue(...)
// OR
jest.spyOn(global, 'fetch').mockResolvedValue(...)
pkirilin
  • 332
  • 2
  • 8
2

In my case, the issue was related to package react-inlinesvg. Package makes a fetch request to get the svg file and since server is not running, it gets redirected to default 127.0.0.1:80. I mocked react-inlinesvg globally to output props including svg filename to assert in testing.

jest.mock('react-inlinesvg', () => (props) => (
    <svg data-testid="mocked-svg">{JSON.stringify(props)}</svg>
));
Kseniya
  • 21
  • 2
1

Slightly different issue, but same error message...

I was having this error when using node-fetch when trying to connect to my own localhost (http://localhost:4000/graphql), and after trying what felt like everything under the sun, my most reliable solution was:

using this script in package.json: "test": "NODE_ENV=test jest --watch" If the terminal shows connection error I just go to the terminal with Jest watching and press a to rerun all tests and they pass without any issue.

¯\_(ツ)_/¯

Success rate continued to improve by renaming the testing folder to __tests__ and moving my index.js to src/index.js.

Very strange, but I am too exhausted to look at the Jest internals to figure out why.

danst3in
  • 69
  • 4
1

I didn't get to the bottom of this error - it wasn't related to the (accepted) leading slash answer.

However, my "fix" was to move the mocks up into the suite definition - into beforeAll and afterAll for cleanup between tests).

Before, I was mocking (global.fetch) in each test, and it was the last test in the suite to use the mock that would cause the error.

Darren Shewry
  • 10,179
  • 4
  • 50
  • 46
0

The rules for supertest are the same as the rules for express. OvernightJS does not require any leading or ending "/" though.

0

For anyone landing on this, but not having issues with trailing slashes:

jest can also return a ECONNREFUSED when your express app takes some time (even just a second) to restart/init. If you are using nodemon like me, you can disable restarts for test files like --ignore *.test.ts.

karlludwigweise
  • 101
  • 1
  • 3
0

This error also occurs if you have not set up a server to catch the request at all (depending on your implementation code and your test, the test may still pass).

Byofuel
  • 325
  • 4
  • 11