如何在Cypress测试中两次Stub prompt方法?问题排查与解决
问题:单条Cypress测试用例中两次Stub prompt失败,仅第一个生效
在单条测试用例中,需完成「创建文件夹→重命名文件夹」的流程,两个操作均依赖外部prompt弹窗,需要分别Stub,但实际仅第一个Stub生效,同时报错:Attempted to wrap prompt which is already wrapped。
以下是文件夹创建方法(单场景测试可正常运行):
addFolder(folderName) { let stub; cy.window().then(win => { stub = cy.stub(win, 'prompt').returns(folderName) // 填入文件夹名称 }) cy.get(this.addFolderButtonLocator).click() cy.wrap(stub).should(() => { expect(stub).to.have.been.calledWith() }) return this; }
以下是文件夹重命名方法(仅调用第一个方法的Stub):
rename(name, newName) { let stub; cy.window().then(win => { stub = cy.stub(win, 'prompt').returns(newName) // 填入新名称 }) this.invokeSideMenu(name); cy.get(`[data-cy="${name}-rename"]`).click(); cy.wrap(stub).should(() => { expect(stub).to.have.been.calledWith() }) return this; }
问题原因
- 重复Stub未清理:Cypress的
cy.stub()包裹window.prompt后,不会自动恢复原方法,第二次尝试Stub时,原方法已被包裹,触发报错。 - 全局Stub未隔离:两次Stub直接覆盖全局的
prompt,第一个Stub未失效前,第二个Stub无法替换生效。
解决方案
方案一:每次Stub后恢复原方法
在每个操作的断言完成后,调用stub.restore()恢复prompt的原始实现,避免重复包裹报错。
修改后的创建文件夹方法:
addFolder(folderName) { let stub; cy.window().then(win => { stub = cy.stub(win, 'prompt').returns(folderName) }) cy.get(this.addFolderButtonLocator).click() cy.wrap(stub).should(() => { expect(stub).to.have.been.calledWith() }).then(() => { stub.restore() // 恢复原生prompt方法 }) return this; }
修改后的重命名方法:
rename(name, newName) { let stub; cy.window().then(win => { stub = cy.stub(win, 'prompt').returns(newName) }) this.invokeSideMenu(name); cy.get(`[data-cy="${name}-rename"]`).click(); cy.wrap(stub).should(() => { expect(stub).to.have.been.calledWith() }).then(() => { stub.restore() // 恢复原生prompt方法 }) return this; }
方案二:单Stub处理多次调用(更简洁)
如果两次prompt的调用顺序固定,可通过单个Stub依次返回不同值,无需在每个方法内单独Stub:
it('创建并重命名文件夹', () => { cy.window().then(win => { cy.stub(win, 'prompt') .onFirstCall().returns('初始文件夹') // 第一次prompt返回创建名称 .onSecondCall().returns('新文件夹名') // 第二次prompt返回重命名名称 }) // 执行流程 yourPageObject.addFolder('初始文件夹') yourPageObject.rename('初始文件夹', '新文件夹名') })
注意事项
- 方案一中的
restore()需在断言完成后执行,避免影响操作流程。 - 方案二需确保
prompt的调用顺序与Stub的onFirstCall/onSecondCall顺序完全匹配,否则会返回错误值。
内容的提问来源于stack exchange,提问作者Alex Y
相关产品推荐
相关产品推荐

