4442
});
4443
});
4444
4445
+ describe('ReactDOM.preloadModule(href, options)', () => {
4446
+ it('preloads scripts as modules', async () => {
4447
+ function App({ssr}) {
4448
+ const prefix = ssr ? 'ssr ' : 'browser ';
4449
+ ReactDOM.preloadModule(prefix + 'plain');
4450
+ ReactDOM.preloadModule(prefix + 'default', {as: 'script'});
4451
+ ReactDOM.preloadModule(prefix + 'cors', {
4452
+ crossOrigin: 'use-credentials',
4453
+ });
4454
+ ReactDOM.preloadModule(prefix + 'integrity', {integrity: 'some hash'});
4455
+ ReactDOM.preloadModule(prefix + 'serviceworker', {as: 'serviceworker'});
4456
+ return <div>hello</div>;
4457
+ }
4458
+ await act(() => {
4459
+ renderToPipeableStream(<App ssr={true} />).pipe(writable);
4460
+ });
4461
+ expect(getMeaningfulChildren(document.body)).toEqual(
4462
+ <div id="container">
4463
+ <link rel="modulepreload" href="ssr plain" />
4464
+ <link rel="modulepreload" href="ssr default" />
4465
+ <link
4466
+ rel="modulepreload"
4467
+ href="ssr cors"
4468
+ crossorigin="use-credentials"
4469
+ />
4470
+ <link
4471
+ rel="modulepreload"
4472
+ href="ssr integrity"
4473
+ integrity="some hash"
4474
+ />
4475
+ <link
4476
+ rel="modulepreload"
4477
+ href="ssr serviceworker"
4478
+ as="serviceworker"
4479
+ />
4480
+ <div>hello</div>
4481
+ </div>,
4482
+ );
4483
+
4484
+ ReactDOMClient.hydrateRoot(container, <App />);
4485
+ await waitForAll([]);
4486
+ expect(getMeaningfulChildren(document)).toEqual(
4487
+ <html>
4488
+ <head>
4489
+ <link rel="modulepreload" href="browser plain" />
4490
+ <link rel="modulepreload" href="browser default" />
4491
+ <link
4492
+ rel="modulepreload"
4493
+ href="browser cors"
4494
+ crossorigin="use-credentials"
4495
+ />
4496
+ <link
4497
+ rel="modulepreload"
4498
+ href="browser integrity"
4499
+ integrity="some hash"
4500
+ />
4501
+ <link
4502
+ rel="modulepreload"
4503
+ href="browser serviceworker"
4504
+ as="serviceworker"
4505
+ />
4506
+ </head>
4507
+ <body>
4508
+ <div id="container">
4509
+ <link rel="modulepreload" href="ssr plain" />
4510
+ <link rel="modulepreload" href="ssr default" />
4511
+ <link
4512
+ rel="modulepreload"
4513
+ href="ssr cors"
4514
+ crossorigin="use-credentials"
4515
+ />
4516
+ <link
4517
+ rel="modulepreload"
4518
+ href="ssr integrity"
4519
+ integrity="some hash"
4520
+ />
4521
+ <link
4522
+ rel="modulepreload"
4523
+ href="ssr serviceworker"
4524
+ as="serviceworker"
4525
+ />
4526
+ <div>hello</div>
4527
+ </div>
4528
+ </body>
4529
+ </html>,
4530
+ );
4531
+ });
4532
+
4533
+ it('warns if you provide invalid arguments', async () => {
4534
+ function App() {
4535
+ ReactDOM.preloadModule();
4536
+ ReactDOM.preloadModule(() => {});
4537
+ ReactDOM.preloadModule('');
4538
+ ReactDOM.preloadModule('1', true);
4539
+ ReactDOM.preloadModule('2', {as: true});
4540
+ return <div>hello</div>;
4541
+ }
4542
+ await expect(async () => {
4543
+ await act(() => {
4544
+ renderToPipeableStream(<App />).pipe(writable);
4545
+ });
4546
+ }).toErrorDev([
4547
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was `undefined`',
4548
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was something with type "function"',
4549
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was an empty string',
4550
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `options` argument encountered was something with type "boolean"',
4551
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `as` option encountered was something with type "boolean"',
4552
+ ]);
4553
+ expect(getMeaningfulChildren(document.body)).toEqual(
4554
+ <div id="container">
4555
+ <link rel="modulepreload" href="1" />
4556
+ <link rel="modulepreload" href="2" />
4557
+ <div>hello</div>
4558
+ </div>,
4559
+ );
4560
+
4561
+ const root = ReactDOMClient.createRoot(
4562
+ document.getElementById('container'),
4563
+ );
4564
+ root.render(<App />);
4565
+ await expect(async () => {
4566
+ await waitForAll([]);
4567
+ }).toErrorDev([
4568
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was `undefined`',
4569
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was something with type "function"',
4570
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `href` argument encountered was an empty string',
4571
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `options` argument encountered was something with type "boolean"',
4572
+ 'ReactDOM.preloadModule(): Expected two arguments, a non-empty `href` string and, optionally, an `options` object with an `as` property valid for a `<link rel="modulepreload" as="..." />` tag. The `as` option encountered was something with type "boolean"',
4573
+ ]);
4574
+ });
4575
+ });
4576
+
4577
describe('ReactDOM.preinit(href, { as: ... })', () => {
4578
// @gate enableFloat
4579
it('creates a stylesheet resource when ReactDOM.preinit(..., {as: "style" }) is called', async () => {
5112
});
5113
});
5114
5115
+ describe('ReactDOM.preinitModule(href, options)', () => {
5116
+ it('creates a script module resources', async () => {
5117
+ function App({ssr}) {
5118
+ const prefix = ssr ? 'ssr ' : 'browser ';
5119
+ ReactDOM.preinitModule(prefix + 'plain');
5120
+ ReactDOM.preinitModule(prefix + 'default', {as: 'script'});
5121
+ ReactDOM.preinitModule(prefix + 'cors', {
5122
+ crossOrigin: 'use-credentials',
5123
+ });
5124
+ ReactDOM.preinitModule(prefix + 'integrity', {integrity: 'some hash'});
5125
+ ReactDOM.preinitModule(prefix + 'warning', {as: 'style'});
5126
+ return <div>hello</div>;
5127
+ }
5128
+ await expect(async () => {
5129
+ await act(() => {
5130
+ renderToPipeableStream(<App ssr={true} />).pipe(writable);
5131
+ });
5132
+ }).toErrorDev([
5133
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `as` option encountered was "style"',
5134
+ ]);
5135
+ expect(getMeaningfulChildren(document.body)).toEqual(
5136
+ <div id="container">
5137
+ <script type="module" src="ssr plain" async="" />
5138
+ <script type="module" src="ssr default" async="" />
5139
+ <script
5140
+ type="module"
5141
+ src="ssr cors"
5142
+ crossorigin="use-credentials"
5143
+ async=""
5144
+ />
5145
+ <script
5146
+ type="module"
5147
+ src="ssr integrity"
5148
+ integrity="some hash"
5149
+ async=""
5150
+ />
5151
+ <div>hello</div>
5152
+ </div>,
5153
+ );
5154
+
5155
+ ReactDOMClient.hydrateRoot(container, <App />);
5156
+ await expect(async () => {
5157
+ await waitForAll([]);
5158
+ }).toErrorDev([
5159
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `as` option encountered was "style"',
5160
+ ]);
5161
+ expect(getMeaningfulChildren(document)).toEqual(
5162
+ <html>
5163
+ <head>
5164
+ <script type="module" src="browser plain" async="" />
5165
+ <script type="module" src="browser default" async="" />
5166
+ <script
5167
+ type="module"
5168
+ src="browser cors"
5169
+ crossorigin="use-credentials"
5170
+ async=""
5171
+ />
5172
+ <script
5173
+ type="module"
5174
+ src="browser integrity"
5175
+ integrity="some hash"
5176
+ async=""
5177
+ />
5178
+ </head>
5179
+ <body>
5180
+ <div id="container">
5181
+ <script type="module" src="ssr plain" async="" />
5182
+ <script type="module" src="ssr default" async="" />
5183
+ <script
5184
+ type="module"
5185
+ src="ssr cors"
5186
+ crossorigin="use-credentials"
5187
+ async=""
5188
+ />
5189
+ <script
5190
+ type="module"
5191
+ src="ssr integrity"
5192
+ integrity="some hash"
5193
+ async=""
5194
+ />
5195
+ <div>hello</div>
5196
+ </div>
5197
+ </body>
5198
+ </html>,
5199
+ );
5200
+ });
5201
+
5202
+ it('warns if you provide invalid arguments', async () => {
5203
+ function App() {
5204
+ ReactDOM.preinitModule();
5205
+ ReactDOM.preinitModule(() => {});
5206
+ ReactDOM.preinitModule('');
5207
+ ReactDOM.preinitModule('1', true);
5208
+ ReactDOM.preinitModule('2', {as: true});
5209
+ return <div>hello</div>;
5210
+ }
5211
+ await expect(async () => {
5212
+ await act(() => {
5213
+ renderToPipeableStream(<App />).pipe(writable);
5214
+ });
5215
+ }).toErrorDev([
5216
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was `undefined`',
5217
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was something with type "function"',
5218
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was an empty string',
5219
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `options` argument encountered was something with type "boolean"',
5220
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `as` option encountered was something with type "boolean"',
5221
+ ]);
5222
+ expect(getMeaningfulChildren(document.body)).toEqual(
5223
+ <div id="container">
5224
+ <script type="module" src="1" async="" />
5225
+ <script type="module" src="2" async="" />
5226
+ <div>hello</div>
5227
+ </div>,
5228
+ );
5229
+
5230
+ const root = ReactDOMClient.createRoot(
5231
+ document.getElementById('container'),
5232
+ );
5233
+ root.render(<App />);
5234
+ await expect(async () => {
5235
+ await waitForAll([]);
5236
+ }).toErrorDev([
5237
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was `undefined`',
5238
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was something with type "function"',
5239
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `href` argument encountered was an empty string',
5240
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `options` argument encountered was something with type "boolean"',
5241
+ 'ReactDOM.preinitModule(): Expected up to two arguments, a non-empty `href` string and, optionally, an `options` object with a valid `as` property. The `as` option encountered was something with type "boolean"',
5242
+ ]);
5243
+ });
5244
+ });
5245
+
5246
describe('Stylesheet Resources', () => {
5247
// @gate enableFloat
5248
it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when server rendering', async () => {