-
Notifications
You must be signed in to change notification settings - Fork 273
fix: *ByRole queries to match their own text text content #1139
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: *ByRole queries to match their own text text content #1139
Conversation
If I understand correctly, the root cause of the issue is that when inside This problem is not a general As @thymikee matching by Perhaps a more robust workaround, but still a workaround, would be to pass const matchAccessibleNameIfNeeded = (
node: ReactTestInstance,
name?: TextMatch
) => {
if (name == null) return true;
// Note: due to queryAllByText matching composite `Text` element, we have to start at parent level
const nodeParentQueries = getQueriesForElement(node.parent);
const matchesText = queryAllByText(name).length > 0;
const nodeQueries = getQueriesForElement(node);
const matchesLabel = queryAllByLabelText(name).length > 0;
return matchesText || matchesLabel;
}; This is also a bit fragile as it assumes that composite @thymikee, @AugustinLF wdyt? |
The proposition to switch to our own internal model that has been discussed a few times already (see #967) would fix this host vs composite component, right? If that's the case, should we then consider a "hack" to solve the problem at hand, while we look into a more long term solution as part of the rewrite? Tested your implementation @mdjastrzebski which works (with a slight fix to make it work with TS) const matchAccessibleNameIfNeeded = (
node: ReactTestInstance,
name?: TextMatch
) => {
if (name == null) return true;
// Note: due to queryAllByText matching composite `Text` element, we have to start at parent level
const nodeParentQueries = getQueriesForElement(node.parent ?? node);
const matchesText = nodeParentQueries.queryAllByText(name).length > 0;
const nodeQueries = getQueriesForElement(node);
const matchesLabel = nodeQueries.queryAllByLabelText(name).length > 0;
return matchesText || matchesLabel;
}; We could also consider climbing up the parent tree util we find a host component, which would make it less brittle for future changes. As discussed this is not ideal because it might pose a problem with future RN versions, but given that we now have support for running our test suite against multiple versions, if this ends up changing, it should be fairly easy for us to make sure RNTL works with all the versions we support. |
@AugustinLF I think we could tweak the solution a bit, by climbing up, but only through composite components to the exported I think the proper way to add this, is to make const view = render(<Text testID="subject">Hello</Text>)`
const hostTextQueries = getQueriesForElement(view.getByTestId("subject"));
expect(hostTextQueries.getByText("Hello")).toBeTruthy(); We could build some helper to check for being host function isHostTextElement(element: ReactTestInstance) {
// Not a host element
if (typeof element.type !== "string") return false;
let current = element.parent;
while(typeof current.type !== 'string') {
if (current.type === RN.Text) {
return true;
}
current = current.parent;
}
return false;
} or similar logic in form of a function getExportedTextForHostElement(element: ReactTestInstance) {
// Not a host element
if (typeof element.type !== "string") return null;
let current = element.parent;
while(typeof current.type !== 'string') {
if (current.type === RN.Text) {
return current;
}
current = current.parent;
}
return null;
} We should be wary not to climb too high the component tree, and then make down queries, as otherwise we might actually catch |
d9865a6
to
1782809
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.
Good work @AugustinLF That PR looks pretty solid. I've found some minor things to address but look forward to having fully functional getByRole
!
@AugustinLF could you refactor the code to use regular |
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.
@AugustinLF Looks good! Recommended some final tweaks to the 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.
Awesome work on these difficult subjects @AugustinLF !
I guess we have all learned a lot about accessibility and host/composite elements tree 😆
Summary
The following test case doesn't work with our new
getByRole(role, {name})
API,Would probably warrant a patch to
11.2
.Closes #1140