Как протестировать асинхронные вызовы в шутку, используя запрос без насмешек и ожидая библиотеки тестирования реактивных крючков

#testing #jestjs #react-hooks #automated-tests #react-hooks-testing-library

Вопрос:

Я не очень хорошо пишу тесты, что касается функций, не связанных с API, я тестировал с помощью JEST с помощью rendererHook, как показано ниже, Пример правильного ТЕСТА:

 import { render, screen, cleanup } from '@testing-library/react';
import useAppDrawer from "../../../utils/hooks/useAppDrawer";
import {act,renderHook} from '@testing-library/react-hooks';
import React from "react";

describe("hook: useAppDrawer", () => {

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

    test('drawer open', () => {
        const {result} = renderHook(useAppDrawer);

        act(()=>{
            result.current.handleDrawerOpen();
        })
        expect(result.current.open).toBe(true);

    });
    test('drawer close', () => {
        const {result} = renderHook(useAppDrawer);

        act(()=>{
            result.current.handleDrawerClose();
        })
        expect(result.current.open).toBe(false);

    });

});
 

Но что мы будем делать в случае вызовов API в ШУТКУ, что все еще сбивает меня с толку. Я все еще не могу понять, как я могу тестировать вызовы API в ШУТКУ, как это показано ниже, Проблемная функция:

 import React, {useContext} from "react";
import request from "../services/Http";
import useIsLoading from "./useIsLoading";
import {Context} from "../store/context/store";
import {SET_BOOTHS} from "../store/context/Constants";

export default function useFetchBooths(){

    const {isLoading, setIsLoading} = useIsLoading()
    const [{booths}, dispatch] = useContext(Context)

    function fetchBooths(){

        setIsLoading(true)

        request.get('/event/get-booth-list')
            .then((res) => {
                setIsLoading(false)
                if (res)
                {
                    dispatch({
                        type: SET_BOOTHS,
                        payload: res.data.booth_data
                    })
                }
            })
    }

    function searchBooths(value){

        if (value)
        {
            let obj = booths.filter(booth => booth.booth_name.toLowerCase().includes(value.toLowerCase()));

            if (obj.length > 0)
            {
                dispatch({
                    type: SET_BOOTHS,
                    payload: obj
                })
            }
            else
            {
                fetchBooths()
            }

        }
        else
        {
            fetchBooths()
        }
    }

    return { booths, fetchBooths, isLoading, searchBooths }
}
 

what would be the possible jest test for the above function? considering cases like if booth is fetched or not as in both cases I am getting booth value to be [].
My attempt so far for this is:

 import { render, screen, cleanup, waitFor } from '@testing-library/react';
import useFetchBooths from "../../../utils/hooks/useFetchBooths";
import {act,renderHook} from '@testing-library/react-hooks';
import React from "react";
import * as requestsModule from "../../../utils/services/Http";
import {Store} from "../../../utils/store/context/store";

describe("hook: useFetchBooths", () => {

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

    test('Booth is fetched', async () => {
        const boothData = [
            {
                "message": "Data fetched Successfully",
                "success": true
            }
        ];
        const wrapper = ({children}) => (
            <Store>{children}</Store>
        )
        const {result } = renderHook(() => useFetchBooths(), {wrapper});
         jest.spyOn(result.current, "fetchBooths").mockResolvedValue(boothData);
         console.log(result.current.fetchBooths())
        await expect(result.current.fetchBooths()).resolves.toEqual([{ "success": true, "message": "Data fetched Successfully" }]);

    });

});
 

Выше тест пройден, но это издевались по API(я создаю данные и сравнивая его с моим собственным письменных данных, но это не я хочу), но я хочу, чтобы мой фактический API работает или нет в этот тест, как я извлечения Бут список в fetchBooths() функцию, так как я могу проверить его с притворным API, когда мои все зависит от реального API, который я хочу протестировать его, проверив мой фактический API на самом деле работает или нет в том, что тест с помощью некоторых асинхронный/ждут , но я сильно застрял в этой точке. Кроме того, я не могу понять, каким будет тестовый случай для функции Searchboots, поскольку она выглядит неопределенной и список стендов отображается как [], хотя это не должно быть [], я все еще не могу найти решение. Пожалуйста, помогите мне написать эти тестовые примеры

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

1. что бы вы хотели проверить здесь? Я предполагаю, что вас не интересует makeStyles само тестирование

