2

我正在尝试测试一个使用 axios 获取一些数据的简单钩子。然而,测试抛出了一个 TypeError:“无法读取未定义的属性 'fetchCompanies'”。这是我的自定义钩子(完整的 repo 在这里):

import { useState, useEffect } from 'react';
import { Company } from '../../models';
import { CompanyService } from '../../services';

export const useCompanyList = (): {
    loading: boolean;
    error: any;
    companies: Array<Company>;
} => {
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState();
    const [companies, setCompanies] = useState<Array<Company>>([]);

    useEffect(() => {
        const fetchData = async () => {
            try {
                setLoading(true);
                const companies = await CompanyService.fetchCompanies();

                // Sort by ticker
                companies.sort((a, b) => {
                    if (a.ticker < b.ticker) return -1;
                    if (a.ticker > b.ticker) return 1;
                    return 0;
                });
                setCompanies(companies);
                setLoading(false);
            } catch (e) {
                setError(e);
            }
        };

        fetchData();
    }, []);

    return { loading, error, companies };
};

这是我的测试:

import { renderHook } from 'react-hooks-testing-library';
import { useCompanyList } from './useCompanyList';

const companiesSorted = [
    {
        ticker: 'AAPL',
        name: 'Apple Inc.'
    },
    ...
];

jest.mock('../../services/CompanyService', () => {
    const companiesUnsorted = [
        {
            ticker: 'MSFT',
            name: 'Microsoft Corporation'
        },
        ...
    ];

    return {
        fetchCompanies: () => companiesUnsorted
    };
});

describe('useCompanyList', () => {
    it('returns a sorted list of companies', () => {
        const { result } = renderHook(() => useCompanyList());

        expect(result.current.loading).toBe(true);
        expect(result.current.error).toBeUndefined();
        expect(result.current.companies).toEqual(companiesSorted);
    });
});

请帮助我了解在这种情况下如何使用 react-hooks-testing-library。

编辑

这似乎与看似已解决的 Jest 问题有关。请参阅https://github.com/facebook/jest/pull/3209

4

1 回答 1

3

TypeError:“无法读取未定义的属性 'fetchCompanies'”

是由您定义CompanyService服务的方式引起的。在代码中,您正在导出一个CompanyService包含所有服务方法的对象。但是在您的测试中,您正在模拟CompanyService返回一个带有方法的对象。

因此,模拟应该返回一个CompanyService对象,该对象是具有所有方法的对象:

jest.mock('../../services/CompanyService', () => {
    const companiesUnsorted = [
        {
            ticker: 'MSFT',
            name: 'Microsoft Corporation'
        },
        ...
    ];

    return {
        CompanyService: {
            fetchCompanies: () => companiesUnsorted
        }
    };
});

现在,一旦你解决了这个问题,你会发现你没有TypeError了,但你的测试没有通过。那是因为您尝试测试的代码是异步的,但您的测试不是。所以,在你渲染你的钩子之后(通过renderHookresult.current.companies将是一个空数组。

您将不得不等待您的承诺解决。幸运的是,react-hooks-testing-library它为我们提供了一个waitForNextUpdate函数,以便等待下一次钩子更新。因此,测试的最终代码如下所示:

it('returns a sorted list of companies', async () => {
    const { result, waitForNextUpdate } = renderHook(() => useCompanyList());

    expect(result.current.loading).toBe(true);
    expect(result.current.error).toBeUndefined();
    expect(result.current.companies).toEqual([]);

    await waitForNextUpdate();

    expect(result.current.loading).toBe(false);
    expect(result.current.error).toBeUndefined();
    expect(result.current.companies).toEqual(companiesSorted);
});
于 2019-05-13T13:14:49.703 回答