【问题标题】:What's the proper typing for a React Testing Library wrapper in typescript?打字稿中 React 测试库包装器的正确类型是什么?
【发布时间】:2021-09-28 07:42:12
【问题描述】:

所以我从 kent c dodd 的库中获得了类似的东西,非常有用


import * as React from 'react'
import {render as rtlRender} from '@testing-library/react'
import {ThemeProvider} from 'components/theme'

function render(ui, {theme = 'light', ...options} = {}) {
  const Wrapper = ({children}) => (
    <ThemeProvider initialTheme={theme}>{children}</ThemeProvider>
  )
  return rtlRender(ui, {wrapper: Wrapper, ...options})
}

export * from '@testing-library/react'
// override React Testing Library's render with our own
export {render}

不过,我在将其转换为打字稿时遇到了麻烦。关于我需要在下面进行微调的任何想法?

import * as React from 'react'
import { ReactNode } from 'react'
import {render as rtlRender} from '@testing-library/react'
import { QueryClientProvider, QueryClient } from 'react-query'

interface WrapperProps {
  children: ReactNode
}

const queryClient = new QueryClient();
function render(ui, {client = queryClient, ...options} = {}) {
  const Wrapper = ({children}: WrapperProps) => (
    <QueryClientProvider client={client}>
      {children}
    </QueryClientProvider>
  )
  return rtlRender(ui, {wrapper: Wrapper, ...options})
}

export * from '@testing-library/react'
// override React Testing Library's render with our own
export {render}

我得到以下关于在包装上打字的信息:

No overload matches this call.
  Overload 1 of 2, '(ui: ReactElement<any, string | JSXElementConstructor<any>>, options: RenderOptions<typeof import("path/node_modules/@testing-library/dom/types/queries"), HTMLElement>): RenderResult<...>', gave the following error.
    Type '({ children }: WrapperProps) => JSX.Element' is not assignable to type 'ComponentType<{}>'.
      Type '({ children }: WrapperProps) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.
        Types of parameters '__0' and 'props' are incompatible.
          Type '{ children?: ReactNode; }' is not assignable to type 'WrapperProps'.
            Property 'children' is optional in type '{ children?: ReactNode; }' but required in type 'WrapperProps'.
  Overload 2 of 2, '(ui: ReactElement<any, string | JSXElementConstructor<any>>, options?: Omit<RenderOptions<typeof import("path/node_modules/@testing-library/dom/types/queries"), HTMLElement>, "queries">): RenderResult<...>', gave the following error.
    Type '({ children }: WrapperProps) => JSX.Element' is not assignable to type 'ComponentType<{}>'.
      Type '({ children }: WrapperProps) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.ts(2769)
index.d.ts(41, 3): The expected type comes from property 'wrapper' which is declared here on type 'RenderOptions<typeof import("path/node_modules/@testing-library/dom/types/queries"), HTMLElement>'
index.d.ts(41, 3): The expected type comes from property 'wrapper' which is declared here on type 'Omit<RenderOptions<typeof import("path/node_modules/@testing-library/dom/types/queries"), HTMLElement>, "queries">'

【问题讨论】:

    标签: reactjs typescript react-testing-library


    【解决方案1】:

    你可以这样输入你的渲染函数

    import { render as testingRender, RenderOptions } from "@testing-library/react";
    
    // ...
    
    const render = (
      ui: React.ReactElement,
      options?: Omit<RenderOptions, "queries">,
    ) => {
      return testingRender(ui, { wrapper: Wrapper, ...options });
    };
    

    你知道,我的包装器被定义为你的

    type WrapperProps = {
      children: React.ReactNode;
    };
    
    const Wrapper = ({ children }: WrapperProps) => {
      return (
        <ChakraProvider>
          <AuthContext.Provider
            value={{
              // ...
            }}
          >
            {children}
          </AuthContext.Provider>
        </ChakraProvider>
      );
    };
    

    【讨论】:

    • 我已选择将render 函数与Wrapper 组件分开,但这根本不是必需的。对我来说更容易理解。
    【解决方案2】:

    试试这个:

    import { ReactElement } from 'react'
    import { render as rtlRender } from '@testing-library/react'
    import { QueryClientProvider, QueryClient } from 'react-query'
    
    const queryClient = new QueryClient();
    
    const render = (ui: ReactElement, { client = queryClient, ...options } = {}) =>
        rtlRender(ui, {
            wrapper: ({ children }) => (
                <QueryClientProvider client={client}>
                    {children}
                </QueryClientProvider>
            ), ...options
        });
    
    export * from '@testing-library/react'
    // override React Testing Library's render with our own
    export { render }
    

    理想情况下,您不应该仅仅为了替换渲染功能而导出整个测试库,您可以创建自己的包装器并将其与测试库一起使用。但是,上面的代码应该可以正常工作。

    【讨论】:

    • 做到了?我是如此接近! :-) 这是有道理的,谢谢!
    【解决方案3】:

    我认为 ts 将 Wrapper 推断为 JSX.Element,但 rtlRender 需要一个“FunctionComponent”。

    所以,您可以Wrapper: FunctionComponent 或使用其快捷方式Wrapper: FC

    另外,不需要WrapperProps 接口,因为会指定子级。

    import * as React from 'react'
    
    import { QueryClient, QueryClientProvider } from 'react-query'
    
    import {render as rtlRender} from '@testing-library/react'
    
    const queryClient = new QueryClient();
    function render(ui, {client = queryClient, ...options} = {}) {
      const Wrapper: React.FC = ({children}) => (
        <QueryClientProvider client={client}>
          {children}
        </QueryClientProvider>
      )
      return rtlRender(ui, {wrapper: Wrapper, ...options})
    }
    
    export * from '@testing-library/react'
    // override React Testing Library's render with our own
    export {render}
    

    【讨论】:

      猜你喜欢
      • 2020-05-31
      • 1970-01-01
      • 2019-07-29
      • 2016-11-06
      • 1970-01-01
      • 2023-02-10
      • 2019-01-12
      • 2022-01-19
      • 2019-01-26
      相关资源
      最近更新 更多