Skip to content
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

add Immutable pretty-format plugins for Immutable.OrderedSet and Immu… #2899

Merged
merged 16 commits into from
Mar 6, 2017

Conversation

cpenarrieta
Copy link
Contributor

@cpenarrieta cpenarrieta commented Feb 16, 2017

Comparing Immutable objects should show a more descriptive failure message

Summary
fixes #2489
I am checking if an object is Immutable.List the same way immutable source code does: https://github.com/facebook/immutable-js/blob/master/src/List.js#L201
I am checking if an object is Immutable.OrderedSet the same way immutable source code does: https://github.com/facebook/immutable-js/blob/master/src/OrderedSet.js#L44

Test plan
Testing it from an external project
image

I also created unit test to test the new plugins
image

@cpenarrieta
Copy link
Contributor Author

I can add the rest of Immutable data structures once we agree this is the way to go. Thanks for reviewing this PR.

@thymikee
Copy link
Collaborator

Hm, I think it would be worth to add all Immutable collections instead of just 2.

@thymikee
Copy link
Collaborator

Also, how about calling it ImmutableJSPlugin and store it in one file?

@cpenarrieta
Copy link
Contributor Author

Ok I'll work on the rest of immutable data structures.
I thought you wanted one plugin per immutable data structures (#2529 (comment))
I can put it all in one file if you want.

@thymikee
Copy link
Collaborator

Oh, I didn't remember that. Now after reading this thread again I'm not super sure using Immutable.toString() is best here, as it would cause troubles with rendering nested data structures we already pretty-print, like React components.
Maybe lets wait for @cpojer to weigh in here.

@cpojer
Copy link
Member

cpojer commented Feb 16, 2017

@thymikee if I remember correctly I made that exact same comment on the previous PR. We cannot use Immutable.toString here because of the problem you mentioned.

@cpenarrieta
Copy link
Contributor Author

cpenarrieta commented Feb 16, 2017

I think the previous PR comment was about not relying on toString() when we are checking if its an immutable data structures or not.
In my case, I'm checking if its an immutable data structure in a different way.
In my case I'm using toString() in the print function only.
Let me know if thats still an issue. If thats the case, would you recommend using pretty-immutable?

@cpojer
Copy link
Member

cpojer commented Feb 16, 2017

I don't think we should call toString and materialize the entire immutable object just to know which type it is.

cc @leebyron can you help us out a bit? What's the best way to find out whether a value is from immutable.js and what type it is without explicitly requiring immutable.js?

@cpenarrieta
Copy link
Contributor Author

cpenarrieta commented Feb 16, 2017

@cpojer I am not using toString to know if its immutable or not.
Please see https://github.com/facebook/jest/pull/2899/files#diff-f105679dfd19fb268caec3ea3d5df94bR25 as an example.
printImmutableList will only be called if test is true.

@cpenarrieta
Copy link
Contributor Author

cpenarrieta commented Feb 16, 2017

@cpojer I am checking if an object is Immutable.List the same way immutable source code does: https://github.com/facebook/immutable-js/blob/master/src/List.js#L201
Same for the rest of the data structures

@codecov-io
Copy link

codecov-io commented Feb 17, 2017

Codecov Report

Merging #2899 into master will increase coverage by 0.45%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master    #2899      +/-   ##
==========================================
+ Coverage   67.86%   68.32%   +0.45%     
==========================================
  Files         147      155       +8     
  Lines        5349     5436      +87     
==========================================
+ Hits         3630     3714      +84     
- Misses       1719     1722       +3
Impacted Files Coverage Δ
...ackages/pretty-format/src/plugins/ImmutableList.js 100% <100%> (ø)
packages/jest-diff/src/index.js 79.59% <100%> (-3.75%)
packages/pretty-format/src/plugins/ImmutableSet.js 100% <100%> (ø)
...ckages/pretty-format/src/plugins/ImmutableStack.js 100% <100%> (ø)
packages/jest-matcher-utils/src/index.js 72.22% <100%> (+0.79%)
...s/pretty-format/src/plugins/ImmutableOrderedMap.js 100% <100%> (ø)
...ages/pretty-format/src/plugins/ImmutablePlugins.js 100% <100%> (ø)
...s/pretty-format/src/plugins/ImmutableOrderedSet.js 100% <100%> (ø)
...ckages/pretty-format/src/plugins/printImmutable.js 100% <100%> (ø)
packages/pretty-format/src/plugins/ImmutableMap.js 100% <100%> (ø)
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9ff938a...7d6143d. Read the comment docs.

@cpenarrieta
Copy link
Contributor Author

@cpojer @leebyron can you take a look at this again.
The way I'm checking if an object is immutable or not is by looking at their sentinel key like immutable project does. See a couple of examples https://github.com/facebook/immutable-js/blob/master/src/List.js#L201 and https://github.com/facebook/immutable-js/blob/master/src/OrderedSet.js#L44
If the object is immutable then we will call the toString() method. We won't call that method if the toString() object is not immutable.
Thanks for reviewing

@thymikee
Copy link
Collaborator

@cpenarrieta the way you test for Immutable is totally OK.

It's just Immutable#toString is not as powerful as we'd like it to be, but maybe it's good for starters? BTW, can you test how it renders a set of react components?

It's also great that you use Immutable as a devDependency, because it's only needed for tests (although most of them could be replaced with snapshots IMO).

@cpenarrieta
Copy link
Contributor Author

@thymikee an Immutable.Set with react components doesn't look good
I'm working on the fix
Does this looks good?
image

@cpenarrieta
Copy link
Contributor Author

@thymikee support for React components inside Immutable elements is done

@cpenarrieta
Copy link
Contributor Author

@thymikee can you look at this again? I did some refactor of the code.
I'm now not using toString
Thanks

Copy link
Collaborator

@thymikee thymikee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great so far. I've left some inline comments and thoughts

if (reactPlugin.test(item)) {
result += addKey(isMap, key) +
reactPlugin.print(item, print, indent, opts, colors) + ', ';
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to remove this, as we don't want Immutable plugin to be dependent on ReactElement plugin. Instead they need to cooperate nicely (which is actually done already!)

You can change this to:

  val.forEach((item: any, key: any) => {
    result += addKey(isMap, key) +
      print(item, print, indent, opts, colors) + ', ';
  });

return result + ' []';
}

result += ' [ ';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a opts argument in print() which looks like this:

{ edgeSpacing: '\n', min: false, spacing: '\n' } // when {min: false}
{ edgeSpacing: '', min: true, spacing: ' ' } // when {min: true}

Can you make sure it renders nicely for both cases?

const reactComponent = React.createElement('Mouse', null, 'Hello World');
assertImmutableObject(
Immutable.OrderedSet([reactComponent, reactComponent]),
'Immutable.OrderedSet [ <Mouse>\n Hello World\n</Mouse> ]'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case you should include ReactElement and ReactTestComponent in plugins

it('supports multiple string elements', () => {
assertImmutableObject(
Immutable.OrderedSet(['jhon', 'mike', 'cristian']),
'Immutable.OrderedSet [ "jhon", "mike", "cristian" ]'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For {min: true} I'd rather print:

Immutable.OrderedSet ["jhon", "mike", "cristian"]

and for {min: false}:

Immutable.OrderedSet [
  "jhon", 
  "mike", 
  "cristian",
]

Just like it works for arrays and objects now.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to all other Immutable entities

ImmutableMapPlugin,
ImmutableSetPlugin,
ImmutableStackPlugin,
];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also use plugins in jest-diff and jest-snapshot.
Alos, maybe we could create ImmutablePlugins.js which exposes an array of all Immutable plugins?

@cpenarrieta
Copy link
Contributor Author

@thymikee I think I solved all your observations, please take a look again.

Copy link
Collaborator

@thymikee thymikee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last 2 changes and I think we're good to go.
cc: @cpojer

assertImmutableObject(
Immutable.OrderedSet(['jhon', 'mike', 'cristian']),
'Immutable.OrderedSet [\n "jhon",\n "mike",\n "cristian",\n]',
{min: false}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

min is set to false by default, so it's not necessary here

@@ -30,6 +31,7 @@ const PLUGINS = [
ReactTestComponentPlugin,
ReactElementPlugin,
AsymmetricMatcherPlugin,
...ImmutablePlugins,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail on Node 4, as array spread is supported only behind a flag. You can use concat.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, looks like it works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right, it fails in circleCI. its fixed now.

package.json Outdated
@@ -30,7 +30,8 @@
"react-test-renderer": "^15.4.1",
"rimraf": "^2.5.4",
"strip-ansi": "^3.0.1",
"typescript": "^2.1.4"
"typescript": "^2.1.4",
"immutable": "^3.8.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you insert this in the right alphabetical location please?

return result.slice(0, -2) + opts.edgeSpacing + closeTag;
} else {
//remove last spacing
return result.slice(0, -1) + opts.edgeSpacing + closeTag;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using slice here, can we build up an array and call join(',' + opts.spacing) down here?


module.exports = {
print: printImmutableStack,
test: (object: Object) => object && isStack(object),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we call each function in every plugin simply "print" and "test"?

That way we can do:

module.exports = {print, test};

and everything will look consistent across plugins.

@cpojer
Copy link
Member

cpojer commented Mar 3, 2017

Nice! cc @leebyron do you have any comments about this? :)

const ImmutablePlugins = require('../plugins/ImmutablePlugins');

function assertImmutableObject(actual, expected, opts) {
expect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use expect.extend instead?

See http://facebook.github.io/jest/docs/expect.html#expectextendmatchers

expect(immutableValue).toPrettyPrintTo('Immutable.OrderedSet')

or something like this?

@cpenarrieta
Copy link
Contributor Author

@cpojer I solved all your observations but the use of expect.extend.
I'll try to solve it later tonight.

@cpenarrieta
Copy link
Contributor Author

@thymikee @cpojer I refactored the tests to use expect.extend
Let me know I need any other refactor, thanks.

@thymikee
Copy link
Collaborator

thymikee commented Mar 4, 2017

Looks good to me

);
const pass = prettyPrintImmutable === expected;

const message = pass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, lovely! Thank you so much @cpenarrieta

print: Function,
indent: Function,
opts: Object,
colors: Object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the flow typing here could be a lot stronger. @cpenarrieta we just added flow types to pretty-format itself – mind sending a second, follow-up PR, where you use the types from the main module? You can extract it into a types.js file like we do in other packages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll work on it
thanks

@cpojer cpojer merged commit 25e9145 into jestjs:master Mar 6, 2017
@cpojer
Copy link
Member

cpojer commented Mar 6, 2017

Solid work, thanks @cpenarrieta!

skovhus pushed a commit to skovhus/jest that referenced this pull request Apr 29, 2017
jestjs#2899)

* add Immutable pretty-format plugins for Immutable.OrderedSet and Immutable.List

* adding immutable pretty-format plugins

* update yarn.lock with immutable library

* adding support for react components in Immutable pretty-format plugins

* adding copyright header

* refactor printImmutable method

* fix flow check

* add support for opts {min: false} for immutable plugins

* change ES2015 spread syntax to .concat

* add missing semicolon

* refactor printImmutable

* adding trailing comma when {min: false}

* refactor immutable tests using expect.extend toPrettyPrintTo
tushardhole pushed a commit to tushardhole/jest that referenced this pull request Aug 21, 2017
jestjs#2899)

* add Immutable pretty-format plugins for Immutable.OrderedSet and Immutable.List

* adding immutable pretty-format plugins

* update yarn.lock with immutable library

* adding support for react components in Immutable pretty-format plugins

* adding copyright header

* refactor printImmutable method

* fix flow check

* add support for opts {min: false} for immutable plugins

* change ES2015 spread syntax to .concat

* add missing semicolon

* refactor printImmutable

* adding trailing comma when {min: false}

* refactor immutable tests using expect.extend toPrettyPrintTo
@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error message when comparing Immutable-js collection to array is confusing
5 participants