Интеграционные тесты Jest / SuperTest Express - Невозможно установить заголовки после их отправки. (когда вы вызываете одну и ту же конечную точку в нескольких тестах) - PullRequest
0 голосов
/ 13 мая 2019

Это меня убивает ..

Я пишу интеграционные тесты для приложения Express (Typescript), используя Jest и Supertest.

У меня есть несколько тестов для одной и той же конечной точки, чтобы проверить ответы от того, когда фиктивная служба возвращает данные правильно и когда она отклоняет обещание с объектом Error.

Тесты выполняются нормально, когда каждый запрос () в каждом блоке it () достигает уникальной конечной точки, но когда конечные точки распределяются между блоками, я получаю следующую ошибку:

Can't set headers after they are sent.

Thisмой тестовый код:

let request = null;
let app = null;
const async = require('async');

import GError from '../../src/services/ErrorService';

const { list } = require('../../src/controllers/RecipeController');

let throwError: boolean = false;
let error = null;
const errorMsg: string = 'Something went wrong!';

const listData: Array<object> = [{id: 1, base: 'something'}];

jest.mock('../../src/services/RecipeService', () => {
    return jest.fn().mockImplementation(() => ({
        list: jest.fn(() => {
            if (throwError) {
                return Promise.reject(error);
            }
            return Promise.resolve(listData);
        })
    }));
});

beforeEach(() => {
    request = require('supertest');
    app = require('../../src/app');
});

afterEach( ( done ) => {
    throwError = false;
    error = null;
    app.close( () => {
       delete require.cache[require.resolve('../../src/app')];
       done();
    });
});

describe('Root Path', () => {

    it('should return a welcome message', (done) => {

        request(app)
            .get('/')
            .end((err, res) => {
                expect(res.text).toEqual('Test API.');
                expect(res.statusCode).toBe(200);
                done();
            });

    });

});

describe('Recipe List', () => {

    it('should call controller and return correct response when successful or error is thrown in service', (done) => {

        const path: string = '/recipes/list';

        request(app)
            .get(path)
            .end((err, res) => {
                expect(JSON.parse(res.text)).toEqual({
                    recipes: listData
                });
                done();
            });

    });

    it('should return an error response if service rejects promise', (done) => {

        throwError = true;
        error = new GError(errorMsg);

        const path: string = '/recipes/list';

        request(app)
            .get(path)
            .end((err, res) => {
                expect(JSON.parse(res.text)).toEqual({
                    errors: {
                        message: errorMsg
                    }
                });
                done();
            });

    });


});

Я думаю, что мне нужно перезагрузить приложение между тестами, чего я и пытаюсь достичь:

beforeEach(() => {
   request = require('supertest');
   app = require('../../src/app');
});

Но без радости,Может ли кто-нибудь зажечь свет?

ОБНОВЛЕНИЕ:

Вот метод контроллера, по которому попадает маршрут:

exports.list = async (req, res, next) => {

    const recipes: IRecipeList = await recipeService.list().catch(err => {
        return next(err);
    });

    const response: IRecipeListResponse = {recipes};

    res.status(200).json(response);

};

решено :

Так получилосьне иметь ничего общего с Jest / Superagent (я был уверен, что это было связано с одним из них).Как ни странно, хотя я получаю эту ошибку только в контексте выполнения интеграционных тестов, при попадании в конечную точку в Postman'е нет ошибки, что было очень запутанно.

ПРОБЛЕМА :

    exports.list = async (req, res, next) => {

        const recipes: IRecipeList = await recipeService.list().catch(err => { .          //this doesn't stop the execution past this await
            return next(err);
        });

        //this still gets processed if the service rejects the promise 
        const response: IRecipeListResponse = {recipes};

        res.status(200).json(response);

    };

РЕШЕНИЕ :

exports.list = async (req, res, next) => {

    let error = false;

    const recipes: IRecipeList = await recipeService.list().catch(err => {
        error = true;
        return next(err);
    });

    if (error) {
        return;
    }

    const response: IRecipeListResponse = {recipes};

    return res.status(200).json(response);

};

1 Ответ

0 голосов
/ 13 мая 2019

Эта ошибка возникает при отправке ответа более одного раза.

...