【问题标题】:Jest spyOn vs mock - both defined and undefined errorsJest spyOn vs mock - 已定义和未定义的错误
【发布时间】:2019-12-04 03:23:13
【问题描述】:

刚刚在我的 jest 配置中升级到 jsdom-14。它工作得很好,但是一个测试失败了。

test('Do the thing', () => {
    window.location.assign = jest.fn();
});

我继承了这个代码。它看起来像一个足够简单的笑话模拟。它抱怨它无法分配只读属性assign,这是有道理的,我认为这是添加的 jsdom 功能。

但是...我也不能做jest.spyOn,这似乎是建议的。我以前没用过 spyOn。

jest.spyOn(window.location.assign);

但这给了我一个未定义的属性错误:

 Cannot spy the undefined property because it is not a function; undefined given instead

在此之前的行,我添加了一个日志只是为了检查。绝对是一个函数:

console.log(window.location.assign);
=> [Function: assign]

我不确定这两个错误如何共存 - 已定义和未定义?

【问题讨论】:

  • 尝试delete这个属性(delete window.location.assign)然后重新添加。

标签: vue.js jestjs


【解决方案1】:

由于 JavaScript 的工作方式,不可能像 spyOn(window.location.assign) 那样编写 spyOn 函数。在spyOn 中,可以检索作为参数提供的window.location.assign 函数,但不能检索window.location 对象和assign 方法名称来执行window.location.assign = jest.fn()

spyOn的签名是:

jest.spyOn(object, methodName)

应该是:

jest.spyOn(window.location, 'assign');

这也可能不可行,因为window.location.assign 在以后的 JSDOM 版本中是只读的,Jest 使用它来模拟 Node.js 中的 DOM。该错误确认这是问题所在。

可以手动模拟只读属性:

const origAssign = Object.getOwnPropertyDescriptor(window.location, 'assign'); 

beforeEach(() => { 
  Object.defineProperty(window.location, 'assign', { value: jest.fn() })
});

afterEach(() => { 
  Object.defineProperty(window.location, 'assign', origAssign)
});

这不适用于真正的 DOM,因为内置函数可能是只读且不可配置的。这是 Chrome 中的问题。出于可测试性的原因,使用 location.href 而不是 location.assign 可能会有所帮助。

【讨论】:

  • jest.spyOn(window.location, "assign"); 给我TypeError: Cannot assign to read only property 'assign' of object '[object Location]'
  • 是的,我正要更新答案。这取决于使用了哪个 Jest 和 JSDOM(Jest 使用它来模拟 DOM)版本。许多内置函数在真实 DOM 中可能是不可模拟的,包括 location.assign。在 Chrome 中就是这样。您可以尝试像答案中描述的那样手动模拟它。但是切换到 location.href 会更容易。
【解决方案2】:

最终解决了一些问题,found this

delete global.window.location;
window.location = { assign : jest.fn()};

由于 jsdom 的后续迭代似乎越来越多地锁定位置对象,直到它完全不可修改,@Estus 的答案仅适用于较低版本的 jsdom/jest。

【讨论】:

  • 请注意,在 beforeEach/afterEach 之外这样做是不安全的,因为这会导致测试交叉污染,window.location = 分配也可能是一个问题。
  • 给我错误The operand of a 'delete' operator must be optional.
猜你喜欢
  • 2022-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多