对于那些根据条件渲染的 React 组件:
1 2 3 4 5 6 7
| export default function PublishedTag({ isPublished }: { isPublished?: boolean }) { if (!isPublished) { return null; }
return <span>Published</span>; }
|
针对组件有时候不会返回任何渲染结果的情况,我是这么写测试用例的:
1 2 3 4 5 6 7
| describe("PublishedTag", () => { it("should render nothing when the isPublished prop is falsy", () => { const { container } = render(<PublishedTag />)
expect(container).toBeEmptyDOMElement(); }); });
|
然后在项目里发现上面的 toBeEmptyDOMElement 断言失败了:
1 2 3 4 5
| should render nothing when the isPublished prop is falsy Error: expect(element).toBeEmptyDOMElement()
Received: "<style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style>"Error: expect(element).toBeEmptyDOMElement()
|
看报错信息并调查发现项目使用了 Mantine 组件库,这个组件库必须要在根组件位置渲染 MantineProvider 才能正常工作:
1 2 3 4 5 6 7
| import { createTheme, MantineProvider } from '@mantine/core';
const theme = createTheme({ ... });
export default function App({ children }: { children: React.ReactNode }) { return <MantineProvider theme={theme}>{children}</MantineProvider> }
|
同样,为了测试组件,测试代码也需要在 render 的时候加上一个 wrapper 来渲染这个 MantineProvider, 不然会抛错,于是就定义了一个自定义的 render 方法:
1 2 3 4 5 6 7 8 9 10
| import { MantineProvider } from "@mantine/core"; import { RenderOptions, RenderResult, render as reactTestingLibRender } from "@testing-library/react"; import { ReactElement } from "react";
export function render(ui: ReactElement, options?: Omit<RenderOptions, "wrapper">): RenderResult { return reactTestingLibRender(ui, { wrapper: ({ children }: { children: React.ReactNode }) => <MantineProvider theme={{}}>{children}</MantineProvider>, ...options, }); }
|
最开始断言失败的问题的原因就是因为渲染了 MantineProvider 导致的,MantineProvider 的渲染结果不是空的,它会返回一个 style 标签:
1
| <style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style>
|
所以即使前述 PublishedTag 组件有时候没有任何渲染结果,由于 MantineProvider 返回的 style 标签的存在,就会导致 toBeEmptyDOMElement 断言的失败。知道原因之后去翻了翻 MantineProvider 的源码,发现它里面的 MantineCssVariables 和 MantineClasses 组件会有可能返回 style 标签:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| export function MantineProvider({ ... withGlobalClasses = true, withCssVariables = true, ... }: MantineProviderProps) {
...
return ( <MantineContext.Provider value={{ ... }} > <MantineThemeProvider theme={theme}> {withCssVariables && ( <MantineCssVariables cssVariablesSelector={cssVariablesSelector} deduplicateCssVariables={deduplicateCssVariables} /> )} {withGlobalClasses && <MantineClasses />} {children} </MantineThemeProvider> </MantineContext.Provider> ); }
|
MantineCssVariables 和 MantineClasses 这两个组件可以通过 withGlobalClasses、withCssVariables 这两个 props 控制到底渲不渲染,于是解决办法也找到了,在测试代码里渲染 MantineProvider 时将这两个值设为 false 即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { MantineProvider } from "@mantine/core"; import { RenderOptions, RenderResult, render as reactTestingLibRender } from "@testing-library/react"; import { ReactElement } from "react";
export function render(ui: ReactElement, options?: Omit<RenderOptions, "wrapper">): RenderResult { return reactTestingLibRender(ui, { wrapper: ({ children }: { children: React.ReactNode }) => ( <MantineProvider withCssVariables={false} withGlobalClasses={false} theme={{}}> {children} </MantineProvider> ), ...options, }); }
|
这样又可以愉快地使用 toBeEmptyDOMElement 断言啦。