-
Notifications
You must be signed in to change notification settings - Fork 4.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
@wordpress/data: Handle more return type values from a mapSelect argument on useSelect #16669
@wordpress/data: Handle more return type values from a mapSelect argument on useSelect #16669
Conversation
@epiqueras would love it if you could review this! |
I don't think I've had this much back and forth on tests before 😃 ! All good though. |
Tests are not only for validating logic and guarding regressions. They serve as living documentation of our code for folks who are adventuring into parts of the codebase that are unknown to them. I don't think they should have different quality standards than our other code. That said, the test is looking a lot better after the initial iterations. There are still a few things I would change like the unnecessary Thanks for taking care of this PR 😄 |
I 100% agree. My comment wasn't a complaint. It was more of an observation of the thoroughness of your review (hence the smiley). I probably could've worded better though. |
'undefined', | ||
[ undefined, 42 ], | ||
], | ||
].forEach( |
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.
Why not use the each([...]).test
approach that Jest supports natively?
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.
Honestly, I just didn't think to use it :). It does look like the test could be switched to use it here but is it functionally any different? Are there some advantages to using it here?
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.
Different reporting I think, and better ESLint 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.
Interesting, good points and I'll give a go at updating the tests to use the built-in test conditions api in jest. It's also something I'm willing to do in a separate pull if this fix is needed to move #16460 along.
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.
implemented in e2f6c28
I didn't assume it was, I try to not make assumptions like that, because so much tone and context is lost through text. But I figured it wouldn't hurt to make my approach as transparent as possible 😄 |
*/ | ||
import isShallowEqual from '@wordpress/is-shallow-equal'; | ||
|
||
const isEqual = ( valueA, valueB ) => { |
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.
Might be worth a brief JSDoc to explain the purpose we're seeking to accomplish with this function.
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.
When I see isEqual
, I think of a deep comparison. Might be good to specify what kind of equality this checks for.
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.
Agreed to both points, I'll try and get this added today sometime.
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.
We should just use the default export of the shallow equality package.
import isShallowEqual from '@wordpress/is-shallow-equal';
I am pretty sure it does the same thing.
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.
doh ya, tests pass with just isShallowEqual
... I'll update and great catch!
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.
We should just use the default export of the shallow equality package.
Implemented in 642d672
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.
We should just use the default export of the shallow equality package.
import isShallowEqual from '@wordpress/is-shallow-equal';
I am pretty sure it does the same thing.
It's true and I think it's fine to ship with it as-is (especially with tests to guard against regressions), and while technically it's the specified behavior, it's probably not exceedingly obvious that in code here we're intentionally anticipating to handle non-object/array values. It could be worth a clarifying comment to that end.
Aside: isShallowEqual
is documented as requiring the arguments be passed:
gutenberg/packages/is-shallow-equal/index.js
Lines 15 to 16 in fcbdd20
* @param {(Array|Object)} a First object or array to compare. | |
* @param {(Array|Object)} b Second object or array to compare. |
But it's tested to handle others:
gutenberg/packages/is-shallow-equal/test/index.js
Lines 136 to 147 in fcbdd20
it( 'falls back to strict equality when one of arguments is non-object-like', () => { | |
expect( isShallowEqual( undefined, {} ) ).toBe( false ); | |
expect( isShallowEqual( undefined, [] ) ).toBe( false ); | |
expect( isShallowEqual( undefined, undefined ) ).toBe( true ); | |
expect( isShallowEqual( {}, null ) ).toBe( false ); | |
expect( isShallowEqual( [], {} ) ).toBe( false ); | |
expect( isShallowEqual( null, [] ) ).toBe( false ); | |
expect( isShallowEqual( null, null ) ).toBe( true ); | |
expect( isShallowEqual( 1, true ) ).toBe( false ); | |
expect( isShallowEqual( true, true ) ).toBe( true ); | |
expect( isShallowEqual( null, undefined ) ).toBe( false ); | |
} ); |
It should probably allow any type.
Also adds tests covering the following return types from a selector map: - string, - array, - number, - boolean
fix spelling Co-Authored-By: Enrique Piqueras <[email protected]>
f3fe2e0
to
1169f9d
Compare
- use native jest each api - improve naming of variables - simplify mocking and test setup.
Description
See #16612 for original report. The
useSelect
hook usesisShallowEqualObjects
for comparing whether the new value returned from themapSelect
callback is equal to the previous value. Seegutenberg/packages/data/src/components/use-select/index.js
Lines 132 to 134 in a894b35
I added some unit tests that demonstrated (when run against original
useSelect
) if amapSelect
callback returns a number or boolean primitive type, it will not get handled as expected by theuseSelect
hook. Oddly enough,array
andstring
types did get handled fine. The same tests pass with the work done in this branch.This pull adds a new utility function
isEqual
(which is not exposed on a public api so should be okay to use naming wise) for handling all primitive types and doing the appropriate comparison. This is then implemented inuseSelect
.Fixes #16612.
How has this been tested?
Types of changes
This is a non-breaking change that simply fixes a problem with expectations (especially considering the current documentation) around what a
mapSelect
callback given as an argument onuseSelect
can return. It can now return a primitive value, an array, or an object.Checklist: