Cypress组件测试中如何断言回调参数?解决二次调用断言失败问题
问题描述
我有一个需要传入回调函数作为props的React组件,目前通过cy.stub()传入存根可以检查回调是否被调用,但需要断言回调的调用参数是否匹配预期对象。测试代码如下:
it('test plain', () => { const expected = {"BusinessPartner": {}} const expected2 = {"BusinessPartner": {...expected.BusinessPartner, ext_id: "123A"}} const onSubmitStub = cy.stub().as('submitted'); cy.mount( <OpenApiForm oajson={oajson} formRootObject="BusinessPartner" onSubmit={onSubmitStub} /> ) cy.get('[data-cy = "submit-form"]').click() cy.get('@submitted').should('have.been.called') // 期望调用参数为expected cy.get('[id = "#/properties/ext_id-input"]').type("123A") cy.get('[data-cy = "submit-form"]').click() cy.get('@submitted').should('have.been.called') // 期望调用参数为expected2 })
尝试用calledWithMatch断言第一次调用成功,但第二次调用的断言失败,即使单独测试第二次操作也无法通过。尝试将回调参数渲染到隐藏div中获取,同样失败,添加cy.wait(500)也无效,但手动操作正常。
解决方案
1. 针对多次调用的精准断言
直接使用calledWithMatch会检查存根的所有调用记录是否存在匹配项,但如果需要断言某一次特定调用的参数,应该用getCall(n)获取第n次调用(从0开始计数),再结合断言:
it('test plain', () => { const expected = {"BusinessPartner": {}} const expected2 = {"BusinessPartner": {...expected.BusinessPartner, ext_id: "123A"}} const onSubmitStub = cy.stub().as('submitted'); cy.mount( <OpenApiForm oajson={oajson} formRootObject="BusinessPartner" onSubmit={onSubmitStub} /> ) // 第一次提交:断言第0次调用的参数 cy.get('[data-cy="submit-form"]').click() cy.get('@submitted').should(stub => { expect(stub.getCall(0)).to.be.calledWithMatch(expected); }); // 输入值后第二次提交:断言第1次调用的参数 cy.get('[id="#/properties/ext_id-input"]').type("123A"); cy.get('[data-cy="submit-form"]').click(); cy.get('@submitted').should(stub => { expect(stub.getCall(1)).to.be.calledWithMatch(expected2); // 调试用:打印实际调用参数,对比预期值 cy.log('第二次调用实际参数:', JSON.stringify(stub.getCall(1).args[0])); }); })
2. 排查参数不匹配的原因
如果第二次断言仍然失败,核心是实际传入的参数和expected2存在差异,可以通过以下方式排查:
添加存根日志:在定义stub时加入
callsFake,实时打印回调接收的参数:const onSubmitStub = cy.stub() .callsFake(submitData => cy.log('实际提交参数:', JSON.stringify(submitData))) .as('submitted');对比打印出的参数和
expected2,检查是否有额外字段、字段值类型不符(比如ext_id是数字而非字符串),或者输入值未正确绑定到表单状态。验证输入操作有效性:检查输入框选择器是否正确,比如
[id="#/properties/ext_id-input"]是否真的指向目标元素(通常id不会包含#,可能是选择器错误)。可以用cy.get('[id="#/properties/ext_id-input"]').should('be.visible').type("123A").should('have.value', '123A')验证输入是否成功。处理异步提交场景:如果组件内部有异步验证或状态更新,回调可能延迟触发。可以通过等待组件的状态变化(比如某个加载提示消失),或者直接针对stub的调用状态断言:
cy.get('[data-cy="submit-form"]').click(); cy.wrap(onSubmitStub).should('have.been.calledWithMatch', expected2);
3. 深层对象匹配的注意事项
calledWithMatch支持部分匹配,但如果需要严格匹配对象的所有属性,可以用deep.equal替代:
expect(stub.getCall(1).args[0]).to.deep.equal(expected2);
这种方式会检查对象的完整结构和值,适合需要精确断言的场景。
内容的提问来源于stack exchange,提问作者KIC

