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

Cypress 12 TypeScript项目AWS Cognito程序化认证报错求助

解决Cypress 12.5 + TypeScript中AWS Cognito认证的Class extends value undefined错误

问题根源

错误堆栈指向@aws-sdk/client-lex-runtime-service模块,本质是AWS Amplify v5+依赖的AWS SDK v3与Cypress的Webpack打包环境不兼容:导入完整aws-amplify包会自动加载大量无关模块(如Lex服务),这些模块的基类在Cypress运行时无法被正确解析,导致继承错误。

解决方案

以下提供两种可行方案,优先推荐方案2(无Amplify依赖,更稳定):


方案1:调整Amplify导入与Webpack配置

仅导入所需的Auth模块,排除冲突的AWS SDK模块:

1.1 修改cypress/support/cognito.ts

替换完整Amplify导入为单独Auth模块导入,并直接配置Auth:

import { Auth, SignInResult } from '@aws-amplify/auth'

// 仅配置Auth模块,无需加载整个Amplify
Auth.configure(Cypress.env('cognito.config'))

Cypress.Commands.add('loginByCognitoApi', (username: string, password: string) => {
  const log = Cypress.log({
    displayName: 'COGNITO LOGIN',
    message: [`🔐 Authenticating | ${username}`],
    autoEnd: false,
  })

  log.snapshot('before')

  return cy.wrap(Auth.signIn({ username, password }), { log: false }).then((cognitoResponse: SignInResult) => {
    if (!cognitoResponse.signInUserSession) {
      throw new Error('Cognito会话获取失败')
    }

    const { username: cognitoUsername, keyPrefix } = cognitoResponse
    const keyPrefixWithUsername = `${keyPrefix}.${cognitoUsername}`

    window.localStorage.setItem(`${keyPrefixWithUsername}.idToken`, cognitoResponse.signInUserSession.idToken.jwtToken)
    window.localStorage.setItem(`${keyPrefixWithUsername}.accessToken`, cognitoResponse.signInUserSession.accessToken.jwtToken)
    window.localStorage.setItem(`${keyPrefixWithUsername}.refreshToken`, cognitoResponse.signInUserSession.refreshToken.token)
    window.localStorage.setItem(`${keyPrefixWithUsername}.clockDrift`, cognitoResponse.signInUserSession.clockDrift.toString())
    window.localStorage.setItem(`${keyPrefix}.LastAuthUser`, cognitoUsername)
    window.localStorage.setItem('amplify-authenticator-authState', 'signedIn')

    log.snapshot('after')
    log.end()
  })
})

1.2 修复TypeScript类型声明(cypress/support/index.ts)

修正命令返回类型(该命令不返回DOM元素):

export {}

declare global {
  namespace Cypress {    
    interface Chainable<Subject = any> {
      loginAs(role: string): Chainable<JQuery<HTMLElement>>;
      clickMenuLink(linkText: string): Chainable<JQuery<HTMLElement>>;
      loginByCognitoApi(username: string, password: string): Chainable<void>;
    }
  }
}

1.3 配置Cypress Webpack排除冲突模块

在cypress.config.ts中添加Webpack预处理器配置:

import { defineConfig } from 'cypress'
import webpack from '@cypress/webpack-preprocessor'

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      const webpackOptions = {
        resolve: { extensions: ['.ts', '.js'] },
        module: {
          rules: [
            {
              test: /\.ts$/,
              exclude: /node_modules/,
              use: { loader: 'ts-loader' }
            }
          ]
        },
        externals: {
          // 排除引发错误的Lex服务模块
          '@aws-sdk/client-lex-runtime-service': 'commonjs @aws-sdk/client-lex-runtime-service',
          // 可选:排除其他无需的AWS SDK v3模块
          '@aws-sdk/client-cognito-identity': 'commonjs @aws-sdk/client-cognito-identity'
        }
      }

      on('file:preprocessor', webpack({ webpackOptions }))
      return config
    },
    env: {
      cognito: {
        config: {
          userPoolId: '你的用户池ID',
          userPoolWebClientId: '你的客户端ID',
          region: '你的区域'
        }
      }
    }
  }
})

方案2:直接调用Cognito API(无Amplify依赖)

完全避开Amplify库,用cy.request直接调用Cognito的InitiateAuth接口,稳定性更高:

修改cypress/support/cognito.ts

Cypress.Commands.add('loginByCognitoApi', (username: string, password: string) => {
  const log = Cypress.log({
    displayName: 'COGNITO LOGIN',
    message: [`🔐 Authenticating | ${username}`],
    autoEnd: false,
  })

  log.snapshot('before')

  const { userPoolId, userPoolWebClientId, region } = Cypress.env('cognito.config')

  return cy.request({
    method: 'POST',
    url: `https://cognito-idp.${region}.amazonaws.com/`,
    headers: {
      'Content-Type': 'application/x-amz-json-1.1',
      'X-Amz-Target': 'AWSCognitoIdentityProviderService.InitiateAuth'
    },
    body: {
      AuthFlow: 'USER_PASSWORD_AUTH',
      ClientId: userPoolWebClientId,
      AuthParameters: { USERNAME: username, PASSWORD: password }
    }
  }).then((response) => {
    const { IdToken, AccessToken, RefreshToken } = response.body.AuthenticationResult
    const keyPrefix = `CognitoIdentityServiceProvider.${userPoolWebClientId}`
    const keyPrefixWithUsername = `${keyPrefix}.${username}`

    window.localStorage.setItem(`${keyPrefixWithUsername}.idToken`, IdToken)
    window.localStorage.setItem(`${keyPrefixWithUsername}.accessToken`, AccessToken)
    window.localStorage.setItem(`${keyPrefixWithUsername}.refreshToken`, RefreshToken)
    window.localStorage.setItem(`${keyPrefix}.LastAuthUser`, username)
    window.localStorage.setItem('amplify-authenticator-authState', 'signedIn')

    log.snapshot('after')
    log.end()
  })
})

测试验证

在测试用例中调用命令:

describe('认证测试', () => {
  it('通过Cognito登录', () => {
    cy.loginByCognitoApi('测试用户名', '测试密码')
    cy.visit('https://myurl.com/login')
    // 验证登录状态,比如检查用户信息元素
    cy.get('.user-profile').should('be.visible')
  })
})

内容的提问来源于stack exchange,提问作者Dave H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:21:31