2. @thedude Я все еще не могу понять, как мы можем написать тест для вызовов API в ШУТКУ. Точно так же, как я написал выше, функция fetchboots (), как я могу писать тесты для нее, учитывая такие случаи, как, если выбран стенд или нет, так как в обоих случаях я получаю значение booth равным [].

3. @thedude Я обновил вопрос. Не могли бы вы, пожалуйста, помочь мне сейчас?

4. Я бы посмотрел, jest.spyOn чтобы высмеять request.get и утверждать, что он был вызван с правильным вводом. Такой же подход можно было бы применить для тестирования makeStyles

5. @thedude не могли бы вы, пожалуйста, подробнее рассказать, например, о том, как я исправил свой код, учитывая мою попытку, описанную выше, например, я могу войти в загрузочный комплект fetchboots(true), но не могу ничего получить из запроса. Дайте мне знать, если возможно, чтобы я мог поделиться с вами своим экраном?

Ответ №1:

В своем тестовом коде используйте a spy для макетирования модуля запросов:

 import * as requestsModule from "../services/Http";

describe("hook: useFetchBooths", () => {

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

    test('Booth is fetched', async () => {

        jest.spyOn(requestsModule, 'get').mockResolvedValue([]) // <-- here you should provide the data you want your hook to see.

        const wrapper = ({children}) => (
            <Store>{children}</Store>
        )

        const {result } = renderHook(() => useFetchBooths(), {wrapper});
        await act(async () => {
            await waitFor(() => result.current.fetchBooths() )
        })

        await act(async () => {
            await waitFor(() => result.current.booths )
            console.log(result.current);
        })
        expect(result.current.booths).toEqual([]);

    });

});
 

Обновление: как издеваться над useContext

  1. создайте пользовательский крючок
 // boothsContext.js

import {Context} from "../store/context/store";

export const useBoothsContext = () => useContext(Context)

 
  1. издевайтесь над крючком, используя jest.spyOn :
 import { wait } from '@testing-library/react'
import * as BoothsContextModule from './boothsContext.js'

...

test('Booth is fetched', async () => {
    const mockDispatch = jest.fn()
    const data = { booths: []} // change this to inject different data into your hook result
    jest.spyOn(BoothsContextModule, 'useBoothsContext')
        .mockReturnValue([data, mockDispatch])

    // perform test steps

   await wait(() => expect(mockDispatch).toHaveBeenCalledWith({
      type: SET_BOOTHS,
      payload: {...} // <-- expected payload you want to assert
   }))

 

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

1. не могу ли я просто проверить что-то вроде того, что если данные будут извлечены, и получить «сообщение»: «Данные получены успешно», то я просто пройду тест ? как я должен добиться этого здесь в ШУТКУ?

2. Я передаю данные, как jest.spyOn(requestsModule, ‘get’).mockResolvedValue({данные:{«успех»: истина, «сообщение»: «Данные получены успешно»},»booth_data»: [ { «booth_id»: «8818», «имя пользователя»: «Изменено», }] }); но я попадаю в ошибку » Ошибка: Не удается обнаружить свойство get, потому что оно не является функцией; вместо этого задано неопределенное »

3. как я буду сравнивать эти издевательские значения с фактическими, чтобы добавить «ожидаемое условие» для передачи, сравнивая исходные данные с издевательскими данными? Не могли бы вы, пожалуйста, обновить ответ как для функции поиска, так и для функции извлечения, включая ожидаемое условие, которое должно быть выполнено для прохождения теста, я буду вам очень благодарен. Если вы спросите, я могу поделиться с вами своим экраном через TeamViewer или что-то в этом роде

4. Я все еще застрял, я обновил свою попытку в соответствии с вашим руководством, и у меня также есть вопрос, если мы просто издеваемся над API, то как мы просто проверим, работает ли реальный API или нет, как я также хочу убедиться, что мой реальный API работает в этом функциональном тесте, что является моей главной проблемой, используя какое-то асинхронное ожидание. Кроме того, каким будет тестовый случай для функции Searchboots Я также запутался при написании этого теста, я упомянул этот файл, о котором идет речь, с жирным названием «Проблемная функция», для которой я хочу написать тест. Любая помощь будет очень признательна

5. Похоже, вы на самом деле не пишете модульные тесты. Лучшая практика-разбить ваш код на блоки, которые можно тестировать отдельно. Если вы действительно хотите вызвать свой API, то вместо того, чтобы издеваться над запросами get, вы можете издеваться над useContext крючком и проверять, был ли сделан правильный dispatch вызов