如何在Nuxt与Cypress中实现模拟认证?
NuxtJS + Cypress 模拟JWT登录测试失败问题排查与解决
问题场景
使用FastAPI后端发放JWT,NuxtJS前端集成认证模块实现登录流程。编写Cypress测试时,模拟登录命令执行后,访问dashboard页面断言$auth.loggedIn为true失败,且用户未按预期完成重定向。
现有代码
测试用例
// cypress/e2e/user_authentication_test.cy.js describe("A User logging in", () => { it.only("can login by supplying the correct credentials", () => { cy.mockLogin().then(() => { cy.visit(`${Cypress.env("BASE_URL")}/dashboard`) .window() .its("$nuxt.$auth") .its("loggedIn") .should("equal", true); }); }); });
Cypress自定义命令
// cypress/support/commands.js Cypress.Commands.add( 'mockLogin', (username = 'someone', password = 'my_secret_password_123') => { cy.intercept('POST', 'http://localhost:5000/api/v1/auth/token', { fixture: 'auth/valid_auth_token.json', }).as('token_mock') cy.visit(`${Cypress.env('BASE_URL')}/login`) cy.get('#login-username').type(username) cy.get('#login-password').type(`${password}{enter}`) cy.wait('@token_mock') } )
Nuxt登录组件逻辑
<!-- components/auth/LoginForm.vue --> <template> <!-- 登录表单结构 --> </template> <script> import jwt_decode from 'jwt-decode' export default { name: 'LoginForm', data() { return { username: '', password: '', } }, methods: { async login() { const formData = new FormData() formData.append('username', this.username) formData.append('password', this.password) try { await this.$auth .loginWith('cookie', { data: formData, }) .then((res) => { const decode = jwt_decode(res.data.access_token) this.$auth.setUser(decode) this.$router.push('/') }) } catch (error) { // 错误处理逻辑 } }, }, } </script>
问题原因分析
- 异步流程未等待完成:
mockLogin仅等待了token请求结束,但Nuxt的$auth状态更新、用户信息存储、路由跳转均为异步操作,命令提前返回导致后续访问dashboard时认证状态未就绪。 - 路由重定向未验证:测试用例直接访问dashboard,若Nuxt配置了认证中间件,会因未登录状态自动重定向到登录页,导致断言失败。
- 响应结构不匹配:若
valid_auth_token.json的格式不符合$auth.loginWith的预期(比如缺少access_token字段),会导致登录逻辑执行异常。
解决方案
1. 优化mockLogin命令,等待登录流程完全完成
修改自定义命令,在等待token请求后,添加路由跳转验证和认证状态断言,确保登录流程彻底完成后再返回:
// cypress/support/commands.js Cypress.Commands.add( 'mockLogin', (username = 'someone', password = 'my_secret_password_123') => { cy.intercept('POST', 'http://localhost:5000/api/v1/auth/token', { fixture: 'auth/valid_auth_token.json', }).as('token_mock') cy.visit(`${Cypress.env('BASE_URL')}/login`) cy.get('#login-username').type(username) cy.get('#login-password').type(`${password}{enter}`) cy.wait('@token_mock') // 等待路由跳转到首页,确认登录成功 cy.url().should('eq', `${Cypress.env('BASE_URL')}/`) // 等待认证状态更新为已登录 cy.window().its('$nuxt.$auth.loggedIn').should('equal', true) } )
2. 调整测试用例逻辑
由于mockLogin已确保登录状态,测试用例可简化为:
// cypress/e2e/user_authentication_test.cy.js describe("A User logging in", () => { it.only("can login by supplying the correct credentials", () => { cy.mockLogin() // 验证登录状态 cy.window().its('$nuxt.$auth.loggedIn').should('equal', true) // 验证可正常访问dashboard cy.visit(`${Cypress.env("BASE_URL")}/dashboard`) cy.contains('Dashboard').should('exist') // 根据实际页面内容调整断言 }); });
3. 确保响应fixture结构正确
valid_auth_token.json需匹配FastAPI token接口的返回格式,示例:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" }
4. 优化登录组件代码(可选)
避免await与then混用,让代码逻辑更清晰:
async login() { const formData = new FormData() formData.append('username', this.username) formData.append('password', this.password) try { const res = await this.$auth.loginWith('cookie', { data: formData }) const decodedUser = jwt_decode(res.data.access_token) this.$auth.setUser(decodedUser) this.$router.push('/') } catch (error) { // 错误处理逻辑 } }
内容的提问来源于stack exchange,提问作者Bradley Marques
相关产品推荐
相关产品推荐

