Res.body в этом тесте пуст, который использует supertest и Node.js

Я тестирую API Node.js с supertest, и я не могу объяснить, почему возврат супертекста res.body пуст. Данные отображаются в объекте res.text, но не res.body, любая идея, как это исправить?

Я использую Express и body-parser:

app.use(bodyParser.json());
app.use(bodyParser.json({ type: jsonMimeType }));
app.use(bodyParser.urlencoded({ extended: true }));

Вот метод API, который я тестирую:

app.get(apiPath + '/menu', function(req, res) {
 var expiration = getExpiration();
 res.set({
 'Content-Type': jsonMimeType,
 'Content-Length': jsonTestData.length,
 'Last-Modified': new Date(),
 'Expires': expiration,
 'ETag': null
 });
 res.json({ items: jsonTestData });
}

Вот тесты, которые я выполняю против этого метода API:

describe('GET /menu', function() {
 describe('HTTP headers', function() {
 it('responds with the right MIME type', function(done) {
 request(app)
 .get(apiPath + '/menu')
 .set('Accept', 'application/vnd.burgers.api+json')
 .expect('Content-Type', 'application/vnd.burgers.api+json; charset=utf-8')
 .expect(200, done);
 });
 it('responds with the right expiration date', function(done) {
 var tomorrow = new Date();
 tomorrow.setDate(tomorrow.getDate() + 1);
 tomorrow.setHours(0,0,0,0);
 request(app)
 .get(apiPath + '/menu')
 .set('Accept', 'application/vnd.burgers.api+json; charset=utf-8')
 .expect('Expires', tomorrow.toUTCString())
 .expect(200, done);
 });
 it('responds with menu items', function(done) {
 request(app)
 .get(apiPath + '/menu')
 .set('Accept', 'application/vnd.burgers.api+json; charset=utf-8')
 .expect(200)
 .expect(function (res) {
 console.log(res);
 res.body.items.length.should.be.above(0);
 })
 .end(done);
 });
 });
});

Сбой, который я получаю:

1) GET /menu HTTP headers responds with menu items:
 TypeError: Cannot read property 'length' of undefined
 at /Users/brian/Development/demos/burgers/menu/test/MenuApiTest.js:42:25
 at Test.assert (/Users/brian/Development/demos/burgers/menu/node_modules/supertest/lib/test.js:213:13)
 at Server.assert (/Users/brian/Development/demos/burgers/menu/node_modules/supertest/lib/test.js:132:12)
 at Server.g (events.js:180:16)
 at Server.emit (events.js:92:17)
 at net.js:1276:10
 at process._tickDomainCallback (node.js:463:13)

И, наконец, вот выдержка из результата console.log(res):

...
text: '{"items":[{"id":"1","name":"cheeseburger","price":3},{"id":"2","name":"hamburger","price":2.5},{"id":"3","name":"veggie burger","price":3},{"id":"4","name":"large fries","price":2},{"id":"5","name":"medium fries","price":1.5},{"id":"6","name":"small fries","price":1},{"id":"7","name":"large drink","price":2.5},{"id":"8","name":"medium drink","price":2},{"id":"9","name":"small drink","price":1}]}',
 body: {},
...
4 ответа

На основании следующего теста вы ожидаете 'application/vnd.burgers.api + json; charset = utf-8 'в качестве Content-Type:

request(app)
 .get(apiPath + '/menu')
 .set('Accept', 'application/vnd.burgers.api+json')
 .expect('Content-Type', 'application/vnd.burgers.api+json; charset=utf-8')
 .expect(200, done);

Этот экспресс-маршрут также показывает настройку заголовка на какое-то пользовательское значение, jsonMimeType:

app.get(apiPath + '/menu', function(req, res) {
 var expiration = getExpiration();
 res.set({
 'Content-Type': jsonMimeType,
 'Content-Length': jsonTestData.length,
 'Last-Modified': new Date(),
 'Expires': expiration,
 'ETag': null
 });
 res.json({ items: jsonTestData });
}

Если это так, supertest не собирается анализировать, что JSON автоматически для вас. Заголовок содержимого должен начинаться со строки "application/json". Если вы не можете это сделать, вам придется использовать функцию JSON.parse самостоятельно, чтобы преобразовать эту текстовую строку в объект.

supertest использует этот файл, чтобы определить, отправляется ли вы json или нет. Под капотом supertest фактически запускает ваш экспресс-сервер, делает один запрос через HTTP и быстро отключает его. После этой HTTP-передачи обслуживания клиентская сторона (которая в основном superagent) этого HTTP-запроса ничего не знает о настройке вашего сервера в отношении ' Приложение /vnd.burgers.api + JSON; кодировка = UTF-8'. Все, что он знает, это то, что он сказал через заголовки, в данном случае, контент-тип.

Кроме того, я попробовал свой собственный заголовок на своей машине, и я также получил пустое тело.

Изменить: обновленную ссылку в таблице, как указано в комментариях


Это старо, но это помогло мне так подумать, что я могу поделиться некоторыми знаниями.

Отключение примера mattr, я обнаружил, что эта информация была фактически в res.text, а не в res.body.

В итоге я добавил специальную обработку для:

if(res.headers['content-type'] == 'myUniqueContentType' && res.body===undefined){ 
 res.body = JSON.parse(res.text);
}


Моя проблема заключалась в том, что метод .set() задавал заголовки запросов, тогда как .send() устанавливает тело запроса с указанными json-данными.

request("/localhost:3000")
 .post("/test")
 .type("json")
 .set({color: "red"}) //this does nothing!
 .expect(200)
 .end(function(res) {
 done();
 });

Исправление:

request("/localhost:3000")
 .post("/test")
 .type("json")
 .send({color: "red"}) //fixed!
 .expect(200)
 .end(function(res) {
 done();
 });


добавить

app.use(bodyParser.json({ type: 'application/*+json' }))

это будет принимать все типы содержимого json: -)

licensed under cc by-sa 3.0 with attribution.