接受第三方回调的方法的 Jest 模拟实现

时间:2021-05-03 12:59:06

标签: javascript typescript unit-testing jestjs nestjs

我正在使用 Nest + Cognito 对应用程序上的用户进行身份验证,我的身份验证服务中有一个方法,我正在尝试测试/模拟:


async cognitoRegister(userPool: CognitoUserPool, {
    name,
    password,
    email
}: AuthRegisterInput): Promise < ISignUpResult > {
    return new Promise((resolve, reject) => {
        return userPool.signUp(
            name,
            password,
            [new CognitoUserAttribute({
                Name: 'email',
                Value: email
            })],
            null,
            (err, result) => {
                if (!result) {
                    reject(err);
                } else {
                    resolve(result);
                }
            },
        );
    });
}

这里的 signUp 函数是一个来自第三方 CognitoUserPool 的方法,我设法在我的 package.json 中使用模块名称映射器来模拟它,它是:

function CognitoUserPool(data) {
  const { UserPoolId, ClientId } = data;
  this.userPoolId = UserPoolId;
  this.clientId = ClientId;
  this.getCurrentUser = jest.fn().mockReturnValue("cognitouserpool");
  // This method
  this.signUp = jest.fn().mockReturnValue(true);
}
module.exports = CognitoUserPool;

是实现:

module.exports = {
  CognitoUserPool: jest.fn().mockImplementation(require("./CognitoUserPool")),
};

由于 signUp 方法接受一个回调,它负责给我一个结果/拒绝值,我应该以某种方式模拟它,否则 Jest 会给我一个超时错误,因为实现返回一个处于挂起状态的 Promise。

基本上我试图模拟这种函数:


const foo = (arg1, cb) => {
    ...do something...
}

const bar = (arg1, arg2...) => {
    return new Promise((resolve, reject) => {
        return foo(arg1, (err, result) => {
            if (!result) {
                reject(err)
            } else {
                resolve(result)
            }
        })
    })
}

这是我在测试中尝试做的事情:

it("should register a cognito user", async () => {
  const mockedCongitoUserPool = new CognitoUserPool({
    UserPoolId: authConfig.userPoolId,
    ClientId: authConfig.clientId,
  });
  const result = await service.cognitoRegister(mockedCongitoUserPool, {
    ...mockedUser,
  });
  console.log(result);
});

我也有一个 git 可以提供帮助:

Main service link

Mocked third party implementation link

Tests implementation link

感谢这里的任何帮助<3,要求进一步解释我真的需要一些帮助。

1 个答案:

答案 0 :(得分:1)

要获得静态解析,您的模拟模块应声明如下实现,而不仅仅是返回值:

this.signUp = jest.fn().mockImplementation((name, pwd, attlist, something, cb) => {
  process.nextTick(cb(null, 'signedup!'))
});

此处 process.nextTick 只是模拟异步,但如果您不在乎,也可以调用 cb(null, 'some result')

如果你想动态控制回调解析,你可以根据你的场景覆盖默认的模拟实现:

let cup: CognitoUserPool;
beforeAll(() => { // or maybe beforeEach, depends on what the mock keeps/does
  cup = new CognitoUserPool({ userPoolId: 'fakeUserPoolId', ClientId: 'fakeClientId' });
});
it('should resolve', async () => {
  const expected = { any: 'thing' };
  cup.signUp.mockImplementation((a, b, c, d, cb) => cb(null, expected));
  await expect(service.cognitoRegister(cup, mockedUser)).resolves.toBe(expected);
});
it('should fail', async () => {
  const expected = new Error('boom!');
  cup.signUp.mockImplementation((a, b, c, d, cb) => cb(expected));
  await expect(service.cognitoRegister(cup, mockedUser)).rejects.toThrow(expected);
});