开玩笑spyOn vs模拟-定义和未定义的错误

时间:2019-07-25 19:22:50

标签: vue.js jestjs

在我的jest配置中,仅升级到jsdom-十四。效果很好,但是一次测试失败了。

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]

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

2 个答案:

答案 0 :(得分:2)

由于JavaScript的工作方式,不可能像spyOn那样编写spyOn(window.location.assign)函数。在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可能是有益的。

答案 1 :(得分:1)

最终完成了一些工作,found this

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

由于后来出现的jsdom迭代将位置对象越来越向下锁定,直到它完全不可修改为止,@ Estus的答案仅在较低版本的jsdom / jest中起作用。