Skip to content

Commit 7431885

Browse files
Organise a11y queries by predicate (#977)
* refactor: make Options generic type optionnal in queries * refactor: extract byLabelText queries and its tests * refactor: extract byA11yHint queries and its tests * refactor: extract byRole queries and its tests * refactor: extract byA11yState queries and its tests * refactor: extract byA11yValue queries and its tests * refactor: extract byA11yStates queries and its tests * refactor: harmonize component declaration in queries testsx * refactor: simplify error helpers in queries tests * refactor: make error helpers more explicit * chore: remove now unused makeA11yQueries * refactor: rename AccessibilityStateKeyQueryParam to AccessibilityStateKeys * refactor: rename param in a11yStates * refactor: simplify matchObject * refactor: fix namings in labelText * refactor: fix namings in a11yHint * refactor: fix queryAll namings' * refactor: fix some namings in a11yState * refactor: fix some namings in role * refactor: fix some namings in a11yValue * refactor: extract matchStringValue * refactor: extract matchObject * refactor: extract matchArrayValue * test: add tests for the matchers * refactor: simplify matchArrayValue to make it more explicit * refactor: reorder imports and object keys * refactor: update types * refactor: small tweaks * refactor: tweaks * refactor: clarify matcher naming * refactor: add missing aliases * chore: fix ci timeout * chore: revert jest timeout increase * chore: revert timeout increase * chore: fix ci tests * chore: re-enable disabled tests * chore: reduce jest paralelizaiton * chore: ci tweaks Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
1 parent 986a029 commit 7431885

28 files changed

+1197
-791
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
steps:
5555
- attach_workspace:
5656
at: ~/react-native-testing-library
57-
- run: yarn test
57+
- run: yarn test:ci
5858
- store_artifacts:
5959
path: coverage
6060
destination: coverage

examples/reactnavigation/jest-setup.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ jest.mock('react-native-reanimated', () => {
1111
});
1212

1313
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
14-
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
14+
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');

jestSetup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"scripts": {
6969
"clean": "del build",
7070
"test": "jest",
71+
"test:ci": "jest --maxWorkers=2",
7172
"typecheck": "tsc",
7273
"flow": "flow",
7374
"copy-flowtypes": "cp typings/index.flow.js build",
@@ -83,6 +84,9 @@
8384
},
8485
"jest": {
8586
"preset": "./jest-preset",
87+
"setupFiles": [
88+
"./jestSetup.js"
89+
],
8690
"testPathIgnorePatterns": [
8791
"timerUtils",
8892
"examples/"
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { matchArrayProp } from '../matchArrayProp';
2+
3+
test('returns true given 2 identical prop and matcher', () => {
4+
expect(matchArrayProp(['banana'], ['banana'])).toEqual(true);
5+
expect(matchArrayProp(['banana', 'apple'], ['banana', 'apple'])).toEqual(
6+
true
7+
);
8+
});
9+
10+
test('returns true when the prop contains all the values of the matcher', () => {
11+
expect(
12+
matchArrayProp(['banana', 'apple', 'orange'], ['banana', 'orange'])
13+
).toEqual(true);
14+
});
15+
16+
test('returns false when the prop does not contain all the values of the matcher', () => {
17+
expect(
18+
matchArrayProp(['banana', 'apple', 'orange'], ['banana', 'pear'])
19+
).toEqual(false);
20+
});
21+
22+
test('returns false when prop is undefined', () => {
23+
expect(matchArrayProp(undefined, ['banana'])).toEqual(false);
24+
});
25+
26+
test('returns false when the matcher is an empty list', () => {
27+
expect(matchArrayProp(['banana'], [])).toEqual(false);
28+
});
29+
30+
test('returns false given 2 different prop and matchers', () => {
31+
expect(matchArrayProp(['banana', 'apple'], ['banana', 'orange'])).toEqual(
32+
false
33+
);
34+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { matchObjectProp } from '../matchObjectProp';
2+
3+
test('returns true given 2 identical objects', () => {
4+
expect(matchObjectProp({ fruit: 'banana' }, { fruit: 'banana' })).toEqual(
5+
true
6+
);
7+
expect(
8+
matchObjectProp(
9+
{ fruit: 'banana', isRipe: true },
10+
{ fruit: 'banana', isRipe: true }
11+
)
12+
).toEqual(true);
13+
});
14+
15+
test('returns false when one of the param is an empty object', () => {
16+
expect(matchObjectProp({}, { fruit: 'banana' })).toEqual(false);
17+
expect(matchObjectProp({ fruit: 'banana' }, {})).toEqual(false);
18+
});
19+
20+
test('returns false given an undefined prop', () => {
21+
expect(matchObjectProp(undefined, { fruit: 'banana' })).toEqual(false);
22+
});
23+
24+
test('returns false given 2 different non empty objects', () => {
25+
expect(matchObjectProp({ fruit: 'banana' }, { fruits: 'banana' })).toEqual(
26+
false
27+
);
28+
expect(matchObjectProp({ fruit: 'banana' }, { fruit: 'orange' })).toEqual(
29+
false
30+
);
31+
expect(
32+
matchObjectProp(
33+
{ fruit: 'banana', isRipe: true },
34+
{ fruit: 'banana', ripe: true }
35+
)
36+
).toEqual(false);
37+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { matchStringProp } from '../matchStringProp';
2+
3+
test.each`
4+
prop | matcher | expectedResult
5+
${'hey'} | ${'hey'} | ${true}
6+
${'hey'} | ${/hey/} | ${true}
7+
${'hey'} | ${'heyyyy'} | ${false}
8+
${'hey'} | ${/heyyy/} | ${false}
9+
${undefined} | ${'hey'} | ${false}
10+
`(
11+
'returns $expectedResult given prop $prop and matcher $matcher',
12+
({ prop, matcher, expectedResult }) => {
13+
expect(matchStringProp(prop, matcher)).toEqual(expectedResult);
14+
}
15+
);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Matches whether given array prop contains the given value, or all given values.
3+
*
4+
* @param prop - The array prop to match.
5+
* @param matcher - The value or values to be included in the array.
6+
* @returns Whether the array prop contains the given value, or all given values.
7+
*/
8+
export function matchArrayProp(
9+
prop: Array<string> | undefined,
10+
matcher: string | Array<string>
11+
): boolean {
12+
if (!prop || matcher.length === 0) {
13+
return false;
14+
}
15+
16+
if (typeof matcher === 'string') {
17+
return prop.includes(matcher);
18+
}
19+
20+
return matcher.every((e) => prop.includes(e));
21+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* check that each key value pair of the objects match
3+
* BE CAREFUL it works only for 1 level deep key value pairs
4+
* won't work for nested objects
5+
*/
6+
7+
/**
8+
* Matches whether given object prop contains all key/value pairs.
9+
* @param prop - The object prop to match.
10+
* @param matcher - The key/value pairs to be included in the object.
11+
* @returns Whether the object prop contains all key/value pairs.
12+
*/
13+
export function matchObjectProp<T extends Record<string, unknown>>(
14+
prop: T | undefined,
15+
matcher: T
16+
): boolean {
17+
if (!prop || Object.keys(matcher).length === 0) {
18+
return false;
19+
}
20+
21+
return (
22+
Object.keys(prop).length !== 0 &&
23+
Object.keys(matcher).every((key) => prop[key] === matcher[key])
24+
);
25+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { TextMatch } from '../../matches';
2+
3+
/**
4+
* Matches the given string property again string or regex matcher.
5+
*
6+
* @param prop - The string prop to match.
7+
* @param matcher - The string or regex to match.
8+
* @returns - Whether the string prop matches the given string or regex.
9+
*/
10+
export function matchStringProp(
11+
prop: string | undefined,
12+
matcher: TextMatch
13+
): boolean {
14+
if (!prop) {
15+
return false;
16+
}
17+
18+
if (typeof matcher === 'string') {
19+
return prop === matcher;
20+
}
21+
22+
return prop.match(matcher) != null;
23+
}

0 commit comments

Comments
 (0)