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
fix: toHaveProp func to work with @testing-library/react-native latest version (7.0.2) #36
fix: toHaveProp func to work with @testing-library/react-native latest version (7.0.2) #36
Conversation
Codecov Report
@@ Coverage Diff @@
## master #36 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 8 8
Lines 95 94 -1
Branches 27 27
=========================================
- Hits 95 94 -1
Continue to review full report at Codecov.
|
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.
Not sure about the fact that composite components with specific displayName are allowed matched by this matcher.
src/to-have-prop.js
Outdated
@@ -18,7 +18,8 @@ export function toHaveProp(element, name, expectedValue) { | |||
const prop = element.props[name]; | |||
|
|||
const isDefined = expectedValue !== undefined; | |||
const isAllowed = VALID_ELEMENTS.includes(element.type); | |||
const elementType = typeof element.type == 'string' ? element.type : element.type?.displayName; | |||
const isAllowed = VALID_ELEMENTS.includes(elementType); |
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'm wondering whether we should have a list of allowed components to check their props. IMO we should be able to check props of any host component. @thymikee, @brunohkbx, wdyt?
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.
Same. A list of valid elements is a remnant of the previous lib implementation
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.
The current impl. seems a bit weird here, as reading the code bellow:
pass: isDefined && isAllowed ? hasProp && equals(prop, expectedValue) : hasProp,
Is the mere prop existence is checked in case either expected value is not defined (which sound fine) and also when element is not on VALID_ELEMENTS
(which sounds kind of strange).
As I see it, the desired behavior is as follows:
- For all host elements:
- if provided
expectedValue
check for prop existence and that it's value matches expectedValue - if not provided
expectedValue
: just check if prop exists.
- if provided
- For composite elements:
- as all RNTL queries already return only host elements, then the dev user had to use some escape hatch like
.parent
,.children
to get hold of that kind of element, - IMO I would allow user to use this check on such elements, because: 1) it's hard to write such test by mistake, so they are rather written deliberately, 2) it reduces the "surprise factor" for the user, 3) it simplifies our codebase.
- as all RNTL queries already return only host elements, then the dev user had to use some escape hatch like
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.
@mdjastrzebski yeah I completely agree.
src/__tests__/to-have-prop.js
Outdated
expect(() => | ||
expect(getByText('text')).toHaveProp('allowFontScaling', 'wrongValue'), | ||
).toThrowError(); |
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.
As far as I don't prefer {get|query}ByTestId
queries, it seems that for consistency and readability it would be better to use 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.
it's just for the example, any reason it should behave this way if using getByText 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.
getByText('text')
vs queryByTestId('text')
is just a stylistic issue here, as for current setup, both elements return exactly the same element.
Optimally, we should be using the same queries, as we encourage our users (ByText
, ByHintText
, ByRole
, etc) everywhere in our tests when possible. But since surrounding code uses queryByTestId
, the second best solution seems to be consistent with surrounding code to reduce cognitive load for reading user.
Be aware that this is a bit nitpicking :-)
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 understand, in the current setup it's correct, the returned element of both accessors is the same,
but this fix is for an issue that pops only when using the 7.0.2 version of testing-library/react-native
, in which the returned elements are not the same, so only the getByTest
func will fail the test (without the fix). that was the logic behind using getByTest
.
but no problem to change it to queryByTestId, tell me what you think is best
src/to-have-prop.js
Outdated
@@ -18,7 +18,8 @@ export function toHaveProp(element, name, expectedValue) { | |||
const prop = element.props[name]; | |||
|
|||
const isDefined = expectedValue !== undefined; | |||
const isAllowed = VALID_ELEMENTS.includes(element.type); | |||
const elementType = typeof element.type == 'string' ? element.type : element.type?.displayName; |
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.
This looks a bit strange, as it will allow any composite component that sets it's displayName to a value from VALID_ELEMENTS list, to have it's props check. AFAIK we want to discourage interaction with composite components in favor of interacting only with host components.
@thymikee, @brunohkbx, wdyt?
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.
Yup, I got the same impression, we shouldn't do that.
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.
can you explain the logic behind not checking the value of a prop for composite components (or any component)?
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.
So the reason why React Native Testing Library ignores composite components, and is only concerned with host components, is that it tries to resemble what user (or manual tester) would see when interacting with the app. This is similar to React Testing Library, when user interacts with rendered HTML and not composite components.
That said, RNTL already filters out composite components in all queries (getBy, queryBy, findBy), so we probably can ignore checking for host/composite component in toHaveProp
matchers, and perform prop check on both types. This should not compromise our goal of making it easy to write good test, and hard to write bad tests.
Additionally, this will reduce the "suprise factor" for users trying to validate props on compisite components that they got from using parent
or children
props for navigation.
@thymikee, what's your take on that?
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'm good with not validating that here. It's the library that's responsible for filtering.
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.
did i understand you correctly that the change should be removing the whole isAllowed
and VALID_ELEMENTS
validation?
…/khealth/jest-native into toHaveProp_not_comparing_val_FIX
@mdjastrzebski, I'v changed the code according to what i understand from your comments, i hope i got it right. |
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.
@yonatan-altaraz I think that the code looks good now. Great thanks for your contribution!
Please updated the docs (README.md) to remove the mention that toHaveProp
checks only native elements (= host elements), as after this change this is no longer the case.
README.md
Outdated
@@ -215,8 +215,7 @@ expect(parent).not.toContainElement(grandparent); | |||
toHaveProp(prop: string, value?: any); | |||
``` | |||
|
|||
Check that an element has a given prop. Only works for native elements, so this is similar to | |||
checking for attributes in the DOM. | |||
Check that an element has a given prop. this is similar to checking for attributes in the DOM. |
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.
Check that an element has a given prop. this is similar to checking for attributes in the DOM. | |
Check that an element has a given prop. |
🎉 This PR is included in version 3.4.3 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
What:
when using the latest @testing-library/react-native version, the function
toHaveProp(attr: string, value?: any)
doesn't work properly when getting the element by text, it checks for the prop existence but does not compare to the expected value, when given, and returns 'pass' even if the expected value is wrong.Why:
to be able to work with this function using the new version of @testing-library/react-native
How:
just changed a couple of row in to-have-props.js
Checklist:
docs (N/A)
to recreate the issue, you can checkout this branch