我正在尝试为更改React模块的密码编写单元测试,但是我无法获得要在方括号中执行的代码。我已经为模块MyAPI编写了一个模拟程序,该模拟代码可以很好地执行,并且可以使用console.log(“ something”)在控制台中看到输出。
但是,我无法让代码在.done(function(data(function,data))。之后运行。最有可能是因为该模拟用自己的代码替换了这些代码。
我知道一种选择是使用像Nock这样的假服务器,但是除非有必要,否则我不想将其变成集成测试。
我要测试的代码:
const MyAPI = require('../../my_api.js');
submitChangePasswordFormEvent(event) {
const self = this;
const params = {};
event.preventDefault();
event.stopPropagation();
params.current_password = this.refs.current_password.getValue();
params.passwordFirst = this.refs.passwordFirst.getValue();
params.passwordSecond = this.refs.passwordSecond.getValue();
MyAPI.my_api('/api/change_password/', params)
.done(function (data) {
// This code i would like to run but can't
const elem = <Success>{t(['settings',
'passwords_changed'])}</Success>;
self.setState({ pwerror: null, pwsuccess: elem });
self.refs.current_password.value = '';
self.refs.password1.value = '';
self.refs.password2.value = '';
})
.error(function (errors) {
// This code i would like to run but can't
let msg = '';
$.each(errors.responseJSON, function (k, v) {
msg += v;
});
msg = <Error>{msg}</Error>;
self.setState({ pwerror: msg, pwsuccess: null });
});
}
MyAPI的模拟文件
var MyAPI = function () {};
MyAPI.prototype.my_api = function(url) {
return $.ajax();
}
module.exports = new MyAPI();
还有Jest设置脚本:
const jqueryMock = {
ajax: function (argument) {
return {done: function (data) {
return {error: function (errors) {
return "success";
}}}}
}}
global.$ = jqueryMock;
答案 0 :(得分:3)
您希望执行.done
或.error
方法,但又不想实际发出请求(顺便说一句,我不知道.error
方法只是{{ 1}})?然后,我将执行以下操作:
在工作目录顶层的.fail
目录内为jquery创建全局模拟:
__mocks__
通过在要测试的模块中请求时,将//__mocks__/jquery.js:
const jQ = jest.requireActual("jquery");
const ajax = jest.fn(() => {
return jQ.Deferred();
});
export const $ = {
...jQ, // We don't want to mock jQuery completely (we might want to alter $.Deferred status)
ajax,
};
export default $;
放在jquery.js
目录中,jQuery就会被笑话自动嘲笑(嗯,在这种情况下,它会被部分嘲笑...)。
使用此设置,您可以运行代码而无需发出实际请求,而通常运行__mocks__
和.done
方法以及已注册的回调。
如果您不想要在.error
或.done
中执行已注册的回调,则需要手动模拟它们,而不是返回.fail
return带有笑话模拟的普通javascript对象。
在特定的测试用例中,您肯定不希望jQ.Deferred()
/ .done
调用注册的回调:
.error
要在特定测试用例中模拟成功或错误时,请再次覆盖全局模拟实现:
为了成功:
// By returning "this" we are able to chain in the way $.ajax("/api", params).done().fail()
const jqXHR = {
done: jest.fn().mockImplementation(function () {
return this;
}),
fail: jest.fn().mockImplementation(function () {
return this;
}),
// some more $.Deferred() methods you want to mock
};
// Overwrite the global $.ajax mock implementation from __mocks__/jquery.js with our custom one
$.ajax.mockImplementation(() => jqXHR)
对于错误:
// success
const dfd = $.Deferred();
$.ajax.mockImplementation(() => {
return dfd.resolve("success"); // this is what your done callback will receive as argument
});
请注意,断言// success
const dfd = $.Deferred();
$.ajax.mockImplementation(() => {
return dfd.reject("error"); // this is what your fail callback will receive as argument
});
或.done
已被调用/未调用是没有意义的,因为总是会调用它们,因为它们都会注册您放置在其中的回调。仅当.fail
解析或拒绝特定的注册回调时,您才可以对其进行测试。
为了更好地进行单元测试,应从$.Deferred
/ .done
中排除匿名函数。由于JavaScript很奇怪,并且不像python(我更喜欢python),因此您不能轻易地在被测模块中模拟特定的函数。因此,您需要将它们放在专用模块中,然后完全模拟该模块。然后,您可以断言它们是成功调用还是错误调用。
花了我一段时间才能弄清楚如何正确地使用jquery进行模拟,所以我想在这里分享我的经验。希望这会有所帮助...