-
Notifications
You must be signed in to change notification settings - Fork 273
feat: accessibility findAll #787
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
Changes from all commits
5c93709
dcf7c14
521a81c
f166a87
b627428
d33da47
d74b3e1
4647edb
0013643
cf8c6cb
1d8b401
897a2b2
fd8ff4d
c574ee9
b11c463
5b5587f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import debugDeep from './helpers/debugDeep'; | |
type Options = { | ||
wrapper?: React.ComponentType<any>, | ||
createNodeMock?: (element: React.Element<any>) => any, | ||
respectAccessibility?: boolean, | ||
}; | ||
type TestRendererOptions = { | ||
createNodeMock: (element: React.Element<any>) => any, | ||
|
@@ -24,7 +25,7 @@ type TestRendererOptions = { | |
*/ | ||
export default function render<T>( | ||
component: React.Element<T>, | ||
{ wrapper: Wrapper, createNodeMock }: Options = {} | ||
{ wrapper: Wrapper, createNodeMock, respectAccessibility }: Options = {} | ||
): { | ||
...FindByAPI, | ||
...QueryByAPI, | ||
|
@@ -45,7 +46,9 @@ export default function render<T>( | |
createNodeMock ? { createNodeMock } : undefined | ||
); | ||
const update = updateWithAct(renderer, wrap); | ||
const instance = renderer.root; | ||
const instance = respectAccessibility | ||
? appendFindAllTrap(renderer) | ||
: renderer.root; | ||
const unmount = () => { | ||
act(() => { | ||
renderer.unmount(); | ||
|
@@ -107,3 +110,64 @@ function debug( | |
debugImpl.shallow = (message) => debugShallow(instance, message); | ||
return debugImpl; | ||
} | ||
|
||
function appendFindAllTrap(renderer: ReactTestRenderer) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest removing We should have some base |
||
return new Proxy(renderer.root, { | ||
get(target, prop) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit, readability: could we get some more type explicit type annotations here? |
||
const isFindAllProp = prop === 'findAll'; | ||
|
||
return isFindAllProp ? newFindAll(target) : target[prop]; | ||
}, | ||
}); | ||
} | ||
|
||
function newFindAll(instance: ReactTestInstance) { | ||
return ( | ||
predicate: (instance: ReactTestInstance) => boolean | ||
): ReactTestInstance[] => { | ||
const elements = instance.findAll(predicate); | ||
|
||
return elements.filter(isReactTestElementVisibleToAccessibility); | ||
}; | ||
} | ||
|
||
function isReactTestElementVisibleToAccessibility( | ||
instance: ReactTestInstance | ||
): boolean { | ||
const isElementVisible = | ||
!accessibilityHiddenIOS(instance) && | ||
!accessibilityHiddenAndroid(instance) && | ||
!hiddenByStyles(instance); | ||
|
||
if (!instance.parent) { | ||
return isElementVisible; | ||
} | ||
|
||
const isParentVisible = isReactTestElementVisibleToAccessibility( | ||
instance.parent | ||
); | ||
|
||
return isParentVisible && isElementVisible; | ||
} | ||
|
||
function accessibilityHiddenIOS(instance: ReactTestInstance): boolean { | ||
const siblingHasAccessibilityViewIsModal = | ||
instance.parent && | ||
instance.parent.children.some( | ||
(c) => | ||
c.props && c.props.accessibilityViewIsModal && !Object.is(c, instance) | ||
); | ||
|
||
return ( | ||
instance.props.accessibilityElementsHidden || | ||
siblingHasAccessibilityViewIsModal | ||
); | ||
} | ||
|
||
function accessibilityHiddenAndroid(instance: ReactTestInstance) { | ||
return instance.props.importantForAccessibility === 'no-hide-descendants'; | ||
} | ||
|
||
function hiddenByStyles(instance: ReactTestInstance) { | ||
return instance.props.style && instance.props.style.display === 'none'; | ||
} |
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 believe that accessibility props (&
style={{ display: 'none' }}
) should be checked only on host components (typeof element.type === 'string'
) in order to reflect how are they rendered in RN. So here you either should use these props on e.g.View
(recommended) or forward them insideOtherComp
.