2

我使用 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()应该没问题,但它仍然有错误。

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

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

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

但仍然有同样的错误

4

1 回答 1

0

最后,我能够通过模拟一个函数来解决这个问题,该函数将返回这样解决的承诺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')

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

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

整个过程是这样的:

  • firebase/auth在名为的模块中有一个实际功能signInWithEmailPassword
  • 但我不想“真的”调用它,因此我制作了一个具有相同名称的假函数,它将返回与内部实际函数相同的东西(在这种情况下为 Promise)jest.mock()
  • 现在,在test部分中,我直接从 Firebase 调用该函数,但现在不是从 Firebase 调用它,而是返回Promise带有我刚才定义的假数据的“假”。
  • 然后我可以通过使用将它与一个值进行比较expect(data.user.uid).toEqual('fakeUid')
于 2021-09-01T18:34:08.903 回答