【问题标题】:Supertest: check for something that happened after res.send()超测:检查 res.send() 之后发生的事情
【发布时间】:2020-03-18 15:15:41
【问题描述】:

我正在做一个 POST 来创建一个项目并将新创建的项目作为响应发送回客户端。

async (req, res, next) => {
  const item = await createItem(xx, yy, zz);
  res.send(201, item);
}

现在我还想在创建项目后发送通知但也要在响应客户端后发送通知 - 以尽可能快地发出请求。

async (req, res, next) => {
  const item = await createItem(xx, yy, zz);
  res.send(201, item);

  sendNotification(item);
}

如果我想使用 jest + supertest 进行测试,它会是这样的:

test('return 201', () => {
  const app = require('./');
  return request(app)
    .post('/api/items')
    .send({})
    .expect(201)
    .then(response => {
      // test something more
    });
}

但是我如何测试sendNotification() 是否被调用?

【问题讨论】:

  • sendNotification() 使用 res 吗?那是行不通的。基本上,send 结束 HTTP 响应。尽管您可以在res.send 之后访问代码,但对res 的任何引用都将失败。 sendNotification 是做什么的?
  • @PruthviKumar 它发送推送通知并且没有使用res
  • 好吧,在这种情况下,您可以使用.done(() => {//test something set/used by sendnotification}) 来验证是否调用了sendNotification
  • @PruthviKumar 不起作用,因为那时还没有调用它

标签: node.js express jestjs restify supertest


【解决方案1】:

好的,不完美,但现在可以使用:

我在异步请求处理程序的末尾添加了对来自另一个包的外部方法的调用。我知道您不应该仅出于测试目的添加代码,但我更喜欢在我的测试中随机添加代码 setTimeouts

hooks.js

const deferreds = [];

exports.hookIntoEnd = () => {
  const p = new Promise((resolve, reject) => {
    deferreds.push({ resolve, reject });
  });
  return p;
};

exports.triggerEndHook = () => {
  if (Array.isArray(deferreds)) {
    deferreds.forEach(d => d.resolve());
  }
};

handler.js

const { triggerEndHook } = require('./hooks');

async (req, res, next) => {
  const item = await createItem(xx, yy, zz);
  res.send(201, item);

  sendNotification(item);

  // this is only here so that we can hook into here from our tests
  triggerEndHook();
}

test.js

test('run + test stuff after res.send', async () => {
  const server = require('../index');
  const { hookIntoEnd } = require('../hooks');
  const aws = require('../utils/aws');

  const getObjectMetadataSpy = jest
    .spyOn(aws, 'getObjectMetadata')
    .mockImplementation(() => Promise.resolve({ Metadata: { a: 'b' } }));

  const p = hookIntoEnd();

  const response = await request(server)
    .post('/api/items')
    .send({ foo: 'bar' })
    .set('Accept', 'application/json')
    .expect('Content-Type', /json/)
    .expect(201);

  expect(response.body).toEqual({ id: 1, name: 'test item'});

  // test for code that was run after res.send
  return p.then(async () => {
    console.log('>>>>>>>>>>> triggerEndHook');
    expect(getObjectMetadataSpy).toHaveBeenCalledTimes(2);
  });
});

【讨论】:

  • @lmoglia 这就是我现在正在使用的 - 不完美但可以完成工作
【解决方案2】:

您可以在 Jest 中使用 mocking 来监视 sendNotification() 函数并断言它已被调用。一个简单的例子:

const sendNotification = require('./sendNotification');
const sendNotificationSpy = jest.spyOn(sendNotification);

test('return 201', () => {
  const app = require('./');
  return request(app)
    .post('/api/items')
    .send({})
    .expect(201)
    .then(response => {
      // test something more
      expect(sendNotificationSpy).toHaveBeenCalled();
    });
}

【讨论】:

  • 这是我尝试过的,但没有成功,因为在触发 sendNotification() 之前调用了 then()
  • 哦,我明白了。 sendNotification 是异步的吗?你有没有在res.send() 之前打电话的原因?
  • 我想尽快响应请求......并在响应之后执行一些其他可选任务。可以是同步的或异步的,并不重要。更多的是关于如何使用 supertest 进行测试
  • 嗨@pkyeck!你有没有找到一些方法来做到这一点?我正在尝试做同样的事情!谢谢!
【解决方案3】:

调用 res.send() 后,程序调用 someService.method({param1}) 函数。

使用 sinon 窥探那个服务方法:

it('test after send', function(done){
  const spy = sinon.spy(someService, 'method');
  agent
    .set('Authorization', token)
    .post('/foo')
    .expect(200)
    .then(() => {
      return setTimeout(function() {
        // Assert the method was called once
        sinon.assert.callCount(spy, 1);
        // Assert the method was called with '{param1}' parameter
        sinon.assert.calledWith(spy, {param1});
        // Test callback!
        done();
      }, 100);
    });
});

- 使用 setTimeout 并尽可能缩短等待方法被调用的时间(毫秒)。

我们将不胜感激建议和改进! (我仍在尝试避免使用任意数量的超时)

【讨论】:

    猜你喜欢
    • 2012-04-13
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多