Skip to content

Commit

Permalink
Organise a11y queries by predicate (#977)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
MattAgn and mdjastrzebski authored Jul 20, 2022
1 parent 986a029 commit 7431885
Show file tree
Hide file tree
Showing 28 changed files with 1,197 additions and 791 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
steps:
- attach_workspace:
at: ~/react-native-testing-library
- run: yarn test
- run: yarn test:ci
- store_artifacts:
path: coverage
destination: coverage
Expand Down
2 changes: 1 addition & 1 deletion examples/reactnavigation/jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ jest.mock('react-native-reanimated', () => {
});

// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
1 change: 1 addition & 0 deletions jestSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"scripts": {
"clean": "del build",
"test": "jest",
"test:ci": "jest --maxWorkers=2",
"typecheck": "tsc",
"flow": "flow",
"copy-flowtypes": "cp typings/index.flow.js build",
Expand All @@ -83,6 +84,9 @@
},
"jest": {
"preset": "./jest-preset",
"setupFiles": [
"./jestSetup.js"
],
"testPathIgnorePatterns": [
"timerUtils",
"examples/"
Expand Down
34 changes: 34 additions & 0 deletions src/helpers/matchers/__tests__/matchArrayValue.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { matchArrayProp } from '../matchArrayProp';

test('returns true given 2 identical prop and matcher', () => {
expect(matchArrayProp(['banana'], ['banana'])).toEqual(true);
expect(matchArrayProp(['banana', 'apple'], ['banana', 'apple'])).toEqual(
true
);
});

test('returns true when the prop contains all the values of the matcher', () => {
expect(
matchArrayProp(['banana', 'apple', 'orange'], ['banana', 'orange'])
).toEqual(true);
});

test('returns false when the prop does not contain all the values of the matcher', () => {
expect(
matchArrayProp(['banana', 'apple', 'orange'], ['banana', 'pear'])
).toEqual(false);
});

test('returns false when prop is undefined', () => {
expect(matchArrayProp(undefined, ['banana'])).toEqual(false);
});

test('returns false when the matcher is an empty list', () => {
expect(matchArrayProp(['banana'], [])).toEqual(false);
});

test('returns false given 2 different prop and matchers', () => {
expect(matchArrayProp(['banana', 'apple'], ['banana', 'orange'])).toEqual(
false
);
});
37 changes: 37 additions & 0 deletions src/helpers/matchers/__tests__/matchObject.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { matchObjectProp } from '../matchObjectProp';

test('returns true given 2 identical objects', () => {
expect(matchObjectProp({ fruit: 'banana' }, { fruit: 'banana' })).toEqual(
true
);
expect(
matchObjectProp(
{ fruit: 'banana', isRipe: true },
{ fruit: 'banana', isRipe: true }
)
).toEqual(true);
});

test('returns false when one of the param is an empty object', () => {
expect(matchObjectProp({}, { fruit: 'banana' })).toEqual(false);
expect(matchObjectProp({ fruit: 'banana' }, {})).toEqual(false);
});

test('returns false given an undefined prop', () => {
expect(matchObjectProp(undefined, { fruit: 'banana' })).toEqual(false);
});

test('returns false given 2 different non empty objects', () => {
expect(matchObjectProp({ fruit: 'banana' }, { fruits: 'banana' })).toEqual(
false
);
expect(matchObjectProp({ fruit: 'banana' }, { fruit: 'orange' })).toEqual(
false
);
expect(
matchObjectProp(
{ fruit: 'banana', isRipe: true },
{ fruit: 'banana', ripe: true }
)
).toEqual(false);
});
15 changes: 15 additions & 0 deletions src/helpers/matchers/__tests__/matchStringValue.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { matchStringProp } from '../matchStringProp';

test.each`
prop | matcher | expectedResult
${'hey'} | ${'hey'} | ${true}
${'hey'} | ${/hey/} | ${true}
${'hey'} | ${'heyyyy'} | ${false}
${'hey'} | ${/heyyy/} | ${false}
${undefined} | ${'hey'} | ${false}
`(
'returns $expectedResult given prop $prop and matcher $matcher',
({ prop, matcher, expectedResult }) => {
expect(matchStringProp(prop, matcher)).toEqual(expectedResult);
}
);
21 changes: 21 additions & 0 deletions src/helpers/matchers/matchArrayProp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Matches whether given array prop contains the given value, or all given values.
*
* @param prop - The array prop to match.
* @param matcher - The value or values to be included in the array.
* @returns Whether the array prop contains the given value, or all given values.
*/
export function matchArrayProp(
prop: Array<string> | undefined,
matcher: string | Array<string>
): boolean {
if (!prop || matcher.length === 0) {
return false;
}

if (typeof matcher === 'string') {
return prop.includes(matcher);
}

return matcher.every((e) => prop.includes(e));
}
25 changes: 25 additions & 0 deletions src/helpers/matchers/matchObjectProp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* check that each key value pair of the objects match
* BE CAREFUL it works only for 1 level deep key value pairs
* won't work for nested objects
*/

/**
* Matches whether given object prop contains all key/value pairs.
* @param prop - The object prop to match.
* @param matcher - The key/value pairs to be included in the object.
* @returns Whether the object prop contains all key/value pairs.
*/
export function matchObjectProp<T extends Record<string, unknown>>(
prop: T | undefined,
matcher: T
): boolean {
if (!prop || Object.keys(matcher).length === 0) {
return false;
}

return (
Object.keys(prop).length !== 0 &&
Object.keys(matcher).every((key) => prop[key] === matcher[key])
);
}
23 changes: 23 additions & 0 deletions src/helpers/matchers/matchStringProp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { TextMatch } from '../../matches';

/**
* Matches the given string property again string or regex matcher.
*
* @param prop - The string prop to match.
* @param matcher - The string or regex to match.
* @returns - Whether the string prop matches the given string or regex.
*/
export function matchStringProp(
prop: string | undefined,
matcher: TextMatch
): boolean {
if (!prop) {
return false;
}

if (typeof matcher === 'string') {
return prop === matcher;
}

return prop.match(matcher) != null;
}
Loading

0 comments on commit 7431885

Please sign in to comment.