使用 MSW 测试 React-query,并将数据传递给子组件

Posted

技术标签:

【中文标题】使用 MSW 测试 React-query,并将数据传递给子组件【英文标题】:Testing React-query with MSW with the data passed to a child component 【发布时间】:2021-12-14 03:18:18 【问题描述】:

我正在使用 React-query 并尝试对其进行测试,在父组件中调用数据并传递给子组件以呈现项目列表。我已经设置了 MSW,但是当我尝试我的测试时:

const queryClient = new QueryClient()

it('Should give a response', async () => 
    render(<QueryClientProvider client=queryClient><Component /></QueryClientProvider>);
    expect(await screen.findByTestId('test-data')).toBeInTheDocument();
)

我明白了:

Unable to find an element by: [data-testid="test-data"]

<body>
  <div>
    <div
      class="mt-5"
    >
      Loading data ...
    </div>
  </div>
</body>

父组件是这样的:

const Component1: React.FunctionComponent = () => 
    const [fetchData, setFetchData] = React.useState<IData[]>([]);

    const queryKey = 'mainData';

    const getData = async (): Promise<any> => 
            await new Promise(resolve => setTimeout(resolve, 1000))
            const response = await axios.get(`xxxxxxx`).then(res => res.data);
            return response;
    

    const  data: result, status, isRefetching, error, refetch : any = useQuery(queryKey, getData,
        
            refetchOnWindowFocus: true,
            staleTime: 0,
            cacheTime: 0,
            refetchInterval: 0,
        
    );
 
    return (
        <>
            status === 'error' && (
                <div className="mt-5">error.message</div>
            )
            status === 'loading' && (
                <div className="mt-5">Loading data ...</div>
            )
            status === 'success' && (
                <div className="row dashboard">
                    <ChildComponent data=fetchData data-testid="test-data"/> // data passed to this component
                    <br />
                </div>
            )
            isRefetching ? 'Updating...' : null 
        </>
    )
;

export default Component1;

设置测试:

import '@testing-library/jest-dom';

import  server  from './mocks/server'
// Establish API mocking before all tests.

beforeAll(() => server.listen())
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.

afterEach(() => server.resetHandlers())

// Clean up after the tests are finished.
afterAll(() => server.close())

处理程序

import  rest  from 'msw';

export const handlers = [
    rest.get('https://xxxxxxxx', (req, res, ctx) => 
        return res(
            ctx.json([
                
                    "titleNumber": 499,
                    "model": "Yes Model",
                ,
                
                    "titleNumber": 434,
                    "model": "No Model",
                ,
            ])
        );
    ),
];

服务器

import  setupServer  from 'msw/node'
import  handlers  from './handlers'
export const server = setupServer(...handlers)

我是不是在错误的地方进行测试?

【问题讨论】:

您确定 MSW 工作正常吗? 是的,但那不是测试 api 调用本身是否正在返回一些东西。你需要测试看看 getData() 是否真的从 msw 返回了一些东西。您可以发布指向 github 存储库或其他内容的链接吗? 我觉得有些东西不见了,你能发个github链接什么的吗?会更容易解决 这正在讨论中,但您应该能够使用旨在捕获 api 调用的 msw 来做到这一点,因此它不应该进入身份验证。这意味着 msw 可能无法正常工作 这是一个非常奇怪的问题。刚刚更新了我的答案 【参考方案1】:

更新答案

好的,这是一个非常奇怪的问题。我复制了它并得到了同样的东西,即使它不应该。我认为问题可能与反应查询和测试有关,而不是与 msw 有关。为了解决它,我只是开玩笑地告诉useFakeTimers,然后它就起作用了

describe('should return data', () => 
    beforeEach(() => 
        jest.useFakeTimers();
    );

    it('Should give a response', async () => 
        render(
            <QueryClientProvider client=queryClient>
                <App />
            </QueryClientProvider>
        );
        expect(await screen.findByTestId('test-data')).toBeInTheDocument();
        // screen.debug();
    );
);

我认为问题在于您将 data-testid="test-data" 作为道具传递到 ChildComponent 并且我猜您没有在组件内部使用它,这意味着它实际上并没有附加到任何DOM 元素。这可以解释为什么它说它找不到元素,因为除非你在 ChildComponent 内部使用它,否则它不会被使用。

尝试将其添加到作为 don 节点而不是组件的元素中,例如它所在的 div。

status === 'success' && (
    <div className="row dashboard" data-testid="test-data">
        <ChildComponent data=fetchData />
        <br />
    </div>
)

【讨论】:

Unable to find an element by: [data-testid="test-data"].. 我想知道我是否将其余的 mock 移到了测试文件本身中。 加载部分没有通过 确实有效,那么'jest.useFakeTimers(); 到底是什么没有遇到过呢? useFakeTimers 只是告诉任何会使用时间(即 setTimeout、setInterval)来伪造它的东西。而不是使用实际的东西。因此,在您的情况下,您使用的是 setTimeout 而不是使用它来伪造它。

以上是关于使用 MSW 测试 React-query,并将数据传递给子组件的主要内容,如果未能解决你的问题,请参考以下文章

使用 MSW 和 Jest 时如何在请求之间的测试中清除 RTK 查询缓存?

如何使用 msw 有条件地模拟错误响应

Jest 使用 Mock Service Worker (MSW) 或其他模拟离线网络?

针对未处理的 Supertest 请求的 MSW 日志记录警告

MSW 与 Jest(困惑)

@testing-library/与 msw/node 反应; window.fetch 未在 POST 上返回正文