res.body在这个使用supertest和Node.js的测试中是空的

时间:2014-10-17 17:04:11

标签: node.js mocha supertest

我正在使用supertest测试Node.js API,我无法解释为什么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 个答案:

答案 0 :(得分:6)

基于以下测试,您期待'application / vnd.burgers.api + json; charset = utf-8'作为内容类型:

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。 content-type标头必须以字符串'application / json'开头。如果你无法实现这一点,那么你必须自己使用JSON.parse函数将该文本字符串转换为对象。

supertest使用this file来确定您是否正在发送json。 supertest实际启动你的快速服务器,通过HTTP发出一个请求,然后快速关闭它。在HTTP切换之后,该HTTP请求的客户端(基本上是superagent)对于'application / vnd.burgers.api + json;的服务器配置一无所知。字符集= UTF-8' 。所有它知道的是它通过标题,在这种情况下,内容类型。

另外,我确实在我的机器上尝试了自定义标题,并且还有一个空体。

修改更新了表格链接,如评论中所述

答案 1 :(得分:0)

这已经过时了,但它让我觉得我可能会分享一些知识。

使用mattr示例,我发现该信息实际上在res.text中,而不是res.body。

我最后添加了一些特殊处理:

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

答案 2 :(得分:0)

我的问题是.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();
    });

答案 3 :(得分:-1)

添加

Step 1) Use CLLocationManagerDelegate Delegate
Step 2) Write It's Delegate Method

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    [self speedCalculator:locations];
}



-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{

    NSLog(@"%@",error.userInfo);
    if([CLLocationManager locationServicesEnabled]){

        NSLog(@"Location Services Enabled");

        if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied){

            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"App Permission Denied" message:@"To re-enable, please go to Settings and turn on Location Service for this app." preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction* ok = [UIAlertAction
                                 actionWithTitle:@"OK"
                                 style:UIAlertActionStyleDefault
                                 handler:nil];

            [alertController addAction:ok];

            [self presentViewController:alertController animated:YES completion:nil];
        }
    }
}




-(void)speedCalculator:(NSArray *)locations
{
    CLLocation *loc = locations.lastObject;
    double speeds = loc.speed;
    if (speeds > 0)
    {
        self.speedLabel.text = [NSString stringWithFormat:@"%.02f",speeds*3.6];
        SpeedValue = (float) (speeds*3.6) ;
    }
    else
    {
        self.speedLabel.text = @"0.00"; // When Device is not moving the Speed Value will become -ve.
        SpeedValue = 0.00 ;
    }

}

这将接受所有json内容类型: - )