我有以下Jest测试,包括使用带有XMLHttpRequest
的ajax调用模拟服务器:
import mock from "xhr-mock";
describe("ajax callbacks", function() {
beforeEach(function() {
mock.setup();
});
afterAll(function() {
mock.teardown();
});
it("gets called when done", function(done) {
mock.get("/get-url", {
status: 200,
body: '{ "key": "value" }'
});
const doneCallback = jest.fn();
const xhr = new XMLHttpRequest();
xhr.open("GET", "/get-url");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
doneCallback();
done();
}
}
xhr.send();
expect(doneCallback).toHaveBeenCalled();
});
});
显然会失败,因为AJAX调用是异步处理的,并且期望是在调用回调之前做出的。
Jest有什么办法可以等到回调被调用才产生期望?
请注意,由于域要求,我无法将请求转换为同步请求。而且我也不能仅仅为了能够对其进行测试就将其转换为基于Promise的API。这只是正在编写的测试的简化版本,以便此处的人们可以轻松地掌握它。实际的代码是不同的,并且对此处编写的内容具有抽象性。
答案 0 :(得分:1)
我基本上通过使用Jest提供的async/await
支持来解决此问题。解决方案是将异步请求包装到Promise
中,并在调用Promise
回调时解析onreadystatechange
。因此:
import mock from "xhr-mock";
describe("ajax callbacks", function() {
beforeEach(function() {
mock.setup();
});
afterAll(function() {
mock.teardown();
});
it("gets called when done", async function() {
mock.get("/get-url", {
status: 200,
body: '{ "key": "value" }'
});
const doneCallback = jest.fn();
const xhr = new XMLHttpRequest();
xhr.open("GET", "/get-url");
await new Promise(function(resolve) {
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
doneCallback();
resolve();
}
}
xhr.send();
});
expect(doneCallback).toHaveBeenCalled();
});
});
使用await
将使测试暂停,直到Promise
得到解决。我知道这感觉有些棘手。但这就是我们目前所拥有的。我尝试研究其他解决方案,但找不到任何解决方案。
要了解有关将async/await
与Jest一起使用的更多信息,请参考here。
答案 1 :(得分:1)
您可以使用Sinon模拟XMLHttpRequests。
Text
查看来自https://sinonjs.org/releases/v9.2.0/fake-xhr-and-server/
的更多信息如果使用xhr-mock,另一种方法是使用setTimeout。将回调断言包装到setTimeout并为Jest测试调用done()回调。感觉有点hack,但是可以。
refresh()