Сбой при тестировании компонента в react с использованием typescript

#reactjs #typescript #testing

#reactjs #typescript #тестирование

Вопрос:

Когда я когда-либо запускаю тест, он терпит неудачу. Я не знаю, какую ошибку я совершаю.

Как я могу протестировать эти операторы if и дочерний компонент. Я использую jest и enzyme для реактивных тестов.

Это мой тестовый файл:

 import React from "react";
import { shallow } from "enzyme";
import LaunchContainer from "./index";
import Launch from "./Launch";

describe("render LaunchContainer component", () => {

    let container: any;
    beforeEach(() => { container = shallow(<LaunchContainer setid={()=>{}} setsuccess={()=>{}} />) });

    it("should render LaunchContainer component", () => {
        expect(container.containsMatchingElement(<Launch setsuccess={()=>{}} setid={()=>{}} data={{}}/>)).toEqual(true);
      });

})
 

Родительский компонент, для которого используется тест:

 import React from "react";
import { useLaunchesQuery } from "../../generated/graphql";
import Launch from './Launch';

interface Props {
    setid: any;
    setsuccess: any;
}

const LaunchContainer: React.FC<Props> = ({setid, setsuccess}) => {
    const {data, loading, error} = useLaunchesQuery();

    if (loading) {
        return <div>loading...</div>
    }

    if (error || !data) {
        return <div>error</div>
    }

    return <Launch setid={setid} data={data} setsuccess={setsuccess} />
}

export default LaunchContainer;
 

Дочерний компонент, который будет добавлен в тест:

 import React from "react";
import { LaunchesQuery } from "../../generated/graphql";
import './style.css';

interface Props {
    data: LaunchesQuery;
    setid: any;
    setsuccess: any;
}

const Launch: React.FC<Props> = ({setid, data, setsuccess}) => {
    return (
        <div className="launches">
            <h3>All Space X Launches</h3>
            <ol className="LaunchesOL">
                {!!data.launches amp;amp; data.launches.map((launch, i) => !!launch amp;amp; 
                    <li key={i} className="LaunchesItem" onClick={() => {
                        setid(launch.flight_number?.toString())
                        setsuccess(JSON.stringify(launch.launch_success))
                    }}>
                        {launch.mission_name} - {launch.launch_year} (<span className={launch.launch_success? "LaunchDetailsSuccess": launch.launch_success===null? "": "LaunchDetailsFailed"}>{JSON.stringify(launch.launch_success)}</span>)
                    </li>
                )}
            </ol>
        </div>
    );
}

export default Launch;
 

Ответ №1:

Чтобы проверить эти операторы if, вы должны издеваться над своими useLaunchesQuery , чтобы возвращать значения loading , error и data , которые соответствуют вашим if операторам. Вы можете использовать mockImplementationOnce или mockReturnValueOnce . Например, вы могли бы написать

 import { useLaunchesQuery } from "../../generated/graphql";

/** 
 * You mock your entire file /generated/graphql so it returns
 * an object containing the mock of useLaunchesQuery.
 * Note that every members in this file and not specified in this mock
 * will not be usable.
 */
jest.mock('../../generated/graphql', () => ({
    useLaunchesQuery: jest.fn(() => ({
        loading: false,
        error: false,
        data: [/**Whatever your mocked data is like */]
    }))
}))

const setid = jest.fn();
const setsuccess = jest.fn();

/**
 * A good practice is to make a setup function that returns
 * your tested component so so you can call it in every test
 */
function setup(props?: any) { // type of your component's props
    // You pass mock functions declared in the upper scope so you can
    // access it later to assert that they have been called the way they should
    return <LaunchContainer setid={setid} setsuccess={setsuccess} {...props} />
    // Spread the props passed in parameters so you overide with whatever you want
}

describe("render LaunchContainer component", () => {
    it('should show loading indicator', () => {
        /** 
         * Here I use mockReturnValueOnce so useLaunchesQuery is mocked to return
         * this value only for the next call of it
         */
        (useLaunchesQuery as jest.Mock).mockReturnValueOnce({ loading: true, error: false, data: [] })

        /** Note that shallow won't render any child of LaunchContainer other than basic JSX tags (div, span, etc)
         * So you better use mount instead 
        */
        const container = mount(setup()); // here i could pass a value for setid or setsuccess

        // Put an id on your loading indicator first
        expect(container.find('#loading-indicator').exists()).toBeTruthy()

        /** The logic for the other if statement remains the same */
    })
}