admin管理员组

文章数量:1297112

I have a hook that retrieves data from a firebase backend if the storage is clear. The unit test keeps failing as a result of the null return value.

Here's the hook

import { useEffect, useState } from "react";
import useGetUserId from "./useGetUserId";

import { app, firebaseConfig } from "../environments/environment";
import { doc, getDoc, getFirestore } from "firebase/firestore";
import 'firebase/firestore';
import { initializeApp } from "firebase/app";

const useGetUserProfile = () => {
  type profile = {
    email: string;
    username: string;
    userBio: string;
    dob: Date;
    gender: string;
    sexo: string;
    education: string;
    drinkingHabits: string;
    smokingHabits: string;
  };

  // const db = getFirestore(app);
  const userId: string | null = useGetUserId();
  const [isLoading, setIsLoading] = useState(true);
  const [userProfile, setUserProfile] = useState<any | null>(null);

  useEffect(() => {
    const userProfile = async () => {
      setIsLoading(true);
      try {
        const userRef = localStorage.getItem("PROFILE_INFO");
        if (userRef) {
          const profile: profile = JSON.parse(userRef);
          setUserProfile(profile);
        } else {
          const app = initializeApp(firebaseConfig);
          const db = getFirestore(app);
          if (userId) {
            const id = JSON.parse(userId);
            const userRef = await getDoc(doc(db, "users", id.user.uid));
            if (userRef.exists()) {
              const profile = userRef.data();
              setUserProfile(profile);
            }
          }
        }
      } catch (error) {
        console.log("error", error);
      } finally {
        setIsLoading(false);
      }
    };
    userProfile();
  }, [setUserProfile]);
  return {
    isLoading,
    userProfile, setUserProfile
  };
};

export default useGetUserProfile;

Here's the unit test

import { renderHook, waitFor } from "@testing-library/react";
import useGetUserProfile from "../../hooks/useGetUserProfile";
import { getDoc } from "../../mocks/firebase/firestore";

jest.mock('firebase/firestore', () => ({
  getDoc: jest.fn(),
  doc: jest.fn(),
}));

const mockProfile = {
    email: '[email protected]',
    username: 'testuser',
    userBio: 'Bio',
    dob: new Date(),
    gender: 'Male',
    sexo: 'M',
    education: 'University',
    drinkingHabits: 'Social',
    smokingHabits: 'No',
  };

beforeEach(() => {
  jest.clearAllMocks();
})

describe("useGetUserProfile", () => {


  it("should fetch data correctly", async () => {
    getDoc.mockResolvedValue({
      exists: () => true,
      data: () => mockProfile,
    });


    const { result } = renderHook(() => useGetUserProfile());
    waitFor
    console.log('results', result.current)
    expect(result.current
    ).toEqual(mockProfile);
  });
});
expect(received).toEqual(expected) // deep equality

- Expected  - 9
+ Received  + 3

  Object {
-   "dob": 2025-02-11T23:39:25.761Z,
-   "drinkingHabits": "Social",
-   "education": "University",
-   "email": "[email protected]",
-   "gender": "Male",
-   "sexo": "M",
-   "smokingHabits": "No",
-   "userBio": "Bio",
-   "username": "testuser",
+   "isLoading": false,
+   "setUserProfile": [Function bound dispatchSetState],
+   "userProfile": null,
  }
console.log
  results {
    isLoading: false,
    userProfile: null,
    setUserProfile: [Function: bound dispatchSetState]
  }

Any help would be greatly appreciated.

"firebase": "^11.0.1",
"react": "^18.3.1",

I have a hook that retrieves data from a firebase backend if the storage is clear. The unit test keeps failing as a result of the null return value.

Here's the hook

import { useEffect, useState } from "react";
import useGetUserId from "./useGetUserId";

import { app, firebaseConfig } from "../environments/environment";
import { doc, getDoc, getFirestore } from "firebase/firestore";
import 'firebase/firestore';
import { initializeApp } from "firebase/app";

const useGetUserProfile = () => {
  type profile = {
    email: string;
    username: string;
    userBio: string;
    dob: Date;
    gender: string;
    sexo: string;
    education: string;
    drinkingHabits: string;
    smokingHabits: string;
  };

  // const db = getFirestore(app);
  const userId: string | null = useGetUserId();
  const [isLoading, setIsLoading] = useState(true);
  const [userProfile, setUserProfile] = useState<any | null>(null);

  useEffect(() => {
    const userProfile = async () => {
      setIsLoading(true);
      try {
        const userRef = localStorage.getItem("PROFILE_INFO");
        if (userRef) {
          const profile: profile = JSON.parse(userRef);
          setUserProfile(profile);
        } else {
          const app = initializeApp(firebaseConfig);
          const db = getFirestore(app);
          if (userId) {
            const id = JSON.parse(userId);
            const userRef = await getDoc(doc(db, "users", id.user.uid));
            if (userRef.exists()) {
              const profile = userRef.data();
              setUserProfile(profile);
            }
          }
        }
      } catch (error) {
        console.log("error", error);
      } finally {
        setIsLoading(false);
      }
    };
    userProfile();
  }, [setUserProfile]);
  return {
    isLoading,
    userProfile, setUserProfile
  };
};

