【问题标题】:How to mock a function that will have then and catch block?如何模拟将具有 then 和 catch 块的函数?
【发布时间】:2021-10-31 03:05:17
【问题描述】:

我使用 Firebase 身份验证,我想使用 Jest 和 react-hooks-testing-library 测试该功能。

我有一个这样的函数:

const loginWithEmailPassword = (email: string, password: string) => {

    const auth = getAuth()

    signInWithEmailAndPassword(auth, email, password)
        .then((userCredential) => {
            // Signed in 
            const user = userCredential.user;
            // ...
        }).catch((error) => {
            const errorCode = error.code;
            const errorMessage = error.message;
        });

}

signInWithEmailPassword() 函数有一个 then()catch() 块。

我用这段代码模拟了这个函数:

const mockSignUp = jest.fn(() => {
    return Promise.resolve({
        user: {
            uid: "fakeuid",
        },
    });
})

jest.mock('firebase/auth', () => ({
    getAuth: () => mockGetAuth,
    signInWithEmailAndPassword: () => mockSignIn,
    createUserWithEmailAndPassword: () => mockSignUp
}))

然后我使用react-hooks-testing-library 测试上面的函数,如下所示:

 test('Login with Email and Password', () => {
    const { result } = renderHook(() => useFirebaseAuth())

    const email = 'abc@gmail.com'
    const password = '123456'
  
    // here fired my loginWithEmailPassword above
    act(() => {
        // the problem come from this line
        result.current.loginWithEmailPassword(email, password)
    })

然后我的测试失败并出现此错误:

 TypeError: (0 , _auth.signInWithEmailAndPassword)(...).then is not a function

      46 |
      47 |         signInWithEmailAndPassword(auth, email, password)
    > 48 |             .then((userCredential) => {

如果我删除 then 块,测试通过。但是,如果我使用调用 then() 的函数,它会得到错误。我检查了我的模拟 signInWithEmailAndPassword 并返回 Promise.resolve() 应该没问题,但它仍然有错误。

我是测试领域的新手。请有人对此提出一些建议并告诉我我的测试有什么问题?我完全不知道

在寻找这个answer之后,我试图像这样模拟它:

const mockSomething = jest.fn().mockImplementation(() => Promise.resolve({
    user: {
        uid: "fakeuid",
    },
}))

但还是有同样的错误

【问题讨论】:

    标签: reactjs firebase jestjs react-testing-library react-hooks-testing-library


    【解决方案1】:

    最后我能够通过模拟一个函数来解决这个问题,该函数将返回用user 解决的承诺,如下所示:

    jest.mock('firebase/auth', () => {
        return {
            getAuth: () => mockGetAuth,
             
            // since this method from firebase return a promise, here need a promise as well 
            signInWithEmailAndPassword: jest.fn().mockResolvedValue({
               user: {
                   uid: "fakeUid",
                },
              }),
            createUserWithEmailAndPassword: jest.fn().mockResolvedValue({
                 user: {
                   uid: "fakeUid",
                 },
              }),
        }
    })
    

    signInWithEmailPassword 中,我直接返回 Promise 而不用 jest.fn() 包装它

    然后在测试中,我可以这样做:

    import { signInWithEmailAndPassword, getAuth } from 'firebase/auth';
    
    // here I can check that `signInWithEmailPassword is call with some value
    expect(signInWithEmailAndPassword).toBeCalledWith(
      getAuth(),
      email,
      password
    );
    
    // Here I can compare my UI to the fakeUid as well 
    expect(data.user.uid).toEqual('fakeUid')
    

    在测试中,我必须直接从firebase/auth 拨打signInWithEmailAndPassword

    由于我已经模拟了jest.mock()中的函数,因此在测试中它将返回我直接定义的假数据,即data: { user: { uid: 'fakeUid' } }

    整个过程是这样的:

    • firebase/auth 模块中有一个实际函数,名为signInWithEmailPassword
    • 但我不想“真的”调用它,因此我创建了一个具有相同名称的假函数,它将返回与jest.mock() 中的实际函数相同的内容(在本例中为 Promise)
    • 现在,在 test 部分,我直接从 Firebase 调用该函数,但现在不是从 Firebase 调用它,而是返回“假”Promise 以及我刚刚定义的假数据.
    • 然后我可以使用expect(data.user.uid).toEqual('fakeUid')将它与一个值进行比较

    【讨论】:

      猜你喜欢
      • 2021-11-08
      • 2021-09-21
      • 1970-01-01
      • 2021-06-09
      • 2018-03-03
      • 2018-04-23
      • 2016-02-14
      • 2019-10-07
      • 2019-12-08
      相关资源
      最近更新 更多