Проверить, была ли вызвана функция — Реагировать,

#reactjs #unit-testing #axios #react-hooks #enzyme

#reactjs #модульное тестирование #axios #реагировать-перехваты #фермент

Вопрос:

Я пытаюсь протестировать простой компонент.

В моем компоненте я вызываю функцию fetchPdf с помощью useEffect .

Внутри функции fetchPdf я делаю запрос axios, и если вызов был успешным, я устанавливаю ответ (который является pdf) в состояние.

Мой компонент:

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

export default function App() {
  const [pdf, setPdf] = useState();

  const fetchPdf = () => {
    // Here I am make an API call - on success I am
    // set the pdf from the response into state

    // axios.get('url/endpoint')
    // .then((res) => {
    //   if (res.status === 200) {
    //     setPdf(res.data);
    //   }
    // }).catch((e) => console.log(e.message));

    setPdf("Mocked PDF");
  };

  useEffect(() => {
    fetchPdf();
  }, []);

  return (
    <div className="App">
      <h1>My pdf from state: {pdf}</h1>
    </div>
  );
}
 

Мой тест:

 import React from "react";
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import App from "./App";

Enzyme.configure({ adapter: new Adapter() });

describe("<App />", () => {
  let wrapper;
  const setState = jest.fn();
  const useStateSpy = jest.spyOn(React, "useState");
  useStateSpy.mockImplementation((init) => [init, setState]);

  beforeEach(() => {
    wrapper = Enzyme.shallow(<App />);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe("calling designPDF", () => {
    it("set designPDF into the state", () => {
      // Not sure how can I test the fetchPDF function as been called
    });
  });
});
 

Пример Codesendbox

Комментарии:

1. Вы изучали насмешливые axios запросы? github.com/ctimmerm/axios-mock-adapter

2. вы должны создать spy for useEffect . и для тестирования axios вы можете использовать внешнюю библиотеку Moxios

Ответ №1:

useEffect пока не поддерживает shallow рендеринг. Поэтому вам следует использовать полный API рендеринга (mount (…)).

Кроме того, вы должны смоделировать axios.get метод и его разрешенное значение. Вызовите whenStable функцию, чтобы убедиться, что обещание, возвращенное axios.get методом, разрешено или отклонено

Например.

App.jsx :

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

export default function App() {
  const [pdf, setPdf] = useState();

  const fetchPdf = () => {
    axios
      .get('url/endpoint')
      .then((res) => {
        if (res.status === 200) {
          setPdf(res.data);
        }
      })
      .catch((e) => console.log(e.message));
  };

  useEffect(() => {
    fetchPdf();
  }, []);

  return (
    <div className="App">
      <h1>My pdf from state: {pdf}</h1>
    </div>
  );
}
 

App.test.jsx :

 import App from './App';
import axios from 'axios';
import { mount } from 'enzyme';
import React from 'react';
import { act } from 'react-dom/test-utils';

const whenStable = async () => {
  await act(async () => {
    await new Promise((resolve) => setTimeout(resolve, 0));
  });
};

describe('65310275', () => {
  it('should get pdf', async () => {
    const getSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: 'Mocked PDF', status: 200 });
    const wrapper = mount(<App></App>);
    await whenStable();
    expect(wrapper.find('h1').text()).toEqual('My pdf from state: Mocked PDF');
    expect(getSpy).toBeCalledWith('url/endpoint');
    getSpy.mockRestore();
  });

  it('should handle error', async () => {
    const mErr = new Error('timeout');
    const getSpy = jest.spyOn(axios, 'get').mockRejectedValueOnce(mErr);
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = mount(<App></App>);
    await whenStable();
    expect(wrapper.find('h1').text()).toEqual('My pdf from state: ');
    expect(getSpy).toBeCalledWith('url/endpoint');
    expect(logSpy).toBeCalledWith('timeout');
    getSpy.mockRestore();
  });
});
 

результат модульного теста:

  PASS  examples/65310275/App.test.jsx
  65310275
    ✓ should get pdf (40 ms)
    ✓ should handle error (13 ms)

  console.log
    timeout

      at CustomConsole.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |       50 |     100 |     100 |                   
 App.jsx  |     100 |       50 |     100 |     100 | 11                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        6.095 s
 

исходный код: https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65310275

Комментарии:

1. Спасибо за ваш ответ, есть способ проверить и само состояние, если я не отображаю элемент <h1>?