export default useGetUserProfile;

Here's the unit test

import { renderHook, waitFor } from "@testing-library/react";
import useGetUserProfile from "../../hooks/useGetUserProfile";
import { getDoc } from "../../mocks/firebase/firestore";

jest.mock('firebase/firestore', () => ({
  getDoc: jest.fn(),
  doc: jest.fn(),
}));

const mockProfile = {
    email: '[email protected]',
    username: 'testuser',
    userBio: 'Bio',
    dob: new Date(),
    gender: 'Male',
    sexo: 'M',
    education: 'University',
    drinkingHabits: 'Social',
    smokingHabits: 'No',
  };

beforeEach(() => {
  jest.clearAllMocks();
})

describe("useGetUserProfile", () => {


  it("should fetch data correctly", async () => {
    getDoc.mockResolvedValue({
      exists: () => true,
      data: () => mockProfile,
    });


    const { result } = renderHook(() => useGetUserProfile());
    waitFor
    console.log('results', result.current)
    expect(result.current
    ).toEqual(mockProfile);
  });
});
expect(received).toEqual(expected) // deep equality

- Expected  - 9
+ Received  + 3

  Object {
-   "dob": 2025-02-11T23:39:25.761Z,
-   "drinkingHabits": "Social",
-   "education": "University",
-   "email": "[email protected]",
-   "gender": "Male",
-   "sexo": "M",
-   "smokingHabits": "No",
-   "userBio": "Bio",
-   "username": "testuser",
+   "isLoading": false,
+   "setUserProfile": [Function bound dispatchSetState],
+   "userProfile": null,
  }
console.log
  results {
    isLoading: false,
    userProfile: null,
    setUserProfile: [Function: bound dispatchSetState]
  }

Any help would be greatly appreciated.

"firebase": "^11.0.1",
"react": "^18.3.1",
Share edited Feb 12 at 0:05 Drew Reese 203k17 gold badges239 silver badges271 bronze badges asked Feb 11 at 23:46 D.HodgesD.Hodges 2,1074 gold badges26 silver badges59 bronze badges 3
  • 1 (1) waitFor is a function that needs to be called with a callback for the "thing" you are waiting for, and (2) your useGetUserProfile returns an object with isLoading, userProfile, and setUserProfile properties, not the user profile object you are mocking. – Drew Reese Commented Feb 12 at 0:30
  • @DrewReese would you happen to know what I'm doing wrong in the mock? I can see from console log it's returning isLoading, userProfile, and setUserProfile but the userProfile is null.. I'm not sure how to set the value for userProfile. – D.Hodges Commented Feb 12 at 2:11
  • The userProfile state value is initially null, so I suspect your test isn't waiting for the effect to run and update the state. Though it seems it got the update false isLoading state value. Maybe there is more you need to mock, or maybe different code is executing than you think. What debugging/investigation have you undertaken? Think you could create a running CodeSandbox demo of your hook and test code that readers could inspect live? – Drew Reese Commented Feb 12 at 2:46
Add a comment  | 

1 Answer 1

Reset to default 0

I followed another tutorial that was simplified and it worked.

import { renderHook, waitFor } from "@testing-library/react";
import useGetUserProfile from "../../hooks/useGetUserProfile";

jest.mock("../../hooks/useGetUserProfile");
const mockedHook = jest.mocked(useGetUserProfile);
const mockProfile = {
  email: "[email protected]",
  username: "testuser",
  userBio: "Bio",
  dob: "mm/dd/yyyy",
  gender: "Male",
  sexo: "M",
  education: "University",
  drinkingHabits: "Social",
  smokingHabits: "No",
};

describe("Can retrieve user profile when the storage is null", () => {
  it("should return the initial values for data, error and loading", async () => {
    //Arrange
    localStorage.clear();
    mockedHook.mockReturnValue({
      isLoading: false,
      userProfile: {
        email: "[email protected]",
        username: "testuser",
        userBio: "Bio",
        dob: "mm/dd/yyyy",
        gender: "Male",
        sexo: "M",
        education: "University",
        drinkingHabits: "Social",
        smokingHabits: "No",
      },
      setUserProfile: jest.fn(),
    });

    //Act
    const { result } = renderHook(() => useGetUserProfile());

    //Assert
    await waitFor(() => {
      expect(result.current.isLoading).toBe(false);
      expect(result.current.userProfile).toEqual(mockProfile);
    });
  });
});

本文标签: javascriptWhy is the mock in my React unit test returning nullStack Overflow