Nei*_*rdi 12 javascript reactjs create-react-app apollo-client react-testing-library
更新: \n尝试升级到 React 18 和 RTL 13,但这并没有解决问题。
\nuseQuery()
我\xe2\x80\x99m 在测试挂载时调用 Apollo 的 React 组件时遇到了长期问题。如果我使用异步 RTL 方法,GraphQL 查询将失败并出现ECONNREFUSED
错误。如果我使用同步 RTL 方法,我不会收到此错误。但是,同步方法不起作用,因为断言在loading
equals时运行true
时运行。因此,数据尚未从查询中返回,因此没有可呈现的内容。
以下是引发此错误的测试中的代码片段:
\nit(\'renders\', async () => {\n renderGrid()\n const columnHeading = await screen.findByText(/Primary Household Member/i)\n expect(columnHeading).toBeInTheDocument()\n})\n
Run Code Online (Sandbox Code Playgroud)\n我已附上控制台中生成的内容的屏幕截图(见下文)。\n如果我将代码更改为同步,如下所示:
\nit(\'renders\', () => {\n renderGrid()\n const columnHeading = screen.getByText(/Primary Household Member/i)\n expect(columnHeading).toBeInTheDocument()\n})\n
Run Code Online (Sandbox Code Playgroud)\n我没有得到ECONNREFUSED
错误。然而,在这种情况下,loading
istrue
和data
以及error
是未定义的。我无法测试网格是否呈现了表格,因为在这种情况下,组件只是返回<div>loading...</div>
. 我尝试将渲染函数包装起来,act()
但这不会改变任何东西。我也尝试waitFor()
过没有效果。
我还尝试了同步代码并将getBy()
调用和断言包装在setTimeout()
. 有趣的是,这实际上会产生误报。网格不会渲染,我可以断言任何我想要的东西并且它会通过。(不确定这是 Jest bug 还是 RTL bug),
我将包含测试的完整代码。请注意,我正在将一些数据写入客户端缓存。这是因为除了发出网络请求之外,组件还通过使用指令查询属性来获取一些本地状态@client
。
以下是查询:
\nimport gql from \'graphql-tag\'\n\n// this data is in the client-side cache only\n// it is local state\n// we write this to the cache in the test\nexport const GET_REPORTING_GRID_SETTINGS = gql`\n query GetReportingGridSettings {\n reportingGridQueryVariables @client\n }\n`\n// this data is in the client-side cache only\n// it is local state\n// we write this to the cache in the test\nexport const GET_COLUMN_SELECTIONS = gql`\n query ColumnSelections {\n columnSelections @client {\n household\n individual\n cases\n activities\n }\n }\n`\n// this data is in the client-side cache only\n// it is local state\n// we write this to the cache in the test\nexport const GET_REPORTING_MODAL_STATE = gql`\n query GetReportingModalState {\n showReportingMainModal @client\n }\n`\n\n// this is a network query\n// we pass this in apollo mocks\nexport const ME = gql`\n query me {\n me {\n id\n isACaseManager\n fullName\n role\n userable {\n ... on CaseManager {\n id\n organization {\n id\n name\n slug\n }\n locations {\n id\n name\n slug\n customFields {\n id\n label\n }\n }\n }\n }\n email\n }\n }\n`\n\n// this is a network query\n// we pass this in apollo mocks\nexport const GET_INDIVIDUAL_DEMOGRAPHICS = gql`\n query getDemographics(\n $pageSize: Int\n $pageNumber: Int\n $sort: [IndividualDemographicReportSortInput!]\n $filter: IndividualDemographicReportFilterInput\n $searchTerm: String\n ) {\n individualDemographicReport(\n pageSize: $pageSize\n pageNumber: $pageNumber\n sort: $sort\n filter: $filter\n searchTerm: $searchTerm\n ) {\n totalCount\n pageCount\n nodes {\n id\n fullName\n annualIncome\n age\n dateOfBirth\n displayDateOfBirth @client #type policy\n relationshipToClient\n employmentCount\n isCurrentlyWorking\n displayIsCurrentlyWorking @client #type policy\n employmentStatus\n additionalIncome\n displayAdditionalIncome @client #type policy\n alimonyAmount\n primaryAccountHolder {\n fullName\n clientLocations {\n id\n }\n lastYearAdjustedGrossIncome\n taxFilingStatus\n displayLastYearAdjustedGrossIncome @client #type policy\n displayTaxFilingStatus @client #type policy\n }\n demographic {\n id\n gender\n race\n ethnicity\n education\n healthInsurance\n hasHealthInsurance\n displayHasHealthInsurance @client #type policy\n isStudent\n displayIsStudent @client #type policy\n isVeteran\n displayIsVeteran @client #type policy\n isDisabled\n isPregnant\n displayIsPregnant @client #type policy\n isUsCitizen\n displayIsUsCitizen @client #type policy\n immigrationStatus\n lengthOfPermanentResidency\n courseLoad\n hasWorkStudy\n displayHasWorkStudy @client #type policy\n expectedFamilyContribution\n costOfAttendance\n displayEfc @client #type policy\n displayCoa @client #type policy\n courseLoad\n }\n alimonyAmount\n childSupportAmount\n pensionAmount\n ssdSsiAmount\n unemploymentInsuranceAmount\n vaBenefitsAmount\n workersCompensationAmount\n otherAdditionalIncomeAmount\n savingsAmount\n claimedAsDependent\n displayClaimedAsDependent @client #type policy\n }\n }\n }\n`\n
Run Code Online (Sandbox Code Playgroud)\n这是测试文件的完整内容。接下来是控制台屏幕截图:
\nimport React from \'react\'\nimport { render, screen } from \'Utils/test-utils\'\nimport {\n GET_INDIVIDUAL_DEMOGRAPHICS,\n GET_REPORTING_GRID_SETTINGS,\n GET_COLUMN_SELECTIONS,\n GET_REPORTING_MODAL_STATE,\n} from \'Components/Reporting/Hooks/gql\'\nimport mockCache, {\n reportingIndividualDateRangeStartVar,\n reportingIndividualDateRangeEndVar,\n} from \'ApolloClient/caseManagementCache\'\nimport {\n apolloMocks,\n mockReportingGridState,\n mockReportingColumnsData,\n mockReportingModalsData,\n} from \'./fixtures\'\nimport ReportingGrid from \'./ReportingGrid\'\nimport getColumnsData from \'Components/CaseManagement/Reporting/Grids/Demographics/Individual/columnsData\'\n\n// Set dateRanges in the cache to match the values used in the Apollo mocks\nbeforeEach(() => {\n // Set dateRanges in the cache to match the values used in the Apollo mocks\n reportingIndividualDateRangeStartVar(\'2022-01-01T05:00:00.000Z\')\n reportingIndividualDateRangeEndVar(\'2022-06-03T13:56:36.662Z\')\n\n mockCache.writeQuery(\n {\n query: GET_REPORTING_GRID_SETTINGS,\n data: mockReportingGridState,\n },\n {\n query: GET_COLUMN_SELECTIONS,\n data: mockReportingColumnsData,\n },\n {\n query: GET_REPORTING_MODAL_STATE,\n data: mockReportingModalsData,\n }\n )\n})\n\nconst renderGrid = () => {\n render(\n <ReportingGrid\n dataQueryTag={GET_INDIVIDUAL_DEMOGRAPHICS}\n defaultSortField={\'fullName\'}\n getColumnsData={getColumnsData}\n sortable\n pageable\n reportEnum={\'INDIVIDUAL\'}\n />,\n {\n apolloMocks,\n cache: mockCache,\n addTypename: true,\n }\n )\n}\n\nit(\'renders\', () => {\n renderGrid()\n const columnHeading = screen.getByText(/Primary Household Member/i)\n expect(columnHeading).toBeInTheDocument()\n})\n
Run Code Online (Sandbox Code Playgroud)\n\n这是 test-utils.js 文件:
\nimport React from \'react\'\nimport { Provider as ReduxProvider } from \'react-redux\'\nimport configureStore from \'redux-mock-store\'\nimport { MockedProvider as MockedApolloProvider } from \'@apollo/client/testing\'\nimport { render } from \'@testing-library/react\'\nimport { renderHook } from \'@testing-library/react-hooks\'\nimport { BrowserRouter as Router } from \'react-router-dom\'\nimport store from \'../Store\'\nimport thunk from \'redux-thunk\'\n\nimport { ThemeProvider as StyledThemeProvider } from \'styled-components/macro\'\nimport { ThemeProvider as MuiThemeProvider } from \'@material-ui/core/styles\'\nimport styledTheme from \'Shared/Theme\'\nimport { mainMuiTheme } from \'Shared/Theme/muiTheme\'\n\n/**\n * [dispatch Dispatch from our store\n * @type {Function}\n */\nconst { dispatch } = store\n\n/**\n * Generates a mock store given an initial state. Middlewares are optional and\n * defaults to thunk. The mock store is used to set initial application state to\n * supply data to UI components. The mock store can also be used to test for\n * dispatched actions.\n *\n * Reducers can be unit tested separately. Testing the full range of user\n * interaction, to action dispatch, to reducer input/output, to state change,\n * would be done in an integration test. The mock store does not invoke reducers\n * or change state.\n *\n * {@link https://github.com/reduxjs/redux-mock-store|redux-mock-store}\n *\n * @param {Object} initialState Initial redux state\n * @param {Array} middlewares Optional middleware, default: [thunk]\n * @return {Object} Mock Redux Store\n */\nconst createMockStore = (initialState, middlewares = [thunk]) =>\n configureStore(middlewares)(initialState)\n\nconst WrapperWithProviders =\n ({ reduxStore, apolloProps }) =>\n ({ children }) =>\n (\n <ReduxProvider store={reduxStore}>\n <MockedApolloProvider {...apolloProps}>\n <StyledThemeProvider theme={styledTheme.mode[\'light\']}>\n <MuiThemeProvider theme={mainMuiTheme}>\n <Router>{children}</Router>\n </MuiThemeProvider>\n </StyledThemeProvider>\n </MockedApolloProvider>\n </ReduxProvider>\n )\n\n// Did we receive a (mocked) reduxStore property in the optional second argument?\n// If so, pass it in to WrapperWithProviders\n// If not, pass the default redux store imported at the top of this file\nconst getReduxStore = (options) =>\n options && options.reduxStore ? options.reduxStore : store\n\n// Did we receive an optional second argument?\n// Did it contain a reduxStore property?\n// If so, remove it from the options before passing them to RTL render()\n// (That argument is for WrapperWithProviders, not RTL)\nconst getOptions = (options) => {\n if (!options) return\n const {\n reduxStore,\n apolloMocks,\n addTypename,\n cache,\n resolvers,\n ...remainingOptions\n } = options\n return remainingOptions\n}\n\nconst mockWrapper = (options) => {\n let apolloMocks = []\n let addTypename = false\n let cache = null\n let resolvers = null\n\n if (options) {\n apolloMocks = options.apolloMocks || apolloMocks\n addTypename = options.addTypename || addTypename\n cache = options.cache || cache\n resolvers = options.resolvers || resolvers\n }\n\n const apolloProps = {\n mocks: apolloMocks,\n addTypename,\n resolvers,\n }\n\n if (cache) {\n apolloProps.cache = cache\n }\n const reduxStore = getReduxStore(options)\n return {\n wrapper: WrapperWithProviders({\n reduxStore,\n apolloProps,\n }),\n ...getOptions(options),\n }\n}\n\nconst customRender = (ui, options) => {\n return render(ui, mockWrapper(options))\n}\n\nconst customRenderHook = (cb, options) => {\n return renderHook(cb, mockWrapper(options))\n}\n// re-export everything\nexport * from \'@testing-library/react\'\n\n// override render method\nexport {\n customRender as render,\n createMockStore,\n customRenderHook as renderHook,\n dispatch,\n}\n
Run Code Online (Sandbox Code Playgroud)\n
小智 0
恐怕我对 Apollo 库不熟悉,但在我看来,模拟不起作用;相反,它正在尝试对 localhost:80 进行真正的 http 调用。
我希望当您不“等待”时看不到错误的原因是因为http请求本身是异步的,因此如果没有“等待”,则在执行断言之前它没有机会运行考试。
查看代码,我猜测您正在用数据预填充缓存,因此它不应该尝试网络访问?我建议使用调试器单步执行“mount”函数或挂钩,并尝试查看模拟数据是否最终达到您期望的位置。我经常对 java 脚本值没有达到我预期的结果感到困惑!
抱歉我无法提供更多帮助。
归档时间: |
|
查看次数: |
644 次 |
最近记录: |