Cypress测试用例登录后点击菜单跳转回登录页如何解决
问题原因
登录后跳转页面就被踢回登录页,本质是没搞懂Cypress的默认执行规则:
Cypress 默认开启测试隔离,每个it()测试用例执行前,都会自动清空当前浏览器的全部状态,包括Cookie、LocalStorage、SessionStorage这些存储登录凭证的内容。
第一个登录用例跑通后,进入下一个用例时Cypress会自动清掉登录状态,这时候点击需要登录才能访问的菜单,服务端检测不到有效登录凭证,自然就重定向回登录页了。
之前把登录写在before钩子里不生效也是同一个原因:before只在整个describe块的最开始执行一次,后面每个用例执行前Cypress还是会清空状态,登录态照样留不住。
解决方法
方案1:关闭测试隔离(仅适合临时调试)
给describe块加配置,关掉默认的状态清除逻辑,同个describe下的用例就能共享浏览器状态,原有代码不需要改动,只需要加一行配置:
describe('Dashboard Page', { testIsolation: false }, function () { // 原有所有it用例直接放在这里即可 })
提醒:这种写法不符合测试用例独立的原则,前面的用例如果执行出错,很容易导致后面所有用例连锁失败,只适合临时调试场景,正式测试不推荐使用。
方案2:自定义登录命令 + beforeEach钩子(官方推荐写法)
这是Cypress官方推荐的标准实现,既能保证每个用例执行前都是已登录状态,又能做到用例之间互不干扰:
- 先在
cypress/support/commands.js文件里封装通用的登录命令,后续所有测试文件都可以直接调用:
Cypress.Commands.add('login', (username = 'Admin', password = 'admin123') => { cy.visit('https://opensource-demo.orangehrmlive.com/') cy.get('#txtUsername').type(username) cy.get('#txtPassword').type(password) cy.get('#btnLogin').click() cy.get('#welcome').contains('Welcome') })
- 改写测试文件,用
beforeEach钩子在每个用例执行前先调用登录逻辑,不需要再单独写登录的it用例:
describe('Dashboard Page', function () { // 每个用例执行前自动完成登录 beforeEach(() => { cy.login() }) it('校验Dashboard页面文本', () => { const expectText = 'Dashboard' cy.get('.head > h1').should('be.visible').then(($el) => { const actualText = $el.text() cy.log(`实际获取的文本为:${actualText}`) expect(actualText).to.eq(expectText) }) }) it('进入My Leave页面校验', () => { cy.get(':nth-child(5) > .quickLaunge > a > .quickLinkText').click() const expectText = 'My Leave List' cy.contains('My Leave List').should('be.visible').then(($el) => { const actualText = $el.text() cy.log(`实际获取的文本为:${actualText}`) expect(actualText).to.eq(expectText) }) }) })
方案3:接口登录(适合用例量大的场景提效)
如果测试用例比较多,每次都走UI输入账号密码登录速度很慢,可以直接调用登录接口拿凭证,跳过UI操作步骤,执行速度能提升好几倍:
// 同样封装成自定义命令 Cypress.Commands.add('loginByApi', (username = 'Admin', password = 'admin123') => { cy.request({ method: 'POST', url: 'https://opensource-demo.orangehrmlive.com/index.php/auth/validateCredentials', form: true, body: { txtUsername: username, txtPassword: password } }).then(() => { cy.visit('https://opensource-demo.orangehrmlive.com/index.php/dashboard') }) })
这个命令和前面的UI登录命令用法完全一致,放在beforeEach里调用即可。
优化建议
- 不要写
cy.wait(2000)这种固定时长的等待,Cypress本身自带元素重试等待机制,直接加should('be.visible')之类的断言,等元素加载完成再操作即可,用例稳定性会高很多。 - 不要把登录步骤写成单独的测试用例,登录是其他页面测试的前置条件,不是要验证的业务测试点,放在钩子或者公共命令里复用更合理。
内容的提问来源于stack exchange,提问作者Nilesh
相关产品推荐
相关产品推荐

