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

Jest模拟amazon-cognito-identity-js的authenticateUser提示未定义问题

问题:Jest模拟Amazon Cognito时出现TypeError: cognitoUser.authenticateUser is not a function

被测代码

const getNewCognitoUser = (username) => {
    const userData = {
        Username: username,
        Pool: userPool,
    };
    return new CognitoUser(userData);
};

const setAWSCredentials = (jwt) => {
    return new Promise((resolve, reject) => {
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: appConfig.IdentityPoolId,
            Logins: {
                [appConfig.Logins.cognito.identityProviderName]: jwt,
            },
        });
        AWS.config.credentials.clearCachedId();
        AWS.config.credentials.refresh((err) => {
            err ? reject(err) : resolve();
        });
    });
};

export const authenticate = (username, password) => {
    const authenticationDetails = new AuthenticationDetails({
        Username: username,
        Password: password,
    });

    cognitoUser = getNewCognitoUser(username);

    return new Promise((resolve, reject) => {
        cognitoUser.authenticateUser(authenticationDetails, {
            onSuccess: function (result) {
                setAWSCredentials(result.idToken.jwtToken)
                    .then(() => {
                        resolve(result);
                    })
                    .catch((err) => {
                        reject(err);
                    });
            },
            onFailure: function (err) {
                reject(err);
            },
            newPasswordRequired: function (userAttributes, requiredAttributes) {
                reject({
                    code: "PasswordResetRequiredException",
                    message: "New Password Required",
                    newPasswordRequired: true,
                });
            },
        });
    });
};

测试代码

import { authenticate } from "../user";
import { CognitoUser } from "amazon-cognito-identity-js";
import AWS from "aws-sdk";

jest.mock("amazon-cognito-identity-js", () => {
    const mCognitoUser = {
        authenticateUser: jest.fn((authenticationDetails, callbacks) => {
            if (callbacks && callbacks.onSuccess) {
                // Simulate a successful authentication
                callbacks.onSuccess({ idToken: { jwtToken: "fakeToken" } });
            }
        }),
    };

    return {
        CognitoUser: jest.fn(() => mCognitoUser),
        CognitoUserPool: jest.fn(),
        AuthenticationDetails: jest.fn(),
        CognitoUserAttribute: jest.fn(),
    };
});

jest.mock("aws-sdk", () => {
    const mCognitoIdentityCredentials = jest.fn().mockImplementation(() => {
        return {
            clearCachedId: jest.fn(),
            refresh: jest.fn(),
        };
    });

    return {
        CognitoIdentityCredentials: mCognitoIdentityCredentials,
        config: {},
    };
});

describe("do I understand mocks", () => {
    test("let's find out", async () => {
        console.log(CognitoUser);
        const mCognitoUser = new CognitoUser();
        console.log(mCognitoUser);
        console.log(mCognitoUser.authenticateUser);

        await authenticate("foo", "bar");
        expect(CognitoUser.authenticate).toBeCalledTimes(1);
    });
});

错误信息

TypeError: cognitoUser.authenticateUser is not a function

问题分析与解决

1. 核心原因:Cognito相关对象未被正确mock

被测代码中的CognitoUser、AuthenticationDetails如果不是从amazon-cognito-identity-js模块导入,而是使用全局对象,Jest的mock将无法生效,导致getNewCognitoUser创建的是真实的CognitoUser实例(而非mock对象),自然没有你定义的authenticateUser方法。

解决:
在被测代码顶部添加正确的模块导入:

import { CognitoUser, AuthenticationDetails, CognitoUserPool } from 'amazon-cognito-identity-js';

同时确保userPool也是通过mock的构造函数创建:

// 假设appConfig是你的配置模块
import appConfig from './path/to/appConfig';

const userPool = new CognitoUserPool({
  UserPoolId: appConfig.UserPoolId,
  ClientId: appConfig.ClientId
});

2. 全局变量导致的意外覆盖

被测代码中cognitoUser = getNewCognitoUser(username);未使用const/let声明,属于全局变量,可能在测试环境中被意外修改,导致指向非mock对象。

解决:
将其改为局部变量:

const cognitoUser = getNewCognitoUser(username);

3. AWS mock的refresh方法未触发Promise resolve

当前AWS mock中refresh只是空函数,未调用传入的回调,会导致setAWSCredentials的Promise一直处于pending状态,进而影响authenticate的执行流程。

解决:
修改AWS mock,让refresh调用回调函数:

jest.mock("aws-sdk", () => {
    const mCognitoIdentityCredentials = jest.fn().mockImplementation(() => {
        return {
            clearCachedId: jest.fn(),
            refresh: jest.fn((callback) => callback(null)), // 传入null表示认证成功
        };
    });

    return {
        CognitoIdentityCredentials: mCognitoIdentityCredentials,
        config: {},
    };
});

4. 测试断言错误

原测试中的expect(CognitoUser.authenticate).toBeCalledTimes(1);是错误的,CognitoUser是构造函数,没有authenticate方法,应该断言构造函数调用次数或authenticateUser的调用次数。

修正后的测试断言:

test("let's find out", async () => {
    const result = await authenticate("foo", "bar");
    
    // 断言CognitoUser构造函数被调用1次
    expect(CognitoUser).toBeCalledTimes(1);
    // 获取mock的CognitoUser实例,断言authenticateUser被调用1次
    const mockCognitoUser = CognitoUser.mock.results[0].value;
    expect(mockCognitoUser.authenticateUser).toBeCalledTimes(1);
    // 断言认证结果正确
    expect(result).toEqual({ idToken: { jwtToken: "fakeToken" } });
});

5. 补充:mock全局配置appConfig

如果appConfig是外部模块,需要同步mock它,避免测试中因配置缺失报错:

jest.mock('../path/to/appConfig', () => ({
  UserPoolId: 'fake-user-pool-id',
  IdentityPoolId: 'fake-identity-pool-id',
  Logins: {
    cognito: {
      identityProviderName: 'fake-provider-name'
    }
  }
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:25:05