9
votes

Pourquoi React Hook génère-t-il l'erreur d'acte lorsqu'il est utilisé avec Fetch Api?

Je reçois toujours un Warning: An update to App inside a test was not wrapped in act(...). dans ma suite de tests chaque fois que je fais une requête API et que je mets à jour l'état.

J'utilise la bibliothèque react-testing. J'ai également essayé d'utiliser les utils de test ReactDOM, j'ai obtenu le même résultat. Une autre chose que j'ai essayée a été de mettre le conteneur en act , j'ai toujours obtenu le même résultat.

Veuillez noter que: Mon application fonctionne et mon test réussit. J'ai juste besoin de savoir ce que je faisais de mal ou si c'est un bogue dans le paquet react-dom qui fait apparaître cette erreur. Et il est mauvais de se moquer de l'erreur de la console et de la désactiver.

const [data, setData] = useState([]);
const [error, setError] = useState('');

const fetchInitData = async () => {
    try {
        const res = await fetch(API_URL);
        const data = await res.json();

        if (data.fault) {
            setError('Rate limit Exceeded');
        } else {
            setData(data.results);
        }
    } catch(e) {
        setError(e.message);
    }
};

useEffect(() => {
    fetchInitData();
}, [isEqual(data)]);

Voici l'implémentation du hook:

global.fetch = require('jest-fetch-mock');

it('should clear select content item', async () => {
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    await wait();

    expect(content.querySelectorAll('.content--item').length).toBe(2);
});


2 commentaires

Tout cela fait-il partie d'une fonction?


Ouais c'est ça. Laisse-moi ajouter que ça marche et que mon test réussit. Le seul problème, ce sont les erreurs ennuyeuses


4 Réponses :


6
votes

C'est un problème connu, vérifiez ce problème dans Github https://github.com/kentcdodds/react-testing-library/issues/281


0 commentaires

2
votes

Pour vous débarrasser de l'avertissement act() vous devez vous assurer que vos promesses se résolvent de manière synchrone. Vous pouvez lire ici comment procéder.

Sommaire:

La solution à cela est un peu compliquée:

  • nous polyfill Promise globalement avec une mise en œuvre qui peut résoudre les promesses `` immédiatement '', comme la promesse
  • transpilez votre javascript avec une configuration babel personnalisée comme celle de ce dépôt
  • utilisez jest.runAllTimers (); cela va également vider la file d'attente des tâches de promesse

0 commentaires

-1
votes

J'ai eu ce problème et j'ai renoncé à utiliser wait and async à la place, j'ai utilisé des faketimers de plaisanterie et ainsi de suite, donc votre code devrait être quelque chose comme ça.

global.fetch = require('jest-fetch-mock');

it('should clear select content item', /*async */ () => {
    jest.useFakeTimers();
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    // await wait();
    act(() => {
      jest.runAllTimers();
    });

    expect(content.querySelectorAll('.content--item').length).toBe(2);
});


0 commentaires

1
votes

Pour tous ceux qui tombent dessus plus d'un an plus tard comme je l'ai fait, le problème mentionné par Giorgio a depuis été résolu, et wait a depuis été remplacé par waitFor , comme documenté ici:

https://testing-library.com/docs/dom-testing-library/api-async/

Cela étant le cas, je pense que la solution à l'avertissement devrait maintenant être quelque chose comme ceci:

  beforeEach(async () => {
    await waitFor(() => render(<App />));
  });

Dans mon cas, j'avais un composant App chargeant des données de manière asynchrone dans un hook useEffect , et je useEffect donc cet avertissement à chaque test, en utilisant beforeEach pour rendre App . C'était la solution spécifique pour mon cas:

import { render, waitFor } from '@testing-library/react';
// ...

it('should clear select content item', async () => {
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    await waitFor(() =>
        expect(content.querySelectorAll('.content--item').length).toBe(2);
    );
});


0 commentaires