Ian*_*ane 10 javascript mocking apollo reactjs react-testing-library
一些背景:我有一个组件在加载时立即调用 useQuery 挂钩。当该查询运行时,我旋转一个加载微调器。一旦完成,我就会根据数据渲染内容。
我添加了一个useEffect
挂钩来监视查询结果并记录数据,这就是我观察此问题的方式。
为了简化事情,它的工作原理如下:
export default function MyComponent(props: ???) {
const result = useQuery(INITIAL_DATA_QUERY, { variables: { id: 1 } });
React.useEffect(() => console.log(JSON.stringify({
loading: result.loading,
data: result.data,
error: result.error,
})), [result]);
if (result.loading) return <LoadingScreen message="Fetching data..."/>;
else if (result.error) return <ErrorPage/>
else return <Stuff info={result.data}> // omitted because it's unimportant to the issue
}
Run Code Online (Sandbox Code Playgroud)
当我在野外运行这个组件时,一切都完全按预期工作。它通过 Apollo 使用 GraphQL 到达端点,根据结果做出渲染决策等。
当我尝试模拟请求时,result.data
和result.error
字段永远不会改变,即使该result.loading
字段发生了变化。我正在用来react-testing-library
运行测试。
我的测试如下所示:
it("should load the data then render the page", () => {
const mocks = [{
request: {
query: INITIAL_DATA_QUERY,
variables: { id: 1 },
},
newData: jest.fn(() => ({
data: {
firstName: "Joe",
lastName: "Random",
}
}))
}];
const mockSpy = mocks[0].newData;
render(
<MockedProvider mocks={mocks} addTypename={false}>
<MyComponent/>
</MockedProvider>
)
// Is it a loading view
expect(result.asFragment()).toMatchSnapshot(); // Passes just fine, and matches expectations
// Wait until the mock has been called once
await waitFor(() => expect(mockSpy).toHaveBeenCalled(1)) // Also passes, meaning the mock was called
// Has the page rendered once the loading mock has finished
expect(result.asFragment()).toMatchSnapshot(); // Passes, but the page has rendered without any of the data
})
Run Code Online (Sandbox Code Playgroud)
问题是这样的:当我运行此测试时,所有三个测试都按预期通过,但在最终片段中,渲染组件中的数据丢失了。我确信正在调用模拟,因为我添加了一些记录器语句来检查。
真正令人困惑的部分是调用模拟时的loading
、data
和值。error
当它们中的任何一个发生更改时,我有一个useEffect
语句记录它们的值,当我运行测试时,输出如下所示:
{ loading: true, data: undefined, error: undefined }
{ loading: false, data: undefined, error: undefined }
Run Code Online (Sandbox Code Playgroud)
这意味着正在调用钩子并开始加载,但是一旦加载结束,加载期间发生的任何事情都不会返回任何数据,也不会生成任何错误。
有谁知道我这里的问题可能是什么?到周日为止我已经看了八种方法,但还是无法弄清楚。
我使用该字段模拟了结果result
。
\n\n该
\nresult
字段可以是执行任意逻辑后返回模拟响应的函数
这对我来说可以。
\nMyComponent.test.tsx
:
import { gql, useQuery } from \'@apollo/client\';\nimport { useEffect } from \'react\';\n\nexport const INITIAL_DATA_QUERY = gql`\n query GetUser($id: ID!) {\n user(id: $id) {\n firstName\n lastName\n }\n }\n`;\n\nexport default function MyComponent(props) {\n const result = useQuery(INITIAL_DATA_QUERY, { variables: { id: 1 } });\n\n useEffect(\n () =>\n console.log(\n JSON.stringify({\n loading: result.loading,\n data: result.data,\n error: result.error,\n }),\n ),\n [result],\n );\n\n if (result.loading) return <p>Fetching data...</p>;\n else if (result.error) return <p>{result.error}</p>;\n else return <p>{result.data.user.firstName}</p>;\n}\n
Run Code Online (Sandbox Code Playgroud)\nMyComponent.test.tsx
:
import { render, waitFor } from \'@testing-library/react\';\nimport MyComponent, { INITIAL_DATA_QUERY } from \'./MyComponent\';\nimport { MockedProvider } from \'@apollo/client/testing\';\n\ndescribe(\'68732957\', () => {\n it(\'should load the data then render the page\', async () => {\n const mocks = [\n {\n request: {\n query: INITIAL_DATA_QUERY,\n variables: { id: 1 },\n },\n result: jest.fn().mockReturnValue({\n data: {\n user: {\n lastName: \'Random\',\n firstName: \'Joe\',\n },\n },\n }),\n },\n ];\n\n const mockSpy = mocks[0].result;\n const result = render(\n <MockedProvider mocks={mocks} addTypename={false}>\n <MyComponent />\n </MockedProvider>,\n );\n\n expect(result.asFragment()).toMatchSnapshot();\n await waitFor(() => expect(mockSpy).toBeCalledTimes(1));\n expect(result.asFragment()).toMatchSnapshot();\n });\n});\n
Run Code Online (Sandbox Code Playgroud)\n测试结果:
\n PASS src/stackoverflow/68732957/MyComponent.test.tsx\n 68732957\n \xe2\x9c\x93 should load the data then render the page (58 ms)\n\n console.log\n {"loading":true}\n\n at src/stackoverflow/68732957/MyComponent.tsx:18:15\n\n console.log\n {"loading":false,"data":{"user":{"firstName":"Joe","lastName":"Random"}}}\n\n at src/stackoverflow/68732957/MyComponent.tsx:18:15\n\nTest Suites: 1 passed, 1 total\nTests: 1 passed, 1 total\nSnapshots: 2 passed, 2 total\nTime: 0.736 s, estimated 1 s\n
Run Code Online (Sandbox Code Playgroud)\nMyComponent.test.tsx.snap
:
// Jest Snapshot v1\n\nexports[`68732957 should load the data then render the page 1`] = `\n<DocumentFragment>\n <p>\n Fetching data...\n </p>\n</DocumentFragment>\n`;\n\nexports[`68732957 should load the data then render the page 2`] = `\n<DocumentFragment>\n <p>\n Joe\n </p>\n</DocumentFragment>\n`;\n
Run Code Online (Sandbox Code Playgroud)\n软件包版本:
\nimport { gql, useQuery } from \'@apollo/client\';\nimport { useEffect } from \'react\';\n\nexport const INITIAL_DATA_QUERY = gql`\n query GetUser($id: ID!) {\n user(id: $id) {\n firstName\n lastName\n }\n }\n`;\n\nexport default function MyComponent(props) {\n const result = useQuery(INITIAL_DATA_QUERY, { variables: { id: 1 } });\n\n useEffect(\n () =>\n console.log(\n JSON.stringify({\n loading: result.loading,\n data: result.data,\n error: result.error,\n }),\n ),\n [result],\n );\n\n if (result.loading) return <p>Fetching data...</p>;\n else if (result.error) return <p>{result.error}</p>;\n else return <p>{result.data.user.firstName}</p>;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
6802 次 |
最近记录: |