-
Notifications
You must be signed in to change notification settings - Fork 272
feat(breaking): add text match options a.k.a string precision API #554
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
feat(breaking): add text match options a.k.a string precision API #554
Conversation
Co-authored-by: Maciej Jastrzebski <[email protected]>
@thymikee is there anything I can do to help this PR to move forward? |
src/__tests__/queryByApi.test.js
Outdated
@@ -48,7 +48,7 @@ test('queryByText not found', () => { | |||
).toBeFalsy(); | |||
}); | |||
|
|||
test('queryByText nested text across multiple <Text> in <Text>', () => { | |||
test('queryByText does not match nested text across multiple <Text> in <Text>', () => { |
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 we're regressing this functionality to be compatible with Testing Library, which also doesn't support this?
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. I checked, testing library doesn't match in this case.
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.
How does this PR change this functionality? Finding the text in nodes still recurses through children
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.
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 must be missing something but how does the logic added to getNodeByText
end up not matching in this case? As I see it the the logic in getChildrenAsText
will return ['Hello', ' ', 'World', '!']
which when joined will be "Hello World!"
, which is an exact match for what you are looking 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.
Yes, the change is to keep matching component with multiple children, but not <Text>Hello <Text>World</Text></Text
, because now getChildrenAsText
don't read its children's children
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, so if the test render looked like this:
<Text>
<Text>Hello</Text>
World!
</Text>
Would this then match the outer text?
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 currently match is the current released version, but wouldn't match in my current implementation. It's the topic of discussion in #554 (comment)
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.
Before merging, I need to make sure that @RafikiTiki gets attribution for his work. Since there are 2 breaking changes here now, I'm considering releasing it in a major update
Yes, I think this should be a major release. I only see the recursive matching as breaking (don't know which other one you're talking about) though. I can help with the release notes if needed. |
src/__tests__/findByApi.test.js
Outdated
await expect( | ||
findByPlaceholderText('Placeholder Text', options) | ||
findByPlaceholderText('Placeholder Text', {}, options) |
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 is the second breaking change I mentioned
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 could provide an easy migration path by looking for waitFor
options (timeout
, interval
) also in the queryOptions
only for findBy
queries and only till next major release. While displaying a console warning to inform the developer. 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.
That's a good idea that I missed, I fixed it in the latest commit d2f9f33
FYI, there's an ongoing discussion in DOM Testing Library regarding matching nested text: testing-library/dom-testing-library#473 (comment). Also, seems like Hope you understand why I'm so hesitant merging this. We're likely regressing a use case that we'd eventually had to add anyway. I'd like to think of a way to not break matching nested nodes using |
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.
Wow a lot of good code! 👍
I've added some comments as there seems to be some minor errors (e.g. typescript types) and opportunities to improve readability/code structure.
src/__tests__/getByApi.test.js
Outdated
</View> | ||
); | ||
|
||
expect(getByText('Text and whitespace')).toBeTruthy(); |
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 like that one 👍
src/__tests__/queryByApi.test.js
Outdated
expect(queryByTextFirstCase('My text')).toBe(null); | ||
expect( | ||
render( | ||
<Text> | ||
Hello <CustomText>World!</CustomText> | ||
</Text> | ||
).queryByText('Hello World!') | ||
).toBeTruthy(); | ||
queryByTextSecondCase('My text', { exact: false })?.props.nativeID | ||
).toBe('2'); |
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.
Does seem strange a bit, that we use one component structure with the default exact: true
and other component structure with exact: false
. If we were to contast exact true/false IMO we should use the same component structure.
Looks like we should do one of the following (in order of preference):
- merge queryByTextFirstCase + queryByTextSecondCase
- add queryByTextFirstCase + exact: false & queryByTextSecondCase + exact: true
- split the test into two unreleated tests
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 do overall believe that tests should be restructured, a lot of cases are tested only because the internal APIs are the same (a lot of edge cases for findByText
are only tested in getByText
for instance), so I'd like to have more tests, and make them more verbose. But I believe it's out of the scope of this PR.
But this specific case makes sense, I'll follow your suggestion, I got a bit lazy and monkey patched some tests without really reconsidering them.
src/__tests__/queryByApi.test.js
Outdated
).toBe(null); | ||
}); | ||
|
||
test('queryAllByText does not match several times the same text', () => { |
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.
👍
src/helpers/getByAPI.js
Outdated
try { | ||
return instance.find((node) => getNodeByText(node, text)); | ||
const results = getAllByText(instance)(text, options); |
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.
👍
typings/index.d.ts
Outdated
findByText: ( | ||
text: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
text: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindReturn; | ||
findByPlaceholderText: ( | ||
placeholder: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
placeholder: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindReturn; | ||
findByDisplayValue: ( | ||
value: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
value: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindReturn; | ||
findByTestId: (testID: string | RegExp, waitForOptions?: WaitForOptions) => FindReturn; | ||
findByTestId: (testID: TextMatch, waitForOptions?: WaitForOptions) => FindReturn; | ||
findAllByText: ( | ||
text: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
text: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindAllReturn; | ||
findAllByPlaceholderText: ( | ||
placeholder: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
placeholder: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindAllReturn; | ||
findAllByDisplayValue: ( | ||
value: string | RegExp, | ||
waitForOptions?: WaitForOptions | ||
value: TextMatch, | ||
waitForOptions?: WaitForOptions, | ||
options?: TextMatchOptions, | ||
) => FindAllReturn; | ||
findAllByTestId: ( | ||
testID: string | RegExp, | ||
testID: TextMatch, | ||
waitForOptions?: WaitForOptions | ||
) => FindAllReturn; |
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 like typescript types for findBy have incorrect options args order.
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.
Oops forgot to update, thanks!
677c78a
to
d2f9f33
Compare
Hey folks, it's never too late to pick up a stale PR! I've addressed one of the comments to reduce the breaking changes, but there's still the main question, which is the issue with matching across multiple nodes and the difference in the API with |
Hey, I'm gonna look at this once again soon. We already release v8, so we're clear to introduce other unrelated breaking changes 💪🏼 |
Hey hey @thymikee, anything I can do to help? I admit that current status is a bit messy since the PR went over several months and building on top of another contribution. If that helps, I could try to make a recap of the whole discussion/status. |
@AugustinLF that won't hurt for sure! I'm pretty sure this is the way we want to move forward. It would help to gather all the breaking changes this can cause and ways to migrate. I'm a bit swamped lately with work and personal stuff and having a really hard time to fit this into my pipeline. But maybe I could only have a brief look and release this as an alpha version for testing. Appreciate you stick with us all this time 🙌🏼 |
* origin/main: (24 commits) v8.0.0 chore(deps): bump dns-packet from 1.3.1 to 1.3.4 in /website (callstack#742) chore(deps-dev): bump @babel/preset-flow from 7.13.13 to 7.14.5 (callstack#765) chore(deps-dev): bump typescript from 4.4.2 to 4.4.4 (callstack#845) chore(deps-dev): bump release-it from 14.6.1 to 14.11.6 (callstack#830) chore(deps-dev): bump @babel/plugin-proposal-class-properties (callstack#846) chore(deps-dev): bump @babel/cli from 7.13.16 to 7.15.7 (callstack#833) chore(deps-dev): bump @testing-library/jest-native from 3.4.3 to 4.0.2 (callstack#842) chore(deps): bump color-string from 1.5.3 to 1.6.0 in /website (callstack#844) chore(deps): bump prismjs from 1.23.0 to 1.25.0 in /website (callstack#843) Forward extra data to press event (callstack#828) chore(deps-dev): bump @babel/preset-react from 7.13.13 to 7.14.5 (callstack#839) chore(deps): bump url-parse from 1.5.1 to 1.5.3 in /website (callstack#813) chore(deps-dev): bump @types/react from 17.0.2 to 17.0.30 (callstack#838) chore(deps): bump postcss from 7.0.29 to 7.0.36 in /website (callstack#756) chore(deps): bump prismjs from 1.23.0 to 1.25.0 in /website (callstack#823) chore(deps): bump path-parse from 1.0.6 to 1.0.7 in /website (callstack#796) chore(deps): bump merge-deep from 3.0.2 to 3.0.3 in /website (callstack#754) chore(deps): bump ws from 6.2.1 to 6.2.2 in /website (callstack#752) chore(deps): bump path-parse from 1.0.6 to 1.0.7 (callstack#795) ...
This PR includes two main changes: it adds Support to TextMatch in all text based queries. This moves the current Nested text matching changes, it will not match text broken across several nodes: // This examples matches before this PR and will not after
render(
<Text>
Hello <CustomText>World!</CustomText>
</Text>
).getByText('Hello World!') Extra care has been put to make sure that the relevant node gets matched, when several nodes could match (in the previous example, when matching These two changes have the benefit of making the API closer to the older implementation of |
@AugustinLF I've pushed a commit with a few updates, please check it. One thing that we're still missing is matching a11y queries, but I'm thinking about introducing it in a separate PR |
Great, that looks good. The a11y queries are very high on my list (to be honest we've reimplemented them in user-land on our side). But I'd love to take a step back and try to get a more holistic view and figure out what we're missing, if anything needs to be improved, I'm planning to try to get some feedback from our devs here at Klarna. I hope to be able to free more time to improve our test infra and Any plan to switch to TS? 👀 |
Yes, let's take some time to make it right. We may even want to revisit the API and maybe somehow mimic the
Yes please! |
Published a pre-release: https://github.com/callstack/react-native-testing-library/releases/tag/v9.0.0-alpha.0. Thank you once again @AugustinLF, much appreciated! |
@thymikee any estimate on when 9.0.0 could be released? |
We need to publish some announcement around those change, I hope to pick that work today or tomorrow #862 (reply in thread) |
Continuation of @RafikiTiki's work of #541
Summary
This does two things, adding some options to the queries (see initial PR), and remove matching strings spread in several levels of text. Namely the following example will not be valid anymore.
This is a breaking change, but it aligns the APIs and behaviour with
@testing-library/react
.Closes #541
Closes #514