首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >React-Query - Unit Test with react-testing-library

React-Query - Unit Test with react-testing-library
EN

Stack Overflow用户
提问于 2021-01-14 19:08:19
回答 1查看 4.7K关注 0票数 4

我有一个包含子组件的Dashboard组件,例如使用react-query的Child

我对开始失败的Dashboard组件进行了现有的单元测试,错误是:

代码语言:javascript
复制
TypeError: queryClient.defaultQueryObserverOptions is not a function

  38 |     const { locale } = React.useContext(LocaleStateContext);
  39 |     const options = getOptions(locale);
> 40 |     return useQuery(
     |            ^
  41 |         rqKey,
  42 |         async () => {
  43 |             const result = await window.fetch(url, options);

测试中的代码片段:

代码语言:javascript
复制
const queryClient = new QueryClient();
const { getByTestId, getByRole } = render(
    <IntlProvider locale="en" messages={messages}>
        <QueryClientProvider client={queryClient}>
            <Dashboard />
        </QueryClientProvider>
    </IntlProvider>,
);

我阅读了关于测试的文档:

https://react-query.tanstack.com/guides/testing#our-first-test

但我不一定要使用renderHook,因为我对结果不感兴趣。

编辑:

Child组件正在使用一个函数:

代码语言:javascript
复制
export function usePosts({ rqKey, url, extraConfig }: CallApiProps) {
    const { locale } = React.useContext(LocaleStateContext);
    const options = getOptions(locale);
    return useQuery(
        rqKey,
        async () => {
            const result = await window.fetch(url, options);
            const data = await result.json();
            return data;
        },
        extraConfig,
    );
}

它就是这样被称为:

代码语言:javascript
复制
const { data, error, isFetching, isError } = usePosts({
        rqKey,
        url,
        extraConfig,
    });

根据您的回答,我应该创建一个单独的函数:

代码语言:javascript
复制
async () => {
            const result = await window.fetch(url, options);
            const data = await result.json();
            return data;
        },

例如:

代码语言:javascript
复制
export async function usePosts({ rqKey, url, extraConfig }: CallApiProps) {
    const { locale } = React.useContext(LocaleStateContext);
    const options = getOptions(locale);
    return useQuery(
        rqKey,
        await getFoos(url, options),
        extraConfig,
    );
}

然后在测试中模拟它。

如果我这样做了,我将如何访问:error, isFetching, isError

因为usePosts()现在将返回一个Promise<QueryObserverResult<unknown, unknown>>

编辑2:

我尝试简化我的代码:

代码语言:javascript
复制
export async function useFetch({ queryKey }: any) {
    const [_key, { url, options }] = queryKey;
    const res = await window.fetch(url, options);
    return await res.json();
}

然后将其用作:

代码语言:javascript
复制
const { isLoading, error, data, isError } = useQuery(
    [rqKey, { url, options }],
    useFetch,
    extraConfig,
);

一切正常。

Dashboard测试中,我执行以下操作:

代码语言:javascript
复制
import * as useFetch from ".";

代码语言:javascript
复制
jest.spyOn(useFetch, "useFetch").mockResolvedValue(["asdf", "asdf"]);

代码语言:javascript
复制
render(
        <IntlProvider locale="en" messages={messages}>
            <QueryClientProvider client={queryClient}>
                <Dashboard />
            </QueryClientProvider>
        </IntlProvider>,
    );

然后返回:

代码语言:javascript
复制
TypeError: queryClient.defaultQueryObserverOptions is not a function

      78 |     const { locale } = React.useContext(LocaleStateContext);
      79 |     const options = getOptions(locale);
    > 80 |     const { isLoading, error, data, isError } = useQuery(
         |                                                 ^
      81 |         [rqKey, { url, options }],
      82 |         useFetch,
      83 |         extraConfig,
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-15 17:12:19

您提到的文档页面解释了如何根据React查询测试自定义钩子。你是在使用基于React Query的自定义钩子,还是只想测试使用useQuery (由React Query提供的钩子)的组件?

如果你只是想测试使用useQuery的孩子,你应该模拟你的“请求函数”(返回承诺的函数,用作useQuery的第二个参数),并在没有任何提供者的情况下呈现你的测试组件。

例如,假设在Child中,你有

代码语言:javascript
复制
const foo = useQuery('key', getFoos, { // additional config here });
// foo is a QueryResult object (https://react-query.tanstack.com/reference/useQuery)
// so your usePost function will return a QueryResult as well
// foo.data holds the query results (or undefined)
// you can access to foo.error, foo.isFetching, foo.status...
// also note that extra parameter to be passed to your async function 
// should be part of the request key. Key should be an array :
// useQuery(['key', params], getFoos, { // additional config });
// so params object props will be passed as parameters for getFoos fucntion
// see https://react-query.tanstack.com/guides/query-keys#array-keys

...and getFoos在path/to/file/defining/getFoos.ts中定义为

代码语言:javascript
复制
const getFoos = async (): Promise<string[]> => await fetch(...);

您可以在Child.test.tsx中使用...then

代码语言:javascript
复制
import * as FooModule from 'path/to/file/defining/getFoos';

// this line could be at the top of file or in a particular test()
jest.spyOn(FooModule, 'getFoos').mockResolvedValue(['mocked', 'foos']);

// now in your Child tests you'll always get ['mocked', 'foos']
// through useQuery (in foo.data), but you'll still have to use https://testing-library.com/docs/dom-testing-library/api-async/#waitfor (mocked but still async)
// No need for QueryClientProvider in this case, just render <Child />

答案:

尽管上面的回答帮助我找到了正确的方向,但潜在的问题是我使用mockImplementation来提供上下文,这使得QueryClientProvider提供的上下文变得无用,例如

代码语言:javascript
复制
jest.spyOn(React, "useContext").mockImplementation(() => ({
    ...
}));

我最终删除了mockImplementation,并在我的UserStateContext.Provider中添加了QueryClientProvider,问题解决了:

代码语言:javascript
复制
render(
    <IntlProvider locale="en" messages={messages}>
        <UserStateContext.Provider value={value}>
            <QueryClientProvider client={queryClient}>
                <Dashboard />
            </QueryClientProvider>
        </UserStateContext.Provider>
    </IntlProvider>,
);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65717859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档