Skip to content

Commit ab8c3f5

Browse files
committed
refactor thumbnail selector tests
- add new testIDs to identify components
1 parent 588594d commit ab8c3f5

File tree

4 files changed

+221
-156
lines changed

4 files changed

+221
-156
lines changed

ThumbnailSelector.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export type ThumbnailSelectorProps = {
4646
animationConfig?: Animated.SpringAnimationConfig;
4747
flatListViewStyle?: ViewStyle;
4848
animatedViewTestID?: string;
49+
flatListTestID?: string;
4950
};
5051

5152
const ThumbnailSelector: React.FunctionComponent<ThumbnailSelectorProps> = ({
@@ -83,6 +84,7 @@ const ThumbnailSelector: React.FunctionComponent<ThumbnailSelectorProps> = ({
8384
},
8485
flatListViewStyle = { backgroundColor: 'grey', padding: 8 },
8586
animatedViewTestID = 'ThumbnailSelector',
87+
flatListTestID = 'thumbnail-selector-flatlist',
8688
}) => {
8789
const window = useWindowDimensions();
8890
const animatedValue = useAnimatedValue(
@@ -124,6 +126,7 @@ const ThumbnailSelector: React.FunctionComponent<ThumbnailSelectorProps> = ({
124126
return (
125127
<TouchableOpacity
126128
{...touchableOpacityProps}
129+
testID={`thumbnail-item-button-${index}`}
127130
onPress={() => {
128131
setItemIndex(index);
129132
if (onSelect) {
@@ -133,11 +136,16 @@ const ThumbnailSelector: React.FunctionComponent<ThumbnailSelectorProps> = ({
133136
>
134137
<Image
135138
{...imageProps}
139+
testID={`thumbnail-item-image-${index}`}
136140
style={[{ borderColor: color }, imageProps.style]}
137141
source={item.imageSrc}
138142
/>
139143
{caption && (
140-
<Text {...textProps} style={[{ color }, textProps.style]}>
144+
<Text
145+
{...textProps}
146+
testID={`thumbnail-item-text-${index}`}
147+
style={[{ color }, textProps.style]}
148+
>
141149
{caption}
142150
</Text>
143151
)}
@@ -177,6 +185,7 @@ const ThumbnailSelector: React.FunctionComponent<ThumbnailSelectorProps> = ({
177185
onLayout={_onLayout}
178186
>
179187
<FlatList
188+
testID={flatListTestID}
180189
style={flatListViewStyle}
181190
data={thumbnails}
182191
initialNumToRender={thumbnails.length}
Lines changed: 110 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,147 @@
11
import React, { act } from 'react';
2-
import { Text } from 'react-native';
3-
import {
4-
render,
5-
fireEvent,
6-
screen,
7-
cleanup,
8-
} from '@testing-library/react-native';
9-
import ThumbnailSelector, { ThumbnailItem } from '../ThumbnailSelector';
2+
import { View, Image, Text } from 'react-native';
3+
import { render, fireEvent, cleanup } from '@testing-library/react-native';
4+
import ThumbnailSelector, { type ThumbnailItem } from '../ThumbnailSelector';
105

116
describe('ThumbnailSelector', () => {
127
afterEach(cleanup);
138

14-
function _truncate(
15-
value: string,
16-
maxLength: number = 15,
17-
ellipsis: string = '...',
9+
function _getThumbnailItemTestId(
10+
type: 'button' | 'image' | 'text',
11+
index: number,
1812
): string {
19-
if (value.length > maxLength) {
20-
const end = maxLength - ellipsis.length;
21-
return `${value.substring(0, end)}${ellipsis}`;
22-
}
23-
return value;
13+
return `thumbnail-item-${type}-${index}`;
2414
}
2515

26-
const thumbnails = [
16+
const imageSrc = { uri: 'https://reactnative.dev/img/tiny_logo.png' };
17+
const thumbnails: ThumbnailItem[] = [
2718
{
28-
caption: 'react-native',
29-
imageSrc: { uri: 'https://reactnative.dev/img/tiny_logo.png' },
19+
caption: 'Caption 1',
20+
imageSrc,
3021
},
3122
{
32-
caption: 'New York City',
33-
imageSrc: { uri: 'https://reactnative.dev/img/tiny_logo.png' },
23+
caption: 'Caption 2',
24+
imageSrc,
3425
},
3526
{
36-
caption:
37-
'Elit cupidatat qui ea deserunt reprehenderit sit velit eu aliqua incididunt sit elit reprehenderit.',
38-
imageSrc: { uri: 'https://reactnative.dev/img/tiny_logo.png' },
27+
caption: 'Caption 3: this is a really long caption',
28+
imageSrc,
3929
},
4030
{
41-
imageSrc: { uri: 'https://reactnative.dev/img/tiny_logo.png' },
31+
imageSrc,
4232
},
4333
];
4434

45-
test('it renders', () => {
46-
const component = render(<ThumbnailSelector thumbnails={thumbnails} />);
47-
thumbnails.forEach(thumbnail => {
35+
function _testOnSelect(onSelect?: jest.Mock): void {
36+
const component = render(
37+
<ThumbnailSelector thumbnails={thumbnails} onSelect={onSelect} />,
38+
);
39+
const selector = component.getByTestId('ThumbnailSelector');
40+
expect(selector).toBeDefined();
41+
const flatlist = component.getByTestId('thumbnail-selector-flatlist');
42+
expect(flatlist).toBeDefined();
43+
44+
thumbnails.forEach((thumbnail, index) => {
45+
const button = component.getByTestId(
46+
_getThumbnailItemTestId('button', index),
47+
);
48+
expect(button).toBeDefined();
49+
expect(button).toBeOnTheScreen();
50+
51+
const image = component.getByTestId(
52+
_getThumbnailItemTestId('image', index),
53+
);
54+
expect(image).toBeDefined();
55+
expect(image).toBeOnTheScreen();
56+
expect(image).toHaveStyle({ borderColor: 'black' });
57+
58+
let text;
4859
if (thumbnail.caption) {
49-
const item = screen.getByText(_truncate(thumbnail.caption));
50-
expect(item).toBeDefined();
51-
fireEvent.press(item);
60+
text = component.getByTestId(_getThumbnailItemTestId('text', index));
61+
expect(text).toBeDefined();
62+
expect(text).toBeOnTheScreen();
63+
expect(text).toHaveStyle({ color: 'black' });
64+
}
65+
66+
fireEvent.press(button);
67+
expect(image).toHaveStyle({ borderColor: 'white' });
68+
if (text) {
69+
expect(text).toHaveStyle({ color: 'white' });
5270
}
5371
});
72+
if (onSelect) {
73+
expect(onSelect).toBeDefined();
74+
expect(onSelect).toHaveBeenCalledTimes(thumbnails.length);
75+
}
5476
expect(component.toJSON()).toMatchSnapshot();
77+
}
78+
79+
test('without onSelect prop', () => {
80+
_testOnSelect();
5581
});
5682

57-
test('onSelect prop', async () => {
58-
let toggle = () => {};
59-
const onSelect = jest.fn();
83+
test('with onSelect prop', () => {
84+
_testOnSelect(jest.fn());
85+
});
86+
87+
test('renderThumbnail prop', () => {
88+
const renderThumbnail = (item: ThumbnailItem, index: number) => {
89+
return (
90+
<View testID={`my-view-${index}`}>
91+
<Image testID={`my-image-${index}`} source={item.imageSrc} />
92+
<Text testID={`my-text-${index}`}>{item.caption}</Text>
93+
</View>
94+
);
95+
};
6096
const component = render(
6197
<ThumbnailSelector
6298
thumbnails={thumbnails}
63-
toggle={func => (toggle = func)}
64-
onSelect={onSelect}
99+
renderThumbnail={renderThumbnail}
65100
/>,
66101
);
67-
await act(async () => toggle());
68-
thumbnails.forEach((thumbnail, index) => {
69-
if (thumbnail.caption) {
70-
const item = screen.getByText(_truncate(thumbnail.caption));
71-
expect(item).toBeDefined();
72-
fireEvent.press(item);
73-
expect(onSelect).toHaveBeenCalledTimes(index + 1);
74-
}
102+
thumbnails.forEach((_thumbnail, index) => {
103+
const elements = [
104+
`my-view-${index}`,
105+
`my-image-${index}`,
106+
`my-text-${index}`,
107+
];
108+
elements.forEach(element => {
109+
const elementTestId = component.getByTestId(element);
110+
expect(elementTestId).toBeDefined();
111+
expect(elementTestId).toBeOnTheScreen();
112+
});
75113
});
76-
expect(component.toJSON()).toMatchSnapshot();
77114
});
78115

79-
test('renderThumbnail prop', async () => {
116+
test('toggle toValue 1', () => {
80117
let toggle = () => {};
81-
const renderThumbnail = (item: ThumbnailItem, index: number) => {
82-
return <Text testID={`${index}`}>{item.caption}</Text>;
83-
};
84118
render(
85119
<ThumbnailSelector
86120
thumbnails={thumbnails}
87121
toggle={func => (toggle = func)}
88-
renderThumbnail={renderThumbnail}
122+
animationConfig={{
123+
toValue: 1,
124+
useNativeDriver: false,
125+
}}
89126
/>,
90127
);
91-
await act(async () => toggle());
92-
thumbnails.forEach((thumbnail, index) => {
93-
if (thumbnail.caption) {
94-
const itemText = screen.getByText(thumbnail.caption);
95-
expect(itemText).toBeDefined();
96-
}
97-
const itemTestId = screen.getByTestId(`${index}`);
98-
expect(itemTestId).toBeDefined();
99-
});
100-
await act(async () => toggle());
128+
act(() => toggle());
101129
});
102130

103-
test('onLayout', () => {
104-
render(<ThumbnailSelector thumbnails={thumbnails} />);
131+
test('toggle toValue 0', () => {
132+
let toggle = () => {};
133+
render(
134+
<ThumbnailSelector
135+
thumbnails={thumbnails}
136+
toggle={func => (toggle = func)}
137+
/>,
138+
);
139+
act(() => toggle());
140+
});
105141

106-
const selector = screen.getByTestId('ThumbnailSelector');
142+
test('onLayout', () => {
143+
const component = render(<ThumbnailSelector thumbnails={thumbnails} />);
144+
const selector = component.getByTestId('ThumbnailSelector');
107145
expect(selector).toBeDefined();
108146

109147
fireEvent(selector, 'layout', {
@@ -117,21 +155,14 @@ describe('ThumbnailSelector', () => {
117155

118156
test('no thumbnails', () => {
119157
const component = render(<ThumbnailSelector thumbnails={[]} />);
120-
thumbnails.forEach(thumbnail => {
121-
if (thumbnail.caption) {
122-
const text = _truncate(thumbnail.caption);
123-
try {
124-
screen.getByText(text);
125-
} catch (error: unknown) {
126-
expect(error).toBeDefined();
127-
if (error instanceof Error) {
128-
expect(error).toBeInstanceOf(Error);
129-
const partialErrorMessage = `Unable to find an element with text: ${text}`;
130-
expect(error.message).toContain(partialErrorMessage);
131-
}
132-
}
133-
}
134-
});
158+
const selector = component.getByTestId('ThumbnailSelector');
159+
expect(selector).toBeDefined();
160+
161+
const flatlist = component.getByTestId('thumbnail-selector-flatlist');
162+
expect(flatlist).toBeDefined();
163+
expect(flatlist.props.data).toStrictEqual([]);
164+
expect(flatlist.props.initialNumToRender).toStrictEqual(0);
165+
135166
expect(component.toJSON()).toMatchSnapshot();
136167
});
137168
});

0 commit comments

Comments
 (0)