Skip to content

Commit d372c4c

Browse files
committed
test(lists): sanitize snapshots by removing _owner
- Add removeOwner helper to strip _owner property causing recursion and breaking tests - Update FlatList, VirtualizedList, and SectionList - Sanitize test snapshots to prevent unstable tests
1 parent 2f4e821 commit d372c4c

6 files changed

Lines changed: 754 additions & 488 deletions

File tree

packages/react-native/Libraries/Lists/__tests__/FlatList-test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ const {create} = require('@react-native/jest-preset/jest/renderer');
1515
const React = require('react');
1616
const {createRef} = require('react');
1717

18+
function removeOwner(obj) {
19+
if (obj === null || typeof obj !== 'object') return obj;
20+
if (Array.isArray(obj)) return obj.map(removeOwner);
21+
22+
const result = {};
23+
for (const key of Object.keys(obj)) {
24+
if (key === '_owner') continue;
25+
result[key] = removeOwner(obj[key]);
26+
}
27+
return result;
28+
}
29+
1830
describe('FlatList', () => {
1931
it('renders simple list', async () => {
2032
const component = await create(
@@ -95,7 +107,7 @@ describe('FlatList', () => {
95107
renderItem={({item}) => <item value={item.id} />}
96108
/>,
97109
);
98-
expect(component).toMatchSnapshot();
110+
expect(removeOwner(component.toJSON())).toMatchSnapshot();
99111
});
100112
it('getNativeScrollRef for case where it returns a native view', async () => {
101113
jest.resetModules();

packages/react-native/Libraries/Lists/__tests__/__snapshots__/FlatList-test.js.snap

Lines changed: 186 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,155 @@ exports[`FlatList ignores invalid data 1`] = `
6060
`;
6161

6262
exports[`FlatList renders all the bells and whistles 1`] = `
63-
<RCTScrollView
64-
ItemSeparatorComponent={[Function]}
65-
ListEmptyComponent={[Function]}
66-
ListFooterComponent={[Function]}
67-
ListHeaderComponent={[Function]}
68-
data={
69-
Array [
63+
Object {
64+
"children": Array [
65+
Object {
66+
"children": null,
67+
"props": Object {},
68+
"type": "RCTRefreshControl",
69+
},
70+
Object {
71+
"children": Array [
72+
Object {
73+
"children": Array [
74+
Object {
75+
"children": null,
76+
"props": Object {},
77+
"type": "header",
78+
},
79+
],
80+
"props": Object {
81+
"collapsable": false,
82+
"onLayout": [Function],
83+
},
84+
"type": "View",
85+
},
86+
Object {
87+
"children": Array [
88+
Object {
89+
"children": Array [
90+
Object {
91+
"children": null,
92+
"props": Object {
93+
"value": "0",
94+
},
95+
"type": "item",
96+
},
97+
Object {
98+
"children": null,
99+
"props": Object {
100+
"value": "1",
101+
},
102+
"type": "item",
103+
},
104+
],
105+
"props": Object {
106+
"style": Object {
107+
"flexDirection": "row",
108+
},
109+
},
110+
"type": "View",
111+
},
112+
Object {
113+
"children": null,
114+
"props": Object {},
115+
"type": "separator",
116+
},
117+
],
118+
"props": Object {
119+
"onFocusCapture": [Function],
120+
"style": null,
121+
},
122+
"type": "View",
123+
},
124+
Object {
125+
"children": Array [
126+
Object {
127+
"children": Array [
128+
Object {
129+
"children": null,
130+
"props": Object {
131+
"value": "2",
132+
},
133+
"type": "item",
134+
},
135+
Object {
136+
"children": null,
137+
"props": Object {
138+
"value": "3",
139+
},
140+
"type": "item",
141+
},
142+
],
143+
"props": Object {
144+
"style": Object {
145+
"flexDirection": "row",
146+
},
147+
},
148+
"type": "View",
149+
},
150+
Object {
151+
"children": null,
152+
"props": Object {},
153+
"type": "separator",
154+
},
155+
],
156+
"props": Object {
157+
"onFocusCapture": [Function],
158+
"style": null,
159+
},
160+
"type": "View",
161+
},
162+
Object {
163+
"children": Array [
164+
Object {
165+
"children": Array [
166+
Object {
167+
"children": null,
168+
"props": Object {
169+
"value": "4",
170+
},
171+
"type": "item",
172+
},
173+
],
174+
"props": Object {
175+
"style": Object {
176+
"flexDirection": "row",
177+
},
178+
},
179+
"type": "View",
180+
},
181+
],
182+
"props": Object {
183+
"onFocusCapture": [Function],
184+
"style": null,
185+
},
186+
"type": "View",
187+
},
188+
Object {
189+
"children": Array [
190+
Object {
191+
"children": null,
192+
"props": Object {},
193+
"type": "footer",
194+
},
195+
],
196+
"props": Object {
197+
"onLayout": [Function],
198+
},
199+
"type": "View",
200+
},
201+
],
202+
"props": Object {},
203+
"type": "View",
204+
},
205+
],
206+
"props": Object {
207+
"ItemSeparatorComponent": [Function],
208+
"ListEmptyComponent": [Function],
209+
"ListFooterComponent": [Function],
210+
"ListHeaderComponent": [Function],
211+
"data": Array [
70212
Object {
71213
"id": "0",
72214
},
@@ -82,104 +224,43 @@ exports[`FlatList renders all the bells and whistles 1`] = `
82224
Object {
83225
"id": "4",
84226
},
85-
]
86-
}
87-
getItem={[Function]}
88-
getItemCount={[Function]}
89-
getItemLayout={[Function]}
90-
keyExtractor={[Function]}
91-
onContentSizeChange={[Function]}
92-
onLayout={[Function]}
93-
onMomentumScrollBegin={[Function]}
94-
onMomentumScrollEnd={[Function]}
95-
onRefresh={[MockFunction]}
96-
onScroll={[Function]}
97-
onScrollBeginDrag={[Function]}
98-
onScrollEndDrag={[Function]}
99-
refreshControl={
100-
<RefreshControlMock
101-
onRefresh={[MockFunction]}
102-
refreshing={false}
103-
/>
104-
}
105-
refreshing={false}
106-
removeClippedSubviews={false}
107-
renderItem={[Function]}
108-
scrollEventThrottle={0.0001}
109-
stickyHeaderIndices={Array []}
110-
viewabilityConfigCallbackPairs={Array []}
111-
>
112-
<RCTRefreshControl />
113-
<View>
114-
<View
115-
collapsable={false}
116-
onLayout={[Function]}
117-
>
118-
<header />
119-
</View>
120-
<View
121-
onFocusCapture={[Function]}
122-
style={null}
123-
>
124-
<View
125-
style={
126-
Object {
127-
"flexDirection": "row",
128-
}
129-
}
130-
>
131-
<item
132-
value="0"
133-
/>
134-
<item
135-
value="1"
136-
/>
137-
</View>
138-
<separator />
139-
</View>
140-
<View
141-
onFocusCapture={[Function]}
142-
style={null}
143-
>
144-
<View
145-
style={
146-
Object {
147-
"flexDirection": "row",
148-
}
149-
}
150-
>
151-
<item
152-
value="2"
153-
/>
154-
<item
155-
value="3"
156-
/>
157-
</View>
158-
<separator />
159-
</View>
160-
<View
161-
onFocusCapture={[Function]}
162-
style={null}
163-
>
164-
<View
165-
style={
166-
Object {
167-
"flexDirection": "row",
168-
}
169-
}
170-
>
171-
<item
172-
value="4"
173-
/>
174-
</View>
175-
</View>
176-
<View
177-
onLayout={[Function]}
178-
>
179-
<footer />
180-
</View>
181-
</View>
182-
</RCTScrollView>
227+
],
228+
"getItem": [Function],
229+
"getItemCount": [Function],
230+
"getItemLayout": [Function],
231+
"invertStickyHeaders": undefined,
232+
"isInvertedVirtualizedList": undefined,
233+
"keyExtractor": [Function],
234+
"maintainVisibleContentPosition": undefined,
235+
"onContentSizeChange": [Function],
236+
"onLayout": [Function],
237+
"onMomentumScrollBegin": [Function],
238+
"onMomentumScrollEnd": [Function],
239+
"onRefresh": [MockFunction],
240+
"onScroll": [Function],
241+
"onScrollBeginDrag": [Function],
242+
"onScrollEndDrag": [Function],
243+
"refreshControl": Object {
244+
"$$typeof": Symbol(react.transitional.element),
245+
"_store": Object {},
246+
"key": null,
247+
"props": Object {
248+
"onRefresh": [MockFunction],
249+
"progressViewOffset": undefined,
250+
"refreshing": false,
251+
},
252+
"type": [Function],
253+
},
254+
"refreshing": false,
255+
"removeClippedSubviews": false,
256+
"renderItem": [Function],
257+
"scrollEventThrottle": 0.0001,
258+
"stickyHeaderIndices": Array [],
259+
"style": undefined,
260+
"viewabilityConfigCallbackPairs": Array [],
261+
},
262+
"type": "RCTScrollView",
263+
}
183264
`;
184265

185266
exports[`FlatList renders array-like data 1`] = `

packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ import {format} from 'util';
1616

1717
jest.useFakeTimers();
1818

19+
function removeOwner(obj) {
20+
if (obj === null || typeof obj !== 'object') return obj;
21+
if (Array.isArray(obj)) return obj.map(removeOwner);
22+
23+
const result = {};
24+
for (const key of Object.keys(obj)) {
25+
if (key === '_owner') continue;
26+
result[key] = removeOwner(obj[key]);
27+
}
28+
return result;
29+
}
30+
1931
const skipTestSilenceLinter = it.skip;
2032

2133
describe('VirtualizedList', () => {
@@ -233,7 +245,7 @@ describe('VirtualizedList', () => {
233245
/>,
234246
);
235247
});
236-
expect(component).toMatchSnapshot();
248+
expect(removeOwner(component.toJSON())).toMatchSnapshot();
237249
});
238250

239251
it('test getItem functionality where data is not an Array', async () => {

packages/virtualized-lists/Lists/__tests__/VirtualizedSectionList-test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ const VirtualizedSectionList = require('../VirtualizedSectionList').default;
1818
const React = require('react');
1919
const ReactTestRenderer = require('react-test-renderer');
2020

21+
function removeOwner(obj) {
22+
if (obj === null || typeof obj !== 'object') return obj;
23+
if (Array.isArray(obj)) return obj.map(removeOwner);
24+
25+
const result = {};
26+
for (const key of Object.keys(obj)) {
27+
if (key === '_owner') continue;
28+
result[key] = removeOwner(obj[key]);
29+
}
30+
return result;
31+
}
32+
2133
describe('VirtualizedSectionList', () => {
2234
it('renders simple list', async () => {
2335
let component;
@@ -122,7 +134,7 @@ describe('VirtualizedSectionList', () => {
122134
/>,
123135
);
124136
});
125-
expect(component).toMatchSnapshot();
137+
expect(removeOwner(component.toJSON())).toMatchSnapshot();
126138
});
127139

128140
it('handles separators correctly', async () => {

0 commit comments

Comments
 (0)