enzyme: Enzyme matchers do not match correctly children of React Fragments
Describe the bug
This is a dedicated issue corresponding to a comment I initially left at https://github.com/airbnb/enzyme/issues/1213#issuecomment-416658762.
When using React Fragments, it looks like only the first child is being picked up by the matchers.
To Reproduce
Assuming the following code:
const Foobar = () => (
<>
<div>Foo</div>
<div>Bar</div>
</>
);
And the following test:
describe('<Foobar />', () => {
test('should include Foo and Bar', () => {
const wrapper = mountWithIntl(<Foobar />);
expect(wrapper).toIncludeText('Foo');
expect(wrapper).toIncludeText('Bar');
});
});
Bar
simply does not get rendered:
FAIL test/src/Foobar.test.jsx
● <Foobar /> › should include Foo and Bar
Expected <IntlProvider> to contain "Bar" but it did not.
Expected HTML: "Bar"
Actual HTML: "Foo"
8 |
9 | expect(wrapper).toIncludeText('Foo');
> 10 | expect(wrapper).toIncludeText('Bar');
| ^
11 | });
12 | });
13 |
at Object.test (test/src/Foobar.test.tsx:10:21)
mountWithIntl
is a simple wrapper that adds an IntlProvider
(from react-intl
) to help us deal with i18n in our tests. If I remove it and replace with bare mount
, I get:
● <Foobar /> › should include Foo and Bar
Trying to get host node of an array
7 | const wrapper = mount(<Foobar />);
8 |
> 9 | expect(wrapper).toIncludeText('Foo');
| ^
10 | expect(wrapper).toIncludeText('Bar');
11 | });
12 | });
I get the same results if I swap the <>...</>
shorthand with <React.Fragment>...</React.Fragment>
.
However, if the code is:
const Foobar = () => (
<div>
<div>Foo</div>
<div>Bar</div>
</div>
);
then now the tests pass fine.
For what it’s worth, the built code for Foobar
(built with tsc
) looks like:
const Foobar = () => (React__default.createElement("div", null,
React__default.createElement("div", null, "Foo"),
React__default.createElement("div", null, "Bar")));
Expected behavior
I’m very confused as Enzyme 3.5 has Fragment support. Do you see something just obviously wrong above?
I’m wondering if the TypeScript compilation doesn’t compile into something that’s causing https://github.com/airbnb/enzyme/issues/1178. Or I’m just doing something wrong…
Additional context
enzyme@3.5.0
enzyme-adapter-react-16@1.3.0
enzyme-matchers@6.0.4
andjest-enzyme@6.0.4
(outside of this project I know)- TypeScript v3.0.1
- Jest and ts-jest
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 7
- Comments: 24 (15 by maintainers)
Commits related to this issue
- [Tests] failing `.text()` tests for #1799 — committed to enzymejs/enzyme by ljharb 6 years ago
- Merge pull request #2001 from airbnb/mac--html-text-fragment-fixes [Fix] `mount`/`shallow`: `.text`/`.html`: handle an array of nodes properly [enzyme-adapter-react-{16,16.1,16.2,16.3}] [New] Make n... — committed to enzymejs/enzyme by ljharb 5 years ago
@astorije I’ll try to see what I can do about this over the weekend
See #2086 and https://github.com/facebook/react/pull/16168
That’s up to Facebook; there’s an open issue for the shallow renderer to support useEffect.
@astorije in that case, can you file a new issue, and fill out the entire issue template?
I believe @madicap is still working on it; anything based on DocumentFragment would only work on mount.
Hey @madicap, did you end up being able to look into this? 😃
I don’t think there’s a workaround at the moment.
I’ve pushed up failing test cases; the issue seems to be that the adapter’s
nodeToHostNode
only returns the first node - even though for fragments, there’s multiple. Additionally, there’s no way in the tree to identify that there’s a fragment.I’m not sure what the best option is - perhaps including the fragment in the tree and flattening it only where needed? or perhaps overloading nodeToHostNode to return an array, or better, a DocumentFragment, in this case? cc @madicap
I’m also curious if reversing the order of the assertions to be
will cause the same assertion to fail, i.e. is this always failing on the second assertion or on the text of the second child?