0
# Configuration and Setup
1
2
Global configuration options and setup utilities for customizing React Native Testing Library behavior across your test suite, including async timeouts, debugging options, and rendering modes.
3
4
## Capabilities
5
6
### Global Configuration
7
8
Configure library-wide settings that affect all tests in your suite.
9
10
```typescript { .api }
11
/**
12
* Configure global options for React Native Testing Library
13
* @param options - Configuration options to apply
14
*/
15
function configure(options: Partial<Config & ConfigAliasOptions>): void;
16
17
/**
18
* Reset all configuration to default values
19
*/
20
function resetToDefaults(): void;
21
22
/**
23
* Get current configuration settings
24
* @returns Current configuration object
25
*/
26
function getConfig(): Config;
27
28
interface Config {
29
/** Default timeout in milliseconds for waitFor and findBy queries */
30
asyncUtilTimeout: number;
31
32
/** Default value for includeHiddenElements query option */
33
defaultIncludeHiddenElements: boolean;
34
35
/** Default options for debug helper function */
36
defaultDebugOptions?: Partial<DebugOptions>;
37
38
/** Enable/disable concurrent rendering by default */
39
concurrentRoot: boolean;
40
}
41
42
interface ConfigAliasOptions {
43
/** Alias for defaultIncludeHiddenElements (RTL compatibility) */
44
defaultHidden: boolean;
45
}
46
47
interface DebugOptions {
48
/** Function to transform props before displaying */
49
mapProps?: (props: Record<string, any>) => Record<string, any>;
50
51
/** Maximum length of debug output */
52
maxLength?: number;
53
}
54
```
55
56
**Usage Examples:**
57
58
```typescript
59
import { configure, resetToDefaults, getConfig } from "@testing-library/react-native";
60
61
describe("configuration examples", () => {
62
afterEach(() => {
63
// Reset to defaults after each test
64
resetToDefaults();
65
});
66
67
test("async timeout configuration", async () => {
68
// Set longer timeout for slow components
69
configure({ asyncUtilTimeout: 5000 });
70
71
const SlowComponent = () => {
72
const [loaded, setLoaded] = useState(false);
73
74
useEffect(() => {
75
setTimeout(() => setLoaded(true), 3000);
76
}, []);
77
78
return loaded ? <Text>Loaded</Text> : <Text>Loading...</Text>;
79
};
80
81
render(<SlowComponent />);
82
83
// This will use the configured 5 second timeout
84
await screen.findByText("Loaded");
85
86
// Verify configuration was applied
87
expect(getConfig().asyncUtilTimeout).toBe(5000);
88
});
89
90
test("hidden elements configuration", () => {
91
// Include hidden elements by default
92
configure({ defaultIncludeHiddenElements: true });
93
94
render(
95
<View>
96
<Text>Visible text</Text>
97
<Text style={{ opacity: 0 }}>Hidden text</Text>
98
<View accessibilityElementsHidden>
99
<Text>Accessibility hidden</Text>
100
</View>
101
</View>
102
);
103
104
// These queries will now include hidden elements by default
105
const allTexts = screen.getAllByText(/text/);
106
expect(allTexts.length).toBeGreaterThan(1);
107
108
// Can still override per query
109
const visibleOnly = screen.getAllByText(/text/, {
110
includeHiddenElements: false
111
});
112
expect(visibleOnly.length).toBeLessThan(allTexts.length);
113
});
114
115
test("debug options configuration", () => {
116
// Configure debug output
117
configure({
118
defaultDebugOptions: {
119
maxLength: 500,
120
mapProps: (props) => ({
121
...props,
122
// Hide functions in debug output
123
onPress: props.onPress ? "[Function]" : undefined,
124
style: "[Style Object]"
125
})
126
}
127
});
128
129
const MyComponent = () => (
130
<Pressable
131
onPress={() => {}}
132
style={{ backgroundColor: "blue" }}
133
>
134
<Text>Debug me</Text>
135
</Pressable>
136
);
137
138
const { debug } = render(<MyComponent />);
139
140
// Debug will use configured options
141
debug(); // Output will show "[Function]" instead of actual function
142
});
143
144
test("concurrent rendering configuration", () => {
145
// Disable concurrent rendering globally
146
configure({ concurrentRoot: false });
147
148
const AsyncComponent = () => {
149
const [value, setValue] = useState("initial");
150
151
useEffect(() => {
152
setValue("updated");
153
}, []);
154
155
return <Text>{value}</Text>;
156
};
157
158
// This will use legacy rendering mode
159
render(<AsyncComponent />);
160
161
expect(screen.getByText("updated")).toBeOnTheScreen();
162
expect(getConfig().concurrentRoot).toBe(false);
163
});
164
165
test("RTL compatibility aliases", () => {
166
// Using RTL-style alias
167
configure({ defaultHidden: true });
168
169
// Should set defaultIncludeHiddenElements
170
expect(getConfig().defaultIncludeHiddenElements).toBe(true);
171
});
172
});
173
```
174
175
### Test Environment Setup
176
177
Configuration patterns for different test environments and frameworks.
178
179
```typescript { .api }
180
/**
181
* Environment-specific setup utilities
182
*/
183
```
184
185
**Usage Examples:**
186
187
```typescript
188
// jest.config.js or test setup file
189
import { configure } from "@testing-library/react-native";
190
191
// Global test suite configuration
192
configure({
193
// Longer timeout for integration tests
194
asyncUtilTimeout: 2000,
195
196
// Include hidden elements for comprehensive testing
197
defaultIncludeHiddenElements: false,
198
199
// Enable concurrent rendering for modern React features
200
concurrentRoot: true,
201
202
// Clean debug output
203
defaultDebugOptions: {
204
maxLength: 1000,
205
mapProps: (props) => {
206
const cleaned = { ...props };
207
208
// Hide complex objects for cleaner output
209
Object.keys(cleaned).forEach(key => {
210
if (typeof cleaned[key] === "function") {
211
cleaned[key] = "[Function]";
212
} else if (key === "style" && typeof cleaned[key] === "object") {
213
cleaned[key] = "[Style]";
214
}
215
});
216
217
return cleaned;
218
}
219
}
220
});
221
222
// Project-specific setup
223
test("project configuration", () => {
224
// Configuration for React Native Paper components
225
configure({
226
defaultDebugOptions: {
227
mapProps: (props) => ({
228
...props,
229
// Paper-specific props cleanup
230
theme: props.theme ? "[Theme]" : undefined,
231
contentStyle: props.contentStyle ? "[Style]" : undefined
232
})
233
}
234
});
235
236
const PaperButton = () => (
237
<Button mode="contained" onPress={() => {}}>
238
Paper Button
239
</Button>
240
);
241
242
const { debug } = render(<PaperButton />);
243
debug(); // Clean output without theme object details
244
});
245
```
246
247
### Auto-Cleanup Configuration
248
249
Configuration for automatic test cleanup behavior.
250
251
```typescript { .api }
252
/**
253
* Auto-cleanup configuration via environment variables and imports
254
*/
255
256
// Standard import with auto-cleanup
257
import { render } from "@testing-library/react-native";
258
259
// Pure import without auto-cleanup
260
import { render } from "@testing-library/react-native/pure";
261
262
// Environment variable to disable auto-cleanup
263
// Set RNTL_SKIP_AUTO_CLEANUP=true to disable automatic cleanup
264
```
265
266
**Usage Examples:**
267
268
```typescript
269
// Standard usage with auto-cleanup (default)
270
describe("auto-cleanup enabled", () => {
271
test("first test", () => {
272
render(<Text>First test</Text>);
273
expect(screen.getByText("First test")).toBeOnTheScreen();
274
// Automatic cleanup happens after this test
275
});
276
277
test("second test", () => {
278
// Screen is clean from previous test
279
render(<Text>Second test</Text>);
280
expect(screen.getByText("Second test")).toBeOnTheScreen();
281
expect(screen.queryByText("First test")).not.toBeOnTheScreen();
282
});
283
});
284
285
// Manual cleanup control
286
describe("manual cleanup control", () => {
287
// Import pure version
288
const { render, cleanup } = require("@testing-library/react-native/pure");
289
290
afterEach(() => {
291
// Manual cleanup after each test
292
cleanup();
293
});
294
295
test("controlled cleanup", () => {
296
render(<Text>Controlled test</Text>);
297
expect(screen.getByText("Controlled test")).toBeOnTheScreen();
298
299
// Could do additional cleanup here if needed
300
cleanup();
301
302
// Screen is now clean
303
expect(screen.queryByText("Controlled test")).not.toBeOnTheScreen();
304
});
305
});
306
307
// Environment variable configuration
308
describe("environment-based cleanup", () => {
309
const originalEnv = process.env.RNTL_SKIP_AUTO_CLEANUP;
310
311
afterAll(() => {
312
// Restore original environment
313
if (originalEnv !== undefined) {
314
process.env.RNTL_SKIP_AUTO_CLEANUP = originalEnv;
315
} else {
316
delete process.env.RNTL_SKIP_AUTO_CLEANUP;
317
}
318
});
319
320
test("disable auto-cleanup via environment", () => {
321
// This would typically be set in test environment configuration
322
process.env.RNTL_SKIP_AUTO_CLEANUP = "true";
323
324
// Re-import would be needed to pick up env change
325
// In practice, this is set before importing the library
326
327
render(<Text>No auto cleanup</Text>);
328
// Manual cleanup required when env var is set
329
});
330
});
331
```
332
333
### Debug Configuration
334
335
Advanced debugging configuration for test development and troubleshooting.
336
337
```typescript { .api }
338
/**
339
* Debug configuration options
340
*/
341
interface DebugOptions {
342
/** Transform props before displaying */
343
mapProps?: (props: Record<string, any>) => Record<string, any>;
344
345
/** Maximum length of debug output */
346
maxLength?: number;
347
}
348
349
/**
350
* Debug function type
351
*/
352
interface DebugFunction {
353
(element?: ReactTestInstance, maxLength?: number, options?: DebugOptions): void;
354
}
355
```
356
357
**Usage Examples:**
358
359
```typescript
360
test("debug configuration examples", () => {
361
// Component with complex props
362
const ComplexComponent = () => (
363
<View>
364
<Pressable
365
onPress={() => console.log("pressed")}
366
style={{
367
backgroundColor: "blue",
368
padding: 10,
369
borderRadius: 5
370
}}
371
testID="complex-button"
372
>
373
<Text>Complex Button</Text>
374
</Pressable>
375
<FlatList
376
data={[1, 2, 3]}
377
renderItem={({ item }) => <Text key={item}>Item {item}</Text>}
378
keyExtractor={(item) => item.toString()}
379
/>
380
</View>
381
);
382
383
const { debug } = render(<ComplexComponent />);
384
385
// Default debug output (might be verbose)
386
debug();
387
388
// Limited length debug
389
debug(undefined, 200);
390
391
// Custom props mapping
392
debug(undefined, undefined, {
393
mapProps: (props) => ({
394
...props,
395
// Simplify complex props
396
onPress: props.onPress ? "[Function]" : undefined,
397
style: props.style ? "[Style Object]" : undefined,
398
data: props.data ? `[Array of ${props.data.length}]` : undefined,
399
renderItem: props.renderItem ? "[Render Function]" : undefined
400
})
401
});
402
403
// Debug specific element
404
const button = screen.getByTestId("complex-button");
405
debug(button, 500, {
406
mapProps: (props) => ({
407
testID: props.testID,
408
onPress: "[Function]",
409
style: "[Simplified]"
410
})
411
});
412
});
413
414
test("debug configuration per test suite", () => {
415
// Suite-specific debug configuration
416
const originalConfig = getConfig();
417
418
configure({
419
defaultDebugOptions: {
420
maxLength: 300,
421
mapProps: (props) => {
422
// Project-specific prop cleaning
423
return Object.keys(props).reduce((clean, key) => {
424
if (key.startsWith("accessibility")) {
425
clean[key] = props[key];
426
} else if (typeof props[key] === "function") {
427
clean[key] = `[${key}Function]`;
428
} else if (key === "children" && Array.isArray(props[key])) {
429
clean[key] = `[${props[key].length} children]`;
430
} else {
431
clean[key] = props[key];
432
}
433
return clean;
434
}, {});
435
}
436
}
437
});
438
439
const TestComponent = () => (
440
<View accessibilityLabel="Test container">
441
<Text>Child 1</Text>
442
<Text>Child 2</Text>
443
<Pressable onPress={() => {}} accessibilityRole="button">
444
<Text>Button</Text>
445
</Pressable>
446
</View>
447
);
448
449
const { debug } = render(<TestComponent />);
450
451
// Uses configured debug options
452
debug();
453
454
// Restore original config
455
configure(originalConfig);
456
});
457
```
458
459
### Performance Configuration
460
461
Configuration options for optimizing test performance.
462
463
```typescript { .api }
464
/**
465
* Performance-related configuration
466
*/
467
```
468
469
**Usage Examples:**
470
471
```typescript
472
describe("performance configuration", () => {
473
test("optimized for fast tests", () => {
474
configure({
475
// Shorter timeout for unit tests
476
asyncUtilTimeout: 500,
477
478
// Disable concurrent rendering for predictable timing
479
concurrentRoot: false,
480
481
// Minimal debug output
482
defaultDebugOptions: {
483
maxLength: 100,
484
mapProps: (props) => ({ testID: props.testID })
485
}
486
});
487
488
const FastComponent = () => {
489
const [value, setValue] = useState("initial");
490
491
useEffect(() => {
492
// Fast update
493
setTimeout(() => setValue("updated"), 10);
494
}, []);
495
496
return <Text testID="fast-text">{value}</Text>;
497
};
498
499
render(<FastComponent />);
500
501
// Fast assertion with short timeout
502
return screen.findByText("updated");
503
});
504
505
test("optimized for integration tests", () => {
506
configure({
507
// Longer timeout for complex interactions
508
asyncUtilTimeout: 10000,
509
510
// Enable concurrent rendering for realistic testing
511
concurrentRoot: true,
512
513
// Include hidden elements for comprehensive testing
514
defaultIncludeHiddenElements: true,
515
516
// Detailed debug output for troubleshooting
517
defaultDebugOptions: {
518
maxLength: 2000
519
}
520
});
521
522
const IntegrationComponent = () => {
523
const [loading, setLoading] = useState(true);
524
const [data, setData] = useState(null);
525
526
useEffect(() => {
527
// Simulate slow API call
528
setTimeout(() => {
529
setData("Integration data");
530
setLoading(false);
531
}, 1000);
532
}, []);
533
534
return loading ? (
535
<Text>Loading integration test...</Text>
536
) : (
537
<Text testID="integration-result">{data}</Text>
538
);
539
};
540
541
render(<IntegrationComponent />);
542
543
// Long timeout for integration test
544
return screen.findByTestId("integration-result");
545
});
546
547
test("memory-conscious configuration", () => {
548
configure({
549
// Compact debug output to reduce memory usage
550
defaultDebugOptions: {
551
maxLength: 50,
552
mapProps: () => ({ "[props]": "..." }) // Minimal prop display
553
}
554
});
555
556
// Large component tree
557
const LargeComponent = () => (
558
<View>
559
{Array.from({ length: 100 }, (_, i) => (
560
<Text key={i} testID={`item-${i}`}>
561
Item {i}
562
</Text>
563
))}
564
</View>
565
);
566
567
const { debug } = render(<LargeComponent />);
568
569
// Compact debug output
570
debug();
571
572
// Test still works normally
573
expect(screen.getByTestId("item-0")).toBeOnTheScreen();
574
expect(screen.getByTestId("item-99")).toBeOnTheScreen();
575
});
576
});
577
```
578
579
### Environment Detection and Adaptation
580
581
Configuration that adapts to different testing environments.
582
583
```typescript { .api }
584
/**
585
* Environment-aware configuration
586
*/
587
```
588
589
**Usage Examples:**
590
591
```typescript
592
// Test environment detection and configuration
593
describe("environment-aware configuration", () => {
594
test("CI environment configuration", () => {
595
const isCI = process.env.CI === "true";
596
597
configure({
598
// Longer timeouts in CI environments
599
asyncUtilTimeout: isCI ? 10000 : 2000,
600
601
// Disable concurrent rendering in CI for stability
602
concurrentRoot: !isCI,
603
604
// More verbose debugging in CI
605
defaultDebugOptions: {
606
maxLength: isCI ? 5000 : 1000
607
}
608
});
609
610
const EnvironmentComponent = () => {
611
const [env, setEnv] = useState("unknown");
612
613
useEffect(() => {
614
// Simulate environment detection
615
setTimeout(() => {
616
setEnv(isCI ? "CI" : "local");
617
}, isCI ? 500 : 100);
618
}, []);
619
620
return <Text testID="env-indicator">Environment: {env}</Text>;
621
};
622
623
render(<EnvironmentComponent />);
624
625
// Timeout will be appropriate for environment
626
return screen.findByText(/Environment: (CI|local)/);
627
});
628
629
test("jest environment configuration", () => {
630
const isJest = typeof jest !== "undefined";
631
632
if (isJest) {
633
configure({
634
defaultDebugOptions: {
635
mapProps: (props) => ({
636
...props,
637
// Jest-specific prop handling
638
onPress: props.onPress ? "[Jest Mock Function]" : undefined
639
})
640
}
641
});
642
}
643
644
const JestComponent = () => {
645
const mockFn = isJest ? jest.fn() : () => {};
646
647
return (
648
<Pressable onPress={mockFn} testID="jest-button">
649
<Text>Jest Button</Text>
650
</Pressable>
651
);
652
};
653
654
const { debug } = render(<JestComponent />);
655
656
if (isJest) {
657
debug(); // Will show "[Jest Mock Function]"
658
}
659
660
expect(screen.getByTestId("jest-button")).toBeOnTheScreen();
661
});
662
663
test("development vs production configuration", () => {
664
const isDev = process.env.NODE_ENV !== "production";
665
666
configure({
667
defaultDebugOptions: {
668
maxLength: isDev ? 2000 : 500,
669
mapProps: isDev
670
? undefined // Full props in development
671
: (props) => ({ testID: props.testID }) // Minimal in production
672
}
673
});
674
675
const DevComponent = () => (
676
<View
677
testID="dev-component"
678
style={{ padding: 10 }}
679
accessibilityLabel="Development component"
680
>
681
<Text>Development Component</Text>
682
</View>
683
);
684
685
const { debug } = render(<DevComponent />);
686
687
// Debug verbosity depends on environment
688
debug();
689
690
expect(screen.getByTestId("dev-component")).toBeOnTheScreen();
691
});
692
});
693
```