feat: add getAllByTestId and queryAllByTestId queries (#198)

* feat: add getAllByTestId and queryAllByTestId queries

* Add test for getAllByTestId and queryAllByTestId

- Filter out intermediate components in getAllByTestId. testIDs may be passed down to child components and appearing multiple times in the render tree. Some React Native components render multiple anyways. <Text> is an example.

* Update TypeScript typings

* Fix flow types

* Update TS typings test
This commit is contained in:
Scotty Waggoner
2019-07-03 01:17:32 -07:00
committed by Michał Pierzchała
parent 9369efee73
commit fead652013
6 changed files with 106 additions and 1 deletions
@@ -45,6 +45,16 @@ exports[`debug 1`] = `
Change freshness!
</Text>
</View>
<Text
testID=\\"duplicateText\\"
>
First Text
</Text>
<Text
testID=\\"duplicateText\\"
>
Second Text
</Text>
</View>"
`;
@@ -93,6 +103,16 @@ exports[`debug changing component: bananaFresh button message should now be "fre
Change freshness!
</Text>
</View>
<Text
testID=\\"duplicateText\\"
>
First Text
</Text>
<Text
testID=\\"duplicateText\\"
>
Second Text
</Text>
</View>"
`;
@@ -128,6 +148,16 @@ exports[`debug: shallow 1`] = `
>
Change freshness!
</Button>
<Text
testID=\\"duplicateText\\"
>
First Text
</Text>
<Text
testID=\\"duplicateText\\"
>
Second Text
</Text>
</View>"
`;
@@ -165,6 +195,16 @@ exports[`debug: shallow with message 1`] = `
>
Change freshness!
</Button>
<Text
testID=\\"duplicateText\\"
>
First Text
</Text>
<Text
testID=\\"duplicateText\\"
>
Second Text
</Text>
</View>"
`;
@@ -215,6 +255,16 @@ exports[`debug: with message 1`] = `
Change freshness!
</Text>
</View>
<Text
testID=\\"duplicateText\\"
>
First Text
</Text>
<Text
testID=\\"duplicateText\\"
>
Second Text
</Text>
</View>"
`;
+22 -1
View File
@@ -71,6 +71,8 @@ class Banana extends React.Component<*, *> {
<Button onPress={this.changeFresh} type="primary">
Change freshness!
</Button>
<Text testID="duplicateText">First Text</Text>
<Text testID="duplicateText">Second Text</Text>
</View>
);
}
@@ -87,6 +89,25 @@ test('getByTestId, queryByTestId', () => {
expect(queryByTestId('InExistent')).toBeNull();
});
test('getAllByTestId, queryAllByTestId', () => {
const { getAllByTestId, queryAllByTestId } = render(<Banana />);
const textElements = getAllByTestId('duplicateText');
expect(textElements.length).toBe(2);
expect(textElements[0].props.children).toBe('First Text');
expect(textElements[1].props.children).toBe('Second Text');
expect(() => getAllByTestId('nonExistentTestId')).toThrow(
'No instances found'
);
const queriedTextElements = queryAllByTestId('duplicateText');
expect(queriedTextElements.length).toBe(2);
expect(queriedTextElements[0]).toBe(textElements[0]);
expect(queriedTextElements[1]).toBe(textElements[1]);
expect(queryAllByTestId('nonExistentTestId')).toHaveLength(0);
});
test('getByName, queryByName', () => {
const { getByTestId, getByName, queryByName } = render(<Banana />);
const bananaFresh = getByTestId('bananaFresh');
@@ -101,7 +122,7 @@ test('getByName, queryByName', () => {
expect(bananaFresh.props.children).toBe('not fresh');
expect(() => getByName('InExistent')).toThrow('No instances found');
expect(() => getByName(Text)).toThrow('Expected 1 but found 3');
expect(() => getByName(Text)).toThrow('Expected 1 but found 5');
expect(queryByName('Button')).toBe(button);
expect(queryByName('InExistent')).toBeNull();
+16
View File
@@ -212,6 +212,21 @@ export const getAllByProps = (instance: ReactTestInstance) =>
return results;
};
export const getAllByTestId = (instance: ReactTestInstance) =>
function getAllByTestIdFn(testID: string): ReactTestInstance[] {
const results = instance
.findAllByProps({ testID })
.filter(element => typeof element.type === 'string');
if (results.length === 0) {
throw new ErrorWithStack(
`No instances found with testID: ${String(testID)}`,
getAllByTestIdFn
);
}
return results;
};
export const getByAPI = (instance: ReactTestInstance) => ({
getByTestId: getByTestId(instance),
getByName: getByName(instance),
@@ -220,6 +235,7 @@ export const getByAPI = (instance: ReactTestInstance) => ({
getByPlaceholder: getByPlaceholder(instance),
getByDisplayValue: getByDisplayValue(instance),
getByProps: getByProps(instance),
getAllByTestId: getAllByTestId(instance),
getAllByName: getAllByName(instance),
getAllByType: getAllByType(instance),
getAllByText: getAllByText(instance),
+12
View File
@@ -8,6 +8,7 @@ import {
getByPlaceholder,
getByDisplayValue,
getByProps,
getAllByTestId,
getAllByName,
getAllByType,
getAllByText,
@@ -142,6 +143,16 @@ export const queryAllByProps = (instance: ReactTestInstance) => (props: {
}
};
export const queryAllByTestId = (instance: ReactTestInstance) => (
testID: string
) => {
try {
return getAllByTestId(instance)(testID);
} catch (error) {
return [];
}
};
export const queryByAPI = (instance: ReactTestInstance) => ({
queryByTestId: queryByTestId(instance),
queryByName: queryByName(instance),
@@ -150,6 +161,7 @@ export const queryByAPI = (instance: ReactTestInstance) => ({
queryByPlaceholder: queryByPlaceholder(instance),
queryByDisplayValue: queryByDisplayValue(instance),
queryByProps: queryByProps(instance),
queryAllByTestId: queryAllByTestId(instance),
queryAllByName: queryAllByName(instance),
queryAllByType: queryAllByType(instance),
queryAllByText: queryAllByText(instance),
+4
View File
@@ -54,6 +54,7 @@ const getByDisplayValueRegExp: ReactTestInstance = tree.getByDisplayValue(
);
const getByProps: ReactTestInstance = tree.getByProps({ value: 2 });
const getByTestId: ReactTestInstance = tree.getByTestId('test-id');
const getAllByTestId: ReactTestInstance[] = tree.getAllByTestId('test-id');
const getAllByNameString: Array<ReactTestInstance> = tree.getAllByName('View');
const getAllByNameConstructor: Array<ReactTestInstance> = tree.getAllByName(
View
@@ -93,6 +94,9 @@ const queryByDisplayValueRegExp: ReactTestInstance | null = tree.queryByDisplayV
);
const queryByProps: ReactTestInstance | null = tree.queryByProps({ value: 2 });
const queryByTestId: ReactTestInstance | null = tree.queryByTestId('test-id');
const queryAllByTestId: ReactTestInstance[] | null = tree.queryAllByTestId(
'test-id'
);
const queryAllByNameString: Array<ReactTestInstance> = tree.queryAllByName(
'View'
);
+2
View File
@@ -9,6 +9,7 @@ export interface GetByAPI {
getByDisplayValue: (value: string | RegExp) => ReactTestInstance;
getByProps: (props: Record<string, any>) => ReactTestInstance;
getByTestId: (testID: string) => ReactTestInstance;
getAllByTestId: (testID: string) => Array<ReactTestInstance>;
getAllByName: (name: React.ReactType | string) => Array<ReactTestInstance>;
getAllByType: <P>(type: React.ComponentType<P>) => Array<ReactTestInstance>;
getAllByText: (text: string | RegExp) => Array<ReactTestInstance>;
@@ -29,6 +30,7 @@ export interface QueryByAPI {
queryByDisplayValue: (value: string | RegExp) => ReactTestInstance | null;
queryByProps: (props: Record<string, any>) => ReactTestInstance | null;
queryByTestId: (testID: string) => ReactTestInstance | null;
queryAllByTestId: (testID: string) => Array<ReactTestInstance> | null;
queryAllByName: (
name: React.ReactType | string
) => Array<ReactTestInstance> | [];