You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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>

问题原因分析

  1. 异步流程未等待完成:mockLogin仅等待了token请求结束,但Nuxt的$auth状态更新、用户信息存储、路由跳转均为异步操作,命令提前返回导致后续访问dashboard时认证状态未就绪。
  2. 路由重定向未验证:测试用例直接访问dashboard,若Nuxt配置了认证中间件,会因未登录状态自动重定向到登录页,导致断言失败。
  3. 响应结构不匹配:若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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:51:29