Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

renderHook: Context Provider, state change in child function act() error

Abierto
#1,206 5 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
25/100
Tipo de issue
Error
Claridad
Necesita aclaración
Estado de actividad
Estancado
Stack tecnológico
javascript, react

Línea de trabajo

Comienza con el hook useUserSearch, su helper FetchUsers, StoreProvider y la especificación de pruebas mostrada en la issue. Ejecuta la prueba del hook con la respuesta simulada de axios y sigue las actualizaciones de estado asíncronas; la issue no define ningún cambio solicitado ni una condición de finalización clara.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

question

I have a custom hook that uses a Context Provider for global state management. I am passing a dispatch and data from the state taken from the context inside the hook to a function that will at the end of requesting data from an endpoint dispatch this data coursing a state update inside the context API Provider passed down to the custom hook.

The issue is when I test the custom hook with a wrapper of the Context Provider passed into renderHook() function, I get in the test run the dreaded "act()" error of:

Warning: An update to StoreProvider inside a test was not wrapped in act(...)
      20 |      .then((res) => {
    > 22 |              setLoading(false)
         |              ^
      23 |              dispatch({ 
      24 |                      type: ActionTypesEnum.FETCH_USERS, 
      25 |                      payload: res.data

you can see the full explanation at: https://stackoverflow.com/questions/76157226/react-hooks-testing-library-context-provider-state-change-in-child-function-ac

The useUserSearch Hook:

const useUserSearch = (searchCriteria: string): SearchHookProps => {
  // data from the context and stored in the state
  const { dispatch, state } = useStateContext();
  const { users } = state;
  const [ userData, setUserData ] = useState<UserProps[]>([]);
  const [ loading, setLoading ] = useState<boolean>(false);
  const [ error, setError ] = useState<boolean>(false);
  // connected to the pagination affected by the search
  const [ currentPage, setCurrentPage ] = useState<number>(1)
  const [ totalPages, setTotalPages ] = useState<number>(1)
  const [ totalUserCount, setTotalUserCount ] = useState<number>(0)
  const totalPerPage = 12

  useEffect(() => {
    if (users === null) FetchUsers(dispatch, searchCriteria, setLoading, setError);
  }, [users]);

  useEffect(() => {
      if (searchCriteria.length > 0) FetchUsers(dispatch, searchCriteria, setLoading, setError);
  }, [searchCriteria]);

  return {
    userData,
    totalUserCount,
    setCurrentPage,
    currentPage,
    totalPages,
    loading,
    error,
  }
}

FetchUsers function:

const FetchUsers = (
	dispatch: Dispatch<any>,
	searchCriteria: string,
	setLoading: Dispatch<SetStateAction<boolean>>,
	setError: Dispatch<SetStateAction<boolean>>,) => {
	const { global: { apiUrl } } = AppConfig

	const search = `?q=${encodeURIComponent(searchCriteria)}`

	setLoading(true)
	axios.get(`${apiUrl}/users?q=${search}+in:login+type:user`)
	.then((res) => {
		setLoading(false)
		dispatch({ 
			type: ActionTypesEnum.FETCH_USERS, 
			payload: res.data
		})
	})
	.catch(() => {
		setLoading(false)
		setError(true)
	})
}

StoreProvider:

import React, { useContext, useReducer, useMemo, createContext } from 'react';
import Reducer from '../../Reducers';
import AppConfig from '../../Configs';
import { StateInterface, StoreInterface, ProviderInterface } from '../../Interfaces';

export const initialState: StateInterface = {
  appConfig: AppConfig,
  users: null,
};

export const StoreContext = createContext({
  state: initialState,
} as StoreInterface);

export const useStateContext = () => useContext(StoreContext);

export const StoreProvider = ({ children }: ProviderInterface) => {
  const [state, dispatch] = useReducer(Reducer, initialState);
  const StoreProviderValue = useMemo(() => ({ state, dispatch }), [state, dispatch]);

  return <StoreContext.Provider value={StoreProviderValue}>{children}</StoreContext.Provider>;
};

The Test spec file:

import React from 'react'
import { render, cleanup, waitFor, renderHook, act } from '@testing-library/react'
import axios from 'axios'

import usersMock from '../__mocks__/usersMock'
import { StoreProvider } from '../Providers'
import useUserSearch from './useUserSearch'

jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe('Test that <User />', () => {
  const renderHookComponent = (searchCriteria: string) => {
    const wrapper = ({ children }: any) => <StoreProvider>{children}</StoreProvider>
    const { result, rerender, unmount } = renderHook(() => useUserSearch(searchCriteria), {
      wrapper: wrapper as React.ComponentType<any>
    })
    return { result, rerender, unmount }
  }

  afterEach(() => {
    cleanup()
  })

  it('renders the hook useUserSearch', async () => {
    mockedAxios.get.mockResolvedValue(usersMock);
    const { result } = renderHookComponent('test')

    // await waitFor(() => {
    //   expect(result.current.userData.length).toBe(0)
    // })
  })
})
Lenguaje dominante
JavaScript
Estrellas
19.7k
Forks
1.2k
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de testing-library/react-testing-library

Todos los issues de testing-library/react-testing-library

Issues similares

Más issues de JavaScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.