-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support array-like iterable children in v3 #1187
Conversation
@@ -0,0 +1,65 @@ | |||
const ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw that enzyme has this elsewhere, but in a different package. If there's a good way to share this across lerna packages, please let me know. I haven't used lerna before 😄
@@ -81,43 +88,6 @@ export function assertDomAvailable(feature) { | |||
} | |||
} | |||
|
|||
export function nodeTypeFromType(type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this to its own file so that elementToTree
could still use it
05f921f
to
2e1b7b8
Compare
After searching around the codebase some more, I see that the I'm going to pause on this for now to see if any maintainers have ideas about how best to tackle this. |
Interesting! I didn't know React had this capability. |
fyi I plan on coming back to this next week! |
@lelandrichardson I have changed this to now be about adding Immutable.js support. Please see the updated description and code and let me know if you have any questions! |
ad838e4
to
8f952c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generic iterables makes sense to me; that's in the language.
A .toArray
function is arbitrary and non-standard; unless React supports this explicitly, I do not think we should support it in enzyme.
8f952c4
to
4475fbe
Compare
Hi @ljharb thanks for the review. I have made this more generic -- I did some more research and found out that all iterables support |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks much better!
@@ -23,6 +24,8 @@ export default function elementToTree(el) { | |||
let rendered = null; | |||
if (Array.isArray(children)) { | |||
rendered = flatten(children, true).map(elementToTree); | |||
} else if (isIterable(children) && typeof children !== 'string') { | |||
rendered = flatten(Array.from(children), true).map(elementToTree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we use babel, this could also be flatten([...children], true)
return ( | ||
typeof Symbol === 'function' && | ||
typeof Symbol.iterator === 'symbol' && | ||
obj != null && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd probably move the obj
check higher, since that's faster then checking Symbols
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, I wasn't aware of that! Thanks!
@@ -104,6 +113,8 @@ export function elementToTree(el) { | |||
let rendered = null; | |||
if (Array.isArray(children)) { | |||
rendered = flatten(children, true).map(elementToTree); | |||
} else if (isIterable(children) && typeof children !== 'string') { | |||
rendered = flatten(Array.from(children), true).map(elementToTree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly, flatten([...children], true)
</div>, | ||
); | ||
treeForEach(node, spy); | ||
expect(spy.callCount).to.equal(3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also use expect(spy.calls).to.deep.equal
in both places, and assert that it's called with the right items?
It'd also be great to test with a Map as well as a Set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes for sure, I like that. The tree objects are pretty complex, how do you feel about just checking part of it, say keys? Like this:
it('should handle Map children', () => {
const spy = sinon.spy();
const twoDivMap = new Map([
[<div key="a" />],
[<div key="b" />],
]);
const node = $(
<div key="root">
{twoDivMap}
</div>,
);
treeForEach(node, spy);
expect(spy.callCount).to.equal(3);
const keys = spy.args.map(arg => arg[0].key);
expect(keys).to.deep.equal(['root', 'a', 'b']);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah nevermind, even better I can just use $
and check the whole thing:
it('should handle Map children', () => {
const spy = sinon.spy();
const twoDivMap = new Map([
[<div key="a" />],
[<div key="b" />],
]);
const divA = $(<div key="a" />);
const divB = $(<div key="b" />);
const node = $(
<div key="root">
{twoDivMap}
</div>,
);
treeForEach(node, spy);
expect(spy.callCount).to.equal(3);
const nodes = spy.args.map(arg => arg[0]);
expect(nodes).to.deep.equal([node, divA, divB]);
});
I'll get this committed soon!
2c90486
to
2d43e65
Compare
Alrighty! @ljharb travis is happy and I think I answered your comments. Can you please review again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Although it does seem like you've only added iterable support in the react 13 adapter - the 14, 15, 15.4, and 16 adapters would need it as well.
Thanks! Actually the v13 adapter is special-cased. The others all use the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks for clarifying :-)
Any idea when this might be released? |
@stevenmusumeche when a few more collaborators have reviewed it. |
would it be helpful if I periodically rebase this? otherwise I can just do it once we're ready |
I hate to be a pest, but is there a way to move the review up in priority for the other collaborators? The code and tests look great to me, but I am not intimately familiar with the codebase. It is something that worked before in v2 and doesn't in v3 and is preventing quite a few companies from upgrading to React 16. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it took so long! I'm taking some time away from OSS right now. This looks good though 👍
@kmcq please do rebase it, yes :-) |
703eb0a
to
3ad399c
Compare
rebased! |
Thank you all so much for what you do. |
Thanks @ljharb! I appreciate everyone's reviews. This was my first time contributing to a library like this and you all made it fun and I learned some things too. Cheers! |
Thanks @kmcq! Any ETA on when a new version will be cut? This was the only thing blocking us from upgrading to react 16. Thanks! |
Looking forward for this to be released! Great work guys! |
@kamui no ETA yet. I'm shooting for this week, ASAP. |
All adapters, as well as enzyme-adapter-utils, have been bumped. |
Hey @ljharb, sorry to bug you but it looks like the React 15 adapter's release didn't make it to NPM: https://www.npmjs.com/package/enzyme-adapter-react-15. I checked and the rest look good 👍 Is that something that you need to handle or is that one just lagging behind? Thanks! Edit: I should point out that this is not a big issue, nor should it block anyone, since the change was in Edit2: It's there now! Thanks so much! |
Hey guys, I'm running enzyme
Above unit test doesn't pass, since I could add Immutable as a dependency of enzyme-adapter-utils to extend I think having support for Immutable children makes sense because:
I'm looking forward to collaborate, keep the great work! |
@ljharb, the test I shared was with Immutable |
@ljharb, I found that the issue was because we are running our unit tests on PhantomJS, and ES6 Symbol API is missing there, and might be the case for old browsers. Tried to run the test on recent Chrome version and works just fine. We could change
in the enzyme-adapter-utils, to
that's exactly what React does. |
Hmm - Can you confirm whether React supported this behavior down to 0.13? Also, can you file a separate issue about this? |
For sure @ljharb, I'll take a look into that. |
Linking to #1334 as well. |
What this is
Fixes #1181.
This adds support for non-Array, but still iterable, children, such as Immutable-js Lists, Sets, etc., which is supported by React:
The React PR that originally added this functionality is here: facebook/react#2376.
The code
children
is iterable, and if so, useArray.from
to convert it to an array.I like this approach because it compartmentalizes the knowledge that children are sometimes things other than arrays.