4

I am pretty new to using jest and Im trying to test a component that makes a state change which acts upon my global state (using Zustand). Basically im clicking a button and its adding an item to my state.traits. Here is my component code:

import { Flex, useToast } from '@chakra-ui/react'
import { FC } from 'react'
import { useProfileStore } from 'stores/profileStore'

interface DataTrait {
    name: string,
    id: string
}

type Props = {
    trait: DataTrait
}

export const ChipItem: FC<Props> = ({ trait }) => {
    const { traits, setTraits } = useProfileStore()
    const toast = useToast()
    const traitNames = traits.map((trait) => trait.name)
    const emptyTraits = traits.filter((trait) => trait.name === "")

    const handleClick = (trait: DataTrait) => {
        if (!traitNames.includes(trait.name) && emptyTraits.length !== 0) {
            let currentItem = traits.filter(trait => trait.name === "")[0]
            let items = [...traits]
            let item = {position: currentItem.position, id: trait.id, name: trait.name}
            items[items.indexOf(currentItem)] = item
            setTraits(items)
        
        } else if (emptyTraits.length === 0){
            toast({
                title: 'Error',
                status: 'error',
                description: 'Only 5 traits can be selected',
                isClosable: true,
                duration: 5000
            })
        } else {
            toast({
                title: 'Error',
                status: 'error',
                description: 'Please select unique traits',
                isClosable: true,
                duration: 5000
            })
        }
    }

    return (
        traitNames.includes(trait.name) ? (
            <Flex mx={4} p={2} cursor="pointer" borderRadius="20px" backgroundColor="green" borderWidth="1px" borderColor="white" textColor="white" onClick={() => handleClick(trait)}>{trait.name}</Flex>
        ) : (
            <Flex mx={4} p={2} cursor="pointer" borderRadius="20px" borderWidth="1px" borderColor="grey" onClick={() => handleClick(trait)}>{trait.name}</Flex>
        )
    )
}

here is my store code:

import create from 'zustand'

export interface Trait {
    position: string,
    name: string,
    id: string,
}

export type Traits = Trait[]

const initialTraits = [
    {position: "0", name: "", id: ""},
    {position: "1", name: "", id: ""},
    {position: "2", name: "", id: ""},
    {position: "3", name: "", id: ""},
    {position: "4", name: "", id: ""},
]

export type ProfileStore = {
    traits: Traits;
    setTraits: (traits: Traits) => void;
    clearTraits: () => void;
}

export const useProfileStore = create<ProfileStore>((set) => ({
    traits: initialTraits,
    setTraits: (traits) => set({ traits }),
    clearTraits: () => set({ traits: initialTraits })
}))

and here is my test code:

import React from 'react';
import { ChipItem } from "../../ChipList/ChipItem";
import { act, render, renderHook } from "@testing-library/react";
import { useProfileStore } from "../../../stores/profileStore";

const stubbedTrait = {
    name: "Doing Work",
    id: "efepofkwpeok"
}

it("displays the trait chip", () => {
    const { queryByText } = render(<ChipItem trait={stubbedTrait} />);
    expect(queryByText("Doing Work")).toBeTruthy();
})

it("sets the chip information in the store", () => {
    act(() =>  {
        const { traits } = renderHook(() => useProfileStore())
        const { getByText } = render(<ChipItem trait={stubbedTrait}/>);
        getByText(stubbedTrait.name).click()
        expect(traits.includes(stubbedTrait)).toBeTruthy()
    })
})

whats happening, is that it keeps telling me that renderHook is not a function and traits always comes back undefined. any help would be greatly appreciated!

1 Answers1

0

Currently you must install and import React Testing Hooks separately

The best way to unit test Zustand state changes inside and specific component is not by using Zustand but by mocking the store hook with Jest.

You should create a test case for the Zustand Store using React Hook Testing library and once you verify the hook behaves as expected, then you mock the store with manual traits and setTraits changes.

Once you have the unit tests then you should test the behaviour of the real hook and components together with integration tests.