UNPKG

@testing-library/react-native

Version:

Simple and complete React Native testing utilities that encourage good testing practices.

242 lines (224 loc) 8.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.accessibilityValueKeys = exports.accessibilityStateKeys = void 0; exports.computeAccessibleName = computeAccessibleName; exports.computeAriaBusy = computeAriaBusy; exports.computeAriaChecked = computeAriaChecked; exports.computeAriaDisabled = computeAriaDisabled; exports.computeAriaExpanded = computeAriaExpanded; exports.computeAriaLabel = computeAriaLabel; exports.computeAriaModal = computeAriaModal; exports.computeAriaSelected = computeAriaSelected; exports.computeAriaValue = computeAriaValue; exports.getRole = getRole; exports.isAccessibilityElement = isAccessibilityElement; exports.isHiddenFromAccessibility = isHiddenFromAccessibility; exports.isInaccessible = void 0; exports.normalizeRole = normalizeRole; exports.rolesSupportingCheckedState = void 0; var _reactNative = require("react-native"); var _componentTree = require("./component-tree"); var _findAll = require("./find-all"); var _hostComponentNames = require("./host-component-names"); var _textContent = require("./text-content"); var _textInput = require("./text-input"); const accessibilityStateKeys = exports.accessibilityStateKeys = ['disabled', 'selected', 'checked', 'busy', 'expanded']; const accessibilityValueKeys = exports.accessibilityValueKeys = ['min', 'max', 'now', 'text']; function isHiddenFromAccessibility(element, { cache } = {}) { if (element == null) { return true; } let current = element; while (current) { let isCurrentSubtreeInaccessible = cache?.get(current); if (isCurrentSubtreeInaccessible === undefined) { isCurrentSubtreeInaccessible = isSubtreeInaccessible(current); cache?.set(current, isCurrentSubtreeInaccessible); } if (isCurrentSubtreeInaccessible) { return true; } current = current.parent; } return false; } /** RTL-compatibility alias for `isHiddenFromAccessibility` */ const isInaccessible = exports.isInaccessible = isHiddenFromAccessibility; function isSubtreeInaccessible(element) { // Null props can happen for React.Fragments if (element.props == null) { return false; } // See: https://reactnative.dev/docs/accessibility#aria-hidden if (element.props['aria-hidden']) { return true; } // iOS: accessibilityElementsHidden // See: https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios if (element.props.accessibilityElementsHidden) { return true; } // Android: importantForAccessibility // See: https://reactnative.dev/docs/accessibility#importantforaccessibility-android if (element.props.importantForAccessibility === 'no-hide-descendants') { return true; } // Note that `opacity: 0` is not treated as inaccessible on iOS const flatStyle = _reactNative.StyleSheet.flatten(element.props.style) ?? {}; if (flatStyle.display === 'none') return true; // iOS: accessibilityViewIsModal or aria-modal // See: https://reactnative.dev/docs/accessibility#accessibilityviewismodal-ios const hostSiblings = (0, _componentTree.getHostSiblings)(element); if (hostSiblings.some(sibling => computeAriaModal(sibling))) { return true; } return false; } function isAccessibilityElement(element) { if (element == null) { return false; } // https://github.com/facebook/react-native/blob/8dabed60f456e76a9e53273b601446f34de41fb5/packages/react-native/Libraries/Image/Image.ios.js#L172 if ((0, _hostComponentNames.isHostImage)(element) && element.props.alt !== undefined) { return true; } if (element.props.accessible !== undefined) { return element.props.accessible; } return (0, _hostComponentNames.isHostText)(element) || (0, _hostComponentNames.isHostTextInput)(element) || (0, _hostComponentNames.isHostSwitch)(element); } /** * Returns the accessibility role for given element. It will return explicit * role from either `role` or `accessibilityRole` props if set. * * If explicit role is not available, it would try to return default element * role: * - `text` for `Text` elements * * In all other cases this functions returns `none`. * * @param element * @returns */ function getRole(element) { const explicitRole = element.props.role ?? element.props.accessibilityRole; if (explicitRole) { return normalizeRole(explicitRole); } if ((0, _hostComponentNames.isHostText)(element)) { return 'text'; } // Note: host Image elements report "image" role in screen reader only on Android, but not on iOS. // It's better to require explicit role for Image elements. return 'none'; } /** * There are some duplications between (ARIA) `Role` and `AccessibilityRole` types. * Resolve them by using ARIA `Role` type where possible. * * @param role Role to normalize * @returns Normalized role */ function normalizeRole(role) { if (role === 'image') { return 'img'; } return role; } function computeAriaModal(element) { return element.props['aria-modal'] ?? element.props.accessibilityViewIsModal; } function computeAriaLabel(element) { const labelElementId = element.props['aria-labelledby'] ?? element.props.accessibilityLabelledBy; if (labelElementId) { const rootElement = (0, _componentTree.getUnsafeRootElement)(element); const labelElement = (0, _findAll.findAll)(rootElement, node => (0, _componentTree.isHostElement)(node) && node.props.nativeID === labelElementId, { includeHiddenElements: true }); if (labelElement.length > 0) { return (0, _textContent.getTextContent)(labelElement[0]); } } const explicitLabel = element.props['aria-label'] ?? element.props.accessibilityLabel; if (explicitLabel) { return explicitLabel; } //https://github.com/facebook/react-native/blob/8dabed60f456e76a9e53273b601446f34de41fb5/packages/react-native/Libraries/Image/Image.ios.js#L173 if ((0, _hostComponentNames.isHostImage)(element) && element.props.alt) { return element.props.alt; } return undefined; } // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#busy-state function computeAriaBusy({ props }) { return props['aria-busy'] ?? props.accessibilityState?.busy ?? false; } // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#checked-state function computeAriaChecked(element) { const { props } = element; if ((0, _hostComponentNames.isHostSwitch)(element)) { return props.value; } const role = getRole(element); if (!rolesSupportingCheckedState[role]) { return undefined; } return props['aria-checked'] ?? props.accessibilityState?.checked; } // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#disabled-state function computeAriaDisabled(element) { if ((0, _hostComponentNames.isHostTextInput)(element) && !(0, _textInput.isEditableTextInput)(element)) { return true; } const { props } = element; if ((0, _hostComponentNames.isHostText)(element) && props.disabled) { return true; } return props['aria-disabled'] ?? props.accessibilityState?.disabled ?? false; } // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#expanded-state function computeAriaExpanded({ props }) { return props['aria-expanded'] ?? props.accessibilityState?.expanded; } // See: https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State#selected-state function computeAriaSelected({ props }) { return props['aria-selected'] ?? props.accessibilityState?.selected ?? false; } function computeAriaValue(element) { const { accessibilityValue, 'aria-valuemax': ariaValueMax, 'aria-valuemin': ariaValueMin, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = element.props; return { max: ariaValueMax ?? accessibilityValue?.max, min: ariaValueMin ?? accessibilityValue?.min, now: ariaValueNow ?? accessibilityValue?.now, text: ariaValueText ?? accessibilityValue?.text }; } function computeAccessibleName(element) { return computeAriaLabel(element) ?? (0, _textContent.getTextContent)(element); } const rolesSupportingCheckedState = exports.rolesSupportingCheckedState = { checkbox: true, radio: true, switch: true }; //# sourceMappingURL=accessibility.js.map