Это меня убивает ..
Я пишу интеграционные тесты для приложения 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);
};