首页 > 解决方案 > 在 Jest 上模拟 jQuery ajax 调用

问题描述

所以我有这个在product.html页面上加载和使用的foo_script.js文件,最后脚本添加了一个包含数据的 DIV DOM 元素。DIV 的信息来自函数“fetchData”:

var fetchData = function (callback) {
  $.ajax({
     url: "foo_data.json",
     type: "GET",
     success: function success(data) {
       assignDataToDiv(data);
       callback();
     }
   });
 }

我正在尝试使用 Jest使用此index.test.js文件测试foo_script.js :

it('fetchs data and changes the div', () => {
  document.body.innerHTML = fs.readFileSync(path.resolve(__dirname, './basic.html'), 'utf8');

  spyOn($, "ajax").mockImplementation(({ success }) => success( {
  url: "https://example.api",
  success: "fooBar"
}));

  spyOn($, 'ajax').andCallFake( function (params) {
   params.success({foo: 'bar'});
 });

  require('./foo_script.js');

  const targetedDiv = document.querySelector('.ugly_class');
  expect(targetedDiv.textContent.indexOf('Ay caramba')).toBeGreaterThan(0);
});

一切都很好,函数fetchData()中的原始 Ajax 调用总是执行,而不是“模拟”ajax 方法。我需要将 fetchData() 函数更改为 Promise 而不是回调吗?还是需要我的 sinon 东西?SpyOn() 方法不是拦截器吗?顺便说一句,我是 Jest 的新手。

标签: ajaxjestjs

解决方案


我是这样做的:

let proxied = window.XMLHttpRequest.prototype.open;
let open = (method, url, async, user, password) => {
  return (method, url, async, user, password) => { proxied.apply(this, arguments); };
};
const onload = jest.fn((_x) => {
  return JSON.stringify({"ip":"189.216.190.174","country_code":"MX","country_name":"Mexico"});
});
const onerror = jest.fn();
const send = jest.fn(function(){
  this.onload();
});
const setRequestHeader = jest.fn();
const xhrMockClass = function () {
  return {
    open,
    send,
    onerror,
    onload,
    setRequestHeader
  };
};

global.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);

推荐阅读