Programing

Typecriptcript를 사용하여 API 호출을 수행하는 React Hook "useEffect"를 테스트하려면 어떻게 해야 하는가?

c10106 2022. 3. 13. 10:06
반응형

Typecriptcript를 사용하여 API 호출을 수행하는 React Hook "useEffect"를 테스트하려면 어떻게 해야 하는가?

나는 Typecript와 새로운 React 후크를 사용하는 간단한 React 앱에 대한 jest-enzyme 테스트를 작성 중이다.

하지만, 실내에서 이루어지는 api 통화의 시뮬레이션을 제대로 할 수 없는 것 같다.useEffect낚싯바늘을 달다

useEffectapi call을 만들고useState"setData"와 함께 "data"로 표시한다.

그런 다음 개체 "데이터"가 해당 테이블 셀에 테이블로 매핑된다.

이것은 모의 api 반응과 효소 탑재로 태클하기 쉬워야 할 것 같은데 자꾸 사용하라고 하는 오류가 생긴다.act()구성 요소 업데이트의 경우

나는 사용하려고 노력했다.act()여러 가지 방법이지만 소용이 없었다.나는 교체해 보았다.axios얄팍한 효소와 반응-시험-반응-반응-반응을 보이는 렌더로 말이야 하지만 아무 효과가 없는 것 같아

구성 요소:

import axios from 'axios'
import React, { useEffect, useState } from 'react';

interface ISUB {
  id: number;
  mediaType: {
    digital: boolean;
    print: boolean;
  };
  monthlyPayment: {
    digital: boolean;
    print: boolean;
  };
  singleIssue: {
    digital: boolean;
    print: boolean;
  };
  subscription: {
    digital: boolean;
    print: boolean;
  };
  title: string;
}

interface IDATA extends Array<ISUB> {}

const initData: IDATA = [];

const SalesPlanTable = () => {
  const [data, setData] = useState(initData);
  useEffect(() => {
    axios
      .get(`/path/to/api`)
      .then(res => {
        setData(res.data.results);
      })
      .catch(error => console.log(error));
  }, []);

  const renderTableRows = () => {
    return data.map((i: ISUB, k: number) => (
      <tr key={k}>
        <td>{i.id}</td>
        <td>
          {i.title}
        </td>
        <td>
          {i.subscription.print}
          {i.mediaType.digital}
        </td>
        <td>
          {i.monthlyPayment.print}
          {i.monthlyPayment.digital}
        </td>
        <td>
          {i.singleIssue.print}
          {i.singleIssue.digital}
        </td>
        <td>
          <button>Submit</button>
        </td>
      </tr>
    ));
  };

  return (
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
          <th>MediaType</th>
          <th>MonthlyPayment</th>
          <th>SingleIssue</th>
          <th/>
        </tr>
      </thead>
      <tbody'>{renderTableRows()}</tbody>
    </table>
  );
};

export default SalesPlanTable;

테스트:

const response = {
  data: {
    results: [
      {
        id: 249,
        mediaType: {
          digital: true,
          print: true
        },
        monthlyPayment: {
          digital: true,
          print: true
        },
        singleIssue: {
          digital: true,
          print: true
        },
        subscription: {
          digital: true,
          print: true
        },
        title: 'ELLE'
      }
    ]
  }
};

//after describe

it('should render a proper table data', () => {
    const mock = new MockAdapter(axios);
    mock.onGet('/path/to/api').reply(200, response.data);
    act(() => {
      component = mount(<SalesPlanTable />);
    })
    console.log(component.debug())
  });

테이블 본체 섹션이 렌더링된 테이블의 html을 기록할 것으로 예상하며, 비동기식 및 다른 방법으로 조롱하려고 시도했다.axios하지만 계속 표 머리말이나 메세지를 받고 있어에 대한 업데이트.SalesPlanTable시험내부는 에 싸여있지 않았다.act(...).나는 여러 시간 동안 해결책을 찾았지만 효과가 있는 것을 찾을 수 없어서 용기를 내서 여기에서 물어보기로 했다.

여기 두가지 문제가 있다.


비동기 호출 위치setData

setData호출을 받다Promise콜백

즉시Promise확인, 대기 중인 콜백은 PromiseJobs 대기열에 대기한다.PromiseJobs 대기열에 있는 모든 보류 중인 작업은 현재 메시지가 완료된 후 다음 메시지가 시작되기 에 실행된다.

이 경우 현재 실행 중인 메시지는 테스트이므로 테스트가 완료되기 전에Promise콜백은 뛸 기회가 있고setData테스트가 끝날 때까지 호출되지 않는다.

이런 것을 이용해서 고칠 수 있다.setImmediate약속 잡스의 콜백 후에 출마할 기회가 있을 때까지 당신의 주장을 연기하는 것.

전화도 해야 할 것 같은데component.update()구성 요소를 새 상태로 다시 조정하십시오.(국가의 변화가 외부적으로 일어나기 때문이라고 추측한다.act콜백 코드를 포장할 방법이 없기 때문에act.)

모두 합쳐서, 작업 테스트는 다음과 같이 보인다.

it('should render a proper table data', done => {
  const mock = new MockAdapter(axios);
  mock.onGet('/path/to/api').reply(200, response.data);
  const component = mount(<SalesPlanTable />);
  setImmediate(() => {
    component.update();
    console.log(component.debug());
    done();
  });
});

경고:...에 대한 업데이트는 행동으로 포장되지 않았다. (...)

경고는 외부 구성 요소에 대한 상태 업데이트에 의해 트리거됨act.

비동기 호출로 인해 함수에 의해 트리거되는 상태 변경은 항상act.

다음은 이러한 행동을 입증하는 매우 간단한 테스트다.

import React, { useState, useEffect } from 'react';
import { mount } from 'enzyme';

const SimpleComponent = () => {
  const [data, setData] = useState('initial');

  useEffect(() => {
    setImmediate(() => setData('updated'));
  }, []);

  return (<div>{data}</div>);
};

test('SimpleComponent', done => {
  const wrapper = mount(<SimpleComponent/>);
  setImmediate(done);
});

내가 더 많은 정보를 찾고 있을 때 나는 겨우 10시간 전에 열린 #2073호에서 이와 같은 행동에 대해 이야기하면서 우연히 알게 되었다.

테스트를 코멘트에 추가해 도움을 주었다.enzymedevs가 그 문제를 해결하다.

해결책

효과가 있고 또 제거된다.test was not wrapped in act(...)경고의

const waitForComponentToPaint = async (wrapper) => {
   await act(async () => {
     await new Promise(resolve => setTimeout(resolve, 0));
     wrapper.update();
   });
};

사용량:

it('should do something', () => {
    const wrapper  = mount(<MyComponent ... />);
    await waitForComponentToPaint(wrapper);
    expect(wrapper).toBlah...
})

덕분에...

edpark11이 자신의 답변에서 언급한 @Brian_Adams 이슈에서 제시한 해결책이다.

원본 게시물: https://github.com/enzymejs/enzyme/issues/2073#issuecomment-565736674

나는 보관을 위해 몇 가지 수정하여 여기에 그 게시물을 베꼈다.

참조URL: https://stackoverflow.com/questions/55388587/how-should-i-test-react-hook-useeffect-making-an-api-call-with-typescript

반응형