如何模拟jQuery .done(),以便它能与Jest正确执行? [英] How to mock jQuery .done() so it executes correctly with Jest?

查看:81
本文介绍了如何模拟jQuery .done(),以便它能与Jest正确执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为更改React模块的密码编写单元测试,但是我无法获得要在方括号中执行的代码.我已经为模块MyAPI编写了一个模拟程序,该模拟代码可以很好地执行,并且可以使用console.log("something")在控制台中看到输出.

I'm trying to write a unit-test for a password changing React-module, but i can't get the code to be executed in brackets. I've written a mock for the module MyAPI, the mock code is executed just fine and with console.log("something") i can see the output in console.

但是,我无法让代码在.done(function(data)(函数(数据))之后运行.最有可能是因为该模拟用自己的代码替换了这些代码.

However, i can't get the code to run after the .done(function (data). It's most likely because the mock is replacing those with it's own code.

我知道一种选择是使用像Nock这样的伪造服务器,但是除非有必要,否则我不想将其转变为集成测试.

I know one option is to use a fake server like Nock, but I wouldn't want to turn it into an integration test unless i have to.

我要测试的代码:

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的模拟文件

Mock-file for MyAPI

var MyAPI = function () {};


 MyAPI.prototype.my_api = function(url) {
 return $.ajax();
}
module.exports = new MyAPI();

还有Jest设置脚本:

And the Jest set-up script:

const jqueryMock = {
ajax: function (argument) {
  return {done: function (data) {
    return {error: function (errors) {
      return "success";
    }}}}
}}

global.$ = jqueryMock;

推荐答案

您希望执行.done.error方法,但不想实际发出请求(顺便说一句,我不知道.error方法与.fail差不多)?然后,我将执行以下操作:

You want that .done or .error methods are executed but don't want to actually make a request (btw. i don't know about an .error method just about .fail) ? Then i would do the following:

在工作目录顶层的__mocks__目录中为jquery创建全局模拟:

Create a global mock for jquery inside a __mocks__ directory at the top level of your working directory:

//__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放在__mocks__目录中,jQuery就会被玩笑自动嘲笑(嗯,在这种情况下,它会被部分嘲笑...).

By putting jquery.js inside the __mocks__ directory jQuery gets automatically mocked by jest when requested in modules you want to test (well, in this case it gets partially mocked...).

使用此设置,您可以运行代码而不发出实际请求,但通常运行.done.error方法以及已注册的回调.

With this setup you can just run your code without making an actual request but normally run .done and .error methods and the registered callbacks.

如果您不想要在.done.fail中执行已注册的回调,则需要手工模拟它们,而不是返回jQ.Deferred()来返回带有笑话的普通javascript对象模拟.

If you don't want to execute the registered callbacks in .done or .fail you need to mock them by hand and instead of returning jQ.Deferred() return a plain javascript object with jest mocks.

在特定的测试用例中,您肯定不希望.done/.error调用已注册的回调:

Inside a specific test case where you definitly don't want that .done/.error calls your registered callback:

// 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)

模拟成功或错误

要在特定测试用例中模拟成功或错误时,请再次覆盖全局模拟实现:

Simulate success or error

When you want to simulate success or error inside a specific test case again overwrite the global mock implementation:

为了成功:

// 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解析或拒绝特定的已注册回调时,您才可以对其进行测试.

Note that it does not make sense to assert that .done or .fail was called/not called since both are always called because they register the callbacks you put inside them. Only when $.Deferred resolves or rejects a specific registered callback gets executed, which you then can test.

为了更好地进行单元测试,应从.done/.error中排除匿名函数.由于JavaScript很奇怪,并且不像python(我更喜欢python),因此您不能轻易地在被测模块中模拟特定的函数.因此,您需要将它们放在专用模块中,然后完全模拟该模块.然后,您可以断言它们是在成功案例还是在错误案例中被调用的.

For better testability w.r.t unit testing you should factor out the anonymous functions from .done/.error. Since JavaScript is weird and not like python (which i like more) you cannot easily mock specific functions inside a module under test. So you would need to put them inside a dedicated module and mock this module completely. Then you could just assert that they were called either in success or error case.

花了我一段时间才弄清楚如何正确地使用jquery处理模拟,所以我想在这里分享我的经验.希望这对您有帮助...

It took me a while to figure out how to correctly handle mocking with jquery so i want to share my experience here. Hope this helps...

这篇关于如何模拟jQuery .done(),以便它能与Jest正确执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