제공자에 대한 옵션을 사용하여 테스트 라이브러리 사용자 정의 렌더링에 반응하십시오.

이미 모든 공급자가 있는 사용자 지정 렌더를 설정하는 방법에는 여러 가지가 있습니다. 여기에서 React Testing Library를 사용하여 구성 요소를 렌더링하고 해당 구성 요소 주변에서 활성화하려는 공급자를 옵션으로 전달할 수 있는 몇 가지 sintax 꿀을 볼 수 있습니다.

이와 유사한 방식으로:

renderUi(<Component />, {
    withReduxProvider: true,
    withReactQueryProvider: true,
})


이 예제에서는 애플리케이션에서 사용하지 않을 수 있는 일부 공급자를 사용하고 여기서는 사용하지 않는 다른 공급자를 사용할 수도 있습니다. 이 동일한 패턴에 따라 코드를 추가하기만 하면 됩니다. 버전도 마찬가지입니다. 이 라이브러리가 구현을 변경하는 방식에 따라 이 코드가 변경될 수 있습니다.

계속합시다.

먼저 이를 가능하게 할 도우미 파일을 만듭니다.

구현




// this file simplifies the component setup process when rendering the component for testing

import React from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { Provider } from 'react-redux';
import { MemoryRouter as Router } from 'react-router-dom';
import { QueryClientProvider } from 'react-query';
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';
import axios from 'axios';
import store from '/services/rootReducer';
import { createTestQueryClient } from '/services/test/utils';

interface IExtendedRenderOptions extends RenderOptions {
  withRouter?: boolean
  routerHistory?: string[]
  withRedux?: boolean
  mockInitialState?: any
  withQueryProvider?: boolean
  mockAxiosCalls?: any
}

// wrappers and contexts
const wrapInRedux = (componentTree: JSX.Element, { mockInitialState }: IExtendedRenderOptions) => {
    const storeConfig = configureStore([thunk]);
    const storeMock = mockInitialState ? storeConfig(mockInitialState) : store;
    // This allows you to use a passed mock store
    return (
        <Provider store={storeMock}>
            {componentTree}
        </Provider>
    );
};

const wrapInRouter = (componentTree: JSX.Element, routerHistory?: string[]) => (
    <Router initialEntries={routerHistory}>
        {componentTree}
    </Router>
);

const wrapInQueryProvider = (componentTree: JSX.Element) => {
    const testQueryClient = createTestQueryClient();
    return (
        <QueryClientProvider client={testQueryClient}>
            {componentTree}
        </QueryClientProvider>
    );
};


// You don't need this option if you are using something more advance such as Mock Service Worker
// This Function Mock axios calls and hand back a response for each call finding the right response by comparing the called endpoint with the endpoint fragment you passed
// You need to pass an array of objects, each object will represent a call
// { endpointFragment: string, expectedMockResponse: yourMockType }
type AxiosCallMock = { endpointFragment: string, expectedMockResponse: any }
// This one will runs on each axios get request
const mockAxiosCallResponsesIfAny = (renderOptions?: IExtendedRenderOptions) => {
    if (renderOptions?.mockAxiosCalls) {
        axios.get.mockImplementation((url) => {
            // If your component has multiple axios calls make sure to pass
            // endpoint fragments that identify them
            const optionObject = renderOptions?.mockAxiosCalls.find((mock: AxiosCallMock) => url.includes(mock.endpointFragment));
            return Promise.resolve(optionObject.expectedMockResponse);
        });
    }
};

const setupComponent = (ui: JSX.Element, renderOptions?: IExtendedRenderOptions) => {
    if (!renderOptions) return ui;
    let componentTree = <>{ui}</>;
    if (renderOptions.withRouter) componentTree = wrapInRouter(componentTree, renderOptions.routerHistory);
    if (renderOptions.withRedux) componentTree = wrapInRedux(componentTree, renderOptions);
    if (renderOptions.withQueryProvider) componentTree = wrapInQueryProvider(componentTree);
    return componentTree;
};

