Open totszwai opened 2 years ago
You're using an unofficial adapter, so I'm afraid there's not really any support I can offer. enzyme does not work with react 17 yet.
@ljharb after 2 days of debugging, I've found the root cause. This is a bug in shallow
.
The following wrappingComponent
will fail, because the shallow
traversal code expect only 1 node.
return (
<StyledEngineProvider injectFirst>
<MuiThemeProvider theme={theme}>
<ThemeProvider theme={theme}>
<GlobalStyle />
<CssBaseline />
{props.children}
</ThemeProvider>
</MuiThemeProvider>
</StyledEngineProvider>
)
The following hack to workaround the shallow
issue...
const EnzymeWorkaround = (props: any) => (<><GlobalStyle /><CssBaseline />{props.children}</>);
return (
<StyledEngineProvider injectFirst>
<MuiThemeProvider theme={props.theme}>
<ThemeProvider theme={props.theme}>
<EnzymeWorkaround>
{props.children}
</EnzymeWorkaround>
</ThemeProvider>
</MuiThemeProvider>
</StyledEngineProvider>
);
The code in shallow
is seeing the following as "3 nodes".
<GlobalStyle />
<CssBaseline />
{props.children}
The depth traversal code of shallow
isn't reliable it seems...
That’s not a bug, that is the design of “wrappingComponent” - it must only be a component that takes a single child.
Your hostile language is not appreciated.
it must only be a component that takes a single child.
That statement is not true? So if I created an additional wrapper that wraps everything together (now is only takes 1 child), it still throws the exact same error... It looks like shallow
still drills down to the deepest child node of the inner React node(s).
export const BlahThemeProvider = (props) => {
return (
<StyledEngineProvider injectFirst>
<MuiThemeProvider theme={props.theme}>
<ThemeProvider theme={props.theme}>
<GlobalStyle />
<CssBaseline />
{props.children}
</ThemeProvider>
</MuiThemeProvider>
</StyledEngineProvider>
);
};
Then in the wrappingComponent
:
function UnitTestThemeWrapper (props: any) {
const theme = props.theme || LightTheme;
// console.log('theme? ', theme);
return (
<BlahThemeProvider theme={theme}>
{props.children} // <== Takes only 1 now
</BlahThemeProvider>
);
}
const shallowWithTheme = (node: ReactElement, options?: ShallowRendererProps): ShallowWrapper => {
options = options || {
wrappingComponent: UnitTestThemeWrapper
};
return shallow(node, options);
};
Yes, you’re right it could be more precisely stated. The wrapping component must end up taking only one child, which your example still takes 3.
The wrapping component must end up taking only one child, which your example still takes 3.
@ljharb BTW, that statement is also not true because I've tried the following, and it will still fail. I've tested the following by shifting the nodes upwards to where they could also be:
<StyledEngineProvider injectFirst>
<MuiThemeProvider theme={props.theme}>
<GlobalStyle />
<CssBaseline />
<ThemeProvider theme={props.theme}>
{props.children} // <== Takes only 1 now
</ThemeProvider>
</MuiThemeProvider>
</StyledEngineProvider>
You get:
Method “type” is meant to be run on 1 node. 3 found instead.
Basically the wrappingComponent
is fairly impractical/limiting as every single level must only take one single node and nothing else.
You should reopen this as a bug IMHO.
It is indeed limiting if you're using the very unidiomatic pattern of having a component that takes no children and sits somewhere just for side effects (CssBaseline and GlobalStyle, both of which should be HOCs or hooks).
If you can reproduce it with the react 16 adapter, I'll be happy to reopen it - enzyme must not be used with react 17 yet, because it does not support it, so bugs are expected.
@ljharb You can't just tell everyone who try to use Enzyme to just wrap everything at most 1 level only... I didn't create those CssBaseline
nor GlobalStyle
, thats how it works. That's how React works.
Here is the enzyme-adapter-react-16 sandbox, reduced test case link: https://codesandbox.io/s/react-enzyme-16-shallow-bug-yvbz7
Below are the official documentations from various framework showcasing the valid use of "a component that takes no children".
CssBaseline from Material UI https://mui.com/components/css-baseline
GlobalStyle from styled-components https://styled-components.com/docs/api#createglobalstyle
Global from emotion https://emotion.sh/docs/globals
Thanks; I'll reopen until I have time to dig further into it.
Yes, I'm aware that the pattern is used in a few places; that doesn't mean it's a good idea.
I found a similar case if you try to use RecoilRoot context (from https://recoiljs.org/), as it renders:
<RecoilRoot>
<Batcher>
{children}
</RecoilRoot>
where batcher is used internally to "The purpose of the Batcher is to observe when React batches end so that Recoil state changes can be batched."
This context is needed whenever you test component that uses any of its hooks.
I am writing it just as a heads up for people wanting to test testing a component that uses Recoil like:
const wrapper = shallow(<MyComponent />, {
wrappingComponent: RecoilRoot,
});
that it is going to fail, so probably you should use mount instead.
@rmontesgar-chwy i'm assuming it renders <Batcher />
- but yes, wrappingComponent
can't work there because it renders more than just its children.
@ljharb I am stuck at similar issue
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react-native": "10.1.1",
"@testing-library/user-event": "^14.4.3",
@wojtekmaj/enzyme-adapter-react-17
"expo": "^44.0.0",
"jest": "29.0.2",
"jest-expo": "^46.0.1",
"jest-environment-jsdom": "^28.1.2",
"jest-expo-enzyme": "^1.4.0",
"jsdom": "^20.0.0",
"jsdom-global": "^3.0.2",
"react-test-renderer": "17.0.1",
@SupriyaPKalghatgi enzyme isn’t compatible with react 17 yet.
@ljharb Thing is I cannot downgrade to React 16 When will Enzyme support React 17?
@SupriyaPKalghatgi hopefully soon, but there's no planned schedule.
Update
React 16 + enzyme-adapter-react-16 reduced use case sandbox here: https://github.com/enzymejs/enzyme/issues/2549#issuecomment-982954339
Current behavior
React 17, using all the latest packages.
I follow one of the enzyme unit test workaround to include Mui's ThemeProvider + styled-components's ThemeProvider
My UT only has the following:
How can I get it to work? When I try to dump the
node
, this is what it prints out:Expected behavior
Your environment
API
Version
Adapter