ladjs / supertest

🕷 Super-agent driven library for testing node.js HTTP servers using a fluent API. Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.
MIT License
13.81k stars 759 forks source link

TypeError: Cannot read property 'address' of undefined #633

Open voiddeveloper opened 4 years ago

voiddeveloper commented 4 years ago

I created an express.js server with ts and tried to test it, but got an error. I can't find a solution no matter how I search.

server.ts

import App from './app';
import PostsRouter from './routes/posts';

export const app = new App(
    [
        new PostsRouter(),
    ],
    3000,
).listen();

app.ts

import * as express from 'express';

class App {
    public app: express.Application;
    public port: number;

    constructor(controllers: any[], port: number) {
        this.app = express();
        this.port = port;

        this.initializeControllers(controllers);
    }

    private initializeControllers(controllers: any[]) {
        controllers.forEach((controller) => {
            this.app.use('/', controller.router);
        });
    }

    public listen() {
        this.app.listen(this.port, () => {
            console.log(`App listening on the port ${this.port}`);
        });
    }
}

export default App;

posts.spec.ts

import * as request from "supertest";
import { app } from "../server";

describe("GET /posts", () => {
    it("respond with json", async done => {
        await request(app)
            .get("/posts")
            .set("Accept", "application/json")
            .expect("Content-Type", /json/)
            .expect(200, done);
    });
});

Screen Shot 2020-03-03 at 7 47 26 AM

matheuseabra commented 4 years ago

Having the exact same issue...

jonathansamines commented 4 years ago

@voiddeveloper Your custom .listen method needs to return the *express application**.

lucasguiss commented 4 years ago

im having the same issue but with e2e test... any news?

mmRoshani commented 4 years ago

i have this issue with e2e test too!

iamdarshanshah commented 4 years ago

@voiddeveloper I was also facing the same issue, this should work

posts.spec.ts

import * as request from "supertest";
import App from '../app';
import PostsRouter from '../routes/posts';

// This will return the express application 
const api = request(new App([
        new PostsRouter(),
    ],
    3000).app);

describe("GET /posts", () => {
    it("respond with json", async done => {
        await api
            .get("/posts")
            .set("Accept", "application/json")
            .expect("Content-Type", /json/)
            .expect(200, done);
    });
});
HADMARINE commented 4 years ago

I have this same issue too..

HADMARINE commented 4 years ago

@voiddeveloper Your custom .listen method needs to return the express application*.

Is there any method to use supertest without returning express application?

HADMARINE commented 4 years ago

It can be fixed by giving "http.Server" type parameter to request function. therefore, app.ts should return http.Server to solve that problem. @voiddeveloper

mirsahib commented 3 years ago

I have the same issue because i forgot to mention module.exports = app in app.js but my folder structure is different here is my folder structure app.js

const http = require("http");
const express = require("express");

const app = express();
const server = http.Server(app);

app.post("/example", function (request, response) {
    // my router logic
});

server.listen(process.env.PORT || 3000, process.env.IP || "0.0.0.0", () => {
  console.log("Server running");
});
module.exports = app

test/app.test.js

const app = require("../app.js"); // runs app.js
const request = require("supertest"); // needed to make API requests

describe("When the example router  is running", () => {
  // Add individual test cases
});
iszlailorand commented 1 year ago

To solve this you need to pass a string to the request method... something like this:

import * as request from "supertest";
import { server } from "../server";

const API = 'http://localhost:3000';

describe("GET /posts", () => {
    it("respond with json", async done => {
        await request(API)
            .get("/posts")
            .set("Accept", "application/json")
            .expect("Content-Type", /json/)
            .expect(200, done);
    });
});