如何使用superagent/supertest链接HTTP调用?

48

我正在使用supertest测试express API。

我发现在一个测试用例中无法使用supertest进行多个请求。以下是我在测试用例中尝试的内容。但是测试用例似乎只执行了最后一个调用,即HTTP GET请求。

it('should respond to GET with added items', function(done) {
    var agent = request(app);
    agent.post('/player').type('json').send({name:"Messi"});
    agent.post('/player').type('json').send({name:"Maradona"});
    agent.get('/player').set("Accept", "application/json")
        .expect(200)
        .end(function(err, res) {
            res.body.should.have.property('items').with.lengthOf(2);
            done();
    });
);

这里我是否漏掉了什么,或者还有另一种使用superagent链接http调用的方法?

5个回答

69

我曾试图在上面的评论中写下这段话,但格式不太对。

我正在使用 async,这是非常标准且非常有效的。

it('should respond to only certain methods', function(done) {
    async.series([
        function(cb) { request(app).get('/').expect(404, cb); },
        function(cb) { request(app).get('/new').expect(200, cb); },
        function(cb) { request(app).post('/').send({prop1: 'new'}).expect(404, cb); },
        function(cb) { request(app).get('/0').expect(200, cb); },
        function(cb) { request(app).get('/0/edit').expect(404, cb); },
        function(cb) { request(app).put('/0').send({prop1: 'new value'}).expect(404, cb); },
        function(cb) { request(app).delete('/0').expect(404, cb); },
    ], done);
});

4
这应该是被认可的答案。在这种情况下,异步工作得非常棒。 - csvan
1
很棒的方法!我稍微扩展了一下,可以在这里查看 https://dev59.com/2WEi5IYBdhLWcg3wpdjJ#45198533 - Tom Söderlund
1
我收到了“找不到名称async”的错误。这需要一个包吗?我在网上找不到答案。 - perepm

29

这些调用是异步的,因此您需要使用回调函数来链接它们。

it('should respond to GET with added items', function(done) {
    var agent = request(app);
    agent.post('/player').type('json').send({name:"Messi"}).end(function(){
        agent.post('/player').type('json').send({name:"Maradona"}).end(function(){
            agent.get('/player')
                .set("Accept", "application/json")
                .expect(200)
                .end(function(err, res) {
                    res.body.should.have.property('items').with.lengthOf(2);
                    done();
                });
        });
    });
});

9
请查看supertest-as-promised,以减少回调嵌套。 - Luke H
不使用 mochait,是否可以链接它们? - gurvinder372
4
2.0.0 版本以来,supertest 已经原生支持 Promise。 - ricca
我无法让这个解决方案工作。然而,我可以让下面 Tim 提供的“async”解决方案工作。 - user952342
2
这个答案是正确的,但已经过时了,使用async/await可以以更简洁的实现方式得到相同的结果。 - Mazen Elkashef
@ricca,您添加到多个帖子中的链接已经无法使用了。 - aderchox

15

这个问题可以用Promise最优雅地解决,还有一个非常有用的库可以让你在使用supertest时使用Promise:https://www.npmjs.com/package/supertest-as-promised

他们的例子:

return request(app)
  .get("/user")
  .expect(200)
  .then(function (res) {
    return request(app)
      .post("/kittens")
      .send({ userId: res})
      .expect(201);
  })
  .then(function (res) {
    // ... 
  });

承诺在这里是一个不错的选择。只需要注意可能需要从该链中的某个位置恢复404的情况。 - backdesk
3
2.0.0版本起,supertest具有原生的Promise支持。 - ricca

9

我在Tim的回答基础上进行了扩展,但是使用了async.waterfall来测试结果的断言(注意:我在这里使用的是Tape而不是Mocha):

test('Test the entire API', function (assert) {
    const app = require('../app/app');
    async.waterfall([
            (cb) => request(app).get('/api/accounts').expect(200, cb),
            (results, cb) => { assert.ok(results.body.length, 'Returned accounts list'); cb(null, results); },
            (results, cb) => { assert.ok(results.body[0].reference, 'account #0 has reference'); cb(null, results); },
            (results, cb) => request(app).get('/api/plans').expect(200, cb),
            (results, cb) => request(app).get('/api/services').expect(200, cb),
            (results, cb) => request(app).get('/api/users').expect(200, cb),
        ],
        (err, results) => {
            app.closeDatabase();
            assert.end();
        }
    );
});

1
你节省了我很多时间。目前,这是最好的答案。 - andrzej1_1

0
这对我有用:
const agent = request(server.app);
const fn = (counter) => {
  agent.get('/').end((_error, res) => {
    if (res.status !== 200) {
      done();
      expect(counter).toEqual(20);
    } else
      fn(counter + 1);
  })
}

fn(1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接