const customRender = (ui: JSX.Element, renderOptions?: IExtendedRenderOptions) => {
    try {
        mockAxiosCallResponsesIfAny(renderOptions);
        const componentTree = setupComponent(ui, renderOptions);
        return render(componentTree);
    } catch (error) {
        console.log(error);
        throw error;
    }
};

export * from '@testing-library/react';
export { customRender, IExtendedRenderOptions };



용법



테스트에서 구성 요소를 렌더링하는 방법입니다.

// Component.test.tsx
import React from 'react';
// we import out customRender
import { customRender, screen, fireEvent, waitFor } from 'ns_libs/testing/testUtils';
import Component from 'pages';

const initialProps: IProps = {
    toggle: () => {},
    isOpen: true,
    target: 'test-popover-target',
    feature: FEATURES_LIST.PORTFOLIO_GROUPS,
    subprojectId: 0,
};

// initialize redux state with any value you want
// maybe same values that is initialized in your app
const initialReduxState = {
           user: {
              name: "",
              age: 0,
           }
        }

const renderUi = (props: IProps = initialProps) => customRender(
    <Component {...props} />, {
        withRouter: true,
        routerHistory: [':some_path_maybe'],
        withRedux: true,
        mockInitialState: initialReduxState,
    },
);


구성 요소에서 발생하는 모의 축 호출에 해당 옵션을 계속 사용해야 하는 경우 모의 축 호출에 모의 데이터를 전달하는 예입니다.

import React from 'react';
import { customRender, screen, act, waitFor } from 'ns_libs/testing/testUtils';
import '@testing-library/jest-dom';
import axios from 'axios';

//  Sample Component
const SampleComponent = () => {
    const [data, setData] = React.useState<any>();
    const [dataTwo, setDataTwo] = React.useState<any>();

    const getTodos = async (): Promise<any> => {
        try {
            const res = await axios.get('https://yourendpoint.todos.com');
            setData(res);
        } catch (error) {
            console.log(error);
        }
    };

    const getOtherThings = async (): Promise<any> => {
        try {
            const res = await axios.get('https://endpoint.otherthings.com');
            setDataTwo(res);
        } catch (error) {
            console.log(error);
        }
    };

    React.useEffect(() => {
        getTodos();
        getOtherThings();
    }, []);

    return (
        <div>
            {data && <h1>{data?.map((item: any) => <span key={item.email}>{item.title}</span>)}</h1>}
            {dataTwo && <h1>{dataTwo?.map((item: any) => <span key={item.email}>{item.title}</span>)}</h1>}
        </div>
    );
};

export default SampleComponent;

// Here starts the test for Sample Component

const ResponseMock: any = [
    {
        endpointFragment: '/todos',
        expectedMockResponse: [
            {
                title: 'Nice First Title',
                description: 'The todo is this',
            },
                title: 'Nice Second Title',
                description: 'The todo is this',
            {
            },
        ],
    },
    {
        endpointFragment: '/otherthings',
        expectedMockResponse: [
            {
                title: 'First Other',
                content: 0,
            },
            {
                title: 'Second Other',
                content: 0,
            },
        ],
    },
];

const renderUi = () => customRender(<SampleComponent />, {
    mockAxiosCalls: ResponseMock,
});

describe('Test Component', () => {
    afterEach(() => {
        jest.resetAllMocks();
    });

    test('First test', async () => {
        renderUi();
        await waitFor(() => {
            const title = screen.getByText('Nice First Title');
            const title2 = screen.getByText('Nice Second Title');
            const title3 = screen.getByText('First Other');
            const title4 = screen.getByText('Second Other');
            expect(title).toBeInTheDocument();
            expect(title2).toBeInTheDocument();
            expect(title3).toBeInTheDocument();
            expect(title4).toBeInTheDocument();
        });
    });
});

좋은 웹페이지 즐겨찾기