Webcomponent Tester:如何断言函数未被调用?
嘿,我之前在Polymer 1.x搭配Web Component Tester(WCT)做测试时,也踩过几乎一模一样的坑!你遇到的问题本质是断言没有被正确执行,所以不管写expect(alert.open).to.have.been.called还是相反的断言,测试都提示“未断言失败”。结合我的踩坑经验,大概率是这几个原因:
可能的问题点
- Spy创建时机不对:如果是在元素已经初始化、甚至
open方法已经被调用之后才创建的spy,那spy根本捕获不到任何调用,断言自然无效。 - 异步操作没处理:Polymer元素的很多行为(比如属性变更、DOM渲染、方法触发)都是异步的,要是你没等这些异步操作完成就跑断言,断言会在实际行为发生前就执行完,WCT就会误以为你没写有效断言。
- Spy挂错了对象:如果
alert是你页面里的自定义元素实例(比如<iron-alert>),你得确保spy是挂在实际被调用的那个实例的open方法上,而不是一个无关的全局对象或者其他实例。
一步步解决
1. 先创建Spy,再实例化元素
在测试的setup钩子里面,先把spy创建好,再通过fixture实例化你的测试元素,这样元素初始化过程中所有对alert.open的调用都会被spy捕获:
suite('你的组件测试', function() { let alertElement; let testElement; setup(function() { // 先获取测试模板里的alert元素 const testFixture = fixture('你的测试模板ID'); alertElement = testFixture.querySelector('iron-alert'); testElement = testFixture.querySelector('你的组件'); // 给alertElement的open方法创建spy sinon.spy(alertElement, 'open'); }); teardown(function() { // 测试结束后恢复原方法,别影响其他测试 alertElement.open.restore(); }); });
2. 等待异步操作完成再断言
Polymer自带了Polymer.Base.async()方法来等待异步队列完成,或者你也可以用WCT支持的done回调、async/await:
test('alert.open 应该不会被调用', function(done) { // 执行可能触发alert.open的操作(比如点击按钮、修改属性) testElement.doSomething(); // 等Polymer的异步操作都跑完再断言 Polymer.Base.async(function() { // 用Chai + Sinon的断言语法 expect(alertElement.open).to.not.have.been.called; // 或者用Sinon原生断言更直接:sinon.assert.notCalled(alertElement.open); done(); // 一定要调用done,告诉WCT测试结束了! }); });
如果习惯用async/await(WCT支持ES2017语法),可以这么写:
test('alert.open 应该不会被调用', async function() { testElement.doSomething(); // 等一个微任务周期,确保Polymer的异步操作都完成 await new Promise(resolve => Polymer.Base.async(resolve)); expect(alertElement.open).to.not.have.been.called; });
3. 先验证Spy是否真的生效
你可以先写个简单的测试,手动调用alertElement.open(),看看spy能不能捕获到,确认spy没问题:
test('验证spy是否正常工作', function() { alertElement.open(); expect(alertElement.open).to.have.been.calledOnce; // 或者检查调用次数:expect(alertElement.open.calledCount).to.equal(1); });
避坑提醒
- 别在测试函数里才创建spy:如果元素在测试前已经初始化,spy会错过之前的所有调用。
- 别忘了调用
done():如果测试里有异步操作,WCT会一直等,直到超时,最后就会报错“未断言”。 - 别spy错对象:比如你spy了全局的
alert,但实际调用的是页面里某个元素实例的alert.open,两者不是同一个对象,spy自然无效。
内容的提问来源于stack exchange,提问作者dman
相关产品推荐
相关产品推荐

