-
Notifications
You must be signed in to change notification settings - Fork 273
feat: option for queries to respect accessibility #1064
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
Conversation
I wonder about naming our option. RTL's @MattAgn @thymikee @AugustinLF wdyt about proper name for this new option? |
Wow so quick @mdjastrzebski 😮 |
@mdjastrzebski thanks a lot for the quick review!
|
5dbe69f
to
898cb06
Compare
I like to have an API as close as possible from rtl web, so using |
re default value: that would be the plan to have a minor with default behaving as is, and then in the next major release swap the switch to more reasonable value of |
Yes sounds good! |
@MattAgn I'm on a fence here, on one hand it mimics RTL convention but on the other hand it's not very self explanatory. However I wonder if the other name ( Seems like this is a concept that is less needed in RTL due to how web navigation works vs RN. I think it will make more sense if/when we switch this feature on by default in a next major release, which btw will probably generate a lot of user commencts due to failing tests ;-) |
@mdjastrzebski I agree that respectAccessibility was not so clear either, especially since we also check styles, maybe we should split it into 2 options
Totally, a migration guide will be required 😄 |
@MattAgn I think that 'hidden' option name will make more sense when we will ignore hidden elements by default. |
@mdjastrzebski oh alright I understand! |
898cb06
to
2f2a8cc
Compare
@mdjastrzebski I found 2 different ways to handle the a11y option and I can't choose between the 2:
Imo, the first option seems the best, because the responsibility argument is the most important to me |
Since
|
@MattAgn not sure but your first example looks a bit too complex. Seems like you could just declare some common
Then inside each query, e.g. function queryAllByTextFn(text, options) {
const results = instance.findAll((node) =>
getNodeByText(node, text, options)
);
return results;
}; with // our new `findAll`
function queryAllByTextFn(text, options) {
const results = findAll(instance, (node) =>
getNodeByText(node, text, options), options.hidden ?? true
);
return results;
}; |
@MattAgn I've added Would you have time to resume working on this PR? Having the |
@mdjastrzebski I was away for a while, i'm ready to start working back on this 🚀 |
Yes sounds good to me |
@MattAgn great to read that you're back! re root.findAll(...).filter(element => {
return hidden === false
? isInaccessible(element, {
isSubtreeInaccessible: cachedIsSubtreeInaccessible,
}) === false
: true
}) It contains some optimization in form of cachedIsSubtreeInaccessible. |
you mean I don't extract the findAll in another function yet but instead we add some caching to isInaccessible? |
@MattAgn We could replicate DTL behavior of using |
sure, always nice to have a little boost in performance. I would still be in favor of extracting the findAll function though, wdyt? The findAll could look something like (I simply copy pasted the code from DTL for now) : export function findAll<Options extends AccessibilityOption>(
instance: ReactTestInstance,
searchCallback: (node: ReactTestInstance) => boolean,
options?: Options
) {
const subtreeIsInaccessibleCache = new WeakMap();
function cachedIsSubtreeInaccessible(element) {
if (!subtreeIsInaccessibleCache.has(element)) {
subtreeIsInaccessibleCache.set(element, isSubtreeInaccessible(element));
}
return subtreeIsInaccessibleCache.get(element);
}
const results = instance.findAll(searchCallback);
if (options?.hidden === false) {
return results;
}
return results.filter(
(result) =>
!isInaccessible(result, { isSubtreeInaccessible: cachedIsSubtreeInaccessible })
);
} |
Looks pretty good, we could rename export function findAll<Options extends AccessibilityOption>(
instance: ReactTestInstance,
predicate: (node: ReactTestInstance) => boolean,
options?: Options
) {
const matchingElement = instance.findAll(predicate);
const hidden = options?.hidden ?? getConfig().defaultHidden; // We will want to add `defaultHidden: boolean` option to `configure`
if (hidden) {
return matchingElement;
}
const subtreeIsInaccessibleCache = new WeakMap();
function cachedIsSubtreeInaccessible(element) {
if (!subtreeIsInaccessibleCache.has(element)) {
subtreeIsInaccessibleCache.set(element, isSubtreeInaccessible(element));
}
return subtreeIsInaccessibleCache.get(element);
}
return matchingElement.filter(
(element) =>
!isInaccessible(element, { isSubtreeInaccessible: cachedIsSubtreeInaccessible })
);
} @MattAgn wdyt? |
8ddad24
to
d1a49d4
Compare
@mdjastrzebski sounds great! I'm almost done, I'm mainly missing the tests |
Indeed completly forgot about flow types! |
@MattAgn let's write docs with the existing |
Good point, i'm on it (and I agree, rebasing all the time is a pain 😅) |
Done for the documentation, I took some inspiration from RTL and the TextMatch option doc in RNTL, 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.
I've suggested some changes to simplify the doc entry and improve its structure a bit.
Pls add also documentation for configure
option.
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 stuff 🚀🧨
Summary
Resolves #970
This PR aims to solve this issue.
It adds a "respectAccessibility" option to all queries (false by default) that enables queries to ignore elements that would be hidden in an environment respecting accessibility props
TODO
hidden
to comply to RTL namingTest plan
The functionUsingisReactElementVisibleToAccessibility
is 100% testedisInaccessible()
which is already testedNext steps
findAll
that would do the a11y check top down instead of bottom up as we do todayMake performance tests to choose the best implementation(Matching DTL implementation (bottom up + cache))