1

警告の原因となる状態の更新後にアサートするものが何もない場合に、Jest/testing-library によってスローされる「act(...) にラップされていません」という警告を防ぐ方法があるかどうかを調べようとしています。または、この警告を無視する必要がある場合。

次の単純なコンポーネントがあるとします。

import React, {useEffect, useState} from 'react';
import {getData} from 'services';

const MyComponent = () => {
  const [arr, setArr] = useState([]);

  useEffect(() => {
    (async () => {
      const {items} = await getData();
      setArr(items);
    })();
  }, []);

  return (
    <div>
      {!(arr.length > 0) && <p>no array items</p>}
      {arr.length > 0 && (
        <ul>
          {arr.map(item => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default MyComponent;

getData()このコンポーネントがデータを返さなくても正常にレンダリングされることを簡単にテストしたいとします。

だから私はこのようなテストを持っています:

import React from 'react';
import {getData} from 'services';
import {render, screen} from 'testUtils';
import MyComponent from './MyComponent';

jest.mock('services', () => ({
  getData: jest.fn(),
}));

it('renders', () => {
  getData.mockResolvedValue({items: []});

  render(<MyComponent />);

  expect(screen.getByText('no array items')).toBeInTheDocument();
});

このテストはパスしますが、「act(...) にラップされていません」という警告が表示されます。これは、テストが終了する前に終了するgetData()ためです。

この場合、からの応答は、最初にコンポーネントの上部にgetData()設定arrした値 (空の配列) に設定されます。そのため、非同期関数が完了した後も UI は変更されません。まだ「配列項目なし」と書かれている段落を見ているだけなので、状態の更新を待つと主張できるものは何もありません。完了します。

できますがexpect(getData).toHaveBeenCalledTimes(1)、関数呼び出し後に状態が実際に更新されるのを待ちません。

setArr(items)発生する時間を確保するために、テストで任意の一時停止を試みました。

it('renders', async () => {
  getData.mockResolvedValue({items: []});

  render(<MyComponent />);

  expect(screen.getByText('no array items')).toBeInTheDocument();
  
  await new Promise(resolve => setTimeout(resolve, 2000));

  expect(screen.getByText('no array items')).toBeInTheDocument();
});

しかし、それは役に立たないようです。正直なところ、その理由はわかりません。

テストのみを変更して、この状況を処理する方法はありますか?

MyComponent をリファクタリングすることで問題を解決できると確信しています。たとえば、arrMyComponent を prop として渡し、呼び出しを親コンポーネントに移動するか、呼び出しを完全にgetData()スキップするテスト専用のカスタム prop を作成しますが、私はしません。getData()テストでの警告を避けるためだけにコンポーネントを変更したくない。

私はtesting-library/react v11.2.2 を使用しています。

4

1 に答える 1

1

(とfindByTextの組み合わせ) を使用して、アサーションの解決時にすべての更新が確実に行われるようにすることができます。getByTextwaitFor

it('renders', async () => {
    getData.mockResolvedValue({items: []});
    render(<MyComponent />);
    expect(await screen.findByText('no array items')).toBeInTheDocument();
});
于 2021-02-20T12:47:25.053 に答える