如何使用Sinon Stub window.innerWidth与innerHeight属性?
解决Sinon无法Stub window.innerWidth/innerHeight的问题
我懂你遇到的困扰——浏览器原生的window.innerWidth和innerHeight是只读属性,它们的属性描述符默认是不可配置的,所以直接用Sinon的sandbox.stub().get()不会生效。下面给你几个可行的解决方案:
方法1:先修改属性描述符,再Stub
因为这类原生属性默认configurable: false,Sinon没法直接覆盖它的getter。我们需要先把它改成可配置的,再进行Stub:
describe('test', () => { let sandbox; beforeEach(() => { sandbox = sinon.sandbox.create(); // 先修改window.innerWidth/innerHeight的属性描述符,开启可配置性 Object.defineProperty(window, 'innerWidth', { configurable: true, writable: true, }); Object.defineProperty(window, 'innerHeight', { configurable: true, writable: true, }); // 现在可以正常Stub了,两种写法都支持: // 直接设值 sandbox.stub(window, 'innerWidth').value(1000); sandbox.stub(window, 'innerHeight').value(1000); // 或者用getter函数 // sandbox.stub(window, 'innerWidth').get(() => 1000); // sandbox.stub(window, 'innerHeight').get(() => 1000); }); afterEach(() => { sandbox.restore(); // 可选:恢复原属性的不可配置性,避免影响其他测试 Object.defineProperty(window, 'innerWidth', { configurable: false, writable: false, }); Object.defineProperty(window, 'innerHeight', { configurable: false, writable: false, }); }); it('should do a thing', () => { console.log(window.innerWidth); // 现在会输出1000了 }); });
方法2:简化版(适合jsdom环境)
如果你是在jsdom(比如Jest默认环境)下测试,甚至可以不用Sinon,直接重写属性:
beforeEach(() => { Object.defineProperty(window, 'innerWidth', { value: 1000, configurable: true, }); }); afterEach(() => { delete window.innerWidth; });
当然如果项目统一用Sinon做Stub,方法1会更符合你的测试习惯。
关键原理
浏览器原生的innerWidth/innerHeight这类属性,默认的属性描述符是:
Object.getOwnPropertyDescriptor(window, 'innerWidth'); // 返回:{ value: 1024, writable: false, enumerable: true, configurable: false }
因为configurable: false,所以任何试图修改属性定义的操作(包括Sinon的Stub)都会被忽略。必须先把configurable改成true,才能让Sinon成功覆盖它的取值逻辑。
内容的提问来源于stack exchange,提问作者Ben Lorantfy
相关产品推荐
相关产品推荐

