0
# React Server Components (RSC)
1
2
Jest Expo provides comprehensive testing support for React Server Components, including specialized presets, utilities for rendering RSC to flight data, and custom Jest matchers for validating RSC output.
3
4
## Capabilities
5
6
### RSC Presets
7
8
Specialized Jest preset configurations for testing React Server Components across different platforms.
9
10
#### RSC Universal Preset
11
12
```javascript { .api }
13
// In package.json or jest.config.js
14
{
15
"jest": {
16
"preset": "jest-expo/rsc"
17
}
18
}
19
```
20
21
**Features:**
22
- Multi-platform RSC testing for iOS, Android, and web
23
- React Server Component testing mode enabled
24
- Prettier snapshot formatting for RSC flight data
25
- Specialized setup for Node.js web APIs (Blob, File, ReadableStream)
26
27
#### Platform-Specific RSC Presets
28
29
```javascript { .api }
30
// Available RSC platform presets
31
"jest-expo/rsc/ios" // RSC iOS testing preset
32
"jest-expo/rsc/android" // RSC Android testing preset
33
"jest-expo/rsc/web" // RSC web testing preset
34
```
35
36
**RSC iOS Preset:**
37
- React Native test environment with RSC enabled
38
- iOS-specific snapshot resolver (`.rsc.ios.snap` files)
39
- Platform set to `ios` with React Server Component mode
40
- Uses `getIOSPreset({ isReactServer: true })`
41
42
**RSC Android Preset:**
43
- React Native test environment with RSC enabled
44
- Android-specific snapshot resolver (`.rsc.android.snap` files)
45
- Platform set to `android` with React Server Component mode
46
- Uses `getAndroidPreset({ isReactServer: true })`
47
48
**RSC Web Preset:**
49
- jsdom test environment with RSC enabled
50
- Web-specific snapshot resolver (`.rsc.web.snap` files)
51
- Platform set to `web` with React Server Component mode
52
- Uses `getWebPreset({ isReactServer: true })`
53
54
**Common RSC Features:**
55
- All presets run in Node.js test environment for RSC compatibility
56
- Test path filters to only run `__rsc_tests__` directories
57
- RSC-specific Babel transforms and bundler configurations
58
- Custom expect matchers for RSC flight data validation
59
60
### RSC Utilities
61
62
Core utilities for rendering React Server Components to flight data format for testing.
63
64
#### Stream to String
65
66
```javascript { .api }
67
/**
68
* Convert ReadableStream to string for testing
69
* @param stream - ReadableStream to convert
70
* @returns Promise that resolves to string content
71
*/
72
function streamToString(stream: ReadableStream): Promise<string>;
73
```
74
75
**Usage Example:**
76
77
```javascript
78
import { streamToString } from "jest-expo/src/rsc-utils";
79
80
test("stream conversion", async () => {
81
const stream = new ReadableStream({
82
start(controller) {
83
controller.enqueue("Hello");
84
controller.enqueue(" World");
85
controller.close();
86
}
87
});
88
89
const result = await streamToString(stream);
90
expect(result).toBe("Hello World");
91
});
92
```
93
94
#### Render JSX to Flight String
95
96
```javascript { .api }
97
/**
98
* Render JSX to RSC payload string
99
* @param jsx - React element to render
100
* @param throwOnError - Whether to throw errors during rendering
101
* @returns Promise that resolves to RSC flight string
102
*/
103
function renderJsxToFlightStringAsync(
104
jsx: React.ReactNode,
105
throwOnError?: boolean
106
): Promise<string>;
107
```
108
109
**Usage Example:**
110
111
```javascript
112
import { renderJsxToFlightStringAsync } from "jest-expo/src/rsc-utils";
113
114
test("RSC rendering", async () => {
115
const element = <div>Hello RSC</div>;
116
const flightString = await renderJsxToFlightStringAsync(element);
117
118
expect(flightString).toContain('"type":"div"');
119
expect(flightString).toContain('Hello RSC');
120
});
121
```
122
123
#### Render JSX to ReadableStream
124
125
```javascript { .api }
126
/**
127
* Render JSX to RSC ReadableStream
128
* @param jsx - React element to render
129
* @param options - Rendering options
130
* @returns Object containing ReadableStream and client boundaries
131
*/
132
function renderJsxToReadableStream(
133
jsx: React.ReactNode,
134
options?: RSCRenderOptions
135
): RSCRenderResult;
136
137
interface RSCRenderOptions {
138
onError?: (error: Error) => void;
139
}
140
141
interface RSCRenderResult {
142
stream: ReadableStream;
143
clientBoundaries: string[];
144
}
145
```
146
147
**Usage Example:**
148
149
```javascript
150
import { renderJsxToReadableStream, streamToString } from "jest-expo/src/rsc-utils";
151
152
test("RSC stream rendering", async () => {
153
const element = <div>Streaming RSC</div>;
154
const { stream, clientBoundaries } = renderJsxToReadableStream(element);
155
const result = await streamToString(stream);
156
157
expect(result).toContain("Streaming RSC");
158
expect(clientBoundaries).toEqual([]);
159
});
160
```
161
162
### RSC Jest Matchers
163
164
Custom Jest matchers specifically designed for testing React Server Components flight data.
165
166
#### toMatchFlight
167
168
```javascript { .api }
169
/**
170
* Compare RSC flight data to expected string
171
* @param expectedFlight - Expected RSC flight string
172
*/
173
expect(data: React.ReactNode | ReadableStream).toMatchFlight(expectedFlight: string);
174
```
175
176
**Features:**
177
- Accepts JSX elements, flight strings, or ReadableStreams
178
- Automatically renders JSX to flight format for comparison
179
- Provides detailed diff output for flight data mismatches
180
- Handles async stream processing
181
182
**Usage Example:**
183
184
```javascript
185
describe("RSC flight matching", () => {
186
test("JSX to flight comparison", () => {
187
const element = <div className="test">Content</div>;
188
const expectedFlight = '{"type":"div","props":{"className":"test"},"children":["Content"]}';
189
190
expect(element).toMatchFlight(expectedFlight);
191
});
192
193
test("stream to flight comparison", async () => {
194
const element = <span>Stream test</span>;
195
const stream = renderJsxToReadableStream(element);
196
const expectedFlight = '{"type":"span","props":{},"children":["Stream test"]}';
197
198
expect(stream).toMatchFlight(expectedFlight);
199
});
200
});
201
```
202
203
#### toMatchFlightSnapshot
204
205
```javascript { .api }
206
/**
207
* Compare RSC flight data to snapshot file
208
*/
209
expect(data: React.ReactNode | ReadableStream).toMatchFlightSnapshot();
210
```
211
212
**Features:**
213
- Creates RSC-specific snapshot files with platform extensions
214
- Automatically handles JSX rendering to flight format
215
- Supports RSC snapshot updates with `--updateSnapshot`
216
- Platform-specific snapshot naming (`.rsc.ios.snap`, etc.)
217
218
**Usage Example:**
219
220
```javascript
221
describe("RSC snapshot testing", () => {
222
test("component flight snapshot", () => {
223
const element = (
224
<div>
225
<h1>Title</h1>
226
<p>Description</p>
227
</div>
228
);
229
230
expect(element).toMatchFlightSnapshot();
231
});
232
233
test("async component snapshot", async () => {
234
const AsyncComponent = async () => {
235
const data = await fetchData();
236
return <div>{data.title}</div>;
237
};
238
239
const element = <AsyncComponent />;
240
expect(element).toMatchFlightSnapshot();
241
});
242
});
243
```
244
245
### RSC Setup and Configuration
246
247
#### Environment Setup
248
249
RSC presets automatically configure the test environment with necessary globals:
250
251
```javascript { .api }
252
// Automatically configured in RSC presets
253
global.__DEV__ = true;
254
global.Blob = Blob;
255
global.File = File;
256
global.ReadableStream = ReadableStream;
257
global.WritableStream = WritableStream;
258
global.TransformStream = TransformStream;
259
global.TextDecoder = TextDecoder;
260
global.TextEncoder = TextEncoder;
261
```
262
263
#### Custom RSC Test Setup
264
265
```javascript
266
// Custom RSC test setup
267
import { expect } from "@jest/globals";
268
269
// Extend Jest matchers with RSC matchers
270
declare global {
271
namespace jest {
272
interface Matchers<R> {
273
toMatchFlight(expectedFlight: string): R;
274
toMatchFlightSnapshot(): R;
275
}
276
}
277
}
278
```
279
280
### Advanced RSC Testing Patterns
281
282
#### Server Component Testing
283
284
```javascript
285
describe("Server Components", () => {
286
test("async server component", async () => {
287
const ServerComponent = async ({ userId }) => {
288
const user = await fetchUser(userId);
289
return <div>Hello {user.name}</div>;
290
};
291
292
const element = <ServerComponent userId="123" />;
293
expect(element).toMatchFlightSnapshot();
294
});
295
});
296
```
297
298
#### Client Component Boundary Testing
299
300
```javascript
301
describe("Client/Server boundaries", () => {
302
test("server component with client children", () => {
303
const ServerWrapper = ({ children }) => (
304
<div className="server-wrapper">{children}</div>
305
);
306
307
const ClientComponent = () => <button>Click me</button>;
308
309
const element = (
310
<ServerWrapper>
311
<ClientComponent />
312
</ServerWrapper>
313
);
314
315
expect(element).toMatchFlightSnapshot();
316
});
317
});
318
```
319
320
## Types
321
322
```typescript { .api }
323
// RSC utility types
324
interface RSCRenderOptions {
325
onError?: (error: Error) => void;
326
identifierPrefix?: string;
327
}
328
329
// Jest matcher interfaces
330
interface JestExpoMatchers<R> extends Record<string, any> {
331
/**
332
* Compare RSC flight data to expected string
333
*/
334
toMatchFlight(expectedFlight: string): R;
335
336
/**
337
* Compare RSC flight data to snapshot file
338
*/
339
toMatchFlightSnapshot(): R;
340
}
341
342
// RSC utility function types
343
declare function streamToString(stream: ReadableStream): Promise<string>;
344
345
declare function renderJsxToFlightStringAsync(
346
jsx: React.ReactNode,
347
throwOnError?: boolean
348
): Promise<string>;
349
350
declare function renderJsxToReadableStream(
351
jsx: React.ReactNode,
352
options?: RSCRenderOptions
353
): RSCRenderResult;
354
355
// RSC utility interfaces
356
interface RSCRenderOptions {
357
onError?: (error: Error) => void;
358
}
359
360
interface RSCRenderResult {
361
stream: ReadableStream;
362
clientBoundaries: string[];
363
}
364
365
// Global extensions for RSC testing
366
declare global {
367
namespace jest {
368
interface Matchers<R> extends JestExpoMatchers<R> {}
369
interface Expect extends JestExpoMatchers<any> {}
370
interface InverseAsymmetricMatchers extends Expect {}
371
}
372
}
373
374
// React Server Component types
375
type ServerComponent<P = {}> = (props: P) => Promise<React.ReactElement>;
376
type ClientComponent<P = {}> = React.ComponentType<P>;
377
378
interface RSCFlightData {
379
type: string;
380
props: Record<string, any>;
381
children?: React.ReactNode[];
382
}
383
```