12
// Polyfills for test environment
13
global.ReadableStream =
14
require('web-streams-polyfill/ponyfill/es6').ReadableStream;
15
+global.WritableStream =
16
+ require('web-streams-polyfill/ponyfill/es6').WritableStream;
17
global.TextEncoder = require('util').TextEncoder;
18
global.TextDecoder = require('util').TextDecoder;
19
18
-// Don't wait before processing work on the server.
19
-// TODO: we can replace this with FlightServer.act().
20
-global.setTimeout = cb => cb();
21
-
20
let clientExports;
21
let turbopackMap;
22
let turbopackModules;
23
let React;
24
+let ReactServer;
25
let ReactDOMServer;
26
let ReactServerDOMServer;
27
let ReactServerDOMClient;
28
let use;
29
+let serverAct;
30
31
describe('ReactFlightTurbopackDOMEdge', () => {
32
beforeEach(() => {
33
jest.resetModules();
34
35
+ serverAct = require('internal-test-utils').serverAct;
36
+
37
// Simulate the condition resolution
38
jest.mock('react', () => require('react/react.react-server'));
39
jest.mock('react-server-dom-turbopack/server', () =>
45
turbopackMap = TurbopackMock.turbopackMap;
46
turbopackModules = TurbopackMock.turbopackModules;
47
48
+ ReactServer = require('react');
49
ReactServerDOMServer = require('react-server-dom-turbopack/server.edge');
50
51
jest.resetModules();
69
}
70
}
71
72
+ function normalizeCodeLocInfo(str) {
73
+ return (
74
+ str &&
75
+ str.replace(/^ +(?:at|in) ([\S]+)[^\n]*/gm, function (m, name) {
76
+ return ' in ' + name + (/\d/.test(m) ? ' (at **)' : '');
77
+ })
78
+ );
79
+ }
80
+
81
it('should allow an alternative module mapping to be used for SSR', async () => {
82
function ClientComponent() {
83
return <span>Client Component</span>;
104
return <ClientComponentOnTheClient />;
105
}
106
95
- const stream = ReactServerDOMServer.renderToReadableStream(
96
- <App />,
97
- turbopackMap,
107
+ const stream = await serverAct(() =>
108
+ ReactServerDOMServer.renderToReadableStream(<App />, turbopackMap),
109
);
110
const response = ReactServerDOMClient.createFromReadableStream(stream, {
111
serverConsumerManifest: {
118
return use(response);
119
}
120
110
- const ssrStream = await ReactDOMServer.renderToReadableStream(
111
- <ClientRoot />,
121
+ const ssrStream = await serverAct(() =>
122
+ ReactDOMServer.renderToReadableStream(<ClientRoot />),
123
);
124
const result = await readResult(ssrStream);
125
expect(result).toEqual('<span>Client Component</span>');
126
});
127
+
128
+ // @gate __DEV__
129
+ it('can transport debug info through a separate debug channel', async () => {
130
+ function Thrower() {
131
+ throw new Error('ssr-throw');
132
+ }
133
+
134
+ const ClientComponentOnTheClient = clientExports(
135
+ Thrower,
136
+ 123,
137
+ 'path/to/chunk.js',
138
+ );
139
+
140
+ const ClientComponentOnTheServer = clientExports(Thrower);
141
+
142
+ function App() {
143
+ return ReactServer.createElement(
144
+ ReactServer.Suspense,
145
+ null,
146
+ ReactServer.createElement(ClientComponentOnTheClient, null),
147
+ );
148
+ }
149
+
150
+ let debugReadableStreamController;
151
+
152
+ const debugReadableStream = new ReadableStream({
153
+ start(controller) {
154
+ debugReadableStreamController = controller;
155
+ },
156
+ });
157
+
158
+ const rscStream = await serverAct(() =>
159
+ ReactServerDOMServer.renderToReadableStream(
160
+ ReactServer.createElement(App, null),
161
+ turbopackMap,
162
+ {
163
+ debugChannel: {
164
+ writable: new WritableStream({
165
+ write(chunk) {
166
+ debugReadableStreamController.enqueue(chunk);
167
+ },
168
+ }),
169
+ },
170
+ },
171
+ ),
172
+ );
173
+
174
+ function ClientRoot({response}) {
175
+ return use(response);
176
+ }
177
+
178
+ const serverConsumerManifest = {
179
+ moduleMap: {
180
+ [turbopackMap[ClientComponentOnTheClient.$$id].id]: {
181
+ '*': turbopackMap[ClientComponentOnTheServer.$$id],
182
+ },
183
+ },
184
+ moduleLoading: null,
185
+ };
186
+
187
+ const response = ReactServerDOMClient.createFromReadableStream(rscStream, {
188
+ serverConsumerManifest,
189
+ debugChannel: {readable: debugReadableStream},
190
+ });
191
+
192
+ let ownerStack;
193
+
194
+ const ssrStream = await serverAct(() =>
195
+ ReactDOMServer.renderToReadableStream(
196
+ <ClientRoot response={response} />,
197
+ {
198
+ onError(err, errorInfo) {
199
+ ownerStack = React.captureOwnerStack
200
+ ? React.captureOwnerStack()
201
+ : null;
202
+ },
203
+ },
204
+ ),
205
+ );
206
+
207
+ const result = await readResult(ssrStream);
208
+
209
+ expect(normalizeCodeLocInfo(ownerStack)).toBe('\n in App (at **)');
210
+
211
+ expect(result).toContain(
212
+ 'Switched to client rendering because the server rendering errored:\n\nssr-throw',
213
+ );
214
+ });
215
});