diff --git a/src/helpers/__tests__/format-default.test.tsx b/src/helpers/__tests__/format-default.test.tsx
index ab67cd700..917d9a12e 100644
--- a/src/helpers/__tests__/format-default.test.tsx
+++ b/src/helpers/__tests__/format-default.test.tsx
@@ -21,6 +21,10 @@ describe('mapPropsForQueryError', () => {
'aria-labelledby': 'ARIA_LABELLED_BY',
'aria-modal': true,
'aria-selected': 'ARIA-SELECTED',
+ 'aria-valuemax': 'ARIA-VALUEMAX',
+ 'aria-valuemin': 'ARIA-VALUEMIN',
+ 'aria-valuenow': 'ARIA-VALUENOW',
+ 'aria-valuetext': 'ARIA-VALUETEXT',
placeholder: 'PLACEHOLDER',
value: 'VALUE',
defaultValue: 'DEFAULT_VALUE',
diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts
index 0e9e1b809..7a4bb0e1d 100644
--- a/src/helpers/accessiblity.ts
+++ b/src/helpers/accessiblity.ts
@@ -112,7 +112,9 @@ export function isAccessibilityElement(
);
}
-export function getAccessibilityRole(element: ReactTestInstance) {
+export function getAccessibilityRole(
+ element: ReactTestInstance
+): string | undefined {
return element.props.role ?? element.props.accessibilityRole;
}
@@ -134,7 +136,9 @@ export function getAccessibilityLabelledBy(
);
}
-export function getAccessibilityState(element: ReactTestInstance) {
+export function getAccessibilityState(
+ element: ReactTestInstance
+): AccessibilityState | undefined {
const {
accessibilityState,
'aria-busy': ariaBusy,
@@ -171,3 +175,33 @@ export function getAccessibilityCheckedState(
const { accessibilityState, 'aria-checked': ariaChecked } = element.props;
return ariaChecked ?? accessibilityState?.checked;
}
+
+export function getAccessibilityValue(
+ element: ReactTestInstance
+): AccessibilityValue | undefined {
+ const {
+ accessibilityValue,
+ 'aria-valuemax': ariaValueMax,
+ 'aria-valuemin': ariaValueMin,
+ 'aria-valuenow': ariaValueNow,
+ 'aria-valuetext': ariaValueText,
+ } = element.props;
+
+ const hasAnyAccessibilityValueProps =
+ accessibilityValue != null ||
+ ariaValueMax != null ||
+ ariaValueMin != null ||
+ ariaValueNow != null ||
+ ariaValueText != null;
+
+ if (!hasAnyAccessibilityValueProps) {
+ return undefined;
+ }
+
+ return {
+ max: ariaValueMax ?? accessibilityValue?.max,
+ min: ariaValueMin ?? accessibilityValue?.min,
+ now: ariaValueNow ?? accessibilityValue?.now,
+ text: ariaValueText ?? accessibilityValue?.text,
+ };
+}
diff --git a/src/helpers/format-default.ts b/src/helpers/format-default.ts
index 0a7752a6a..717bed9ec 100644
--- a/src/helpers/format-default.ts
+++ b/src/helpers/format-default.ts
@@ -17,6 +17,10 @@ const propsToDisplay = [
'aria-labelledby',
'aria-modal',
'aria-selected',
+ 'aria-valuemax',
+ 'aria-valuemin',
+ 'aria-valuenow',
+ 'aria-valuetext',
'defaultValue',
'importantForAccessibility',
'nativeID',
diff --git a/src/helpers/matchers/accessibilityValue.ts b/src/helpers/matchers/accessibilityValue.ts
index ef72c1cdb..0c8a04c09 100644
--- a/src/helpers/matchers/accessibilityValue.ts
+++ b/src/helpers/matchers/accessibilityValue.ts
@@ -1,5 +1,5 @@
-import { AccessibilityValue } from 'react-native';
import { ReactTestInstance } from 'react-test-renderer';
+import { getAccessibilityValue } from '../accessiblity';
import { TextMatch } from '../../matches';
import { matchStringProp } from './matchStringProp';
@@ -14,11 +14,11 @@ export function matchAccessibilityValue(
node: ReactTestInstance,
matcher: AccessibilityValueMatcher
): boolean {
- const value: AccessibilityValue = node.props.accessibilityValue ?? {};
+ const value = getAccessibilityValue(node);
return (
- (matcher.min === undefined || matcher.min === value.min) &&
- (matcher.max === undefined || matcher.max === value.max) &&
- (matcher.now === undefined || matcher.now === value.now) &&
- (matcher.text === undefined || matchStringProp(value.text, matcher.text))
+ (matcher.min === undefined || matcher.min === value?.min) &&
+ (matcher.max === undefined || matcher.max === value?.max) &&
+ (matcher.now === undefined || matcher.now === value?.now) &&
+ (matcher.text === undefined || matchStringProp(value?.text, matcher.text))
);
}
diff --git a/src/matchers/__tests__/to-be-checked.test.tsx b/src/matchers/__tests__/to-be-checked.test.tsx
index 83f75c3b2..4e7549177 100644
--- a/src/matchers/__tests__/to-be-checked.test.tsx
+++ b/src/matchers/__tests__/to-be-checked.test.tsx
@@ -176,3 +176,12 @@ test('throws error for invalid role', () => {
`"toBeChecked() works only on accessibility elements with "checkbox" or "radio" role."`
);
});
+
+test('throws error for non-accessibility element', () => {
+ render();
+
+ const view = screen.getByTestId('test');
+ expect(() => expect(view).toBeChecked()).toThrowErrorMatchingInlineSnapshot(
+ `"toBeChecked() works only on accessibility elements with "checkbox" or "radio" role."`
+ );
+});
diff --git a/src/matchers/to-be-checked.tsx b/src/matchers/to-be-checked.tsx
index 7a9a67e0d..6e641ef39 100644
--- a/src/matchers/to-be-checked.tsx
+++ b/src/matchers/to-be-checked.tsx
@@ -35,9 +35,11 @@ export function toBeChecked(
};
}
-const VALID_ROLES = new Set(['checkbox', 'radio']);
-
function hasValidAccessibilityRole(element: ReactTestInstance) {
+ if (!isAccessibilityElement(element)) {
+ return false;
+ }
+
const role = getAccessibilityRole(element);
- return isAccessibilityElement(element) && VALID_ROLES.has(role);
+ return role === 'checkbox' || role === 'radio';
}
diff --git a/src/queries/__tests__/a11yValue.test.tsx b/src/queries/__tests__/a11yValue.test.tsx
index 8cbd2851a..7236cc3ae 100644
--- a/src/queries/__tests__/a11yValue.test.tsx
+++ b/src/queries/__tests__/a11yValue.test.tsx
@@ -307,3 +307,37 @@ test('error message renders the element tree, preserving only helpful props', as
/>"
`);
});
+
+describe('getByAccessibilityValue supports "aria-*" props', () => {
+ test('supports "aria-valuemax"', () => {
+ const screen = render();
+ expect(screen.getByAccessibilityValue({ max: 10 })).toBeTruthy();
+ });
+
+ test('supports "aria-valuemin"', () => {
+ const screen = render();
+ expect(screen.getByAccessibilityValue({ min: 20 })).toBeTruthy();
+ });
+
+ test('supports "aria-valuenow"', () => {
+ const screen = render();
+ expect(screen.getByAccessibilityValue({ now: 30 })).toBeTruthy();
+ });
+
+ test('supports "aria-valuetext"', () => {
+ const screen = render();
+ expect(
+ screen.getByAccessibilityValue({ text: 'Hello World' })
+ ).toBeTruthy();
+ expect(screen.getByAccessibilityValue({ text: /hello/i })).toBeTruthy();
+ });
+
+ test('supports multiple "aria-value*" props', () => {
+ const screen = render(
+
+ );
+ expect(
+ screen.getByAccessibilityValue({ now: 50, min: 0, max: 100 })
+ ).toBeTruthy();
+ });
+});
diff --git a/src/queries/__tests__/makeQueries.test.tsx b/src/queries/__tests__/makeQueries.test.tsx
index 506603263..5b2d39813 100644
--- a/src/queries/__tests__/makeQueries.test.tsx
+++ b/src/queries/__tests__/makeQueries.test.tsx
@@ -71,6 +71,10 @@ describe('printing element tree', () => {
aria-labelledby="ARIA_LABELLED_BY"
aria-modal={true}
aria-selected={false}
+ aria-valuemax={30}
+ aria-valuemin={10}
+ aria-valuenow={20}
+ aria-valuetext="Hello Value"
importantForAccessibility="yes"
nativeID="NATIVE_ID"
role="summary"
diff --git a/src/queries/__tests__/role-value.test.tsx b/src/queries/__tests__/role-value.test.tsx
index c1da194fa..eed847111 100644
--- a/src/queries/__tests__/role-value.test.tsx
+++ b/src/queries/__tests__/role-value.test.tsx
@@ -173,4 +173,55 @@ describe('accessibility value', () => {
"
`);
});
+
+ test('supports "aria-valuemax" prop', () => {
+ const screen = render();
+ expect(screen.getByRole('slider', { value: { max: 10 } })).toBeTruthy();
+ expect(screen.queryByRole('slider', { value: { max: 20 } })).toBeNull();
+ });
+
+ test('supports "aria-valuemin" prop', () => {
+ const screen = render();
+ expect(screen.getByRole('slider', { value: { min: 20 } })).toBeTruthy();
+ expect(screen.queryByRole('slider', { value: { min: 30 } })).toBeNull();
+ });
+
+ test('supports "aria-valuenow" prop', () => {
+ const screen = render();
+ expect(screen.getByRole('slider', { value: { now: 30 } })).toBeTruthy();
+ expect(screen.queryByRole('slider', { value: { now: 10 } })).toBeNull();
+ });
+
+ test('supports "aria-valuetext" prop', () => {
+ const screen = render(
+
+ );
+ expect(
+ screen.getByRole('slider', { value: { text: 'Hello World' } })
+ ).toBeTruthy();
+ expect(
+ screen.getByRole('slider', { value: { text: /hello/i } })
+ ).toBeTruthy();
+ expect(
+ screen.queryByRole('slider', { value: { text: 'Hello' } })
+ ).toBeNull();
+ expect(
+ screen.queryByRole('slider', { value: { text: /salut/i } })
+ ).toBeNull();
+ });
+
+ test('supports multiple "aria-value*" props', () => {
+ const screen = render(
+
+ );
+ expect(
+ screen.getByRole('slider', { value: { now: 50, min: 0, max: 100 } })
+ ).toBeTruthy();
+ });
});
diff --git a/website/docs/Queries.md b/website/docs/Queries.md
index 25a6aa83a..462752d29 100644
--- a/website/docs/Queries.md
+++ b/website/docs/Queries.md
@@ -121,7 +121,7 @@ const element3 = screen.getByRole('button', { name: 'Hello', disabled: true });
`expanded`: You can filter elements by their expanded state (coming either from `aria-expanded` prop or `accessbilityState.expanded` prop). The possible values are `true` or `false`. See [React Native's accessibilityState](https://reactnative.dev/docs/accessibility#accessibilitystate) docs to learn more about the `expanded` state.
-`value`: Filter elements by their accessibility, available value entries include numeric `min`, `max` & `now`, as well as string or regex `text` key. See React Native [accessibilityValue](https://reactnative.dev/docs/accessibility#accessibilityvalue) docs to learn more about this prop.
+`value`: Filter elements by their accessibility value, based on either `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, `aria-valuetext` or `accessibilityValue` props. Accessiblity value conceptually consists of numeric `min`, `max` and `now` entries, as well as string `text` entry. See React Native [accessibilityValue](https://reactnative.dev/docs/accessibility#accessibilityvalue) docs to learn more about the accessibility value concept.
### `ByText`
@@ -371,7 +371,7 @@ getByA11yValue(
): ReactTestInstance;
```
-Returns a host element with matching `accessibilityValue` prop entries. Only entires provided to the query will be used to match elements. Element might have additional accessibility value entries and still be matched.
+Returns a host element with matching accessibility value based on `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, `aria-valuetext` & `accessibilityValue` props. Only value entires provided to the query will be used to match elements. Element might have additional accessibility value entries and still be matched.
When querying by `text` entry a string or regex might be used.