1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @emails react-core
    
  8.  * @jest-environment ./scripts/jest/ReactDOMServerIntegrationEnvironment
    
  9.  */
    
  10. 
    
  11. 'use strict';
    
  12. import {
    
  13.   insertNodesAndExecuteScripts,
    
  14.   mergeOptions,
    
  15.   withLoadingReadyState,
    
  16. } from '../test-utils/FizzTestUtils';
    
  17. 
    
  18. let JSDOM;
    
  19. let Stream;
    
  20. let React;
    
  21. let ReactDOM;
    
  22. let ReactDOMClient;
    
  23. let ReactDOMFizzServer;
    
  24. let Suspense;
    
  25. let textCache;
    
  26. let loadCache;
    
  27. let writable;
    
  28. const CSPnonce = null;
    
  29. let container;
    
  30. let buffer = '';
    
  31. let hasErrored = false;
    
  32. let fatalError = undefined;
    
  33. let renderOptions;
    
  34. let waitForAll;
    
  35. let waitForThrow;
    
  36. let assertLog;
    
  37. let Scheduler;
    
  38. let clientAct;
    
  39. let streamingContainer;
    
  40. 
    
  41. describe('ReactDOMFloat', () => {
    
  42.   beforeEach(() => {
    
  43.     jest.resetModules();
    
  44.     JSDOM = require('jsdom').JSDOM;
    
  45. 
    
  46.     const jsdom = new JSDOM(
    
  47.       '<!DOCTYPE html><html><head></head><body><div id="container">',
    
  48.       {
    
  49.         runScripts: 'dangerously',
    
  50.       },
    
  51.     );
    
  52.     // We mock matchMedia. for simplicity it only matches 'all' or '' and misses everything else
    
  53.     Object.defineProperty(jsdom.window, 'matchMedia', {
    
  54.       writable: true,
    
  55.       value: jest.fn().mockImplementation(query => ({
    
  56.         matches: query === 'all' || query === '',
    
  57.         media: query,
    
  58.       })),
    
  59.     });
    
  60.     streamingContainer = null;
    
  61.     global.window = jsdom.window;
    
  62.     global.document = global.window.document;
    
  63.     global.navigator = global.window.navigator;
    
  64.     global.Node = global.window.Node;
    
  65.     global.addEventListener = global.window.addEventListener;
    
  66.     global.MutationObserver = global.window.MutationObserver;
    
  67.     container = document.getElementById('container');
    
  68. 
    
  69.     React = require('react');
    
  70.     ReactDOM = require('react-dom');
    
  71.     ReactDOMClient = require('react-dom/client');
    
  72.     ReactDOMFizzServer = require('react-dom/server');
    
  73.     Stream = require('stream');
    
  74.     Suspense = React.Suspense;
    
  75.     Scheduler = require('scheduler/unstable_mock');
    
  76. 
    
  77.     const InternalTestUtils = require('internal-test-utils');
    
  78.     waitForAll = InternalTestUtils.waitForAll;
    
  79.     waitForThrow = InternalTestUtils.waitForThrow;
    
  80.     assertLog = InternalTestUtils.assertLog;
    
  81.     clientAct = InternalTestUtils.act;
    
  82. 
    
  83.     textCache = new Map();
    
  84.     loadCache = new Set();
    
  85. 
    
  86.     buffer = '';
    
  87.     hasErrored = false;
    
  88. 
    
  89.     writable = new Stream.PassThrough();
    
  90.     writable.setEncoding('utf8');
    
  91.     writable.on('data', chunk => {
    
  92.       buffer += chunk;
    
  93.     });
    
  94.     writable.on('error', error => {
    
  95.       hasErrored = true;
    
  96.       fatalError = error;
    
  97.     });
    
  98. 
    
  99.     renderOptions = {};
    
  100.     if (gate(flags => flags.enableFizzExternalRuntime)) {
    
  101.       renderOptions.unstable_externalRuntimeSrc =
    
  102.         'react-dom/unstable_server-external-runtime';
    
  103.     }
    
  104.   });
    
  105. 
    
  106.   const bodyStartMatch = /<body(?:>| .*?>)/;
    
  107.   const headStartMatch = /<head(?:>| .*?>)/;
    
  108. 
    
  109.   async function act(callback) {
    
  110.     await callback();
    
  111.     // Await one turn around the event loop.
    
  112.     // This assumes that we'll flush everything we have so far.
    
  113.     await new Promise(resolve => {
    
  114.       setImmediate(resolve);
    
  115.     });
    
  116.     if (hasErrored) {
    
  117.       throw fatalError;
    
  118.     }
    
  119.     // JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
    
  120.     // We also want to execute any scripts that are embedded.
    
  121.     // We assume that we have now received a proper fragment of HTML.
    
  122.     let bufferedContent = buffer;
    
  123.     buffer = '';
    
  124. 
    
  125.     if (!bufferedContent) {
    
  126.       return;
    
  127.     }
    
  128. 
    
  129.     await withLoadingReadyState(async () => {
    
  130.       const bodyMatch = bufferedContent.match(bodyStartMatch);
    
  131.       const headMatch = bufferedContent.match(headStartMatch);
    
  132. 
    
  133.       if (streamingContainer === null) {
    
  134.         // This is the first streamed content. We decide here where to insert it. If we get <html>, <head>, or <body>
    
  135.         // we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the
    
  136.         // container. This is not really production behavior because you can't correctly stream into a deep div effectively
    
  137.         // but it's pragmatic for tests.
    
  138. 
    
  139.         if (
    
  140.           bufferedContent.startsWith('<head>') ||
    
  141.           bufferedContent.startsWith('<head ') ||
    
  142.           bufferedContent.startsWith('<body>') ||
    
  143.           bufferedContent.startsWith('<body ')
    
  144.         ) {
    
  145.           // wrap in doctype to normalize the parsing process
    
  146.           bufferedContent = '<!DOCTYPE html><html>' + bufferedContent;
    
  147.         } else if (
    
  148.           bufferedContent.startsWith('<html>') ||
    
  149.           bufferedContent.startsWith('<html ')
    
  150.         ) {
    
  151.           throw new Error(
    
  152.             'Recieved <html> without a <!DOCTYPE html> which is almost certainly a bug in React',
    
  153.           );
    
  154.         }
    
  155. 
    
  156.         if (bufferedContent.startsWith('<!DOCTYPE html>')) {
    
  157.           // we can just use the whole document
    
  158.           const tempDom = new JSDOM(bufferedContent);
    
  159. 
    
  160.           // Wipe existing head and body content
    
  161.           document.head.innerHTML = '';
    
  162.           document.body.innerHTML = '';
    
  163. 
    
  164.           // Copy the <html> attributes over
    
  165.           const tempHtmlNode = tempDom.window.document.documentElement;
    
  166.           for (let i = 0; i < tempHtmlNode.attributes.length; i++) {
    
  167.             const attr = tempHtmlNode.attributes[i];
    
  168.             document.documentElement.setAttribute(attr.name, attr.value);
    
  169.           }
    
  170. 
    
  171.           if (headMatch) {
    
  172.             // We parsed a head open tag. we need to copy head attributes and insert future
    
  173.             // content into <head>
    
  174.             streamingContainer = document.head;
    
  175.             const tempHeadNode = tempDom.window.document.head;
    
  176.             for (let i = 0; i < tempHeadNode.attributes.length; i++) {
    
  177.               const attr = tempHeadNode.attributes[i];
    
  178.               document.head.setAttribute(attr.name, attr.value);
    
  179.             }
    
  180.             const source = document.createElement('head');
    
  181.             source.innerHTML = tempHeadNode.innerHTML;
    
  182.             await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
    
  183.           }
    
  184. 
    
  185.           if (bodyMatch) {
    
  186.             // We parsed a body open tag. we need to copy head attributes and insert future
    
  187.             // content into <body>
    
  188.             streamingContainer = document.body;
    
  189.             const tempBodyNode = tempDom.window.document.body;
    
  190.             for (let i = 0; i < tempBodyNode.attributes.length; i++) {
    
  191.               const attr = tempBodyNode.attributes[i];
    
  192.               document.body.setAttribute(attr.name, attr.value);
    
  193.             }
    
  194.             const source = document.createElement('body');
    
  195.             source.innerHTML = tempBodyNode.innerHTML;
    
  196.             await insertNodesAndExecuteScripts(source, document.body, CSPnonce);
    
  197.           }
    
  198. 
    
  199.           if (!headMatch && !bodyMatch) {
    
  200.             throw new Error('expected <head> or <body> after <html>');
    
  201.           }
    
  202.         } else {
    
  203.           // we assume we are streaming into the default container'
    
  204.           streamingContainer = container;
    
  205.           const div = document.createElement('div');
    
  206.           div.innerHTML = bufferedContent;
    
  207.           await insertNodesAndExecuteScripts(div, container, CSPnonce);
    
  208.         }
    
  209.       } else if (streamingContainer === document.head) {
    
  210.         bufferedContent = '<!DOCTYPE html><html><head>' + bufferedContent;
    
  211.         const tempDom = new JSDOM(bufferedContent);
    
  212. 
    
  213.         const tempHeadNode = tempDom.window.document.head;
    
  214.         const source = document.createElement('head');
    
  215.         source.innerHTML = tempHeadNode.innerHTML;
    
  216.         await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
    
  217. 
    
  218.         if (bodyMatch) {
    
  219.           streamingContainer = document.body;
    
  220. 
    
  221.           const tempBodyNode = tempDom.window.document.body;
    
  222.           for (let i = 0; i < tempBodyNode.attributes.length; i++) {
    
  223.             const attr = tempBodyNode.attributes[i];
    
  224.             document.body.setAttribute(attr.name, attr.value);
    
  225.           }
    
  226.           const bodySource = document.createElement('body');
    
  227.           bodySource.innerHTML = tempBodyNode.innerHTML;
    
  228.           await insertNodesAndExecuteScripts(
    
  229.             bodySource,
    
  230.             document.body,
    
  231.             CSPnonce,
    
  232.           );
    
  233.         }
    
  234.       } else {
    
  235.         const div = document.createElement('div');
    
  236.         div.innerHTML = bufferedContent;
    
  237.         await insertNodesAndExecuteScripts(div, streamingContainer, CSPnonce);
    
  238.       }
    
  239.     }, document);
    
  240.   }
    
  241. 
    
  242.   function getMeaningfulChildren(element) {
    
  243.     const children = [];
    
  244.     let node = element.firstChild;
    
  245.     while (node) {
    
  246.       if (node.nodeType === 1) {
    
  247.         if (
    
  248.           // some tags are ambiguous and might be hidden because they look like non-meaningful children
    
  249.           // so we have a global override where if this data attribute is included we also include the node
    
  250.           node.hasAttribute('data-meaningful') ||
    
  251.           (node.tagName === 'SCRIPT' &&
    
  252.             node.hasAttribute('src') &&
    
  253.             node.getAttribute('src') !==
    
  254.               renderOptions.unstable_externalRuntimeSrc &&
    
  255.             node.hasAttribute('async')) ||
    
  256.           (node.tagName !== 'SCRIPT' &&
    
  257.             node.tagName !== 'TEMPLATE' &&
    
  258.             node.tagName !== 'template' &&
    
  259.             !node.hasAttribute('hidden') &&
    
  260.             !node.hasAttribute('aria-hidden'))
    
  261.         ) {
    
  262.           const props = {};
    
  263.           const attributes = node.attributes;
    
  264.           for (let i = 0; i < attributes.length; i++) {
    
  265.             if (
    
  266.               attributes[i].name === 'id' &&
    
  267.               attributes[i].value.includes(':')
    
  268.             ) {
    
  269.               // We assume this is a React added ID that's a non-visual implementation detail.
    
  270.               continue;
    
  271.             }
    
  272.             props[attributes[i].name] = attributes[i].value;
    
  273.           }
    
  274.           props.children = getMeaningfulChildren(node);
    
  275.           children.push(React.createElement(node.tagName.toLowerCase(), props));
    
  276.         }
    
  277.       } else if (node.nodeType === 3) {
    
  278.         children.push(node.data);
    
  279.       }
    
  280.       node = node.nextSibling;
    
  281.     }
    
  282.     return children.length === 0
    
  283.       ? undefined
    
  284.       : children.length === 1
    
  285.       ? children[0]
    
  286.       : children;
    
  287.   }
    
  288. 
    
  289.   function BlockedOn({value, children}) {
    
  290.     readText(value);
    
  291.     return children;
    
  292.   }
    
  293. 
    
  294.   function resolveText(text) {
    
  295.     const record = textCache.get(text);
    
  296.     if (record === undefined) {
    
  297.       const newRecord = {
    
  298.         status: 'resolved',
    
  299.         value: text,
    
  300.       };
    
  301.       textCache.set(text, newRecord);
    
  302.     } else if (record.status === 'pending') {
    
  303.       const thenable = record.value;
    
  304.       record.status = 'resolved';
    
  305.       record.value = text;
    
  306.       thenable.pings.forEach(t => t());
    
  307.     }
    
  308.   }
    
  309. 
    
  310.   function readText(text) {
    
  311.     const record = textCache.get(text);
    
  312.     if (record !== undefined) {
    
  313.       switch (record.status) {
    
  314.         case 'pending':
    
  315.           throw record.value;
    
  316.         case 'rejected':
    
  317.           throw record.value;
    
  318.         case 'resolved':
    
  319.           return record.value;
    
  320.       }
    
  321.     } else {
    
  322.       const thenable = {
    
  323.         pings: [],
    
  324.         then(resolve) {
    
  325.           if (newRecord.status === 'pending') {
    
  326.             thenable.pings.push(resolve);
    
  327.           } else {
    
  328.             Promise.resolve().then(() => resolve(newRecord.value));
    
  329.           }
    
  330.         },
    
  331.       };
    
  332. 
    
  333.       const newRecord = {
    
  334.         status: 'pending',
    
  335.         value: thenable,
    
  336.       };
    
  337.       textCache.set(text, newRecord);
    
  338. 
    
  339.       throw thenable;
    
  340.     }
    
  341.   }
    
  342. 
    
  343.   function AsyncText({text}) {
    
  344.     return readText(text);
    
  345.   }
    
  346. 
    
  347.   function renderToPipeableStream(jsx, options) {
    
  348.     // Merge options with renderOptions, which may contain featureFlag specific behavior
    
  349.     return ReactDOMFizzServer.renderToPipeableStream(
    
  350.       jsx,
    
  351.       mergeOptions(options, renderOptions),
    
  352.     );
    
  353.   }
    
  354. 
    
  355.   function loadPreloads(hrefs) {
    
  356.     const event = new window.Event('load');
    
  357.     const nodes = document.querySelectorAll('link[rel="preload"]');
    
  358.     resolveLoadables(hrefs, nodes, event, href =>
    
  359.       Scheduler.log('load preload: ' + href),
    
  360.     );
    
  361.   }
    
  362. 
    
  363.   function errorPreloads(hrefs) {
    
  364.     const event = new window.Event('error');
    
  365.     const nodes = document.querySelectorAll('link[rel="preload"]');
    
  366.     resolveLoadables(hrefs, nodes, event, href =>
    
  367.       Scheduler.log('error preload: ' + href),
    
  368.     );
    
  369.   }
    
  370. 
    
  371.   function loadStylesheets(hrefs) {
    
  372.     const event = new window.Event('load');
    
  373.     const nodes = document.querySelectorAll('link[rel="stylesheet"]');
    
  374.     resolveLoadables(hrefs, nodes, event, href =>
    
  375.       Scheduler.log('load stylesheet: ' + href),
    
  376.     );
    
  377.   }
    
  378. 
    
  379.   function errorStylesheets(hrefs) {
    
  380.     const event = new window.Event('error');
    
  381.     const nodes = document.querySelectorAll('link[rel="stylesheet"]');
    
  382.     resolveLoadables(hrefs, nodes, event, href => {
    
  383.       Scheduler.log('error stylesheet: ' + href);
    
  384.     });
    
  385.   }
    
  386. 
    
  387.   function resolveLoadables(hrefs, nodes, event, onLoad) {
    
  388.     const hrefSet = hrefs ? new Set(hrefs) : null;
    
  389.     for (let i = 0; i < nodes.length; i++) {
    
  390.       const node = nodes[i];
    
  391.       if (loadCache.has(node)) {
    
  392.         continue;
    
  393.       }
    
  394.       const href = node.getAttribute('href');
    
  395.       if (!hrefSet || hrefSet.has(href)) {
    
  396.         loadCache.add(node);
    
  397.         onLoad(href);
    
  398.         node.dispatchEvent(event);
    
  399.       }
    
  400.     }
    
  401.   }
    
  402. 
    
  403.   // @gate enableFloat
    
  404.   it('can render resources before singletons', async () => {
    
  405.     const root = ReactDOMClient.createRoot(document);
    
  406.     root.render(
    
  407.       <>
    
  408.         <title>foo</title>
    
  409.         <html>
    
  410.           <head>
    
  411.             <link rel="foo" href="foo" />
    
  412.           </head>
    
  413.           <body>hello world</body>
    
  414.         </html>
    
  415.       </>,
    
  416.     );
    
  417.     try {
    
  418.       await waitForAll([]);
    
  419.     } catch (e) {
    
  420.       // for DOMExceptions that happen when expecting this test to fail we need
    
  421.       // to clear the scheduler first otherwise the expected failure will fail
    
  422.       await waitForAll([]);
    
  423.       throw e;
    
  424.     }
    
  425.     expect(getMeaningfulChildren(document)).toEqual(
    
  426.       <html>
    
  427.         <head>
    
  428.           <title>foo</title>
    
  429.           <link rel="foo" href="foo" />
    
  430.         </head>
    
  431.         <body>hello world</body>
    
  432.       </html>,
    
  433.     );
    
  434.   });
    
  435. 
    
  436.   // @gate enableFloat
    
  437.   it('can hydrate non Resources in head when Resources are also inserted there', async () => {
    
  438.     await act(() => {
    
  439.       const {pipe} = renderToPipeableStream(
    
  440.         <html>
    
  441.           <head>
    
  442.             <meta property="foo" content="bar" />
    
  443.             <link rel="foo" href="bar" onLoad={() => {}} />
    
  444.             <title>foo</title>
    
  445.             <noscript>
    
  446.               <link rel="icon" href="icon" />
    
  447.             </noscript>
    
  448.             <base target="foo" href="bar" />
    
  449.             <script async={true} src="foo" onLoad={() => {}} />
    
  450.           </head>
    
  451.           <body>foo</body>
    
  452.         </html>,
    
  453.       );
    
  454.       pipe(writable);
    
  455.     });
    
  456.     expect(getMeaningfulChildren(document)).toEqual(
    
  457.       <html>
    
  458.         <head>
    
  459.           <meta property="foo" content="bar" />
    
  460.           <title>foo</title>
    
  461.           <link rel="foo" href="bar" />
    
  462.           <noscript>&lt;link rel="icon" href="icon"&gt;</noscript>
    
  463.           <base target="foo" href="bar" />
    
  464.           <script async="" src="foo" />
    
  465.         </head>
    
  466.         <body>foo</body>
    
  467.       </html>,
    
  468.     );
    
  469. 
    
  470.     ReactDOMClient.hydrateRoot(
    
  471.       document,
    
  472.       <html>
    
  473.         <head>
    
  474.           <meta property="foo" content="bar" />
    
  475.           <link rel="foo" href="bar" onLoad={() => {}} />
    
  476.           <title>foo</title>
    
  477.           <noscript>
    
  478.             <link rel="icon" href="icon" />
    
  479.           </noscript>
    
  480.           <base target="foo" href="bar" />
    
  481.           <script async={true} src="foo" onLoad={() => {}} />
    
  482.         </head>
    
  483.         <body>foo</body>
    
  484.       </html>,
    
  485.     );
    
  486.     await waitForAll([]);
    
  487.     expect(getMeaningfulChildren(document)).toEqual(
    
  488.       <html>
    
  489.         <head>
    
  490.           <meta property="foo" content="bar" />
    
  491.           <title>foo</title>
    
  492.           <link rel="foo" href="bar" />
    
  493.           <noscript>&lt;link rel="icon" href="icon"&gt;</noscript>
    
  494.           <base target="foo" href="bar" />
    
  495.           <script async="" src="foo" />
    
  496.         </head>
    
  497.         <body>foo</body>
    
  498.       </html>,
    
  499.     );
    
  500.   });
    
  501. 
    
  502.   // @gate enableFloat || !__DEV__
    
  503.   it('warns if you render resource-like elements above <head> or <body>', async () => {
    
  504.     const root = ReactDOMClient.createRoot(document);
    
  505. 
    
  506.     await expect(async () => {
    
  507.       root.render(
    
  508.         <>
    
  509.           <noscript>foo</noscript>
    
  510.           <html>
    
  511.             <body>foo</body>
    
  512.           </html>
    
  513.         </>,
    
  514.       );
    
  515.       const aggregateError = await waitForThrow();
    
  516.       expect(aggregateError.errors.length).toBe(2);
    
  517.       expect(aggregateError.errors[0].message).toContain(
    
  518.         'Invalid insertion of NOSCRIPT',
    
  519.       );
    
  520.       expect(aggregateError.errors[1].message).toContain(
    
  521.         'The node to be removed is not a child of this node',
    
  522.       );
    
  523.     }).toErrorDev(
    
  524.       [
    
  525.         'Cannot render <noscript> outside the main document. Try moving it into the root <head> tag.',
    
  526.         'Warning: validateDOMNesting(...): <noscript> cannot appear as a child of <#document>.',
    
  527.       ],
    
  528.       {withoutStack: 1},
    
  529.     );
    
  530. 
    
  531.     await expect(async () => {
    
  532.       root.render(
    
  533.         <html>
    
  534.           <template>foo</template>
    
  535.           <body>foo</body>
    
  536.         </html>,
    
  537.       );
    
  538.       await waitForAll([]);
    
  539.     }).toErrorDev([
    
  540.       'Cannot render <template> outside the main document. Try moving it into the root <head> tag.',
    
  541.       'Warning: validateDOMNesting(...): <template> cannot appear as a child of <html>.',
    
  542.     ]);
    
  543. 
    
  544.     await expect(async () => {
    
  545.       root.render(
    
  546.         <html>
    
  547.           <body>foo</body>
    
  548.           <style>foo</style>
    
  549.         </html>,
    
  550.       );
    
  551.       await waitForAll([]);
    
  552.     }).toErrorDev([
    
  553.       'Cannot render a <style> outside the main document without knowing its precedence and a unique href key. React can hoist and deduplicate <style> tags if you provide a `precedence` prop along with an `href` prop that does not conflic with the `href` values used in any other hoisted <style> or <link rel="stylesheet" ...> tags.  Note that hoisting <style> tags is considered an advanced feature that most will not use directly. Consider moving the <style> tag to the <head> or consider adding a `precedence="default"` and `href="some unique resource identifier"`, or move the <style> to the <style> tag.',
    
  554.       'Warning: validateDOMNesting(...): <style> cannot appear as a child of <html>.',
    
  555.     ]);
    
  556. 
    
  557.     await expect(async () => {
    
  558.       root.render(
    
  559.         <>
    
  560.           <html>
    
  561.             <body>foo</body>
    
  562.           </html>
    
  563.           <link rel="stylesheet" href="foo" />
    
  564.         </>,
    
  565.       );
    
  566.       const aggregateError = await waitForThrow();
    
  567.       expect(aggregateError.errors.length).toBe(2);
    
  568.       expect(aggregateError.errors[0].message).toContain(
    
  569.         'Invalid insertion of LINK',
    
  570.       );
    
  571.       expect(aggregateError.errors[1].message).toContain(
    
  572.         'The node to be removed is not a child of this node',
    
  573.       );
    
  574.     }).toErrorDev(
    
  575.       [
    
  576.         'Cannot render a <link rel="stylesheet" /> outside the main document without knowing its precedence. Consider adding precedence="default" or moving it into the root <head> tag.',
    
  577.         'Warning: validateDOMNesting(...): <link> cannot appear as a child of <#document>.',
    
  578.       ],
    
  579.       {withoutStack: 1},
    
  580.     );
    
  581. 
    
  582.     await expect(async () => {
    
  583.       root.render(
    
  584.         <>
    
  585.           <html>
    
  586.             <body>foo</body>
    
  587.             <script href="foo" />
    
  588.           </html>
    
  589.         </>,
    
  590.       );
    
  591.       await waitForAll([]);
    
  592.     }).toErrorDev([
    
  593.       'Cannot render a sync or defer <script> outside the main document without knowing its order. Try adding async="" or moving it into the root <head> tag.',
    
  594.       'Warning: validateDOMNesting(...): <script> cannot appear as a child of <html>.',
    
  595.     ]);
    
  596. 
    
  597.     await expect(async () => {
    
  598.       root.render(
    
  599.         <html>
    
  600.           <script async={true} onLoad={() => {}} href="bar" />
    
  601.           <body>foo</body>
    
  602.         </html>,
    
  603.       );
    
  604.       await waitForAll([]);
    
  605.     }).toErrorDev([
    
  606.       'Cannot render a <script> with onLoad or onError listeners outside the main document. Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or somewhere in the <body>.',
    
  607.     ]);
    
  608. 
    
  609.     await expect(async () => {
    
  610.       root.render(
    
  611.         <>
    
  612.           <link rel="foo" onLoad={() => {}} href="bar" />
    
  613.           <html>
    
  614.             <body>foo</body>
    
  615.           </html>
    
  616.         </>,
    
  617.       );
    
  618.       const aggregateError = await waitForThrow();
    
  619.       expect(aggregateError.errors.length).toBe(2);
    
  620.       expect(aggregateError.errors[0].message).toContain(
    
  621.         'Invalid insertion of LINK',
    
  622.       );
    
  623.       expect(aggregateError.errors[1].message).toContain(
    
  624.         'The node to be removed is not a child of this node',
    
  625.       );
    
  626.     }).toErrorDev(
    
  627.       [
    
  628.         'Cannot render a <link> with onLoad or onError listeners outside the main document. Try removing onLoad={...} and onError={...} or moving it into the root <head> tag or somewhere in the <body>.',
    
  629.       ],
    
  630.       {withoutStack: 1},
    
  631.     );
    
  632.   });
    
  633. 
    
  634.   // @gate enableFloat
    
  635.   it('can acquire a resource after releasing it in the same commit', async () => {
    
  636.     const root = ReactDOMClient.createRoot(container);
    
  637.     root.render(
    
  638.       <>
    
  639.         <script async={true} src="foo" />
    
  640.       </>,
    
  641.     );
    
  642.     await waitForAll([]);
    
  643.     expect(getMeaningfulChildren(document)).toEqual(
    
  644.       <html>
    
  645.         <head>
    
  646.           <script async="" src="foo" />
    
  647.         </head>
    
  648.         <body>
    
  649.           <div id="container" />
    
  650.         </body>
    
  651.       </html>,
    
  652.     );
    
  653. 
    
  654.     root.render(
    
  655.       <>
    
  656.         {null}
    
  657.         <script data-new="new" async={true} src="foo" />
    
  658.       </>,
    
  659.     );
    
  660.     await waitForAll([]);
    
  661.     // we don't see the attribute because the resource is the same and was not reconstructed
    
  662.     expect(getMeaningfulChildren(document)).toEqual(
    
  663.       <html>
    
  664.         <head>
    
  665.           <script async="" src="foo" />
    
  666.         </head>
    
  667.         <body>
    
  668.           <div id="container" />
    
  669.         </body>
    
  670.       </html>,
    
  671.     );
    
  672.   });
    
  673. 
    
  674.   // @gate enableFloat
    
  675.   it('emits resources before everything else when rendering with no head', async () => {
    
  676.     function App() {
    
  677.       return (
    
  678.         <>
    
  679.           <title>foo</title>
    
  680.           <link rel="preload" href="foo" as="style" />
    
  681.         </>
    
  682.       );
    
  683.     }
    
  684. 
    
  685.     await act(() => {
    
  686.       buffer = `<!DOCTYPE html><html><head>${ReactDOMFizzServer.renderToString(
    
  687.         <App />,
    
  688.       )}</head><body>foo</body></html>`;
    
  689.     });
    
  690.     expect(getMeaningfulChildren(document)).toEqual(
    
  691.       <html>
    
  692.         <head>
    
  693.           <link rel="preload" href="foo" as="style" />
    
  694.           <title>foo</title>
    
  695.         </head>
    
  696.         <body>foo</body>
    
  697.       </html>,
    
  698.     );
    
  699.   });
    
  700. 
    
  701.   // @gate enableFloat
    
  702.   it('emits resources before everything else when rendering with just a head', async () => {
    
  703.     function App() {
    
  704.       return (
    
  705.         <head>
    
  706.           <title>foo</title>
    
  707.           <link rel="preload" href="foo" as="style" />
    
  708.         </head>
    
  709.       );
    
  710.     }
    
  711. 
    
  712.     await act(() => {
    
  713.       buffer = `<!DOCTYPE html><html>${ReactDOMFizzServer.renderToString(
    
  714.         <App />,
    
  715.       )}<body>foo</body></html>`;
    
  716.     });
    
  717.     expect(getMeaningfulChildren(document)).toEqual(
    
  718.       <html>
    
  719.         <head>
    
  720.           <link rel="preload" href="foo" as="style" />
    
  721.           <title>foo</title>
    
  722.         </head>
    
  723.         <body>foo</body>
    
  724.       </html>,
    
  725.     );
    
  726.   });
    
  727. 
    
  728.   // @gate enableFloat
    
  729.   it('emits an implicit <head> element to hold resources when none is rendered but an <html> is rendered', async () => {
    
  730.     const chunks = [];
    
  731. 
    
  732.     writable.on('data', chunk => {
    
  733.       chunks.push(chunk);
    
  734.     });
    
  735. 
    
  736.     await act(() => {
    
  737.       const {pipe} = renderToPipeableStream(
    
  738.         <>
    
  739.           <title>foo</title>
    
  740.           <html>
    
  741.             <body>bar</body>
    
  742.           </html>
    
  743.           <script async={true} src="foo" />
    
  744.         </>,
    
  745.       );
    
  746.       pipe(writable);
    
  747.     });
    
  748.     expect(chunks).toEqual([
    
  749.       '<!DOCTYPE html><html><head><script async="" src="foo"></script><title>foo</title></head><body>bar',
    
  750.       '</body></html>',
    
  751.     ]);
    
  752.   });
    
  753. 
    
  754.   // @gate enableFloat
    
  755.   it('dedupes if the external runtime is explicitly loaded using preinit', async () => {
    
  756.     const unstable_externalRuntimeSrc = 'src-of-external-runtime';
    
  757.     function App() {
    
  758.       ReactDOM.preinit(unstable_externalRuntimeSrc, {as: 'script'});
    
  759.       return (
    
  760.         <div>
    
  761.           <Suspense fallback={<h1>Loading...</h1>}>
    
  762.             <AsyncText text="Hello" />
    
  763.           </Suspense>
    
  764.         </div>
    
  765.       );
    
  766.     }
    
  767. 
    
  768.     await act(() => {
    
  769.       const {pipe} = renderToPipeableStream(
    
  770.         <html>
    
  771.           <head />
    
  772.           <body>
    
  773.             <App />
    
  774.           </body>
    
  775.         </html>,
    
  776.         {
    
  777.           unstable_externalRuntimeSrc,
    
  778.         },
    
  779.       );
    
  780.       pipe(writable);
    
  781.     });
    
  782. 
    
  783.     expect(
    
  784.       Array.from(document.getElementsByTagName('script')).map(n => n.outerHTML),
    
  785.     ).toEqual(['<script src="src-of-external-runtime" async=""></script>']);
    
  786.   });
    
  787. 
    
  788.   // @gate enableFloat
    
  789.   it('can avoid inserting a late stylesheet if it already rendered on the client', async () => {
    
  790.     await act(() => {
    
  791.       renderToPipeableStream(
    
  792.         <html>
    
  793.           <body>
    
  794.             <Suspense fallback="loading foo...">
    
  795.               <BlockedOn value="foo">
    
  796.                 <link rel="stylesheet" href="foo" precedence="foo" />
    
  797.                 foo
    
  798.               </BlockedOn>
    
  799.             </Suspense>
    
  800.             <Suspense fallback="loading bar...">
    
  801.               <BlockedOn value="bar">
    
  802.                 <link rel="stylesheet" href="bar" precedence="bar" />
    
  803.                 bar
    
  804.               </BlockedOn>
    
  805.             </Suspense>
    
  806.           </body>
    
  807.         </html>,
    
  808.       ).pipe(writable);
    
  809.     });
    
  810. 
    
  811.     expect(getMeaningfulChildren(document)).toEqual(
    
  812.       <html>
    
  813.         <head />
    
  814.         <body>
    
  815.           {'loading foo...'}
    
  816.           {'loading bar...'}
    
  817.         </body>
    
  818.       </html>,
    
  819.     );
    
  820. 
    
  821.     ReactDOMClient.hydrateRoot(
    
  822.       document,
    
  823.       <html>
    
  824.         <body>
    
  825.           <link rel="stylesheet" href="foo" precedence="foo" />
    
  826.           <Suspense fallback="loading foo...">
    
  827.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  828.             foo
    
  829.           </Suspense>
    
  830.           <Suspense fallback="loading bar...">
    
  831.             <link rel="stylesheet" href="bar" precedence="bar" />
    
  832.             bar
    
  833.           </Suspense>
    
  834.         </body>
    
  835.       </html>,
    
  836.     );
    
  837.     await waitForAll([]);
    
  838.     expect(getMeaningfulChildren(document)).toEqual(
    
  839.       <html>
    
  840.         <head>
    
  841.           <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  842.           <link as="style" href="foo" rel="preload" />
    
  843.         </head>
    
  844.         <body>
    
  845.           {'loading foo...'}
    
  846.           {'loading bar...'}
    
  847.         </body>
    
  848.       </html>,
    
  849.     );
    
  850. 
    
  851.     await act(() => {
    
  852.       resolveText('bar');
    
  853.     });
    
  854.     await act(() => {
    
  855.       const sheets = document.querySelectorAll(
    
  856.         'link[rel="stylesheet"][data-precedence]',
    
  857.       );
    
  858.       const event = document.createEvent('Event');
    
  859.       event.initEvent('load', true, true);
    
  860.       for (let i = 0; i < sheets.length; i++) {
    
  861.         sheets[i].dispatchEvent(event);
    
  862.       }
    
  863.     });
    
  864.     expect(getMeaningfulChildren(document)).toEqual(
    
  865.       <html>
    
  866.         <head>
    
  867.           <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  868.           <link rel="stylesheet" href="bar" data-precedence="bar" />
    
  869.           <link as="style" href="foo" rel="preload" />
    
  870.         </head>
    
  871.         <body>
    
  872.           {'loading foo...'}
    
  873.           {'bar'}
    
  874.           <link as="style" href="bar" rel="preload" />
    
  875.         </body>
    
  876.       </html>,
    
  877.     );
    
  878. 
    
  879.     await act(() => {
    
  880.       resolveText('foo');
    
  881.     });
    
  882.     await act(() => {
    
  883.       const sheets = document.querySelectorAll(
    
  884.         'link[rel="stylesheet"][data-precedence]',
    
  885.       );
    
  886.       const event = document.createEvent('Event');
    
  887.       event.initEvent('load', true, true);
    
  888.       for (let i = 0; i < sheets.length; i++) {
    
  889.         sheets[i].dispatchEvent(event);
    
  890.       }
    
  891.     });
    
  892.     expect(getMeaningfulChildren(document)).toEqual(
    
  893.       <html>
    
  894.         <head>
    
  895.           <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  896.           <link rel="stylesheet" href="bar" data-precedence="bar" />
    
  897.           <link as="style" href="foo" rel="preload" />
    
  898.         </head>
    
  899.         <body>
    
  900.           {'foo'}
    
  901.           {'bar'}
    
  902.           <link as="style" href="bar" rel="preload" />
    
  903.           <link as="style" href="foo" rel="preload" />
    
  904.         </body>
    
  905.       </html>,
    
  906.     );
    
  907.   });
    
  908. 
    
  909.   // @gate enableFloat
    
  910.   it('can hoist <link rel="stylesheet" .../> and <style /> tags together, respecting order of discovery', async () => {
    
  911.     const css = `
    
  912. body {
    
  913.   background-color: red;
    
  914. }`;
    
  915. 
    
  916.     await act(() => {
    
  917.       renderToPipeableStream(
    
  918.         <html>
    
  919.           <body>
    
  920.             <link rel="stylesheet" href="one1" precedence="one" />
    
  921.             <style href="two1" precedence="two">
    
  922.               {css}
    
  923.             </style>
    
  924.             <link rel="stylesheet" href="three1" precedence="three" />
    
  925.             <style href="four1" precedence="four">
    
  926.               {css}
    
  927.             </style>
    
  928.             <Suspense>
    
  929.               <BlockedOn value="block">
    
  930.                 <link rel="stylesheet" href="one2" precedence="one" />
    
  931.                 <link rel="stylesheet" href="two2" precedence="two" />
    
  932.                 <style href="three2" precedence="three">
    
  933.                   {css}
    
  934.                 </style>
    
  935.                 <style href="four2" precedence="four">
    
  936.                   {css}
    
  937.                 </style>
    
  938.                 <link rel="stylesheet" href="five1" precedence="five" />
    
  939.               </BlockedOn>
    
  940.             </Suspense>
    
  941.             <Suspense>
    
  942.               <BlockedOn value="block2">
    
  943.                 <style href="one3" precedence="one">
    
  944.                   {css}
    
  945.                 </style>
    
  946.                 <style href="two3" precedence="two">
    
  947.                   {css}
    
  948.                 </style>
    
  949.                 <link rel="stylesheet" href="three3" precedence="three" />
    
  950.                 <link rel="stylesheet" href="four3" precedence="four" />
    
  951.                 <style href="six1" precedence="six">
    
  952.                   {css}
    
  953.                 </style>
    
  954.               </BlockedOn>
    
  955.             </Suspense>
    
  956.             <Suspense>
    
  957.               <BlockedOn value="block again">
    
  958.                 <link rel="stylesheet" href="one2" precedence="one" />
    
  959.                 <link rel="stylesheet" href="two2" precedence="two" />
    
  960.                 <style href="three2" precedence="three">
    
  961.                   {css}
    
  962.                 </style>
    
  963.                 <style href="four2" precedence="four">
    
  964.                   {css}
    
  965.                 </style>
    
  966.                 <link rel="stylesheet" href="five1" precedence="five" />
    
  967.               </BlockedOn>
    
  968.             </Suspense>
    
  969.           </body>
    
  970.         </html>,
    
  971.       ).pipe(writable);
    
  972.     });
    
  973. 
    
  974.     expect(getMeaningfulChildren(document)).toEqual(
    
  975.       <html>
    
  976.         <head>
    
  977.           <link rel="stylesheet" href="one1" data-precedence="one" />
    
  978.           <style data-href="two1" data-precedence="two">
    
  979.             {css}
    
  980.           </style>
    
  981.           <link rel="stylesheet" href="three1" data-precedence="three" />
    
  982.           <style data-href="four1" data-precedence="four">
    
  983.             {css}
    
  984.           </style>
    
  985.         </head>
    
  986.         <body />
    
  987.       </html>,
    
  988.     );
    
  989. 
    
  990.     await act(() => {
    
  991.       resolveText('block');
    
  992.     });
    
  993. 
    
  994.     expect(getMeaningfulChildren(document)).toEqual(
    
  995.       <html>
    
  996.         <head>
    
  997.           <link rel="stylesheet" href="one1" data-precedence="one" />
    
  998.           <link rel="stylesheet" href="one2" data-precedence="one" />
    
  999.           <style data-href="two1" data-precedence="two">
    
  1000.             {css}
    
  1001.           </style>
    
  1002.           <link rel="stylesheet" href="two2" data-precedence="two" />
    
  1003.           <link rel="stylesheet" href="three1" data-precedence="three" />
    
  1004.           <style data-href="three2" data-precedence="three">
    
  1005.             {css}
    
  1006.           </style>
    
  1007.           <style data-href="four1" data-precedence="four">
    
  1008.             {css}
    
  1009.           </style>
    
  1010.           <style data-href="four2" data-precedence="four">
    
  1011.             {css}
    
  1012.           </style>
    
  1013.           <link rel="stylesheet" href="five1" data-precedence="five" />
    
  1014.         </head>
    
  1015.         <body>
    
  1016.           <link rel="preload" href="one2" as="style" />
    
  1017.           <link rel="preload" href="two2" as="style" />
    
  1018.           <link rel="preload" href="five1" as="style" />
    
  1019.         </body>
    
  1020.       </html>,
    
  1021.     );
    
  1022. 
    
  1023.     await act(() => {
    
  1024.       resolveText('block2');
    
  1025.     });
    
  1026. 
    
  1027.     expect(getMeaningfulChildren(document)).toEqual(
    
  1028.       <html>
    
  1029.         <head>
    
  1030.           <link rel="stylesheet" href="one1" data-precedence="one" />
    
  1031.           <link rel="stylesheet" href="one2" data-precedence="one" />
    
  1032.           <style data-href="one3" data-precedence="one">
    
  1033.             {css}
    
  1034.           </style>
    
  1035.           <style data-href="two1" data-precedence="two">
    
  1036.             {css}
    
  1037.           </style>
    
  1038.           <link rel="stylesheet" href="two2" data-precedence="two" />
    
  1039.           <style data-href="two3" data-precedence="two">
    
  1040.             {css}
    
  1041.           </style>
    
  1042.           <link rel="stylesheet" href="three1" data-precedence="three" />
    
  1043.           <style data-href="three2" data-precedence="three">
    
  1044.             {css}
    
  1045.           </style>
    
  1046.           <link rel="stylesheet" href="three3" data-precedence="three" />
    
  1047.           <style data-href="four1" data-precedence="four">
    
  1048.             {css}
    
  1049.           </style>
    
  1050.           <style data-href="four2" data-precedence="four">
    
  1051.             {css}
    
  1052.           </style>
    
  1053.           <link rel="stylesheet" href="four3" data-precedence="four" />
    
  1054.           <link rel="stylesheet" href="five1" data-precedence="five" />
    
  1055.           <style data-href="six1" data-precedence="six">
    
  1056.             {css}
    
  1057.           </style>
    
  1058.         </head>
    
  1059.         <body>
    
  1060.           <link rel="preload" href="one2" as="style" />
    
  1061.           <link rel="preload" href="two2" as="style" />
    
  1062.           <link rel="preload" href="five1" as="style" />
    
  1063.           <link rel="preload" href="three3" as="style" />
    
  1064.           <link rel="preload" href="four3" as="style" />
    
  1065.         </body>
    
  1066.       </html>,
    
  1067.     );
    
  1068. 
    
  1069.     await act(() => {
    
  1070.       resolveText('block again');
    
  1071.     });
    
  1072. 
    
  1073.     expect(getMeaningfulChildren(document)).toEqual(
    
  1074.       <html>
    
  1075.         <head>
    
  1076.           <link rel="stylesheet" href="one1" data-precedence="one" />
    
  1077.           <link rel="stylesheet" href="one2" data-precedence="one" />
    
  1078.           <style data-href="one3" data-precedence="one">
    
  1079.             {css}
    
  1080.           </style>
    
  1081.           <style data-href="two1" data-precedence="two">
    
  1082.             {css}
    
  1083.           </style>
    
  1084.           <link rel="stylesheet" href="two2" data-precedence="two" />
    
  1085.           <style data-href="two3" data-precedence="two">
    
  1086.             {css}
    
  1087.           </style>
    
  1088.           <link rel="stylesheet" href="three1" data-precedence="three" />
    
  1089.           <style data-href="three2" data-precedence="three">
    
  1090.             {css}
    
  1091.           </style>
    
  1092.           <link rel="stylesheet" href="three3" data-precedence="three" />
    
  1093.           <style data-href="four1" data-precedence="four">
    
  1094.             {css}
    
  1095.           </style>
    
  1096.           <style data-href="four2" data-precedence="four">
    
  1097.             {css}
    
  1098.           </style>
    
  1099.           <link rel="stylesheet" href="four3" data-precedence="four" />
    
  1100.           <link rel="stylesheet" href="five1" data-precedence="five" />
    
  1101.           <style data-href="six1" data-precedence="six">
    
  1102.             {css}
    
  1103.           </style>
    
  1104.         </head>
    
  1105.         <body>
    
  1106.           <link rel="preload" href="one2" as="style" />
    
  1107.           <link rel="preload" href="two2" as="style" />
    
  1108.           <link rel="preload" href="five1" as="style" />
    
  1109.           <link rel="preload" href="three3" as="style" />
    
  1110.           <link rel="preload" href="four3" as="style" />
    
  1111.         </body>
    
  1112.       </html>,
    
  1113.     );
    
  1114. 
    
  1115.     ReactDOMClient.hydrateRoot(
    
  1116.       document,
    
  1117.       <html>
    
  1118.         <body>
    
  1119.           <link rel="stylesheet" href="one4" precedence="one" />
    
  1120.           <style href="two4" precedence="two">
    
  1121.             {css}
    
  1122.           </style>
    
  1123.           <link rel="stylesheet" href="three4" precedence="three" />
    
  1124.           <style href="four4" precedence="four">
    
  1125.             {css}
    
  1126.           </style>
    
  1127.           <link rel="stylesheet" href="seven1" precedence="seven" />
    
  1128.           <style href="eight1" precedence="eight">
    
  1129.             {css}
    
  1130.           </style>
    
  1131.         </body>
    
  1132.       </html>,
    
  1133.     );
    
  1134.     await waitForAll([]);
    
  1135. 
    
  1136.     expect(getMeaningfulChildren(document)).toEqual(
    
  1137.       <html>
    
  1138.         <head>
    
  1139.           <link rel="stylesheet" href="one1" data-precedence="one" />
    
  1140.           <link rel="stylesheet" href="one2" data-precedence="one" />
    
  1141.           <style data-href="one3" data-precedence="one">
    
  1142.             {css}
    
  1143.           </style>
    
  1144.           <link rel="stylesheet" href="one4" data-precedence="one" />
    
  1145.           <style data-href="two1" data-precedence="two">
    
  1146.             {css}
    
  1147.           </style>
    
  1148.           <link rel="stylesheet" href="two2" data-precedence="two" />
    
  1149.           <style data-href="two3" data-precedence="two">
    
  1150.             {css}
    
  1151.           </style>
    
  1152.           <style data-href="two4" data-precedence="two">
    
  1153.             {css}
    
  1154.           </style>
    
  1155.           <link rel="stylesheet" href="three1" data-precedence="three" />
    
  1156.           <style data-href="three2" data-precedence="three">
    
  1157.             {css}
    
  1158.           </style>
    
  1159.           <link rel="stylesheet" href="three3" data-precedence="three" />
    
  1160.           <link rel="stylesheet" href="three4" data-precedence="three" />
    
  1161.           <style data-href="four1" data-precedence="four">
    
  1162.             {css}
    
  1163.           </style>
    
  1164.           <style data-href="four2" data-precedence="four">
    
  1165.             {css}
    
  1166.           </style>
    
  1167.           <link rel="stylesheet" href="four3" data-precedence="four" />
    
  1168.           <style data-href="four4" data-precedence="four">
    
  1169.             {css}
    
  1170.           </style>
    
  1171.           <link rel="stylesheet" href="five1" data-precedence="five" />
    
  1172.           <style data-href="six1" data-precedence="six">
    
  1173.             {css}
    
  1174.           </style>
    
  1175.           <link rel="stylesheet" href="seven1" data-precedence="seven" />
    
  1176.           <style data-href="eight1" data-precedence="eight">
    
  1177.             {css}
    
  1178.           </style>
    
  1179.           <link rel="preload" href="one4" as="style" />
    
  1180.           <link rel="preload" href="three4" as="style" />
    
  1181.           <link rel="preload" href="seven1" as="style" />
    
  1182.         </head>
    
  1183.         <body>
    
  1184.           <link rel="preload" href="one2" as="style" />
    
  1185.           <link rel="preload" href="two2" as="style" />
    
  1186.           <link rel="preload" href="five1" as="style" />
    
  1187.           <link rel="preload" href="three3" as="style" />
    
  1188.           <link rel="preload" href="four3" as="style" />
    
  1189.         </body>
    
  1190.       </html>,
    
  1191.     );
    
  1192.   });
    
  1193. 
    
  1194.   // @gate enableFloat
    
  1195.   it('client renders a boundary if a style Resource dependency fails to load', async () => {
    
  1196.     function App() {
    
  1197.       return (
    
  1198.         <html>
    
  1199.           <head />
    
  1200.           <body>
    
  1201.             <Suspense fallback="loading...">
    
  1202.               <BlockedOn value="unblock">
    
  1203.                 <link rel="stylesheet" href="foo" precedence="arbitrary" />
    
  1204.                 <link rel="stylesheet" href="bar" precedence="arbitrary" />
    
  1205.                 Hello
    
  1206.               </BlockedOn>
    
  1207.             </Suspense>
    
  1208.           </body>
    
  1209.         </html>
    
  1210.       );
    
  1211.     }
    
  1212.     await act(() => {
    
  1213.       const {pipe} = renderToPipeableStream(<App />);
    
  1214.       pipe(writable);
    
  1215.     });
    
  1216. 
    
  1217.     await act(() => {
    
  1218.       resolveText('unblock');
    
  1219.     });
    
  1220. 
    
  1221.     expect(getMeaningfulChildren(document)).toEqual(
    
  1222.       <html>
    
  1223.         <head>
    
  1224.           <link rel="stylesheet" href="foo" data-precedence="arbitrary" />
    
  1225.           <link rel="stylesheet" href="bar" data-precedence="arbitrary" />
    
  1226.         </head>
    
  1227.         <body>
    
  1228.           loading...
    
  1229.           <link rel="preload" href="foo" as="style" />
    
  1230.           <link rel="preload" href="bar" as="style" />
    
  1231.         </body>
    
  1232.       </html>,
    
  1233.     );
    
  1234. 
    
  1235.     errorStylesheets(['bar']);
    
  1236.     assertLog(['error stylesheet: bar']);
    
  1237. 
    
  1238.     await waitForAll([]);
    
  1239. 
    
  1240.     const boundaryTemplateInstance = document.getElementById('B:0');
    
  1241.     const suspenseInstance = boundaryTemplateInstance.previousSibling;
    
  1242. 
    
  1243.     expect(suspenseInstance.data).toEqual('$!');
    
  1244.     expect(boundaryTemplateInstance.dataset.dgst).toBe(
    
  1245.       'Resource failed to load',
    
  1246.     );
    
  1247. 
    
  1248.     expect(getMeaningfulChildren(document)).toEqual(
    
  1249.       <html>
    
  1250.         <head>
    
  1251.           <link rel="stylesheet" href="foo" data-precedence="arbitrary" />
    
  1252.           <link rel="stylesheet" href="bar" data-precedence="arbitrary" />
    
  1253.         </head>
    
  1254.         <body>
    
  1255.           loading...
    
  1256.           <link rel="preload" href="foo" as="style" />
    
  1257.           <link rel="preload" href="bar" as="style" />
    
  1258.         </body>
    
  1259.       </html>,
    
  1260.     );
    
  1261. 
    
  1262.     const errors = [];
    
  1263.     ReactDOMClient.hydrateRoot(document, <App />, {
    
  1264.       onRecoverableError(err, errInfo) {
    
  1265.         errors.push(err.message);
    
  1266.         errors.push(err.digest);
    
  1267.       },
    
  1268.     });
    
  1269.     await waitForAll([]);
    
  1270.     // When binding a stylesheet that was SSR'd in a boundary reveal there is a loadingState promise
    
  1271.     // We need to use that promise to resolve the suspended commit because we don't know if the load or error
    
  1272.     // events have already fired. This requires the load to be awaited for the commit to have a chance to flush
    
  1273.     // We could change this by tracking the loadingState's fulfilled status directly on the loadingState similar
    
  1274.     // to thenables however this slightly increases the fizz runtime code size.
    
  1275.     await clientAct(() => loadStylesheets());
    
  1276.     assertLog(['load stylesheet: foo']);
    
  1277.     expect(getMeaningfulChildren(document)).toEqual(
    
  1278.       <html>
    
  1279.         <head>
    
  1280.           <link rel="stylesheet" href="foo" data-precedence="arbitrary" />
    
  1281.           <link rel="stylesheet" href="bar" data-precedence="arbitrary" />
    
  1282.         </head>
    
  1283.         <body>
    
  1284.           <link rel="preload" href="foo" as="style" />
    
  1285.           <link rel="preload" href="bar" as="style" />
    
  1286.           Hello
    
  1287.         </body>
    
  1288.       </html>,
    
  1289.     );
    
  1290.     expect(errors).toEqual([
    
  1291.       'The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.',
    
  1292.       'Resource failed to load',
    
  1293.     ]);
    
  1294.   });
    
  1295. 
    
  1296.   // @gate enableFloat
    
  1297.   it('treats stylesheet links with a precedence as a resource', async () => {
    
  1298.     await act(() => {
    
  1299.       const {pipe} = renderToPipeableStream(
    
  1300.         <html>
    
  1301.           <head />
    
  1302.           <body>
    
  1303.             <link rel="stylesheet" href="foo" precedence="arbitrary" />
    
  1304.             Hello
    
  1305.           </body>
    
  1306.         </html>,
    
  1307.       );
    
  1308.       pipe(writable);
    
  1309.     });
    
  1310.     expect(getMeaningfulChildren(document)).toEqual(
    
  1311.       <html>
    
  1312.         <head>
    
  1313.           <link rel="stylesheet" href="foo" data-precedence="arbitrary" />
    
  1314.         </head>
    
  1315.         <body>Hello</body>
    
  1316.       </html>,
    
  1317.     );
    
  1318. 
    
  1319.     ReactDOMClient.hydrateRoot(
    
  1320.       document,
    
  1321.       <html>
    
  1322.         <head />
    
  1323.         <body>Hello</body>
    
  1324.       </html>,
    
  1325.     );
    
  1326.     await waitForAll([]);
    
  1327.     expect(getMeaningfulChildren(document)).toEqual(
    
  1328.       <html>
    
  1329.         <head>
    
  1330.           <link rel="stylesheet" href="foo" data-precedence="arbitrary" />
    
  1331.         </head>
    
  1332.         <body>Hello</body>
    
  1333.       </html>,
    
  1334.     );
    
  1335.   });
    
  1336. 
    
  1337.   // @gate enableFloat
    
  1338.   it('inserts text separators following text when followed by an element that is converted to a resource and thus removed from the html inline', async () => {
    
  1339.     // If you render many of these as siblings the values get emitted as a single text with no separator sometimes
    
  1340.     // because the link gets elided as a resource
    
  1341.     function AsyncTextWithResource({text, href, precedence}) {
    
  1342.       const value = readText(text);
    
  1343.       return (
    
  1344.         <>
    
  1345.           {value}
    
  1346.           <link rel="stylesheet" href={href} precedence={precedence} />
    
  1347.         </>
    
  1348.       );
    
  1349.     }
    
  1350. 
    
  1351.     await act(() => {
    
  1352.       const {pipe} = renderToPipeableStream(
    
  1353.         <html>
    
  1354.           <head />
    
  1355.           <body>
    
  1356.             <AsyncTextWithResource text="foo" href="foo" precedence="one" />
    
  1357.             <AsyncTextWithResource text="bar" href="bar" precedence="two" />
    
  1358.             <AsyncTextWithResource text="baz" href="baz" precedence="three" />
    
  1359.           </body>
    
  1360.         </html>,
    
  1361.       );
    
  1362.       pipe(writable);
    
  1363.       resolveText('foo');
    
  1364.       resolveText('bar');
    
  1365.       resolveText('baz');
    
  1366.     });
    
  1367. 
    
  1368.     expect(getMeaningfulChildren(document)).toEqual(
    
  1369.       <html>
    
  1370.         <head>
    
  1371.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1372.           <link rel="stylesheet" href="bar" data-precedence="two" />
    
  1373.           <link rel="stylesheet" href="baz" data-precedence="three" />
    
  1374.         </head>
    
  1375.         <body>
    
  1376.           {'foo'}
    
  1377.           {'bar'}
    
  1378.           {'baz'}
    
  1379.         </body>
    
  1380.       </html>,
    
  1381.     );
    
  1382.   });
    
  1383. 
    
  1384.   // @gate enableFloat
    
  1385.   it('hoists late stylesheets the correct precedence', async () => {
    
  1386.     function PresetPrecedence() {
    
  1387.       ReactDOM.preinit('preset', {as: 'style', precedence: 'preset'});
    
  1388.     }
    
  1389.     await act(() => {
    
  1390.       const {pipe} = renderToPipeableStream(
    
  1391.         <html>
    
  1392.           <head />
    
  1393.           <body>
    
  1394.             <link rel="stylesheet" href="initial" precedence="one" />
    
  1395.             <PresetPrecedence />
    
  1396.             <div>
    
  1397.               <Suspense fallback="loading foo bar...">
    
  1398.                 <div>foo</div>
    
  1399.                 <link rel="stylesheet" href="foo" precedence="one" />
    
  1400.                 <BlockedOn value="bar">
    
  1401.                   <div>bar</div>
    
  1402.                   <link rel="stylesheet" href="bar" precedence="default" />
    
  1403.                 </BlockedOn>
    
  1404.               </Suspense>
    
  1405.             </div>
    
  1406.             <div>
    
  1407.               <Suspense fallback="loading bar baz qux...">
    
  1408.                 <BlockedOn value="bar">
    
  1409.                   <div>bar</div>
    
  1410.                   <link rel="stylesheet" href="bar" precedence="default" />
    
  1411.                 </BlockedOn>
    
  1412.                 <BlockedOn value="baz">
    
  1413.                   <div>baz</div>
    
  1414.                   <link rel="stylesheet" href="baz" precedence="two" />
    
  1415.                 </BlockedOn>
    
  1416.                 <BlockedOn value="qux">
    
  1417.                   <div>qux</div>
    
  1418.                   <link rel="stylesheet" href="qux" precedence="one" />
    
  1419.                 </BlockedOn>
    
  1420.               </Suspense>
    
  1421.             </div>
    
  1422.             <div>
    
  1423.               <Suspense fallback="loading bar baz qux...">
    
  1424.                 <BlockedOn value="unblock">
    
  1425.                   <BlockedOn value="bar">
    
  1426.                     <div>bar</div>
    
  1427.                     <link rel="stylesheet" href="bar" precedence="default" />
    
  1428.                   </BlockedOn>
    
  1429.                   <BlockedOn value="baz">
    
  1430.                     <div>baz</div>
    
  1431.                     <link rel="stylesheet" href="baz" precedence="two" />
    
  1432.                   </BlockedOn>
    
  1433.                   <BlockedOn value="qux">
    
  1434.                     <div>qux</div>
    
  1435.                     <link rel="stylesheet" href="qux" precedence="one" />
    
  1436.                   </BlockedOn>
    
  1437.                 </BlockedOn>
    
  1438.               </Suspense>
    
  1439.             </div>
    
  1440.           </body>
    
  1441.         </html>,
    
  1442.       );
    
  1443.       pipe(writable);
    
  1444.     });
    
  1445. 
    
  1446.     expect(getMeaningfulChildren(document)).toEqual(
    
  1447.       <html>
    
  1448.         <head>
    
  1449.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1450.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1451.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1452.         </head>
    
  1453.         <body>
    
  1454.           <div>loading foo bar...</div>
    
  1455.           <div>loading bar baz qux...</div>
    
  1456.           <div>loading bar baz qux...</div>
    
  1457.         </body>
    
  1458.       </html>,
    
  1459.     );
    
  1460. 
    
  1461.     await act(() => {
    
  1462.       resolveText('foo');
    
  1463.       resolveText('bar');
    
  1464.     });
    
  1465. 
    
  1466.     expect(getMeaningfulChildren(document)).toEqual(
    
  1467.       <html>
    
  1468.         <head>
    
  1469.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1470.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1471.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1472.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1473.         </head>
    
  1474.         <body>
    
  1475.           <div>loading foo bar...</div>
    
  1476.           <div>loading bar baz qux...</div>
    
  1477.           <div>loading bar baz qux...</div>
    
  1478.           <link rel="preload" href="bar" as="style" />
    
  1479.         </body>
    
  1480.       </html>,
    
  1481.     );
    
  1482. 
    
  1483.     await act(() => {
    
  1484.       const link = document.querySelector('link[rel="stylesheet"][href="foo"]');
    
  1485.       const event = document.createEvent('Events');
    
  1486.       event.initEvent('load', true, true);
    
  1487.       link.dispatchEvent(event);
    
  1488.     });
    
  1489. 
    
  1490.     expect(getMeaningfulChildren(document)).toEqual(
    
  1491.       <html>
    
  1492.         <head>
    
  1493.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1494.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1495.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1496.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1497.         </head>
    
  1498.         <body>
    
  1499.           <div>loading foo bar...</div>
    
  1500.           <div>loading bar baz qux...</div>
    
  1501.           <div>loading bar baz qux...</div>
    
  1502.           <link rel="preload" href="bar" as="style" />
    
  1503.         </body>
    
  1504.       </html>,
    
  1505.     );
    
  1506. 
    
  1507.     await act(() => {
    
  1508.       const link = document.querySelector('link[rel="stylesheet"][href="bar"]');
    
  1509.       const event = document.createEvent('Events');
    
  1510.       event.initEvent('load', true, true);
    
  1511.       link.dispatchEvent(event);
    
  1512.     });
    
  1513. 
    
  1514.     expect(getMeaningfulChildren(document)).toEqual(
    
  1515.       <html>
    
  1516.         <head>
    
  1517.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1518.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1519.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1520.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1521.         </head>
    
  1522.         <body>
    
  1523.           <div>
    
  1524.             <div>foo</div>
    
  1525.             <div>bar</div>
    
  1526.           </div>
    
  1527.           <div>loading bar baz qux...</div>
    
  1528.           <div>loading bar baz qux...</div>
    
  1529.           <link rel="preload" href="bar" as="style" />
    
  1530.         </body>
    
  1531.       </html>,
    
  1532.     );
    
  1533. 
    
  1534.     await act(() => {
    
  1535.       resolveText('baz');
    
  1536.     });
    
  1537. 
    
  1538.     expect(getMeaningfulChildren(document)).toEqual(
    
  1539.       <html>
    
  1540.         <head>
    
  1541.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1542.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1543.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1544.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1545.         </head>
    
  1546.         <body>
    
  1547.           <div>
    
  1548.             <div>foo</div>
    
  1549.             <div>bar</div>
    
  1550.           </div>
    
  1551.           <div>loading bar baz qux...</div>
    
  1552.           <div>loading bar baz qux...</div>
    
  1553.           <link rel="preload" as="style" href="bar" />
    
  1554.           <link rel="preload" as="style" href="baz" />
    
  1555.         </body>
    
  1556.       </html>,
    
  1557.     );
    
  1558. 
    
  1559.     await act(() => {
    
  1560.       resolveText('qux');
    
  1561.     });
    
  1562. 
    
  1563.     expect(getMeaningfulChildren(document)).toEqual(
    
  1564.       <html>
    
  1565.         <head>
    
  1566.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1567.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1568.           <link rel="stylesheet" href="qux" data-precedence="one" />
    
  1569.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1570.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1571.           <link rel="stylesheet" href="baz" data-precedence="two" />
    
  1572.         </head>
    
  1573.         <body>
    
  1574.           <div>
    
  1575.             <div>foo</div>
    
  1576.             <div>bar</div>
    
  1577.           </div>
    
  1578.           <div>loading bar baz qux...</div>
    
  1579.           <div>loading bar baz qux...</div>
    
  1580.           <link rel="preload" as="style" href="bar" />
    
  1581.           <link rel="preload" as="style" href="baz" />
    
  1582.           <link rel="preload" as="style" href="qux" />
    
  1583.         </body>
    
  1584.       </html>,
    
  1585.     );
    
  1586. 
    
  1587.     await act(() => {
    
  1588.       const bazlink = document.querySelector(
    
  1589.         'link[rel="stylesheet"][href="baz"]',
    
  1590.       );
    
  1591.       const quxlink = document.querySelector(
    
  1592.         'link[rel="stylesheet"][href="qux"]',
    
  1593.       );
    
  1594.       const presetLink = document.querySelector(
    
  1595.         'link[rel="stylesheet"][href="preset"]',
    
  1596.       );
    
  1597.       const event = document.createEvent('Events');
    
  1598.       event.initEvent('load', true, true);
    
  1599.       bazlink.dispatchEvent(event);
    
  1600.       quxlink.dispatchEvent(event);
    
  1601.       presetLink.dispatchEvent(event);
    
  1602.     });
    
  1603. 
    
  1604.     expect(getMeaningfulChildren(document)).toEqual(
    
  1605.       <html>
    
  1606.         <head>
    
  1607.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1608.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1609.           <link rel="stylesheet" href="qux" data-precedence="one" />
    
  1610.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1611.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1612.           <link rel="stylesheet" href="baz" data-precedence="two" />
    
  1613.         </head>
    
  1614.         <body>
    
  1615.           <div>
    
  1616.             <div>foo</div>
    
  1617.             <div>bar</div>
    
  1618.           </div>
    
  1619.           <div>
    
  1620.             <div>bar</div>
    
  1621.             <div>baz</div>
    
  1622.             <div>qux</div>
    
  1623.           </div>
    
  1624.           <div>loading bar baz qux...</div>
    
  1625.           <link rel="preload" as="style" href="bar" />
    
  1626.           <link rel="preload" as="style" href="baz" />
    
  1627.           <link rel="preload" as="style" href="qux" />
    
  1628.         </body>
    
  1629.       </html>,
    
  1630.     );
    
  1631. 
    
  1632.     await act(() => {
    
  1633.       resolveText('unblock');
    
  1634.     });
    
  1635. 
    
  1636.     expect(getMeaningfulChildren(document)).toEqual(
    
  1637.       <html>
    
  1638.         <head>
    
  1639.           <link rel="stylesheet" href="initial" data-precedence="one" />
    
  1640.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1641.           <link rel="stylesheet" href="qux" data-precedence="one" />
    
  1642.           <link rel="stylesheet" href="preset" data-precedence="preset" />
    
  1643.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1644.           <link rel="stylesheet" href="baz" data-precedence="two" />
    
  1645.         </head>
    
  1646.         <body>
    
  1647.           <div>
    
  1648.             <div>foo</div>
    
  1649.             <div>bar</div>
    
  1650.           </div>
    
  1651.           <div>
    
  1652.             <div>bar</div>
    
  1653.             <div>baz</div>
    
  1654.             <div>qux</div>
    
  1655.           </div>
    
  1656.           <div>
    
  1657.             <div>bar</div>
    
  1658.             <div>baz</div>
    
  1659.             <div>qux</div>
    
  1660.           </div>
    
  1661.           <link rel="preload" as="style" href="bar" />
    
  1662.           <link rel="preload" as="style" href="baz" />
    
  1663.           <link rel="preload" as="style" href="qux" />
    
  1664.         </body>
    
  1665.       </html>,
    
  1666.     );
    
  1667.   });
    
  1668. 
    
  1669.   // @gate enableFloat
    
  1670.   it('normalizes stylesheet resource precedence for all boundaries inlined as part of the shell flush', async () => {
    
  1671.     await act(() => {
    
  1672.       const {pipe} = renderToPipeableStream(
    
  1673.         <html>
    
  1674.           <head />
    
  1675.           <body>
    
  1676.             <div>
    
  1677.               outer
    
  1678.               <link rel="stylesheet" href="1one" precedence="one" />
    
  1679.               <link rel="stylesheet" href="1two" precedence="two" />
    
  1680.               <link rel="stylesheet" href="1three" precedence="three" />
    
  1681.               <link rel="stylesheet" href="1four" precedence="four" />
    
  1682.               <Suspense fallback={null}>
    
  1683.                 <div>
    
  1684.                   middle
    
  1685.                   <link rel="stylesheet" href="2one" precedence="one" />
    
  1686.                   <link rel="stylesheet" href="2two" precedence="two" />
    
  1687.                   <link rel="stylesheet" href="2three" precedence="three" />
    
  1688.                   <link rel="stylesheet" href="2four" precedence="four" />
    
  1689.                   <Suspense fallback={null}>
    
  1690.                     <div>
    
  1691.                       inner
    
  1692.                       <link rel="stylesheet" href="3five" precedence="five" />
    
  1693.                       <link rel="stylesheet" href="3one" precedence="one" />
    
  1694.                       <link rel="stylesheet" href="3two" precedence="two" />
    
  1695.                       <link rel="stylesheet" href="3three" precedence="three" />
    
  1696.                       <link rel="stylesheet" href="3four" precedence="four" />
    
  1697.                     </div>
    
  1698.                   </Suspense>
    
  1699.                 </div>
    
  1700.               </Suspense>
    
  1701.               <Suspense fallback={null}>
    
  1702.                 <div>middle</div>
    
  1703.                 <link rel="stylesheet" href="4one" precedence="one" />
    
  1704.                 <link rel="stylesheet" href="4two" precedence="two" />
    
  1705.                 <link rel="stylesheet" href="4three" precedence="three" />
    
  1706.                 <link rel="stylesheet" href="4four" precedence="four" />
    
  1707.               </Suspense>
    
  1708.             </div>
    
  1709.           </body>
    
  1710.         </html>,
    
  1711.       );
    
  1712.       pipe(writable);
    
  1713.     });
    
  1714. 
    
  1715.     expect(getMeaningfulChildren(document)).toEqual(
    
  1716.       <html>
    
  1717.         <head>
    
  1718.           <link rel="stylesheet" href="1one" data-precedence="one" />
    
  1719.           <link rel="stylesheet" href="2one" data-precedence="one" />
    
  1720.           <link rel="stylesheet" href="3one" data-precedence="one" />
    
  1721.           <link rel="stylesheet" href="4one" data-precedence="one" />
    
  1722. 
    
  1723.           <link rel="stylesheet" href="1two" data-precedence="two" />
    
  1724.           <link rel="stylesheet" href="2two" data-precedence="two" />
    
  1725.           <link rel="stylesheet" href="3two" data-precedence="two" />
    
  1726.           <link rel="stylesheet" href="4two" data-precedence="two" />
    
  1727. 
    
  1728.           <link rel="stylesheet" href="1three" data-precedence="three" />
    
  1729.           <link rel="stylesheet" href="2three" data-precedence="three" />
    
  1730.           <link rel="stylesheet" href="3three" data-precedence="three" />
    
  1731.           <link rel="stylesheet" href="4three" data-precedence="three" />
    
  1732. 
    
  1733.           <link rel="stylesheet" href="1four" data-precedence="four" />
    
  1734.           <link rel="stylesheet" href="2four" data-precedence="four" />
    
  1735.           <link rel="stylesheet" href="3four" data-precedence="four" />
    
  1736.           <link rel="stylesheet" href="4four" data-precedence="four" />
    
  1737. 
    
  1738.           <link rel="stylesheet" href="3five" data-precedence="five" />
    
  1739.         </head>
    
  1740.         <body>
    
  1741.           <div>
    
  1742.             outer
    
  1743.             <div>
    
  1744.               middle<div>inner</div>
    
  1745.             </div>
    
  1746.             <div>middle</div>
    
  1747.           </div>
    
  1748.         </body>
    
  1749.       </html>,
    
  1750.     );
    
  1751.   });
    
  1752. 
    
  1753.   // @gate enableFloat
    
  1754.   it('stylesheet resources are inserted according to precedence order on the client', async () => {
    
  1755.     await act(() => {
    
  1756.       const {pipe} = renderToPipeableStream(
    
  1757.         <html>
    
  1758.           <head />
    
  1759.           <body>
    
  1760.             <div>
    
  1761.               <link rel="stylesheet" href="foo" precedence="one" />
    
  1762.               <link rel="stylesheet" href="bar" precedence="two" />
    
  1763.               Hello
    
  1764.             </div>
    
  1765.           </body>
    
  1766.         </html>,
    
  1767.       );
    
  1768.       pipe(writable);
    
  1769.     });
    
  1770. 
    
  1771.     expect(getMeaningfulChildren(document)).toEqual(
    
  1772.       <html>
    
  1773.         <head>
    
  1774.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1775.           <link rel="stylesheet" href="bar" data-precedence="two" />
    
  1776.         </head>
    
  1777.         <body>
    
  1778.           <div>Hello</div>
    
  1779.         </body>
    
  1780.       </html>,
    
  1781.     );
    
  1782. 
    
  1783.     const root = ReactDOMClient.hydrateRoot(
    
  1784.       document,
    
  1785.       <html>
    
  1786.         <head />
    
  1787.         <body>
    
  1788.           <div>
    
  1789.             <link rel="stylesheet" href="foo" precedence="one" />
    
  1790.             <link rel="stylesheet" href="bar" precedence="two" />
    
  1791.             Hello
    
  1792.           </div>
    
  1793.         </body>
    
  1794.       </html>,
    
  1795.     );
    
  1796.     await waitForAll([]);
    
  1797.     expect(getMeaningfulChildren(document)).toEqual(
    
  1798.       <html>
    
  1799.         <head>
    
  1800.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1801.           <link rel="stylesheet" href="bar" data-precedence="two" />
    
  1802.         </head>
    
  1803.         <body>
    
  1804.           <div>Hello</div>
    
  1805.         </body>
    
  1806.       </html>,
    
  1807.     );
    
  1808. 
    
  1809.     root.render(
    
  1810.       <html>
    
  1811.         <head />
    
  1812.         <body>
    
  1813.           <div>Goodbye</div>
    
  1814.           <link rel="stylesheet" href="baz" precedence="one" />
    
  1815.         </body>
    
  1816.       </html>,
    
  1817.     );
    
  1818.     await waitForAll([]);
    
  1819.     expect(getMeaningfulChildren(document)).toEqual(
    
  1820.       <html>
    
  1821.         <head>
    
  1822.           <link rel="stylesheet" href="foo" data-precedence="one" />
    
  1823.           <link rel="stylesheet" href="baz" data-precedence="one" />
    
  1824.           <link rel="stylesheet" href="bar" data-precedence="two" />
    
  1825.           <link rel="preload" as="style" href="baz" />
    
  1826.         </head>
    
  1827.         <body>
    
  1828.           <div>Goodbye</div>
    
  1829.         </body>
    
  1830.       </html>,
    
  1831.     );
    
  1832.   });
    
  1833. 
    
  1834.   // @gate enableFloat
    
  1835.   it('inserts preloads in render phase eagerly', async () => {
    
  1836.     function Throw() {
    
  1837.       throw new Error('Uh oh!');
    
  1838.     }
    
  1839.     class ErrorBoundary extends React.Component {
    
  1840.       state = {hasError: false, error: null};
    
  1841.       static getDerivedStateFromError(error) {
    
  1842.         return {
    
  1843.           hasError: true,
    
  1844.           error,
    
  1845.         };
    
  1846.       }
    
  1847.       render() {
    
  1848.         if (this.state.hasError) {
    
  1849.           return this.state.error.message;
    
  1850.         }
    
  1851.         return this.props.children;
    
  1852.       }
    
  1853.     }
    
  1854. 
    
  1855.     const root = ReactDOMClient.createRoot(container);
    
  1856.     root.render(
    
  1857.       <ErrorBoundary>
    
  1858.         <link rel="stylesheet" href="foo" precedence="default" />
    
  1859.         <div>foo</div>
    
  1860.         <Throw />
    
  1861.       </ErrorBoundary>,
    
  1862.     );
    
  1863.     await waitForAll([]);
    
  1864.     expect(getMeaningfulChildren(document)).toEqual(
    
  1865.       <html>
    
  1866.         <head>
    
  1867.           <link rel="preload" href="foo" as="style" />
    
  1868.         </head>
    
  1869.         <body>
    
  1870.           <div id="container">Uh oh!</div>
    
  1871.         </body>
    
  1872.       </html>,
    
  1873.     );
    
  1874.   });
    
  1875. 
    
  1876.   // @gate enableFloat
    
  1877.   it('will include child boundary stylesheet resources in the boundary reveal instruction', async () => {
    
  1878.     await act(() => {
    
  1879.       const {pipe} = renderToPipeableStream(
    
  1880.         <html>
    
  1881.           <head />
    
  1882.           <body>
    
  1883.             <div>
    
  1884.               <Suspense fallback="loading foo...">
    
  1885.                 <BlockedOn value="foo">
    
  1886.                   <div>foo</div>
    
  1887.                   <link rel="stylesheet" href="foo" precedence="default" />
    
  1888.                   <Suspense fallback="loading bar...">
    
  1889.                     <BlockedOn value="bar">
    
  1890.                       <div>bar</div>
    
  1891.                       <link rel="stylesheet" href="bar" precedence="default" />
    
  1892.                       <Suspense fallback="loading baz...">
    
  1893.                         <BlockedOn value="baz">
    
  1894.                           <div>baz</div>
    
  1895.                           <link
    
  1896.                             rel="stylesheet"
    
  1897.                             href="baz"
    
  1898.                             precedence="default"
    
  1899.                           />
    
  1900.                         </BlockedOn>
    
  1901.                       </Suspense>
    
  1902.                     </BlockedOn>
    
  1903.                   </Suspense>
    
  1904.                 </BlockedOn>
    
  1905.               </Suspense>
    
  1906.             </div>
    
  1907.           </body>
    
  1908.         </html>,
    
  1909.       );
    
  1910.       pipe(writable);
    
  1911.     });
    
  1912. 
    
  1913.     expect(getMeaningfulChildren(document)).toEqual(
    
  1914.       <html>
    
  1915.         <head />
    
  1916.         <body>
    
  1917.           <div>loading foo...</div>
    
  1918.         </body>
    
  1919.       </html>,
    
  1920.     );
    
  1921. 
    
  1922.     await act(() => {
    
  1923.       resolveText('bar');
    
  1924.     });
    
  1925.     expect(getMeaningfulChildren(document)).toEqual(
    
  1926.       <html>
    
  1927.         <head />
    
  1928.         <body>
    
  1929.           <div>loading foo...</div>
    
  1930.         </body>
    
  1931.       </html>,
    
  1932.     );
    
  1933. 
    
  1934.     await act(() => {
    
  1935.       resolveText('baz');
    
  1936.     });
    
  1937.     expect(getMeaningfulChildren(document)).toEqual(
    
  1938.       <html>
    
  1939.         <head />
    
  1940.         <body>
    
  1941.           <div>loading foo...</div>
    
  1942.         </body>
    
  1943.       </html>,
    
  1944.     );
    
  1945. 
    
  1946.     await act(() => {
    
  1947.       resolveText('foo');
    
  1948.     });
    
  1949.     expect(getMeaningfulChildren(document)).toEqual(
    
  1950.       <html>
    
  1951.         <head>
    
  1952.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  1953.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1954.           <link rel="stylesheet" href="baz" data-precedence="default" />
    
  1955.         </head>
    
  1956.         <body>
    
  1957.           <div>loading foo...</div>
    
  1958.           <link rel="preload" href="foo" as="style" />
    
  1959.           <link rel="preload" href="bar" as="style" />
    
  1960.           <link rel="preload" href="baz" as="style" />
    
  1961.         </body>
    
  1962.       </html>,
    
  1963.     );
    
  1964. 
    
  1965.     await act(() => {
    
  1966.       const event = document.createEvent('Events');
    
  1967.       event.initEvent('load', true, true);
    
  1968.       Array.from(document.querySelectorAll('link[rel="stylesheet"]')).forEach(
    
  1969.         el => {
    
  1970.           el.dispatchEvent(event);
    
  1971.         },
    
  1972.       );
    
  1973.     });
    
  1974.     expect(getMeaningfulChildren(document)).toEqual(
    
  1975.       <html>
    
  1976.         <head>
    
  1977.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  1978.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  1979.           <link rel="stylesheet" href="baz" data-precedence="default" />
    
  1980.         </head>
    
  1981.         <body>
    
  1982.           <div>
    
  1983.             <div>foo</div>
    
  1984.             <div>bar</div>
    
  1985.             <div>baz</div>
    
  1986.           </div>
    
  1987.           <link rel="preload" href="foo" as="style" />
    
  1988.           <link rel="preload" href="bar" as="style" />
    
  1989.           <link rel="preload" href="baz" as="style" />
    
  1990.         </body>
    
  1991.       </html>,
    
  1992.     );
    
  1993.   });
    
  1994. 
    
  1995.   // @gate enableFloat
    
  1996.   it('will hoist resources of child boundaries emitted as part of a partial boundary to the parent boundary', async () => {
    
  1997.     await act(() => {
    
  1998.       const {pipe} = renderToPipeableStream(
    
  1999.         <html>
    
  2000.           <head />
    
  2001.           <body>
    
  2002.             <div>
    
  2003.               <Suspense fallback="loading...">
    
  2004.                 <div>
    
  2005.                   <BlockedOn value="foo">
    
  2006.                     <div>foo</div>
    
  2007.                     <link rel="stylesheet" href="foo" precedence="default" />
    
  2008.                     <Suspense fallback="loading bar...">
    
  2009.                       <BlockedOn value="bar">
    
  2010.                         <div>bar</div>
    
  2011.                         <link
    
  2012.                           rel="stylesheet"
    
  2013.                           href="bar"
    
  2014.                           precedence="default"
    
  2015.                         />
    
  2016.                         <Suspense fallback="loading baz...">
    
  2017.                           <div>
    
  2018.                             <BlockedOn value="baz">
    
  2019.                               <div>baz</div>
    
  2020.                               <link
    
  2021.                                 rel="stylesheet"
    
  2022.                                 href="baz"
    
  2023.                                 precedence="default"
    
  2024.                               />
    
  2025.                             </BlockedOn>
    
  2026.                           </div>
    
  2027.                         </Suspense>
    
  2028.                       </BlockedOn>
    
  2029.                     </Suspense>
    
  2030.                   </BlockedOn>
    
  2031.                   <BlockedOn value="qux">
    
  2032.                     <div>qux</div>
    
  2033.                     <link rel="stylesheet" href="qux" precedence="default" />
    
  2034.                   </BlockedOn>
    
  2035.                 </div>
    
  2036.               </Suspense>
    
  2037.             </div>
    
  2038.           </body>
    
  2039.         </html>,
    
  2040.       );
    
  2041.       pipe(writable);
    
  2042.     });
    
  2043. 
    
  2044.     expect(getMeaningfulChildren(document)).toEqual(
    
  2045.       <html>
    
  2046.         <head />
    
  2047.         <body>
    
  2048.           <div>loading...</div>
    
  2049.         </body>
    
  2050.       </html>,
    
  2051.     );
    
  2052. 
    
  2053.     // This will enqueue a stylesheet resource in a deep blocked boundary (loading baz...).
    
  2054.     await act(() => {
    
  2055.       resolveText('baz');
    
  2056.     });
    
  2057.     expect(getMeaningfulChildren(document)).toEqual(
    
  2058.       <html>
    
  2059.         <head />
    
  2060.         <body>
    
  2061.           <div>loading...</div>
    
  2062.         </body>
    
  2063.       </html>,
    
  2064.     );
    
  2065. 
    
  2066.     // This will enqueue a stylesheet resource in the intermediate blocked boundary (loading bar...).
    
  2067.     await act(() => {
    
  2068.       resolveText('bar');
    
  2069.     });
    
  2070.     expect(getMeaningfulChildren(document)).toEqual(
    
  2071.       <html>
    
  2072.         <head />
    
  2073.         <body>
    
  2074.           <div>loading...</div>
    
  2075.         </body>
    
  2076.       </html>,
    
  2077.     );
    
  2078. 
    
  2079.     // This will complete a segment in the top level boundary that is still blocked on another segment.
    
  2080.     // It will flush the completed segment however the inner boundaries should not emit their style dependencies
    
  2081.     // because they are not going to be revealed yet. instead their dependencies are hoisted to the blocked
    
  2082.     // boundary (top level).
    
  2083.     await act(() => {
    
  2084.       resolveText('foo');
    
  2085.     });
    
  2086.     expect(getMeaningfulChildren(document)).toEqual(
    
  2087.       <html>
    
  2088.         <head />
    
  2089.         <body>
    
  2090.           <div>loading...</div>
    
  2091.           <link rel="preload" href="foo" as="style" />
    
  2092.           <link rel="preload" href="bar" as="style" />
    
  2093.           <link rel="preload" href="baz" as="style" />
    
  2094.         </body>
    
  2095.       </html>,
    
  2096.     );
    
  2097. 
    
  2098.     // This resolves the last blocked segment on the top level boundary so we see all dependencies of the
    
  2099.     // nested boundaries emitted at this level
    
  2100.     await act(() => {
    
  2101.       resolveText('qux');
    
  2102.     });
    
  2103.     expect(getMeaningfulChildren(document)).toEqual(
    
  2104.       <html>
    
  2105.         <head>
    
  2106.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  2107.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  2108.           <link rel="stylesheet" href="baz" data-precedence="default" />
    
  2109.           <link rel="stylesheet" href="qux" data-precedence="default" />
    
  2110.         </head>
    
  2111.         <body>
    
  2112.           <div>loading...</div>
    
  2113.           <link rel="preload" href="foo" as="style" />
    
  2114.           <link rel="preload" href="bar" as="style" />
    
  2115.           <link rel="preload" href="baz" as="style" />
    
  2116.           <link rel="preload" href="qux" as="style" />
    
  2117.         </body>
    
  2118.       </html>,
    
  2119.     );
    
  2120. 
    
  2121.     // We load all stylesheets and confirm the content is revealed
    
  2122.     await act(() => {
    
  2123.       const event = document.createEvent('Events');
    
  2124.       event.initEvent('load', true, true);
    
  2125.       Array.from(document.querySelectorAll('link[rel="stylesheet"]')).forEach(
    
  2126.         el => {
    
  2127.           el.dispatchEvent(event);
    
  2128.         },
    
  2129.       );
    
  2130.     });
    
  2131.     expect(getMeaningfulChildren(document)).toEqual(
    
  2132.       <html>
    
  2133.         <head>
    
  2134.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  2135.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  2136.           <link rel="stylesheet" href="baz" data-precedence="default" />
    
  2137.           <link rel="stylesheet" href="qux" data-precedence="default" />
    
  2138.         </head>
    
  2139.         <body>
    
  2140.           <div>
    
  2141.             <div>
    
  2142.               <div>foo</div>
    
  2143.               <div>bar</div>
    
  2144.               <div>
    
  2145.                 <div>baz</div>
    
  2146.               </div>
    
  2147.               <div>qux</div>
    
  2148.             </div>
    
  2149.           </div>
    
  2150.           <link rel="preload" href="foo" as="style" />
    
  2151.           <link rel="preload" href="bar" as="style" />
    
  2152.           <link rel="preload" href="baz" as="style" />
    
  2153.           <link rel="preload" href="qux" as="style" />
    
  2154.         </body>
    
  2155.       </html>,
    
  2156.     );
    
  2157.   });
    
  2158. 
    
  2159.   // @gate enableFloat
    
  2160.   it('encodes attributes consistently whether resources are flushed in shell or in late boundaries', async () => {
    
  2161.     function App() {
    
  2162.       return (
    
  2163.         <html>
    
  2164.           <head />
    
  2165.           <body>
    
  2166.             <div>
    
  2167.               <link
    
  2168.                 // This preload is explicit so it can flush with a lot of potential attrs
    
  2169.                 // We will duplicate this as a style that flushes after the shell
    
  2170.                 rel="stylesheet"
    
  2171.                 href="foo"
    
  2172.                 // precedence is not a special attribute for preloads so this will just flush as is
    
  2173.                 precedence="default"
    
  2174.                 // Some standard link props
    
  2175.                 crossOrigin="anonymous"
    
  2176.                 media="all"
    
  2177.                 integrity="somehash"
    
  2178.                 referrerPolicy="origin"
    
  2179.                 // data and non starndard attributes that should flush
    
  2180.                 data-foo={'"quoted"'}
    
  2181.                 nonStandardAttr="attr"
    
  2182.                 properlyformattednonstandardattr="attr"
    
  2183.                 // attributes that should be filtered out for violating certain rules
    
  2184.                 onSomething="this should be removed b/c event handler"
    
  2185.                 shouldnotincludefunctions={() => {}}
    
  2186.                 norsymbols={Symbol('foo')}
    
  2187.               />
    
  2188.               <Suspense fallback={'loading...'}>
    
  2189.                 <BlockedOn value="unblock">
    
  2190.                   <link
    
  2191.                     // This preload is explicit so it can flush with a lot of potential attrs
    
  2192.                     // We will duplicate this as a style that flushes after the shell
    
  2193.                     rel="stylesheet"
    
  2194.                     href="bar"
    
  2195.                     // opt-in property to get this treated as a resource
    
  2196.                     precedence="default"
    
  2197.                     // Some standard link props
    
  2198.                     crossOrigin="anonymous"
    
  2199.                     media="all"
    
  2200.                     integrity="somehash"
    
  2201.                     referrerPolicy="origin"
    
  2202.                     // data and non starndard attributes that should flush
    
  2203.                     data-foo={'"quoted"'}
    
  2204.                     nonStandardAttr="attr"
    
  2205.                     properlyformattednonstandardattr="attr"
    
  2206.                     // attributes that should be filtered out for violating certain rules
    
  2207.                     onSomething="this should be removed b/c event handler"
    
  2208.                     shouldnotincludefunctions={() => {}}
    
  2209.                     norsymbols={Symbol('foo')}
    
  2210.                   />
    
  2211.                 </BlockedOn>
    
  2212.               </Suspense>
    
  2213.             </div>
    
  2214.           </body>
    
  2215.         </html>
    
  2216.       );
    
  2217.     }
    
  2218.     await expect(async () => {
    
  2219.       await act(() => {
    
  2220.         const {pipe} = renderToPipeableStream(<App />);
    
  2221.         pipe(writable);
    
  2222.       });
    
  2223.       expect(getMeaningfulChildren(document)).toEqual(
    
  2224.         <html>
    
  2225.           <head>
    
  2226.             <link
    
  2227.               rel="stylesheet"
    
  2228.               href="foo"
    
  2229.               data-precedence="default"
    
  2230.               crossorigin="anonymous"
    
  2231.               media="all"
    
  2232.               integrity="somehash"
    
  2233.               referrerpolicy="origin"
    
  2234.               data-foo={'"quoted"'}
    
  2235.               nonstandardattr="attr"
    
  2236.               properlyformattednonstandardattr="attr"
    
  2237.             />
    
  2238.           </head>
    
  2239.           <body>
    
  2240.             <div>loading...</div>
    
  2241.           </body>
    
  2242.         </html>,
    
  2243.       );
    
  2244.     }).toErrorDev([
    
  2245.       'React does not recognize the `nonStandardAttr` prop on a DOM element.' +
    
  2246.         ' If you intentionally want it to appear in the DOM as a custom attribute,' +
    
  2247.         ' spell it as lowercase `nonstandardattr` instead. If you accidentally passed it from a' +
    
  2248.         ' parent component, remove it from the DOM element.',
    
  2249.       'Invalid values for props `shouldnotincludefunctions`, `norsymbols` on <link> tag. Either remove them from' +
    
  2250.         ' the element, or pass a string or number value to keep them in the DOM. For' +
    
  2251.         ' details, see https://reactjs.org/link/attribute-behavior',
    
  2252.     ]);
    
  2253. 
    
  2254.     // Now we flush the stylesheet with the boundary
    
  2255.     await act(() => {
    
  2256.       resolveText('unblock');
    
  2257.     });
    
  2258. 
    
  2259.     expect(getMeaningfulChildren(document)).toEqual(
    
  2260.       <html>
    
  2261.         <head>
    
  2262.           <link
    
  2263.             rel="stylesheet"
    
  2264.             href="foo"
    
  2265.             data-precedence="default"
    
  2266.             crossorigin="anonymous"
    
  2267.             media="all"
    
  2268.             integrity="somehash"
    
  2269.             referrerpolicy="origin"
    
  2270.             data-foo={'"quoted"'}
    
  2271.             nonstandardattr="attr"
    
  2272.             properlyformattednonstandardattr="attr"
    
  2273.           />
    
  2274.           <link
    
  2275.             rel="stylesheet"
    
  2276.             href="bar"
    
  2277.             data-precedence="default"
    
  2278.             crossorigin="anonymous"
    
  2279.             media="all"
    
  2280.             integrity="somehash"
    
  2281.             referrerpolicy="origin"
    
  2282.             data-foo={'"quoted"'}
    
  2283.             nonstandardattr="attr"
    
  2284.             properlyformattednonstandardattr="attr"
    
  2285.           />
    
  2286.         </head>
    
  2287.         <body>
    
  2288.           <div>loading...</div>
    
  2289.           <link
    
  2290.             rel="preload"
    
  2291.             as="style"
    
  2292.             href="bar"
    
  2293.             crossorigin="anonymous"
    
  2294.             media="all"
    
  2295.             integrity="somehash"
    
  2296.             referrerpolicy="origin"
    
  2297.           />
    
  2298.         </body>
    
  2299.       </html>,
    
  2300.     );
    
  2301.   });
    
  2302. 
    
  2303.   // @gate enableFloat
    
  2304.   it('boundary stylesheet resource dependencies hoist to a parent boundary when flushed inline', async () => {
    
  2305.     await act(() => {
    
  2306.       const {pipe} = renderToPipeableStream(
    
  2307.         <html>
    
  2308.           <head />
    
  2309.           <body>
    
  2310.             <div>
    
  2311.               <Suspense fallback="loading A...">
    
  2312.                 <BlockedOn value="unblock">
    
  2313.                   <AsyncText text="A" />
    
  2314.                   <link rel="stylesheet" href="A" precedence="A" />
    
  2315.                   <Suspense fallback="loading AA...">
    
  2316.                     <AsyncText text="AA" />
    
  2317.                     <link rel="stylesheet" href="AA" precedence="AA" />
    
  2318.                     <Suspense fallback="loading AAA...">
    
  2319.                       <AsyncText text="AAA" />
    
  2320.                       <link rel="stylesheet" href="AAA" precedence="AAA" />
    
  2321.                       <Suspense fallback="loading AAAA...">
    
  2322.                         <AsyncText text="AAAA" />
    
  2323.                         <link rel="stylesheet" href="AAAA" precedence="AAAA" />
    
  2324.                       </Suspense>
    
  2325.                     </Suspense>
    
  2326.                   </Suspense>
    
  2327.                 </BlockedOn>
    
  2328.               </Suspense>
    
  2329.             </div>
    
  2330.           </body>
    
  2331.         </html>,
    
  2332.       );
    
  2333.       pipe(writable);
    
  2334.     });
    
  2335.     expect(getMeaningfulChildren(document)).toEqual(
    
  2336.       <html>
    
  2337.         <head />
    
  2338.         <body>
    
  2339.           <div>loading A...</div>
    
  2340.         </body>
    
  2341.       </html>,
    
  2342.     );
    
  2343. 
    
  2344.     await act(() => {
    
  2345.       resolveText('unblock');
    
  2346.       resolveText('AAAA');
    
  2347.       resolveText('AA');
    
  2348.     });
    
  2349.     expect(getMeaningfulChildren(document)).toEqual(
    
  2350.       <html>
    
  2351.         <head />
    
  2352.         <body>
    
  2353.           <div>loading A...</div>
    
  2354.           <link rel="preload" as="style" href="A" />
    
  2355.           <link rel="preload" as="style" href="AA" />
    
  2356.           <link rel="preload" as="style" href="AAA" />
    
  2357.           <link rel="preload" as="style" href="AAAA" />
    
  2358.         </body>
    
  2359.       </html>,
    
  2360.     );
    
  2361. 
    
  2362.     await act(() => {
    
  2363.       resolveText('A');
    
  2364.     });
    
  2365.     await act(() => {
    
  2366.       document.querySelectorAll('link[rel="stylesheet"]').forEach(l => {
    
  2367.         const event = document.createEvent('Events');
    
  2368.         event.initEvent('load', true, true);
    
  2369.         l.dispatchEvent(event);
    
  2370.       });
    
  2371.     });
    
  2372.     expect(getMeaningfulChildren(document)).toEqual(
    
  2373.       <html>
    
  2374.         <head>
    
  2375.           <link rel="stylesheet" href="A" data-precedence="A" />
    
  2376.           <link rel="stylesheet" href="AA" data-precedence="AA" />
    
  2377.         </head>
    
  2378.         <body>
    
  2379.           <div>
    
  2380.             {'A'}
    
  2381.             {'AA'}
    
  2382.             {'loading AAA...'}
    
  2383.           </div>
    
  2384.           <link rel="preload" as="style" href="A" />
    
  2385.           <link rel="preload" as="style" href="AA" />
    
  2386.           <link rel="preload" as="style" href="AAA" />
    
  2387.           <link rel="preload" as="style" href="AAAA" />
    
  2388.         </body>
    
  2389.       </html>,
    
  2390.     );
    
  2391. 
    
  2392.     await act(() => {
    
  2393.       resolveText('AAA');
    
  2394.     });
    
  2395.     await act(() => {
    
  2396.       document.querySelectorAll('link[rel="stylesheet"]').forEach(l => {
    
  2397.         const event = document.createEvent('Events');
    
  2398.         event.initEvent('load', true, true);
    
  2399.         l.dispatchEvent(event);
    
  2400.       });
    
  2401.     });
    
  2402.     expect(getMeaningfulChildren(document)).toEqual(
    
  2403.       <html>
    
  2404.         <head>
    
  2405.           <link rel="stylesheet" href="A" data-precedence="A" />
    
  2406.           <link rel="stylesheet" href="AA" data-precedence="AA" />
    
  2407.           <link rel="stylesheet" href="AAA" data-precedence="AAA" />
    
  2408.           <link rel="stylesheet" href="AAAA" data-precedence="AAAA" />
    
  2409.         </head>
    
  2410.         <body>
    
  2411.           <div>
    
  2412.             {'A'}
    
  2413.             {'AA'}
    
  2414.             {'AAA'}
    
  2415.             {'AAAA'}
    
  2416.           </div>
    
  2417.           <link rel="preload" as="style" href="A" />
    
  2418.           <link rel="preload" as="style" href="AA" />
    
  2419.           <link rel="preload" as="style" href="AAA" />
    
  2420.           <link rel="preload" as="style" href="AAAA" />
    
  2421.         </body>
    
  2422.       </html>,
    
  2423.     );
    
  2424.   });
    
  2425. 
    
  2426.   // @gate enableFloat
    
  2427.   it('always enforces crossOrigin "anonymous" for font preloads', async () => {
    
  2428.     function App() {
    
  2429.       ReactDOM.preload('foo', {as: 'font', type: 'font/woff2'});
    
  2430.       ReactDOM.preload('bar', {as: 'font', crossOrigin: 'foo'});
    
  2431.       ReactDOM.preload('baz', {as: 'font', crossOrigin: 'use-credentials'});
    
  2432.       ReactDOM.preload('qux', {as: 'font', crossOrigin: 'anonymous'});
    
  2433.       return (
    
  2434.         <html>
    
  2435.           <head />
    
  2436.           <body />
    
  2437.         </html>
    
  2438.       );
    
  2439.     }
    
  2440.     await act(() => {
    
  2441.       const {pipe} = renderToPipeableStream(<App />);
    
  2442.       pipe(writable);
    
  2443.     });
    
  2444.     expect(getMeaningfulChildren(document)).toEqual(
    
  2445.       <html>
    
  2446.         <head>
    
  2447.           <link
    
  2448.             rel="preload"
    
  2449.             as="font"
    
  2450.             href="foo"
    
  2451.             crossorigin=""
    
  2452.             type="font/woff2"
    
  2453.           />
    
  2454.           <link rel="preload" as="font" href="bar" crossorigin="" />
    
  2455.           <link rel="preload" as="font" href="baz" crossorigin="" />
    
  2456.           <link rel="preload" as="font" href="qux" crossorigin="" />
    
  2457.         </head>
    
  2458.         <body />
    
  2459.       </html>,
    
  2460.     );
    
  2461.   });
    
  2462. 
    
  2463.   it('does not hoist anything with an itemprop prop', async () => {
    
  2464.     function App() {
    
  2465.       return (
    
  2466.         <html>
    
  2467.           <head>
    
  2468.             <meta itemProp="outside" content="unscoped" />
    
  2469.             <link itemProp="link" rel="foo" href="foo" />
    
  2470.             <title itemProp="outside-title">title</title>
    
  2471.             <link
    
  2472.               itemProp="outside-stylesheet"
    
  2473.               rel="stylesheet"
    
  2474.               href="bar"
    
  2475.               precedence="default"
    
  2476.             />
    
  2477.             <style itemProp="outside-style" href="baz" precedence="default">
    
  2478.               outside style
    
  2479.             </style>
    
  2480.             <script itemProp="outside-script" async={true} src="qux" />
    
  2481.           </head>
    
  2482.           <body>
    
  2483.             <div itemScope={true}>
    
  2484.               <div>
    
  2485.                 <meta itemProp="inside-meta" content="scoped" />
    
  2486.                 <link itemProp="inside-link" rel="foo" href="foo" />
    
  2487.                 <title itemProp="inside-title">title</title>
    
  2488.                 <link
    
  2489.                   itemProp="inside-stylesheet"
    
  2490.                   rel="stylesheet"
    
  2491.                   href="bar"
    
  2492.                   precedence="default"
    
  2493.                 />
    
  2494.                 <style itemProp="inside-style" href="baz" precedence="default">
    
  2495.                   inside style
    
  2496.                 </style>
    
  2497.                 <script itemProp="inside-script" async={true} src="qux" />
    
  2498.               </div>
    
  2499.             </div>
    
  2500.           </body>
    
  2501.         </html>
    
  2502.       );
    
  2503.     }
    
  2504.     await act(() => {
    
  2505.       renderToPipeableStream(<App />).pipe(writable);
    
  2506.     });
    
  2507. 
    
  2508.     expect(getMeaningfulChildren(document)).toEqual(
    
  2509.       <html>
    
  2510.         <head>
    
  2511.           <meta itemprop="outside" content="unscoped" />
    
  2512.           <link itemprop="link" rel="foo" href="foo" />
    
  2513.           <title itemprop="outside-title">title</title>
    
  2514.           <link
    
  2515.             itemprop="outside-stylesheet"
    
  2516.             rel="stylesheet"
    
  2517.             href="bar"
    
  2518.             precedence="default"
    
  2519.           />
    
  2520.           <style itemprop="outside-style" href="baz" precedence="default">
    
  2521.             outside style
    
  2522.           </style>
    
  2523.           <script itemprop="outside-script" async="" src="qux" />
    
  2524.         </head>
    
  2525.         <body>
    
  2526.           <div itemscope="">
    
  2527.             <div>
    
  2528.               <meta itemprop="inside-meta" content="scoped" />
    
  2529.               <link itemprop="inside-link" rel="foo" href="foo" />
    
  2530.               <title itemprop="inside-title">title</title>
    
  2531.               <link
    
  2532.                 itemprop="inside-stylesheet"
    
  2533.                 rel="stylesheet"
    
  2534.                 href="bar"
    
  2535.                 precedence="default"
    
  2536.               />
    
  2537.               <style itemprop="inside-style" href="baz" precedence="default">
    
  2538.                 inside style
    
  2539.               </style>
    
  2540.               <script itemprop="inside-script" async="" src="qux" />
    
  2541.             </div>
    
  2542.           </div>
    
  2543.         </body>
    
  2544.       </html>,
    
  2545.     );
    
  2546. 
    
  2547.     ReactDOMClient.hydrateRoot(document, <App />);
    
  2548.     await waitForAll([]);
    
  2549. 
    
  2550.     expect(getMeaningfulChildren(document)).toEqual(
    
  2551.       <html>
    
  2552.         <head>
    
  2553.           <meta itemprop="outside" content="unscoped" />
    
  2554.           <link itemprop="link" rel="foo" href="foo" />
    
  2555.           <title itemprop="outside-title">title</title>
    
  2556.           <link
    
  2557.             itemprop="outside-stylesheet"
    
  2558.             rel="stylesheet"
    
  2559.             href="bar"
    
  2560.             precedence="default"
    
  2561.           />
    
  2562.           <style itemprop="outside-style" href="baz" precedence="default">
    
  2563.             outside style
    
  2564.           </style>
    
  2565.           <script itemprop="outside-script" async="" src="qux" />
    
  2566.         </head>
    
  2567.         <body>
    
  2568.           <div itemscope="">
    
  2569.             <div>
    
  2570.               <meta itemprop="inside-meta" content="scoped" />
    
  2571.               <link itemprop="inside-link" rel="foo" href="foo" />
    
  2572.               <title itemprop="inside-title">title</title>
    
  2573.               <link
    
  2574.                 itemprop="inside-stylesheet"
    
  2575.                 rel="stylesheet"
    
  2576.                 href="bar"
    
  2577.                 precedence="default"
    
  2578.               />
    
  2579.               <style itemprop="inside-style" href="baz" precedence="default">
    
  2580.                 inside style
    
  2581.               </style>
    
  2582.               <script itemprop="inside-script" async="" src="qux" />
    
  2583.             </div>
    
  2584.           </div>
    
  2585.         </body>
    
  2586.       </html>,
    
  2587.     );
    
  2588.   });
    
  2589. 
    
  2590.   it('warns if you render a tag with itemProp outside <body> or <head>', async () => {
    
  2591.     const root = ReactDOMClient.createRoot(document);
    
  2592.     root.render(
    
  2593.       <html>
    
  2594.         <meta itemProp="foo" />
    
  2595.         <title itemProp="foo">title</title>
    
  2596.         <style itemProp="foo">style</style>
    
  2597.         <link itemProp="foo" />
    
  2598.         <script itemProp="foo" />
    
  2599.       </html>,
    
  2600.     );
    
  2601.     await expect(async () => {
    
  2602.       await waitForAll([]);
    
  2603.     }).toErrorDev([
    
  2604.       'Cannot render a <meta> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <meta> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
    
  2605.       'Cannot render a <title> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <title> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
    
  2606.       'Cannot render a <style> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <style> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
    
  2607.       'Cannot render a <link> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <link> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
    
  2608.       'Cannot render a <script> outside the main document if it has an `itemProp` prop. `itemProp` suggests the tag belongs to an `itemScope` which can appear anywhere in the DOM. If you were intending for React to hoist this <script> remove the `itemProp` prop. Otherwise, try moving this tag into the <head> or <body> of the Document.',
    
  2609.       'validateDOMNesting(...): <meta> cannot appear as a child of <html>',
    
  2610.       'validateDOMNesting(...): <title> cannot appear as a child of <html>',
    
  2611.       'validateDOMNesting(...): <style> cannot appear as a child of <html>',
    
  2612.       'validateDOMNesting(...): <link> cannot appear as a child of <html>',
    
  2613.       'validateDOMNesting(...): <script> cannot appear as a child of <html>',
    
  2614.     ]);
    
  2615.   });
    
  2616. 
    
  2617.   // @gate enableFloat
    
  2618.   it('can hydrate resources and components in the head and body even if a browser or 3rd party script injects extra html nodes', async () => {
    
  2619.     // This is a stress test case for hydrating a complex combination of hoistable elements, hoistable resources and host components
    
  2620.     // in an environment that has been manipulated by 3rd party scripts/extensions to modify the <head> and <body>
    
  2621.     function App() {
    
  2622.       return (
    
  2623.         <>
    
  2624.           <link rel="foo" href="foo" />
    
  2625.           <script async={true} src="rendered" />
    
  2626.           <link rel="stylesheet" href="stylesheet" precedence="default" />
    
  2627.           <html itemScope={true}>
    
  2628.             <head>
    
  2629.               {/* Component */}
    
  2630.               <link rel="stylesheet" href="stylesheet" />
    
  2631.               <script src="sync rendered" data-meaningful="" />
    
  2632.               <style>{'body { background-color: red; }'}</style>
    
  2633.               <script src="async rendered" async={true} onLoad={() => {}} />
    
  2634.               <noscript>
    
  2635.                 <meta name="noscript" content="noscript" />
    
  2636.               </noscript>
    
  2637.               <link rel="foo" href="foo" onLoad={() => {}} />
    
  2638.             </head>
    
  2639.             <body>
    
  2640.               {/* Component because it has itemProp */}
    
  2641.               <meta name="foo" content="foo" itemProp="a prop" />
    
  2642.               {/* regular Hoistable */}
    
  2643.               <meta name="foo" content="foo" />
    
  2644.               {/* regular Hoistable */}
    
  2645.               <title>title</title>
    
  2646.               <div itemScope={true}>
    
  2647.                 <div>
    
  2648.                   <div>deep hello</div>
    
  2649.                   {/* Component because it has itemProp */}
    
  2650.                   <meta name="foo" content="foo" itemProp="a prop" />
    
  2651.                 </div>
    
  2652.               </div>
    
  2653.             </body>
    
  2654.           </html>
    
  2655.           <link rel="foo" href="foo" />
    
  2656.         </>
    
  2657.       );
    
  2658.     }
    
  2659. 
    
  2660.     await act(() => {
    
  2661.       renderToPipeableStream(<App />).pipe(writable);
    
  2662.     });
    
  2663. 
    
  2664.     expect(getMeaningfulChildren(document)).toEqual(
    
  2665.       <html itemscope="">
    
  2666.         <head>
    
  2667.           {/* Hoisted Resources and elements */}
    
  2668.           <link rel="stylesheet" href="stylesheet" data-precedence="default" />
    
  2669.           <script async="" src="rendered" />
    
  2670.           <link rel="foo" href="foo" />
    
  2671.           <meta name="foo" content="foo" />
    
  2672.           <title>title</title>
    
  2673.           <link rel="foo" href="foo" />
    
  2674.           {/* rendered host components */}
    
  2675.           <link rel="stylesheet" href="stylesheet" />
    
  2676.           <script src="sync rendered" data-meaningful="" />
    
  2677.           <style>{'body { background-color: red; }'}</style>
    
  2678.           <script src="async rendered" async="" />
    
  2679.           <noscript>&lt;meta name="noscript" content="noscript"&gt;</noscript>
    
  2680.           <link rel="foo" href="foo" />
    
  2681.         </head>
    
  2682.         <body>
    
  2683.           <meta name="foo" content="foo" itemprop="a prop" />
    
  2684.           <div itemscope="">
    
  2685.             <div>
    
  2686.               <div>deep hello</div>
    
  2687.               <meta name="foo" content="foo" itemprop="a prop" />
    
  2688.             </div>
    
  2689.           </div>
    
  2690.         </body>
    
  2691.       </html>,
    
  2692.     );
    
  2693. 
    
  2694.     // We inject some styles, divs, scripts into the begginning, middle, and end
    
  2695.     // of the head / body.
    
  2696.     const injectedStyle = document.createElement('style');
    
  2697.     injectedStyle.textContent = 'body { background-color: blue; }';
    
  2698.     document.head.prepend(injectedStyle.cloneNode(true));
    
  2699.     document.head.appendChild(injectedStyle.cloneNode(true));
    
  2700.     document.body.prepend(injectedStyle.cloneNode(true));
    
  2701.     document.body.appendChild(injectedStyle.cloneNode(true));
    
  2702. 
    
  2703.     const injectedDiv = document.createElement('div');
    
  2704.     document.head.prepend(injectedDiv);
    
  2705.     document.head.appendChild(injectedDiv.cloneNode(true));
    
  2706.     // We do not prepend a <div> in body because this will conflict with hyration
    
  2707.     // We still mostly hydrate by matchign tag and <div> does not have any attributes to
    
  2708.     // differentiate between likely-inject and likely-rendered cases. If a <div> is prepended
    
  2709.     // in the <body> and you render a <div> as the first child of <body> there will be a conflict.
    
  2710.     // We consider this a rare edge case and even if it does happen the fallback to client rendering
    
  2711.     // should patch up the DOM correctly
    
  2712.     document.body.appendChild(injectedDiv.cloneNode(true));
    
  2713. 
    
  2714.     const injectedScript = document.createElement('script');
    
  2715.     injectedScript.setAttribute('async', '');
    
  2716.     injectedScript.setAttribute('src', 'injected');
    
  2717.     document.head.prepend(injectedScript);
    
  2718.     document.head.appendChild(injectedScript.cloneNode(true));
    
  2719.     document.body.prepend(injectedScript.cloneNode(true));
    
  2720.     document.body.appendChild(injectedScript.cloneNode(true));
    
  2721. 
    
  2722.     // We hydrate the same App and confirm the output is identical except for the async
    
  2723.     // script insertion that happens because we do not SSR async scripts with load handlers.
    
  2724.     // All the extra inject nodes are preset
    
  2725.     const root = ReactDOMClient.hydrateRoot(document, <App />);
    
  2726.     await waitForAll([]);
    
  2727.     expect(getMeaningfulChildren(document)).toEqual(
    
  2728.       <html itemscope="">
    
  2729.         <head>
    
  2730.           <script async="" src="injected" />
    
  2731.           <div />
    
  2732.           <style>{'body { background-color: blue; }'}</style>
    
  2733.           <link rel="stylesheet" href="stylesheet" data-precedence="default" />
    
  2734.           <script async="" src="rendered" />
    
  2735.           <link rel="foo" href="foo" />
    
  2736.           <meta name="foo" content="foo" />
    
  2737.           <title>title</title>
    
  2738.           <link rel="foo" href="foo" />
    
  2739.           <link rel="stylesheet" href="stylesheet" />
    
  2740.           <script src="sync rendered" data-meaningful="" />
    
  2741.           <style>{'body { background-color: red; }'}</style>
    
  2742.           <script src="async rendered" async="" />
    
  2743.           <noscript>&lt;meta name="noscript" content="noscript"&gt;</noscript>
    
  2744.           <link rel="foo" href="foo" />
    
  2745.           <style>{'body { background-color: blue; }'}</style>
    
  2746.           <div />
    
  2747.           <script async="" src="injected" />
    
  2748.         </head>
    
  2749.         <body>
    
  2750.           <script async="" src="injected" />
    
  2751.           <style>{'body { background-color: blue; }'}</style>
    
  2752.           <meta name="foo" content="foo" itemprop="a prop" />
    
  2753.           <div itemscope="">
    
  2754.             <div>
    
  2755.               <div>deep hello</div>
    
  2756.               <meta name="foo" content="foo" itemprop="a prop" />
    
  2757.             </div>
    
  2758.           </div>
    
  2759.           <style>{'body { background-color: blue; }'}</style>
    
  2760.           <div />
    
  2761.           <script async="" src="injected" />
    
  2762.         </body>
    
  2763.       </html>,
    
  2764.     );
    
  2765. 
    
  2766.     // We unmount. The nodes that remain are
    
  2767.     // 1. Hoisted resources (we don't clean these up on unmount to address races with streaming suspense and navigation)
    
  2768.     // 2. preloads that are injected to hint the browser to load a resource but are not associated to Fibers directly
    
  2769.     // 3. Nodes that React skipped over during hydration
    
  2770.     root.unmount();
    
  2771.     expect(getMeaningfulChildren(document)).toEqual(
    
  2772.       <html>
    
  2773.         <head>
    
  2774.           <script async="" src="injected" />
    
  2775.           <div />
    
  2776.           <style>{'body { background-color: blue; }'}</style>
    
  2777.           <link rel="stylesheet" href="stylesheet" data-precedence="default" />
    
  2778.           <script async="" src="rendered" />
    
  2779.           <style>{'body { background-color: blue; }'}</style>
    
  2780.           <div />
    
  2781.           <script async="" src="injected" />
    
  2782.         </head>
    
  2783.         <body>
    
  2784.           <script async="" src="injected" />
    
  2785.           <style>{'body { background-color: blue; }'}</style>
    
  2786.           <style>{'body { background-color: blue; }'}</style>
    
  2787.           <div />
    
  2788.           <script async="" src="injected" />
    
  2789.         </body>
    
  2790.       </html>,
    
  2791.     );
    
  2792.   });
    
  2793. 
    
  2794.   it('does not preload nomodule scripts', async () => {
    
  2795.     await act(() => {
    
  2796.       renderToPipeableStream(
    
  2797.         <html>
    
  2798.           <body>
    
  2799.             <script src="foo" noModule={true} data-meaningful="" />
    
  2800.             <script async={true} src="bar" noModule={true} data-meaningful="" />
    
  2801.           </body>
    
  2802.         </html>,
    
  2803.       ).pipe(writable);
    
  2804.     });
    
  2805.     expect(getMeaningfulChildren(document)).toEqual(
    
  2806.       <html>
    
  2807.         <head>
    
  2808.           <script async="" src="bar" nomodule="" data-meaningful="" />
    
  2809.         </head>
    
  2810.         <body>
    
  2811.           <script src="foo" nomodule="" data-meaningful="" />
    
  2812.         </body>
    
  2813.       </html>,
    
  2814.     );
    
  2815.   });
    
  2816. 
    
  2817.   it('can delay commit until css resources load', async () => {
    
  2818.     const root = ReactDOMClient.createRoot(container);
    
  2819.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2820.     React.startTransition(() => {
    
  2821.       root.render(
    
  2822.         <>
    
  2823.           <link rel="stylesheet" href="foo" precedence="default" />
    
  2824.           <div>hello</div>
    
  2825.         </>,
    
  2826.       );
    
  2827.     });
    
  2828.     await waitForAll([]);
    
  2829.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2830.     expect(getMeaningfulChildren(document.head)).toEqual(
    
  2831.       <link rel="preload" as="style" href="foo" />,
    
  2832.     );
    
  2833. 
    
  2834.     loadPreloads();
    
  2835.     assertLog(['load preload: foo']);
    
  2836. 
    
  2837.     // We expect that the stylesheet is inserted now but the commit has not happened yet.
    
  2838.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2839.     expect(getMeaningfulChildren(document.head)).toEqual([
    
  2840.       <link rel="stylesheet" href="foo" data-precedence="default" />,
    
  2841.       <link rel="preload" as="style" href="foo" />,
    
  2842.     ]);
    
  2843. 
    
  2844.     loadStylesheets();
    
  2845.     assertLog(['load stylesheet: foo']);
    
  2846. 
    
  2847.     // We expect that the commit finishes synchronously after the stylesheet loads.
    
  2848.     expect(getMeaningfulChildren(container)).toEqual(<div>hello</div>);
    
  2849.     expect(getMeaningfulChildren(document.head)).toEqual([
    
  2850.       <link rel="stylesheet" href="foo" data-precedence="default" />,
    
  2851.       <link rel="preload" as="style" href="foo" />,
    
  2852.     ]);
    
  2853.   });
    
  2854. 
    
  2855.   // https://github.com/facebook/react/issues/27585
    
  2856.   it('does not reinsert already inserted stylesheets during a delayed commit', async () => {
    
  2857.     await act(() => {
    
  2858.       renderToPipeableStream(
    
  2859.         <html>
    
  2860.           <body>
    
  2861.             <link rel="stylesheet" href="first" precedence="default" />
    
  2862.             <link rel="stylesheet" href="second" precedence="default" />
    
  2863.             server
    
  2864.           </body>
    
  2865.         </html>,
    
  2866.       ).pipe(writable);
    
  2867.     });
    
  2868. 
    
  2869.     expect(getMeaningfulChildren(document)).toEqual(
    
  2870.       <html>
    
  2871.         <head>
    
  2872.           <link rel="stylesheet" href="first" data-precedence="default" />
    
  2873.           <link rel="stylesheet" href="second" data-precedence="default" />
    
  2874.         </head>
    
  2875.         <body>server</body>
    
  2876.       </html>,
    
  2877.     );
    
  2878. 
    
  2879.     const root = ReactDOMClient.createRoot(document.body);
    
  2880.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2881.     root.render(
    
  2882.       <>
    
  2883.         <link rel="stylesheet" href="first" precedence="default" />
    
  2884.         <link rel="stylesheet" href="third" precedence="default" />
    
  2885.         <div>client</div>
    
  2886.       </>,
    
  2887.     );
    
  2888.     await waitForAll([]);
    
  2889.     expect(getMeaningfulChildren(document)).toEqual(
    
  2890.       <html>
    
  2891.         <head>
    
  2892.           <link rel="stylesheet" href="first" data-precedence="default" />
    
  2893.           <link rel="stylesheet" href="second" data-precedence="default" />
    
  2894.           <link rel="stylesheet" href="third" data-precedence="default" />
    
  2895.           <link rel="preload" href="third" as="style" />
    
  2896.         </head>
    
  2897.         <body>
    
  2898.           <div>client</div>
    
  2899.         </body>
    
  2900.       </html>,
    
  2901.     );
    
  2902. 
    
  2903.     // In a transition we add another reference to an already loaded resource
    
  2904.     // https://github.com/facebook/react/issues/27585
    
  2905.     React.startTransition(() => {
    
  2906.       root.render(
    
  2907.         <>
    
  2908.           <link rel="stylesheet" href="first" precedence="default" />
    
  2909.           <link rel="stylesheet" href="third" precedence="default" />
    
  2910.           <div>client</div>
    
  2911.           <link rel="stylesheet" href="first" precedence="default" />
    
  2912.         </>,
    
  2913.       );
    
  2914.     });
    
  2915.     await waitForAll([]);
    
  2916.     // In https://github.com/facebook/react/issues/27585 the order updated
    
  2917.     // to second, third, first
    
  2918.     expect(getMeaningfulChildren(document)).toEqual(
    
  2919.       <html>
    
  2920.         <head>
    
  2921.           <link rel="stylesheet" href="first" data-precedence="default" />
    
  2922.           <link rel="stylesheet" href="second" data-precedence="default" />
    
  2923.           <link rel="stylesheet" href="third" data-precedence="default" />
    
  2924.           <link rel="preload" href="third" as="style" />
    
  2925.         </head>
    
  2926.         <body>
    
  2927.           <div>client</div>
    
  2928.         </body>
    
  2929.       </html>,
    
  2930.     );
    
  2931.   });
    
  2932. 
    
  2933.   xit('can delay commit until css resources error', async () => {
    
  2934.     // TODO: This test fails and crashes jest. need to figure out why before unskipping.
    
  2935.     const root = ReactDOMClient.createRoot(container);
    
  2936.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2937.     React.startTransition(() => {
    
  2938.       root.render(
    
  2939.         <>
    
  2940.           <link rel="stylesheet" href="foo" precedence="default" />
    
  2941.           <link rel="stylesheet" href="bar" precedence="default" />
    
  2942.           <div>hello</div>
    
  2943.         </>,
    
  2944.       );
    
  2945.     });
    
  2946.     await waitForAll([]);
    
  2947.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2948.     expect(getMeaningfulChildren(document.head)).toEqual([
    
  2949.       <link rel="preload" as="style" href="foo" />,
    
  2950.       <link rel="preload" as="style" href="bar" />,
    
  2951.     ]);
    
  2952. 
    
  2953.     loadPreloads(['foo']);
    
  2954.     errorPreloads(['bar']);
    
  2955.     assertLog(['load preload: foo', 'error preload: bar']);
    
  2956. 
    
  2957.     // We expect that the stylesheet is inserted now but the commit has not happened yet.
    
  2958.     expect(getMeaningfulChildren(container)).toBe(undefined);
    
  2959.     expect(getMeaningfulChildren(document.head)).toEqual([
    
  2960.       <link rel="stylesheet" href="foo" data-precedence="default" />,
    
  2961.       <link rel="stylesheet" href="bar" data-precedence="default" />,
    
  2962.       <link rel="preload" as="style" href="foo" />,
    
  2963.       <link rel="preload" as="style" href="bar" />,
    
  2964.     ]);
    
  2965. 
    
  2966.     // Try just this and crash all of Jest
    
  2967.     errorStylesheets(['bar']);
    
  2968. 
    
  2969.     // // Try this and it fails the test when it shouldn't
    
  2970.     // await act(() => {
    
  2971.     //   errorStylesheets(['bar']);
    
  2972.     // });
    
  2973. 
    
  2974.     // // Try this there is nothing throwing here which is not really surprising since
    
  2975.     // // the error is bubbling up through some kind of unhandled promise rejection thingy but
    
  2976.     // // still I thought it was worth confirming
    
  2977.     // try {
    
  2978.     //   await act(() => {
    
  2979.     //     errorStylesheets(['bar']);
    
  2980.     //   });
    
  2981.     // } catch (e) {
    
  2982.     //   console.log(e);
    
  2983.     // }
    
  2984. 
    
  2985.     loadStylesheets(['foo']);
    
  2986.     assertLog(['load stylesheet: foo', 'error stylesheet: bar']);
    
  2987. 
    
  2988.     // We expect that the commit finishes synchronously after the stylesheet loads.
    
  2989.     expect(getMeaningfulChildren(container)).toEqual(<div>hello</div>);
    
  2990.     expect(getMeaningfulChildren(document.head)).toEqual([
    
  2991.       <link rel="stylesheet" href="foo" data-precedence="default" />,
    
  2992.       <link rel="stylesheet" href="bar" data-precedence="default" />,
    
  2993.       <link rel="preload" as="style" href="foo" />,
    
  2994.       <link rel="preload" as="style" href="bar" />,
    
  2995.     ]);
    
  2996.   });
    
  2997. 
    
  2998.   it('assumes stylesheets that load in the shell loaded already', async () => {
    
  2999.     await act(() => {
    
  3000.       renderToPipeableStream(
    
  3001.         <html>
    
  3002.           <body>
    
  3003.             <link rel="stylesheet" href="foo" precedence="default" />
    
  3004.             hello
    
  3005.           </body>
    
  3006.         </html>,
    
  3007.       ).pipe(writable);
    
  3008.     });
    
  3009. 
    
  3010.     let root;
    
  3011.     React.startTransition(() => {
    
  3012.       root = ReactDOMClient.hydrateRoot(
    
  3013.         document,
    
  3014.         <html>
    
  3015.           <body>
    
  3016.             <link rel="stylesheet" href="foo" precedence="default" />
    
  3017.             hello
    
  3018.           </body>
    
  3019.         </html>,
    
  3020.       );
    
  3021.     });
    
  3022.     await waitForAll([]);
    
  3023.     expect(getMeaningfulChildren(document)).toEqual(
    
  3024.       <html>
    
  3025.         <head>
    
  3026.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3027.         </head>
    
  3028.         <body>hello</body>
    
  3029.       </html>,
    
  3030.     );
    
  3031. 
    
  3032.     React.startTransition(() => {
    
  3033.       root.render(
    
  3034.         <html>
    
  3035.           <body>
    
  3036.             <link rel="stylesheet" href="foo" precedence="default" />
    
  3037.             hello2
    
  3038.           </body>
    
  3039.         </html>,
    
  3040.       );
    
  3041.     });
    
  3042.     await waitForAll([]);
    
  3043.     expect(getMeaningfulChildren(document)).toEqual(
    
  3044.       <html>
    
  3045.         <head>
    
  3046.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3047.         </head>
    
  3048.         <body>hello2</body>
    
  3049.       </html>,
    
  3050.     );
    
  3051. 
    
  3052.     React.startTransition(() => {
    
  3053.       root.render(
    
  3054.         <html>
    
  3055.           <body>
    
  3056.             <link rel="stylesheet" href="foo" precedence="default" />
    
  3057.             hello3
    
  3058.             <link rel="stylesheet" href="bar" precedence="default" />
    
  3059.           </body>
    
  3060.         </html>,
    
  3061.       );
    
  3062.     });
    
  3063.     await waitForAll([]);
    
  3064.     expect(getMeaningfulChildren(document)).toEqual(
    
  3065.       <html>
    
  3066.         <head>
    
  3067.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3068.           <link rel="preload" href="bar" as="style" />
    
  3069.         </head>
    
  3070.         <body>hello2</body>
    
  3071.       </html>,
    
  3072.     );
    
  3073. 
    
  3074.     loadPreloads();
    
  3075.     assertLog(['load preload: bar']);
    
  3076.     expect(getMeaningfulChildren(document)).toEqual(
    
  3077.       <html>
    
  3078.         <head>
    
  3079.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3080.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3081.           <link rel="preload" href="bar" as="style" />
    
  3082.         </head>
    
  3083.         <body>hello2</body>
    
  3084.       </html>,
    
  3085.     );
    
  3086. 
    
  3087.     loadStylesheets(['bar']);
    
  3088.     assertLog(['load stylesheet: bar']);
    
  3089.     expect(getMeaningfulChildren(document)).toEqual(
    
  3090.       <html>
    
  3091.         <head>
    
  3092.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3093.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3094.           <link rel="preload" href="bar" as="style" />
    
  3095.         </head>
    
  3096.         <body>hello3</body>
    
  3097.       </html>,
    
  3098.     );
    
  3099.   });
    
  3100. 
    
  3101.   it('can interrupt a suspended commit with a new update', async () => {
    
  3102.     function App({children}) {
    
  3103.       return (
    
  3104.         <html>
    
  3105.           <body>{children}</body>
    
  3106.         </html>
    
  3107.       );
    
  3108.     }
    
  3109.     const root = ReactDOMClient.createRoot(document);
    
  3110. 
    
  3111.     // Do an initial render. This means subsequent insertions will suspend,
    
  3112.     // unless they are wrapped inside a fresh Suspense boundary.
    
  3113.     root.render(<App />);
    
  3114.     await waitForAll([]);
    
  3115. 
    
  3116.     // Insert a stylesheet. This will suspend because it's a transition.
    
  3117.     React.startTransition(() => {
    
  3118.       root.render(
    
  3119.         <App>
    
  3120.           hello
    
  3121.           <link rel="stylesheet" href="foo" precedence="default" />
    
  3122.         </App>,
    
  3123.       );
    
  3124.     });
    
  3125.     await waitForAll([]);
    
  3126.     // Although the commit suspended, a preload was inserted.
    
  3127.     expect(getMeaningfulChildren(document)).toEqual(
    
  3128.       <html>
    
  3129.         <head>
    
  3130.           <link rel="preload" href="foo" as="style" />
    
  3131.         </head>
    
  3132.         <body />
    
  3133.       </html>,
    
  3134.     );
    
  3135. 
    
  3136.     // Before the stylesheet has loaded, do an urgent update. This will insert a
    
  3137.     // different stylesheet, and cancel the first one. This stylesheet will not
    
  3138.     // suspend, even though it hasn't loaded, because it's an urgent update.
    
  3139.     root.render(
    
  3140.       <App>
    
  3141.         hello2
    
  3142.         {null}
    
  3143.         <link rel="stylesheet" href="bar" precedence="default" />
    
  3144.       </App>,
    
  3145.     );
    
  3146.     await waitForAll([]);
    
  3147. 
    
  3148.     // The bar stylesheet was inserted. There's still a "foo" preload, even
    
  3149.     // though that update was superseded.
    
  3150.     expect(getMeaningfulChildren(document)).toEqual(
    
  3151.       <html>
    
  3152.         <head>
    
  3153.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3154.           <link rel="preload" href="foo" as="style" />
    
  3155.           <link rel="preload" href="bar" as="style" />
    
  3156.         </head>
    
  3157.         <body>hello2</body>
    
  3158.       </html>,
    
  3159.     );
    
  3160. 
    
  3161.     // When "foo" finishes loading, nothing happens, because "foo" was not
    
  3162.     // included in the last root update. However, if we insert "foo" again
    
  3163.     // later, it should immediately commit without suspending, because it's
    
  3164.     // been preloaded.
    
  3165.     loadPreloads(['foo']);
    
  3166.     assertLog(['load preload: foo']);
    
  3167.     expect(getMeaningfulChildren(document)).toEqual(
    
  3168.       <html>
    
  3169.         <head>
    
  3170.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3171.           <link rel="preload" href="foo" as="style" />
    
  3172.           <link rel="preload" href="bar" as="style" />
    
  3173.         </head>
    
  3174.         <body>hello2</body>
    
  3175.       </html>,
    
  3176.     );
    
  3177. 
    
  3178.     // Now insert "foo" again.
    
  3179.     React.startTransition(() => {
    
  3180.       root.render(
    
  3181.         <App>
    
  3182.           hello3
    
  3183.           <link rel="stylesheet" href="foo" precedence="default" />
    
  3184.           <link rel="stylesheet" href="bar" precedence="default" />
    
  3185.         </App>,
    
  3186.       );
    
  3187.     });
    
  3188.     await waitForAll([]);
    
  3189.     // Commits without suspending because "foo" was preloaded.
    
  3190.     expect(getMeaningfulChildren(document)).toEqual(
    
  3191.       <html>
    
  3192.         <head>
    
  3193.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3194.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3195.           <link rel="preload" href="foo" as="style" />
    
  3196.           <link rel="preload" href="bar" as="style" />
    
  3197.         </head>
    
  3198.         <body>hello3</body>
    
  3199.       </html>,
    
  3200.     );
    
  3201. 
    
  3202.     loadStylesheets(['foo']);
    
  3203.     assertLog(['load stylesheet: foo']);
    
  3204.     expect(getMeaningfulChildren(document)).toEqual(
    
  3205.       <html>
    
  3206.         <head>
    
  3207.           <link rel="stylesheet" href="bar" data-precedence="default" />
    
  3208.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3209.           <link rel="preload" href="foo" as="style" />
    
  3210.           <link rel="preload" href="bar" as="style" />
    
  3211.         </head>
    
  3212.         <body>hello3</body>
    
  3213.       </html>,
    
  3214.     );
    
  3215.   });
    
  3216. 
    
  3217.   it('can suspend commits on more than one root for the same resource at the same time', async () => {
    
  3218.     document.body.innerHTML = '';
    
  3219.     const container1 = document.createElement('div');
    
  3220.     const container2 = document.createElement('div');
    
  3221.     document.body.appendChild(container1);
    
  3222.     document.body.appendChild(container2);
    
  3223. 
    
  3224.     const root1 = ReactDOMClient.createRoot(container1);
    
  3225.     const root2 = ReactDOMClient.createRoot(container2);
    
  3226. 
    
  3227.     React.startTransition(() => {
    
  3228.       root1.render(
    
  3229.         <div>
    
  3230.           one
    
  3231.           <link rel="stylesheet" href="foo" precedence="default" />
    
  3232.           <link rel="stylesheet" href="one" precedence="default" />
    
  3233.         </div>,
    
  3234.       );
    
  3235.     });
    
  3236.     await waitForAll([]);
    
  3237.     React.startTransition(() => {
    
  3238.       root2.render(
    
  3239.         <div>
    
  3240.           two
    
  3241.           <link rel="stylesheet" href="foo" precedence="default" />
    
  3242.           <link rel="stylesheet" href="two" precedence="default" />
    
  3243.         </div>,
    
  3244.       );
    
  3245.     });
    
  3246.     await waitForAll([]);
    
  3247. 
    
  3248.     expect(getMeaningfulChildren(document)).toEqual(
    
  3249.       <html>
    
  3250.         <head>
    
  3251.           <link rel="preload" href="foo" as="style" />
    
  3252.           <link rel="preload" href="one" as="style" />
    
  3253.           <link rel="preload" href="two" as="style" />
    
  3254.         </head>
    
  3255.         <body>
    
  3256.           <div />
    
  3257.           <div />
    
  3258.         </body>
    
  3259.       </html>,
    
  3260.     );
    
  3261. 
    
  3262.     loadPreloads(['foo', 'two']);
    
  3263.     assertLog(['load preload: foo', 'load preload: two']);
    
  3264.     expect(getMeaningfulChildren(document)).toEqual(
    
  3265.       <html>
    
  3266.         <head>
    
  3267.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3268.           <link rel="stylesheet" href="two" data-precedence="default" />
    
  3269.           <link rel="preload" href="foo" as="style" />
    
  3270.           <link rel="preload" href="one" as="style" />
    
  3271.           <link rel="preload" href="two" as="style" />
    
  3272.         </head>
    
  3273.         <body>
    
  3274.           <div />
    
  3275.           <div />
    
  3276.         </body>
    
  3277.       </html>,
    
  3278.     );
    
  3279. 
    
  3280.     loadStylesheets(['foo', 'two']);
    
  3281.     assertLog(['load stylesheet: foo', 'load stylesheet: two']);
    
  3282.     expect(getMeaningfulChildren(document)).toEqual(
    
  3283.       <html>
    
  3284.         <head>
    
  3285.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3286.           <link rel="stylesheet" href="two" data-precedence="default" />
    
  3287.           <link rel="preload" href="foo" as="style" />
    
  3288.           <link rel="preload" href="one" as="style" />
    
  3289.           <link rel="preload" href="two" as="style" />
    
  3290.         </head>
    
  3291.         <body>
    
  3292.           <div />
    
  3293.           <div>
    
  3294.             <div>two</div>
    
  3295.           </div>
    
  3296.         </body>
    
  3297.       </html>,
    
  3298.     );
    
  3299. 
    
  3300.     loadPreloads();
    
  3301.     loadStylesheets();
    
  3302.     assertLog(['load preload: one', 'load stylesheet: one']);
    
  3303.     expect(getMeaningfulChildren(document)).toEqual(
    
  3304.       <html>
    
  3305.         <head>
    
  3306.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3307.           <link rel="stylesheet" href="two" data-precedence="default" />
    
  3308.           <link rel="stylesheet" href="one" data-precedence="default" />
    
  3309.           <link rel="preload" href="foo" as="style" />
    
  3310.           <link rel="preload" href="one" as="style" />
    
  3311.           <link rel="preload" href="two" as="style" />
    
  3312.         </head>
    
  3313.         <body>
    
  3314.           <div>
    
  3315.             <div>one</div>
    
  3316.           </div>
    
  3317.           <div>
    
  3318.             <div>two</div>
    
  3319.           </div>
    
  3320.         </body>
    
  3321.       </html>,
    
  3322.     );
    
  3323.   });
    
  3324. 
    
  3325.   it('stylesheets block render, with a really long timeout', async () => {
    
  3326.     function App({children}) {
    
  3327.       return (
    
  3328.         <html>
    
  3329.           <body>{children}</body>
    
  3330.         </html>
    
  3331.       );
    
  3332.     }
    
  3333.     const root = ReactDOMClient.createRoot(document);
    
  3334.     root.render(<App />);
    
  3335.     React.startTransition(() => {
    
  3336.       root.render(
    
  3337.         <App>
    
  3338.           hello
    
  3339.           <link rel="stylesheet" href="foo" precedence="default" />
    
  3340.         </App>,
    
  3341.       );
    
  3342.     });
    
  3343.     await waitForAll([]);
    
  3344.     expect(getMeaningfulChildren(document)).toEqual(
    
  3345.       <html>
    
  3346.         <head>
    
  3347.           <link rel="preload" href="foo" as="style" />
    
  3348.         </head>
    
  3349.         <body />
    
  3350.       </html>,
    
  3351.     );
    
  3352. 
    
  3353.     // Advance time by 50 seconds. Even still, the transition is suspended.
    
  3354.     jest.advanceTimersByTime(50000);
    
  3355.     await waitForAll([]);
    
  3356.     expect(getMeaningfulChildren(document)).toEqual(
    
  3357.       <html>
    
  3358.         <head>
    
  3359.           <link rel="preload" href="foo" as="style" />
    
  3360.         </head>
    
  3361.         <body />
    
  3362.       </html>,
    
  3363.     );
    
  3364. 
    
  3365.     // Advance time by 10 seconds more. A full minute total has elapsed. At this
    
  3366.     // point, something must have really gone wrong, so we time out and allow
    
  3367.     // unstyled content to be displayed.
    
  3368.     jest.advanceTimersByTime(10000);
    
  3369.     expect(getMeaningfulChildren(document)).toEqual(
    
  3370.       <html>
    
  3371.         <head>
    
  3372.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3373.           <link rel="preload" href="foo" as="style" />
    
  3374.         </head>
    
  3375.         <body>hello</body>
    
  3376.       </html>,
    
  3377.     );
    
  3378. 
    
  3379.     // We will load these after the commit finishes to ensure nothing errors and nothing new inserts
    
  3380.     loadPreloads(['foo']);
    
  3381.     loadStylesheets(['foo']);
    
  3382.     expect(getMeaningfulChildren(document)).toEqual(
    
  3383.       <html>
    
  3384.         <head>
    
  3385.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3386.           <link rel="preload" href="foo" as="style" />
    
  3387.         </head>
    
  3388.         <body>hello</body>
    
  3389.       </html>,
    
  3390.     );
    
  3391.   });
    
  3392. 
    
  3393.   it('can interrupt a suspended commit with a new transition', async () => {
    
  3394.     function App({children}) {
    
  3395.       return (
    
  3396.         <html>
    
  3397.           <body>{children}</body>
    
  3398.         </html>
    
  3399.       );
    
  3400.     }
    
  3401.     const root = ReactDOMClient.createRoot(document);
    
  3402.     root.render(<App>(empty)</App>);
    
  3403. 
    
  3404.     // Start a transition to "A"
    
  3405.     React.startTransition(() => {
    
  3406.       root.render(
    
  3407.         <App>
    
  3408.           A
    
  3409.           <link rel="stylesheet" href="A" precedence="default" />
    
  3410.         </App>,
    
  3411.       );
    
  3412.     });
    
  3413.     await waitForAll([]);
    
  3414. 
    
  3415.     // "A" hasn't loaded yet, so we remain on the initial UI. Its preload
    
  3416.     // has been inserted into the head, though.
    
  3417.     expect(getMeaningfulChildren(document)).toEqual(
    
  3418.       <html>
    
  3419.         <head>
    
  3420.           <link rel="preload" href="A" as="style" />
    
  3421.         </head>
    
  3422.         <body>(empty)</body>
    
  3423.       </html>,
    
  3424.     );
    
  3425. 
    
  3426.     // Interrupt the "A" transition with a new one, "B"
    
  3427.     React.startTransition(() => {
    
  3428.       root.render(
    
  3429.         <App>
    
  3430.           B
    
  3431.           <link rel="stylesheet" href="B" precedence="default" />
    
  3432.         </App>,
    
  3433.       );
    
  3434.     });
    
  3435.     await waitForAll([]);
    
  3436. 
    
  3437.     // Still on the initial UI because "B" hasn't loaded, but its preload
    
  3438.     // is now in the head, too.
    
  3439.     expect(getMeaningfulChildren(document)).toEqual(
    
  3440.       <html>
    
  3441.         <head>
    
  3442.           <link rel="preload" href="A" as="style" />
    
  3443.           <link rel="preload" href="B" as="style" />
    
  3444.         </head>
    
  3445.         <body>(empty)</body>
    
  3446.       </html>,
    
  3447.     );
    
  3448. 
    
  3449.     // Finish loading
    
  3450.     loadPreloads();
    
  3451.     loadStylesheets();
    
  3452.     assertLog(['load preload: A', 'load preload: B', 'load stylesheet: B']);
    
  3453.     // The "B" transition has finished.
    
  3454.     expect(getMeaningfulChildren(document)).toEqual(
    
  3455.       <html>
    
  3456.         <head>
    
  3457.           <link rel="stylesheet" href="B" data-precedence="default" />
    
  3458.           <link rel="preload" href="A" as="style" />
    
  3459.           <link rel="preload" href="B" as="style" />
    
  3460.         </head>
    
  3461.         <body>B</body>
    
  3462.       </html>,
    
  3463.     );
    
  3464.   });
    
  3465. 
    
  3466.   it('loading a stylesheet as part of an error boundary UI, during initial render', async () => {
    
  3467.     class ErrorBoundary extends React.Component {
    
  3468.       state = {error: null};
    
  3469.       static getDerivedStateFromError(error) {
    
  3470.         return {error};
    
  3471.       }
    
  3472.       render() {
    
  3473.         const error = this.state.error;
    
  3474.         if (error !== null) {
    
  3475.           return (
    
  3476.             <>
    
  3477.               <link rel="stylesheet" href="A" precedence="default" />
    
  3478.               {error.message}
    
  3479.             </>
    
  3480.           );
    
  3481.         }
    
  3482.         return this.props.children;
    
  3483.       }
    
  3484.     }
    
  3485. 
    
  3486.     function Throws() {
    
  3487.       throw new Error('Oops!');
    
  3488.     }
    
  3489. 
    
  3490.     function App() {
    
  3491.       return (
    
  3492.         <html>
    
  3493.           <body>
    
  3494.             <ErrorBoundary>
    
  3495.               <Suspense fallback="Loading...">
    
  3496.                 <Throws />
    
  3497.               </Suspense>
    
  3498.             </ErrorBoundary>
    
  3499.           </body>
    
  3500.         </html>
    
  3501.       );
    
  3502.     }
    
  3503. 
    
  3504.     // Initial server render. Because something threw, a Suspense fallback
    
  3505.     // is shown.
    
  3506.     await act(() => {
    
  3507.       renderToPipeableStream(<App />, {
    
  3508.         onError(x) {
    
  3509.           Scheduler.log('Caught server error: ' + x.message);
    
  3510.         },
    
  3511.       }).pipe(writable);
    
  3512.     });
    
  3513.     expect(getMeaningfulChildren(document)).toEqual(
    
  3514.       <html>
    
  3515.         <head />
    
  3516.         <body>Loading...</body>
    
  3517.       </html>,
    
  3518.     );
    
  3519.     assertLog(['Caught server error: Oops!']);
    
  3520. 
    
  3521.     // Hydrate the tree. The error boundary will capture the error and attempt
    
  3522.     // to show an error screen. However, the error screen includes a stylesheet,
    
  3523.     // so the commit should suspend until the stylesheet loads.
    
  3524.     ReactDOMClient.hydrateRoot(document, <App />);
    
  3525.     await waitForAll([]);
    
  3526. 
    
  3527.     // A preload for the stylesheet is inserted, but we still haven't committed
    
  3528.     // the error screen.
    
  3529.     expect(getMeaningfulChildren(document)).toEqual(
    
  3530.       <html>
    
  3531.         <head>
    
  3532.           <link as="style" href="A" rel="preload" />
    
  3533.         </head>
    
  3534.         <body>Loading...</body>
    
  3535.       </html>,
    
  3536.     );
    
  3537. 
    
  3538.     // Finish loading the stylesheets. The commit should be unblocked, and the
    
  3539.     // error screen should appear.
    
  3540.     await clientAct(() => loadStylesheets());
    
  3541.     expect(getMeaningfulChildren(document)).toEqual(
    
  3542.       <html>
    
  3543.         <head>
    
  3544.           <link data-precedence="default" href="A" rel="stylesheet" />
    
  3545.           <link as="style" href="A" rel="preload" />
    
  3546.         </head>
    
  3547.         <body>Oops!</body>
    
  3548.       </html>,
    
  3549.     );
    
  3550.   });
    
  3551. 
    
  3552.   it('will not flush a preload for a new rendered Stylesheet Resource if one was already flushed', async () => {
    
  3553.     function Component() {
    
  3554.       ReactDOM.preload('foo', {as: 'style'});
    
  3555.       return (
    
  3556.         <div>
    
  3557.           <Suspense fallback="loading...">
    
  3558.             <BlockedOn value="blocked">
    
  3559.               <link rel="stylesheet" href="foo" precedence="default" />
    
  3560.               hello
    
  3561.             </BlockedOn>
    
  3562.           </Suspense>
    
  3563.         </div>
    
  3564.       );
    
  3565.     }
    
  3566.     await act(() => {
    
  3567.       renderToPipeableStream(
    
  3568.         <html>
    
  3569.           <body>
    
  3570.             <Component />
    
  3571.           </body>
    
  3572.         </html>,
    
  3573.       ).pipe(writable);
    
  3574.     });
    
  3575. 
    
  3576.     expect(getMeaningfulChildren(document)).toEqual(
    
  3577.       <html>
    
  3578.         <head>
    
  3579.           <link rel="preload" as="style" href="foo" />
    
  3580.         </head>
    
  3581.         <body>
    
  3582.           <div>loading...</div>
    
  3583.         </body>
    
  3584.       </html>,
    
  3585.     );
    
  3586.     await act(() => {
    
  3587.       resolveText('blocked');
    
  3588.     });
    
  3589.     await act(loadStylesheets);
    
  3590.     assertLog(['load stylesheet: foo']);
    
  3591.     expect(getMeaningfulChildren(document)).toEqual(
    
  3592.       <html>
    
  3593.         <head>
    
  3594.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3595.           <link rel="preload" as="style" href="foo" />
    
  3596.         </head>
    
  3597.         <body>
    
  3598.           <div>hello</div>
    
  3599.         </body>
    
  3600.       </html>,
    
  3601.     );
    
  3602.   });
    
  3603. 
    
  3604.   it('will not flush a preload for a new preinitialized Stylesheet Resource if one was already flushed', async () => {
    
  3605.     function Component() {
    
  3606.       ReactDOM.preload('foo', {as: 'style'});
    
  3607.       return (
    
  3608.         <div>
    
  3609.           <Suspense fallback="loading...">
    
  3610.             <BlockedOn value="blocked">
    
  3611.               <Preinit />
    
  3612.               hello
    
  3613.             </BlockedOn>
    
  3614.           </Suspense>
    
  3615.         </div>
    
  3616.       );
    
  3617.     }
    
  3618. 
    
  3619.     function Preinit() {
    
  3620.       ReactDOM.preinit('foo', {as: 'style'});
    
  3621.     }
    
  3622.     await act(() => {
    
  3623.       renderToPipeableStream(
    
  3624.         <html>
    
  3625.           <body>
    
  3626.             <Component />
    
  3627.           </body>
    
  3628.         </html>,
    
  3629.       ).pipe(writable);
    
  3630.     });
    
  3631. 
    
  3632.     expect(getMeaningfulChildren(document)).toEqual(
    
  3633.       <html>
    
  3634.         <head>
    
  3635.           <link rel="preload" as="style" href="foo" />
    
  3636.         </head>
    
  3637.         <body>
    
  3638.           <div>loading...</div>
    
  3639.         </body>
    
  3640.       </html>,
    
  3641.     );
    
  3642.     await act(() => {
    
  3643.       resolveText('blocked');
    
  3644.     });
    
  3645.     expect(getMeaningfulChildren(document)).toEqual(
    
  3646.       <html>
    
  3647.         <head>
    
  3648.           <link rel="preload" as="style" href="foo" />
    
  3649.         </head>
    
  3650.         <body>
    
  3651.           <div>hello</div>
    
  3652.         </body>
    
  3653.       </html>,
    
  3654.     );
    
  3655.   });
    
  3656. 
    
  3657.   it('will not insert a preload if the underlying resource already exists in the Document', async () => {
    
  3658.     await act(() => {
    
  3659.       renderToPipeableStream(
    
  3660.         <html>
    
  3661.           <head>
    
  3662.             <link rel="stylesheet" href="foo" precedence="default" />
    
  3663.             <script async={true} src="bar" />
    
  3664.             <link rel="preload" href="baz" as="font" />
    
  3665.           </head>
    
  3666.           <body>
    
  3667.             <div id="container" />
    
  3668.           </body>
    
  3669.         </html>,
    
  3670.       ).pipe(writable);
    
  3671.     });
    
  3672. 
    
  3673.     expect(getMeaningfulChildren(document)).toEqual(
    
  3674.       <html>
    
  3675.         <head>
    
  3676.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3677.           <script async="" src="bar" />
    
  3678.           <link rel="preload" href="baz" as="font" />
    
  3679.         </head>
    
  3680.         <body>
    
  3681.           <div id="container" />
    
  3682.         </body>
    
  3683.       </html>,
    
  3684.     );
    
  3685. 
    
  3686.     container = document.getElementById('container');
    
  3687. 
    
  3688.     function ClientApp() {
    
  3689.       ReactDOM.preload('foo', {as: 'style'});
    
  3690.       ReactDOM.preload('bar', {as: 'script'});
    
  3691.       ReactDOM.preload('baz', {as: 'font'});
    
  3692.       return 'foo';
    
  3693.     }
    
  3694. 
    
  3695.     const root = ReactDOMClient.createRoot(container);
    
  3696. 
    
  3697.     await clientAct(() => root.render(<ClientApp />));
    
  3698.     expect(getMeaningfulChildren(document)).toEqual(
    
  3699.       <html>
    
  3700.         <head>
    
  3701.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  3702.           <script async="" src="bar" />
    
  3703.           <link rel="preload" href="baz" as="font" />
    
  3704.         </head>
    
  3705.         <body>
    
  3706.           <div id="container">foo</div>
    
  3707.         </body>
    
  3708.       </html>,
    
  3709.     );
    
  3710.   });
    
  3711. 
    
  3712.   it('uses imageSrcSet and imageSizes when keying image preloads', async () => {
    
  3713.     function App({isClient}) {
    
  3714.       // Will key off href in absense of imageSrcSet
    
  3715.       ReactDOM.preload('foo', {as: 'image'});
    
  3716.       ReactDOM.preload('foo', {as: 'image'});
    
  3717. 
    
  3718.       // Will key off imageSrcSet + imageSizes
    
  3719.       ReactDOM.preload('foo', {as: 'image', imageSrcSet: 'fooset'});
    
  3720.       ReactDOM.preload('foo2', {as: 'image', imageSrcSet: 'fooset'});
    
  3721. 
    
  3722.       // Will key off imageSrcSet + imageSizes
    
  3723.       ReactDOM.preload('foo', {
    
  3724.         as: 'image',
    
  3725.         imageSrcSet: 'fooset',
    
  3726.         imageSizes: 'foosizes',
    
  3727.       });
    
  3728.       ReactDOM.preload('foo2', {
    
  3729.         as: 'image',
    
  3730.         imageSrcSet: 'fooset',
    
  3731.         imageSizes: 'foosizes',
    
  3732.       });
    
  3733. 
    
  3734.       // Will key off href in absense of imageSrcSet, imageSizes is ignored. these should match the
    
  3735.       // first preloads not not emit a new preload tag
    
  3736.       ReactDOM.preload('foo', {as: 'image', imageSizes: 'foosizes'});
    
  3737.       ReactDOM.preload('foo', {as: 'image', imageSizes: 'foosizes'});
    
  3738. 
    
  3739.       // These preloads are for something that isn't an image
    
  3740.       // They should all key off the href
    
  3741.       ReactDOM.preload('bar', {as: 'somethingelse'});
    
  3742.       ReactDOM.preload('bar', {
    
  3743.         as: 'somethingelse',
    
  3744.         imageSrcSet: 'makes no sense',
    
  3745.       });
    
  3746.       ReactDOM.preload('bar', {
    
  3747.         as: 'somethingelse',
    
  3748.         imageSrcSet: 'makes no sense',
    
  3749.         imageSizes: 'makes no sense',
    
  3750.       });
    
  3751. 
    
  3752.       if (isClient) {
    
  3753.         // Will key off href in absense of imageSrcSet
    
  3754.         ReactDOM.preload('client', {as: 'image'});
    
  3755.         ReactDOM.preload('client', {as: 'image'});
    
  3756. 
    
  3757.         // Will key off imageSrcSet + imageSizes
    
  3758.         ReactDOM.preload('client', {as: 'image', imageSrcSet: 'clientset'});
    
  3759.         ReactDOM.preload('client2', {as: 'image', imageSrcSet: 'clientset'});
    
  3760. 
    
  3761.         // Will key off imageSrcSet + imageSizes
    
  3762.         ReactDOM.preload('client', {
    
  3763.           as: 'image',
    
  3764.           imageSrcSet: 'clientset',
    
  3765.           imageSizes: 'clientsizes',
    
  3766.         });
    
  3767.         ReactDOM.preload('client2', {
    
  3768.           as: 'image',
    
  3769.           imageSrcSet: 'clientset',
    
  3770.           imageSizes: 'clientsizes',
    
  3771.         });
    
  3772. 
    
  3773.         // Will key off href in absense of imageSrcSet, imageSizes is ignored. these should match the
    
  3774.         // first preloads not not emit a new preload tag
    
  3775.         ReactDOM.preload('client', {as: 'image', imageSizes: 'clientsizes'});
    
  3776.         ReactDOM.preload('client', {as: 'image', imageSizes: 'clientsizes'});
    
  3777.       }
    
  3778. 
    
  3779.       return (
    
  3780.         <html>
    
  3781.           <body>hello</body>
    
  3782.         </html>
    
  3783.       );
    
  3784.     }
    
  3785. 
    
  3786.     await act(() => {
    
  3787.       renderToPipeableStream(<App />).pipe(writable);
    
  3788.     });
    
  3789.     expect(getMeaningfulChildren(document)).toEqual(
    
  3790.       <html>
    
  3791.         <head>
    
  3792.           <link rel="preload" as="image" href="foo" />
    
  3793.           <link rel="preload" as="image" imagesrcset="fooset" />
    
  3794.           <link
    
  3795.             rel="preload"
    
  3796.             as="image"
    
  3797.             imagesrcset="fooset"
    
  3798.             imagesizes="foosizes"
    
  3799.           />
    
  3800.           <link rel="preload" as="somethingelse" href="bar" />
    
  3801.         </head>
    
  3802.         <body>hello</body>
    
  3803.       </html>,
    
  3804.     );
    
  3805. 
    
  3806.     const root = ReactDOMClient.hydrateRoot(document, <App />);
    
  3807.     await waitForAll([]);
    
  3808.     expect(getMeaningfulChildren(document)).toEqual(
    
  3809.       <html>
    
  3810.         <head>
    
  3811.           <link rel="preload" as="image" href="foo" />
    
  3812.           <link rel="preload" as="image" imagesrcset="fooset" />
    
  3813.           <link
    
  3814.             rel="preload"
    
  3815.             as="image"
    
  3816.             imagesrcset="fooset"
    
  3817.             imagesizes="foosizes"
    
  3818.           />
    
  3819.           <link rel="preload" as="somethingelse" href="bar" />
    
  3820.         </head>
    
  3821.         <body>hello</body>
    
  3822.       </html>,
    
  3823.     );
    
  3824. 
    
  3825.     root.render(<App isClient={true} />);
    
  3826.     await waitForAll([]);
    
  3827.     expect(getMeaningfulChildren(document)).toEqual(
    
  3828.       <html>
    
  3829.         <head>
    
  3830.           <link rel="preload" as="image" href="foo" />
    
  3831.           <link rel="preload" as="image" imagesrcset="fooset" />
    
  3832.           <link
    
  3833.             rel="preload"
    
  3834.             as="image"
    
  3835.             imagesrcset="fooset"
    
  3836.             imagesizes="foosizes"
    
  3837.           />
    
  3838.           <link rel="preload" as="somethingelse" href="bar" />
    
  3839.           <link rel="preload" as="image" href="client" />
    
  3840.           <link rel="preload" as="image" imagesrcset="clientset" />
    
  3841.           <link
    
  3842.             rel="preload"
    
  3843.             as="image"
    
  3844.             imagesrcset="clientset"
    
  3845.             imagesizes="clientsizes"
    
  3846.           />
    
  3847.         </head>
    
  3848.         <body>hello</body>
    
  3849.       </html>,
    
  3850.     );
    
  3851.   });
    
  3852. 
    
  3853.   it('should handle referrerPolicy on image preload', async () => {
    
  3854.     function App({isClient}) {
    
  3855.       ReactDOM.preload('/server', {
    
  3856.         as: 'image',
    
  3857.         imageSrcSet: '/server',
    
  3858.         imageSizes: '100vw',
    
  3859.         referrerPolicy: 'no-referrer',
    
  3860.       });
    
  3861. 
    
  3862.       if (isClient) {
    
  3863.         ReactDOM.preload('/client', {
    
  3864.           as: 'image',
    
  3865.           imageSrcSet: '/client',
    
  3866.           imageSizes: '100vw',
    
  3867.           referrerPolicy: 'no-referrer',
    
  3868.         });
    
  3869.       }
    
  3870. 
    
  3871.       return (
    
  3872.         <html>
    
  3873.           <body>hello</body>
    
  3874.         </html>
    
  3875.       );
    
  3876.     }
    
  3877. 
    
  3878.     await act(() => {
    
  3879.       renderToPipeableStream(<App />).pipe(writable);
    
  3880.     });
    
  3881.     expect(getMeaningfulChildren(document)).toEqual(
    
  3882.       <html>
    
  3883.         <head>
    
  3884.           <link
    
  3885.             rel="preload"
    
  3886.             as="image"
    
  3887.             imagesrcset="/server"
    
  3888.             imagesizes="100vw"
    
  3889.             referrerpolicy="no-referrer"
    
  3890.           />
    
  3891.         </head>
    
  3892.         <body>hello</body>
    
  3893.       </html>,
    
  3894.     );
    
  3895. 
    
  3896.     const root = ReactDOMClient.hydrateRoot(document, <App />);
    
  3897.     await waitForAll([]);
    
  3898.     expect(getMeaningfulChildren(document)).toEqual(
    
  3899.       <html>
    
  3900.         <head>
    
  3901.           <link
    
  3902.             rel="preload"
    
  3903.             as="image"
    
  3904.             imagesrcset="/server"
    
  3905.             imagesizes="100vw"
    
  3906.             referrerpolicy="no-referrer"
    
  3907.           />
    
  3908.         </head>
    
  3909.         <body>hello</body>
    
  3910.       </html>,
    
  3911.     );
    
  3912. 
    
  3913.     root.render(<App isClient={true} />);
    
  3914.     await waitForAll([]);
    
  3915.     expect(getMeaningfulChildren(document)).toEqual(
    
  3916.       <html>
    
  3917.         <head>
    
  3918.           <link
    
  3919.             rel="preload"
    
  3920.             as="image"
    
  3921.             imagesrcset="/server"
    
  3922.             imagesizes="100vw"
    
  3923.             referrerpolicy="no-referrer"
    
  3924.           />
    
  3925.           <link
    
  3926.             rel="preload"
    
  3927.             as="image"
    
  3928.             imagesrcset="/client"
    
  3929.             imagesizes="100vw"
    
  3930.             referrerpolicy="no-referrer"
    
  3931.           />
    
  3932.         </head>
    
  3933.         <body>hello</body>
    
  3934.       </html>,
    
  3935.     );
    
  3936.   });
    
  3937. 
    
  3938.   it('can emit preloads for non-lazy images that are rendered', async () => {
    
  3939.     function App() {
    
  3940.       ReactDOM.preload('script', {as: 'script'});
    
  3941.       ReactDOM.preload('a', {as: 'image'});
    
  3942.       ReactDOM.preload('b', {as: 'image'});
    
  3943.       return (
    
  3944.         <html>
    
  3945.           <body>
    
  3946.             <img src="a" />
    
  3947.             <img src="b" loading="lazy" />
    
  3948.             <img src="b2" loading="lazy" />
    
  3949.             <img src="c" srcSet="srcsetc" />
    
  3950.             <img src="d" srcSet="srcsetd" sizes="sizesd" />
    
  3951.             <img src="d" srcSet="srcsetd" sizes="sizesd2" />
    
  3952.           </body>
    
  3953.         </html>
    
  3954.       );
    
  3955.     }
    
  3956. 
    
  3957.     await act(() => {
    
  3958.       renderToPipeableStream(<App />).pipe(writable);
    
  3959.     });
    
  3960. 
    
  3961.     // non-lazy images are first, then arbitrary preloads like for the script and lazy images
    
  3962.     expect(getMeaningfulChildren(document)).toEqual(
    
  3963.       <html>
    
  3964.         <head>
    
  3965.           <link rel="preload" href="a" as="image" />
    
  3966.           <link rel="preload" as="image" imagesrcset="srcsetc" />
    
  3967.           <link
    
  3968.             rel="preload"
    
  3969.             as="image"
    
  3970.             imagesrcset="srcsetd"
    
  3971.             imagesizes="sizesd"
    
  3972.           />
    
  3973.           <link
    
  3974.             rel="preload"
    
  3975.             as="image"
    
  3976.             imagesrcset="srcsetd"
    
  3977.             imagesizes="sizesd2"
    
  3978.           />
    
  3979.           <link rel="preload" href="script" as="script" />
    
  3980.           <link rel="preload" href="b" as="image" />
    
  3981.         </head>
    
  3982.         <body>
    
  3983.           <img src="a" />
    
  3984.           <img src="b" loading="lazy" />
    
  3985.           <img src="b2" loading="lazy" />
    
  3986.           <img src="c" srcset="srcsetc" />
    
  3987.           <img src="d" srcset="srcsetd" sizes="sizesd" />
    
  3988.           <img src="d" srcset="srcsetd" sizes="sizesd2" />
    
  3989.         </body>
    
  3990.       </html>,
    
  3991.     );
    
  3992.   });
    
  3993. 
    
  3994.   it('Does not preload lazy images', async () => {
    
  3995.     function App() {
    
  3996.       ReactDOM.preload('a', {as: 'image'});
    
  3997.       return (
    
  3998.         <html>
    
  3999.           <body>
    
  4000.             <img src="a" fetchPriority="low" />
    
  4001.             <img src="b" fetchPriority="low" />
    
  4002.           </body>
    
  4003.         </html>
    
  4004.       );
    
  4005.     }
    
  4006.     await act(() => {
    
  4007.       renderToPipeableStream(<App />).pipe(writable);
    
  4008.     });
    
  4009. 
    
  4010.     expect(getMeaningfulChildren(document)).toEqual(
    
  4011.       <html>
    
  4012.         <head>
    
  4013.           <link rel="preload" as="image" href="a" />
    
  4014.         </head>
    
  4015.         <body>
    
  4016.           <img src="a" fetchpriority="low" />
    
  4017.           <img src="b" fetchpriority="low" />
    
  4018.         </body>
    
  4019.       </html>,
    
  4020.     );
    
  4021.   });
    
  4022. 
    
  4023.   it('preloads up to 10 suspensey images as high priority when fetchPriority is not specified', async () => {
    
  4024.     function App() {
    
  4025.       ReactDOM.preload('1', {as: 'image', fetchPriority: 'high'});
    
  4026.       ReactDOM.preload('auto', {as: 'image'});
    
  4027.       ReactDOM.preload('low', {as: 'image', fetchPriority: 'low'});
    
  4028.       ReactDOM.preload('9', {as: 'image', fetchPriority: 'high'});
    
  4029.       ReactDOM.preload('10', {as: 'image', fetchPriority: 'high'});
    
  4030.       return (
    
  4031.         <html>
    
  4032.           <body>
    
  4033.             {/* skipping 1 */}
    
  4034.             <img src="2" />
    
  4035.             <img src="3" fetchPriority="auto" />
    
  4036.             <img src="4" fetchPriority="high" />
    
  4037.             <img src="5" />
    
  4038.             <img src="5low" fetchPriority="low" />
    
  4039.             <img src="6" />
    
  4040.             <img src="7" />
    
  4041.             <img src="8" />
    
  4042.             <img src="9" />
    
  4043.             {/* skipping 10 */}
    
  4044.             <img src="11" />
    
  4045.             <img src="12" fetchPriority="high" />
    
  4046.           </body>
    
  4047.         </html>
    
  4048.       );
    
  4049.     }
    
  4050.     await act(() => {
    
  4051.       renderToPipeableStream(<App />).pipe(writable);
    
  4052.     });
    
  4053. 
    
  4054.     expect(getMeaningfulChildren(document)).toEqual(
    
  4055.       <html>
    
  4056.         <head>
    
  4057.           {/* First we see the preloads calls that made it to the high priority image queue */}
    
  4058.           <link rel="preload" as="image" href="1" fetchpriority="high" />
    
  4059.           <link rel="preload" as="image" href="9" fetchpriority="high" />
    
  4060.           <link rel="preload" as="image" href="10" fetchpriority="high" />
    
  4061.           {/* Next we see up to 7 more images qualify for high priority image queue */}
    
  4062.           <link rel="preload" as="image" href="2" />
    
  4063.           <link rel="preload" as="image" href="3" fetchpriority="auto" />
    
  4064.           <link rel="preload" as="image" href="4" fetchpriority="high" />
    
  4065.           <link rel="preload" as="image" href="5" />
    
  4066.           <link rel="preload" as="image" href="6" />
    
  4067.           <link rel="preload" as="image" href="7" />
    
  4068.           <link rel="preload" as="image" href="8" />
    
  4069.           {/* Next we see images that are explicitly high priority and thus make it to the high priority image queue */}
    
  4070.           <link rel="preload" as="image" href="12" fetchpriority="high" />
    
  4071.           {/* Next we see the remaining preloads that did not make it to the high priority image queue */}
    
  4072.           <link rel="preload" as="image" href="auto" />
    
  4073.           <link rel="preload" as="image" href="low" fetchpriority="low" />
    
  4074.           <link rel="preload" as="image" href="11" />
    
  4075.         </head>
    
  4076.         <body>
    
  4077.           {/* skipping 1 */}
    
  4078.           <img src="2" />
    
  4079.           <img src="3" fetchpriority="auto" />
    
  4080.           <img src="4" fetchpriority="high" />
    
  4081.           <img src="5" />
    
  4082.           <img src="5low" fetchpriority="low" />
    
  4083.           <img src="6" />
    
  4084.           <img src="7" />
    
  4085.           <img src="8" />
    
  4086.           <img src="9" />
    
  4087.           {/* skipping 10 */}
    
  4088.           <img src="11" />
    
  4089.           <img src="12" fetchpriority="high" />
    
  4090.         </body>
    
  4091.       </html>,
    
  4092.     );
    
  4093.   });
    
  4094. 
    
  4095.   it('can promote images to high priority when at least one instance specifies a high fetchPriority', async () => {
    
  4096.     function App() {
    
  4097.       // If a ends up in a higher priority queue than b it will flush first
    
  4098.       ReactDOM.preload('a', {as: 'image'});
    
  4099.       ReactDOM.preload('b', {as: 'image'});
    
  4100.       return (
    
  4101.         <html>
    
  4102.           <body>
    
  4103.             <link rel="stylesheet" href="foo" precedence="default" />
    
  4104.             <img src="1" />
    
  4105.             <img src="2" />
    
  4106.             <img src="3" />
    
  4107.             <img src="4" />
    
  4108.             <img src="5" />
    
  4109.             <img src="6" />
    
  4110.             <img src="7" />
    
  4111.             <img src="8" />
    
  4112.             <img src="9" />
    
  4113.             <img src="10" />
    
  4114.             <img src="11" />
    
  4115.             <img src="12" />
    
  4116.             <img src="a" fetchPriority="low" />
    
  4117.             <img src="a" />
    
  4118.             <img src="a" fetchPriority="high" />
    
  4119.             <img src="a" />
    
  4120.             <img src="a" />
    
  4121.           </body>
    
  4122.         </html>
    
  4123.       );
    
  4124.     }
    
  4125. 
    
  4126.     await act(() => {
    
  4127.       renderToPipeableStream(<App />).pipe(writable);
    
  4128.     });
    
  4129.     expect(getMeaningfulChildren(document)).toEqual(
    
  4130.       <html>
    
  4131.         <head>
    
  4132.           {/* The First 10 high priority images were just the first 10 rendered images */}
    
  4133.           <link rel="preload" as="image" href="1" />
    
  4134.           <link rel="preload" as="image" href="2" />
    
  4135.           <link rel="preload" as="image" href="3" />
    
  4136.           <link rel="preload" as="image" href="4" />
    
  4137.           <link rel="preload" as="image" href="5" />
    
  4138.           <link rel="preload" as="image" href="6" />
    
  4139.           <link rel="preload" as="image" href="7" />
    
  4140.           <link rel="preload" as="image" href="8" />
    
  4141.           <link rel="preload" as="image" href="9" />
    
  4142.           <link rel="preload" as="image" href="10" />
    
  4143.           {/* The "a" image was rendered a few times but since at least one of those was with
    
  4144.           fetchPriorty="high" it ends up in the high priority queue */}
    
  4145.           <link rel="preload" as="image" href="a" />
    
  4146.           {/* Stylesheets come in between high priority images and regular preloads */}
    
  4147.           <link rel="stylesheet" href="foo" data-precedence="default" />
    
  4148.           {/* The remainig images that preloaded at regular priority */}
    
  4149.           <link rel="preload" as="image" href="b" />
    
  4150.           <link rel="preload" as="image" href="11" />
    
  4151.           <link rel="preload" as="image" href="12" />
    
  4152.         </head>
    
  4153.         <body>
    
  4154.           <img src="1" />
    
  4155.           <img src="2" />
    
  4156.           <img src="3" />
    
  4157.           <img src="4" />
    
  4158.           <img src="5" />
    
  4159.           <img src="6" />
    
  4160.           <img src="7" />
    
  4161.           <img src="8" />
    
  4162.           <img src="9" />
    
  4163.           <img src="10" />
    
  4164.           <img src="11" />
    
  4165.           <img src="12" />
    
  4166.           <img src="a" fetchpriority="low" />
    
  4167.           <img src="a" />
    
  4168.           <img src="a" fetchpriority="high" />
    
  4169.           <img src="a" />
    
  4170.           <img src="a" />
    
  4171.         </body>
    
  4172.       </html>,
    
  4173.     );
    
  4174.   });
    
  4175. 
    
  4176.   it('preloads from rendered images properly use srcSet and sizes', async () => {
    
  4177.     function App() {
    
  4178.       ReactDOM.preload('1', {as: 'image', imageSrcSet: 'ss1'});
    
  4179.       ReactDOM.preload('2', {
    
  4180.         as: 'image',
    
  4181.         imageSrcSet: 'ss2',
    
  4182.         imageSizes: 's2',
    
  4183.       });
    
  4184.       return (
    
  4185.         <html>
    
  4186.           <body>
    
  4187.             <img src="1" srcSet="ss1" />
    
  4188.             <img src="2" srcSet="ss2" sizes="s2" />
    
  4189.             <img src="3" srcSet="ss3" />
    
  4190.             <img src="4" srcSet="ss4" sizes="s4" />
    
  4191.           </body>
    
  4192.         </html>
    
  4193.       );
    
  4194.     }
    
  4195.     await act(() => {
    
  4196.       renderToPipeableStream(<App />).pipe(writable);
    
  4197.     });
    
  4198. 
    
  4199.     expect(getMeaningfulChildren(document)).toEqual(
    
  4200.       <html>
    
  4201.         <head>
    
  4202.           <link rel="preload" as="image" imagesrcset="ss1" />
    
  4203.           <link rel="preload" as="image" imagesrcset="ss2" imagesizes="s2" />
    
  4204.           <link rel="preload" as="image" imagesrcset="ss3" />
    
  4205.           <link rel="preload" as="image" imagesrcset="ss4" imagesizes="s4" />
    
  4206.         </head>
    
  4207.         <body>
    
  4208.           <img src="1" srcset="ss1" />
    
  4209.           <img src="2" srcset="ss2" sizes="s2" />
    
  4210.           <img src="3" srcset="ss3" />
    
  4211.           <img src="4" srcset="ss4" sizes="s4" />
    
  4212.         </body>
    
  4213.       </html>,
    
  4214.     );
    
  4215.   });
    
  4216. 
    
  4217.   it('should not preload images that have a data URIs for src or srcSet', async () => {
    
  4218.     function App() {
    
  4219.       return (
    
  4220.         <html>
    
  4221.           <body>
    
  4222.             <img src="data:1" />
    
  4223.             <img src="data:2" srcSet="ss2" />
    
  4224.             <img srcSet="data:3a, data:3b 2x" />
    
  4225.             <img src="4" srcSet="data:4a, data4b 2x" />
    
  4226.           </body>
    
  4227.         </html>
    
  4228.       );
    
  4229.     }
    
  4230.     await act(() => {
    
  4231.       renderToPipeableStream(<App />).pipe(writable);
    
  4232.     });
    
  4233. 
    
  4234.     expect(getMeaningfulChildren(document)).toEqual(
    
  4235.       <html>
    
  4236.         <head />
    
  4237.         <body>
    
  4238.           <img src="data:1" />
    
  4239.           <img src="data:2" srcset="ss2" />
    
  4240.           <img srcset="data:3a, data:3b 2x" />
    
  4241.           <img src="4" srcset="data:4a, data4b 2x" />
    
  4242.         </body>
    
  4243.       </html>,
    
  4244.     );
    
  4245.   });
    
  4246. 
    
  4247.   // https://github.com/vercel/next.js/discussions/54799
    
  4248.   it('omits preloads when an <img> is inside a <picture>', async () => {
    
  4249.     await act(() => {
    
  4250.       renderToPipeableStream(
    
  4251.         <html>
    
  4252.           <body>
    
  4253.             <picture>
    
  4254.               <img src="foo" />
    
  4255.             </picture>
    
  4256.             <picture>
    
  4257.               <source type="image/webp" srcSet="webpsrc" />
    
  4258.               <img src="jpg fallback" />
    
  4259.             </picture>
    
  4260.           </body>
    
  4261.         </html>,
    
  4262.       ).pipe(writable);
    
  4263.     });
    
  4264. 
    
  4265.     expect(getMeaningfulChildren(document)).toEqual(
    
  4266.       <html>
    
  4267.         <head />
    
  4268.         <body>
    
  4269.           <picture>
    
  4270.             <img src="foo" />
    
  4271.           </picture>
    
  4272.           <picture>
    
  4273.             <source type="image/webp" srcset="webpsrc" />
    
  4274.             <img src="jpg fallback" />
    
  4275.           </picture>
    
  4276.         </body>
    
  4277.       </html>,
    
  4278.     );
    
  4279.   });
    
  4280. 
    
  4281.   it('should warn if you preload a stylesheet and then render a style tag with the same href', async () => {
    
  4282.     const style = 'body { color: red; }';
    
  4283.     function App() {
    
  4284.       ReactDOM.preload('foo', {as: 'style'});
    
  4285.       return (
    
  4286.         <html>
    
  4287.           <body>
    
  4288.             hello
    
  4289.             <style precedence="default" href="foo">
    
  4290.               {style}
    
  4291.             </style>
    
  4292.           </body>
    
  4293.         </html>
    
  4294.       );
    
  4295.     }
    
  4296. 
    
  4297.     await expect(async () => {
    
  4298.       await act(() => {
    
  4299.         renderToPipeableStream(<App />).pipe(writable);
    
  4300.       });
    
  4301.     }).toErrorDev([
    
  4302.       'React encountered a hoistable style tag for the same href as a preload: "foo". When using a style tag to inline styles you should not also preload it as a stylsheet.',
    
  4303.     ]);
    
  4304. 
    
  4305.     expect(getMeaningfulChildren(document)).toEqual(
    
  4306.       <html>
    
  4307.         <head>
    
  4308.           <style data-precedence="default" data-href="foo">
    
  4309.             {style}
    
  4310.           </style>
    
  4311.           <link rel="preload" as="style" href="foo" />
    
  4312.         </head>
    
  4313.         <body>hello</body>
    
  4314.       </html>,
    
  4315.     );
    
  4316.   });
    
  4317. 
    
  4318.   it('should preload only once even if you discover a stylesheet, script, or moduleScript late', async () => {
    
  4319.     function App() {
    
  4320.       // We start with preinitializing some resources first
    
  4321.       ReactDOM.preinit('shell preinit/shell', {as: 'style'});
    
  4322.       ReactDOM.preinit('shell preinit/shell', {as: 'script'});
    
  4323.       ReactDOM.preinitModule('shell preinit/shell', {as: 'script'});
    
  4324. 
    
  4325.       // We initiate all the shell preloads
    
  4326.       ReactDOM.preload('shell preinit/shell', {as: 'style'});
    
  4327.       ReactDOM.preload('shell preinit/shell', {as: 'script'});
    
  4328.       ReactDOM.preloadModule('shell preinit/shell', {as: 'script'});
    
  4329. 
    
  4330.       ReactDOM.preload('shell/shell preinit', {as: 'style'});
    
  4331.       ReactDOM.preload('shell/shell preinit', {as: 'script'});
    
  4332.       ReactDOM.preloadModule('shell/shell preinit', {as: 'script'});
    
  4333. 
    
  4334.       ReactDOM.preload('shell/shell render', {as: 'style'});
    
  4335.       ReactDOM.preload('shell/shell render', {as: 'script'});
    
  4336.       ReactDOM.preloadModule('shell/shell render');
    
  4337. 
    
  4338.       ReactDOM.preload('shell/late preinit', {as: 'style'});
    
  4339.       ReactDOM.preload('shell/late preinit', {as: 'script'});
    
  4340.       ReactDOM.preloadModule('shell/late preinit');
    
  4341. 
    
  4342.       ReactDOM.preload('shell/late render', {as: 'style'});
    
  4343.       ReactDOM.preload('shell/late render', {as: 'script'});
    
  4344.       ReactDOM.preloadModule('shell/late render');
    
  4345. 
    
  4346.       // we preinit later ones that should be created by
    
  4347.       ReactDOM.preinit('shell/shell preinit', {as: 'style'});
    
  4348.       ReactDOM.preinit('shell/shell preinit', {as: 'script'});
    
  4349.       ReactDOM.preinitModule('shell/shell preinit');
    
  4350. 
    
  4351.       ReactDOM.preinit('late/shell preinit', {as: 'style'});
    
  4352.       ReactDOM.preinit('late/shell preinit', {as: 'script'});
    
  4353.       ReactDOM.preinitModule('late/shell preinit');
    
  4354.       return (
    
  4355.         <html>
    
  4356.           <body>
    
  4357.             <link
    
  4358.               rel="stylesheet"
    
  4359.               precedence="default"
    
  4360.               href="shell/shell render"
    
  4361.             />
    
  4362.             <script async={true} src="shell/shell render" />
    
  4363.             <script type="module" async={true} src="shell/shell render" />
    
  4364.             <link
    
  4365.               rel="stylesheet"
    
  4366.               precedence="default"
    
  4367.               href="late/shell render"
    
  4368.             />
    
  4369.             <script async={true} src="late/shell render" />
    
  4370.             <script type="module" async={true} src="late/shell render" />
    
  4371.             <Suspense fallback="late...">
    
  4372.               <BlockedOn value="late">
    
  4373.                 <Late />
    
  4374.               </BlockedOn>
    
  4375.             </Suspense>
    
  4376.             <Suspense fallback="later...">
    
  4377.               <BlockedOn value="later">
    
  4378.                 <Later />
    
  4379.               </BlockedOn>
    
  4380.             </Suspense>
    
  4381.           </body>
    
  4382.         </html>
    
  4383.       );
    
  4384.     }
    
  4385. 
    
  4386.     function Late() {
    
  4387.       ReactDOM.preload('late/later preinit', {as: 'style'});
    
  4388.       ReactDOM.preload('late/later preinit', {as: 'script'});
    
  4389.       ReactDOM.preloadModule('late/later preinit');
    
  4390. 
    
  4391.       ReactDOM.preload('late/later render', {as: 'style'});
    
  4392.       ReactDOM.preload('late/later render', {as: 'script'});
    
  4393.       ReactDOM.preloadModule('late/later render');
    
  4394. 
    
  4395.       ReactDOM.preload('late/shell preinit', {as: 'style'});
    
  4396.       ReactDOM.preload('late/shell preinit', {as: 'script'});
    
  4397.       ReactDOM.preloadModule('late/shell preinit');
    
  4398. 
    
  4399.       ReactDOM.preload('late/shell render', {as: 'style'});
    
  4400.       ReactDOM.preload('late/shell render', {as: 'script'});
    
  4401.       ReactDOM.preloadModule('late/shell render');
    
  4402. 
    
  4403.       // late preinits don't actually flush so we won't see this in the DOM as a stylesehet but we should see
    
  4404.       // the preload for this resource
    
  4405.       ReactDOM.preinit('shell/late preinit', {as: 'style'});
    
  4406.       ReactDOM.preinit('shell/late preinit', {as: 'script'});
    
  4407.       ReactDOM.preinitModule('shell/late preinit');
    
  4408.       return (
    
  4409.         <>
    
  4410.           Late
    
  4411.           <link
    
  4412.             rel="stylesheet"
    
  4413.             precedence="default"
    
  4414.             href="shell/late render"
    
  4415.           />
    
  4416.           <script async={true} src="shell/late render" />
    
  4417.           <script type="module" async={true} src="shell/late render" />
    
  4418.         </>
    
  4419.       );
    
  4420.     }
    
  4421. 
    
  4422.     function Later() {
    
  4423.       // late preinits don't actually flush so we won't see this in the DOM as a stylesehet but we should see
    
  4424.       // the preload for this resource
    
  4425.       ReactDOM.preinit('late/later preinit', {as: 'style'});
    
  4426.       ReactDOM.preinit('late/later preinit', {as: 'script'});
    
  4427.       ReactDOM.preinitModule('late/later preinit');
    
  4428.       return (
    
  4429.         <>
    
  4430.           Later
    
  4431.           <link
    
  4432.             rel="stylesheet"
    
  4433.             precedence="default"
    
  4434.             href="late/later render"
    
  4435.           />
    
  4436.           <script async={true} src="late/later render" />
    
  4437.           <script type="module" async={true} src="late/later render" />
    
  4438.         </>
    
  4439.       );
    
  4440.     }
    
  4441. 
    
  4442.     await act(() => {
    
  4443.       renderToPipeableStream(<App />).pipe(writable);
    
  4444.     });
    
  4445.     expect(getMeaningfulChildren(document)).toEqual(
    
  4446.       <html>
    
  4447.         <head>
    
  4448.           <link
    
  4449.             rel="stylesheet"
    
  4450.             data-precedence="default"
    
  4451.             href="shell preinit/shell"
    
  4452.           />
    
  4453.           <link
    
  4454.             rel="stylesheet"
    
  4455.             data-precedence="default"
    
  4456.             href="shell/shell preinit"
    
  4457.           />
    
  4458.           <link
    
  4459.             rel="stylesheet"
    
  4460.             data-precedence="default"
    
  4461.             href="late/shell preinit"
    
  4462.           />
    
  4463.           <link
    
  4464.             rel="stylesheet"
    
  4465.             data-precedence="default"
    
  4466.             href="shell/shell render"
    
  4467.           />
    
  4468.           <link
    
  4469.             rel="stylesheet"
    
  4470.             data-precedence="default"
    
  4471.             href="late/shell render"
    
  4472.           />
    
  4473.           <script async="" src="shell preinit/shell" />
    
  4474.           <script async="" src="shell preinit/shell" type="module" />
    
  4475.           <script async="" src="shell/shell preinit" />
    
  4476.           <script async="" src="shell/shell preinit" type="module" />
    
  4477.           <script async="" src="late/shell preinit" />
    
  4478.           <script async="" src="late/shell preinit" type="module" />
    
  4479.           <script async="" src="shell/shell render" />
    
  4480.           <script async="" src="shell/shell render" type="module" />
    
  4481.           <script async="" src="late/shell render" />
    
  4482.           <script async="" src="late/shell render" type="module" />
    
  4483.           <link rel="preload" as="style" href="shell/late preinit" />
    
  4484.           <link rel="preload" as="script" href="shell/late preinit" />
    
  4485.           <link rel="modulepreload" href="shell/late preinit" />
    
  4486.           <link rel="preload" as="style" href="shell/late render" />
    
  4487.           <link rel="preload" as="script" href="shell/late render" />
    
  4488.           <link rel="modulepreload" href="shell/late render" />
    
  4489.         </head>
    
  4490.         <body>
    
  4491.           {'late...'}
    
  4492.           {'later...'}
    
  4493.         </body>
    
  4494.       </html>,
    
  4495.     );
    
  4496. 
    
  4497.     await act(() => {
    
  4498.       resolveText('late');
    
  4499.     });
    
  4500.     expect(getMeaningfulChildren(document)).toEqual(
    
  4501.       <html>
    
  4502.         <head>
    
  4503.           <link
    
  4504.             rel="stylesheet"
    
  4505.             data-precedence="default"
    
  4506.             href="shell preinit/shell"
    
  4507.           />
    
  4508.           <link
    
  4509.             rel="stylesheet"
    
  4510.             data-precedence="default"
    
  4511.             href="shell/shell preinit"
    
  4512.           />
    
  4513.           <link
    
  4514.             rel="stylesheet"
    
  4515.             data-precedence="default"
    
  4516.             href="late/shell preinit"
    
  4517.           />
    
  4518.           <link
    
  4519.             rel="stylesheet"
    
  4520.             data-precedence="default"
    
  4521.             href="shell/shell render"
    
  4522.           />
    
  4523.           <link
    
  4524.             rel="stylesheet"
    
  4525.             data-precedence="default"
    
  4526.             href="late/shell render"
    
  4527.           />
    
  4528.           {/* FROM HERE */}
    
  4529.           <link
    
  4530.             rel="stylesheet"
    
  4531.             data-precedence="default"
    
  4532.             href="shell/late render"
    
  4533.           />
    
  4534.           {/** TO HERE:
    
  4535.            * This was hoisted by boundary complete instruction. The preload was already emitted in the
    
  4536.            * shell but we see it below because this was inserted clientside by precedence.
    
  4537.            * We don't observe the "shell/late preinit" because these do not flush unless they are flushing
    
  4538.            * with the shell
    
  4539.            * */}
    
  4540.           <script async="" src="shell preinit/shell" />
    
  4541.           <script async="" src="shell preinit/shell" type="module" />
    
  4542.           <script async="" src="shell/shell preinit" />
    
  4543.           <script async="" src="shell/shell preinit" type="module" />
    
  4544.           <script async="" src="late/shell preinit" />
    
  4545.           <script async="" src="late/shell preinit" type="module" />
    
  4546.           <script async="" src="shell/shell render" />
    
  4547.           <script async="" src="shell/shell render" type="module" />
    
  4548.           <script async="" src="late/shell render" />
    
  4549.           <script async="" src="late/shell render" type="module" />
    
  4550.           <link rel="preload" as="style" href="shell/late preinit" />
    
  4551.           <link rel="preload" as="script" href="shell/late preinit" />
    
  4552.           <link rel="modulepreload" href="shell/late preinit" />
    
  4553.           <link rel="preload" as="style" href="shell/late render" />
    
  4554.           <link rel="preload" as="script" href="shell/late render" />
    
  4555.           <link rel="modulepreload" href="shell/late render" />
    
  4556.         </head>
    
  4557.         <body>
    
  4558.           {'late...'}
    
  4559.           {'later...'}
    
  4560.           {/* FROM HERE */}
    
  4561.           <script async="" src="shell/late preinit" />
    
  4562.           <script async="" src="shell/late preinit" type="module" />
    
  4563.           <script async="" src="shell/late render" />
    
  4564.           <script async="" src="shell/late render" type="module" />
    
  4565.           <link rel="preload" as="style" href="late/later preinit" />
    
  4566.           <link rel="preload" as="script" href="late/later preinit" />
    
  4567.           <link rel="modulepreload" href="late/later preinit" />
    
  4568.           <link rel="preload" as="style" href="late/later render" />
    
  4569.           <link rel="preload" as="script" href="late/later render" />
    
  4570.           <link rel="modulepreload" href="late/later render" />
    
  4571.           {/** TO HERE:
    
  4572.            * These resources streamed into the body during the boundary flush. Scripts go first then
    
  4573.            * preloads according to our streaming queue priorities. Note also that late/shell resources
    
  4574.            * where the resource already emitted in the shell and the preload is invoked later do not
    
  4575.            * end up with a preload in the document at all.
    
  4576.            * */}
    
  4577.         </body>
    
  4578.       </html>,
    
  4579.     );
    
  4580. 
    
  4581.     await act(() => {
    
  4582.       resolveText('later');
    
  4583.     });
    
  4584.     expect(getMeaningfulChildren(document)).toEqual(
    
  4585.       <html>
    
  4586.         <head>
    
  4587.           <link
    
  4588.             rel="stylesheet"
    
  4589.             data-precedence="default"
    
  4590.             href="shell preinit/shell"
    
  4591.           />
    
  4592.           <link
    
  4593.             rel="stylesheet"
    
  4594.             data-precedence="default"
    
  4595.             href="shell/shell preinit"
    
  4596.           />
    
  4597.           <link
    
  4598.             rel="stylesheet"
    
  4599.             data-precedence="default"
    
  4600.             href="late/shell preinit"
    
  4601.           />
    
  4602.           <link
    
  4603.             rel="stylesheet"
    
  4604.             data-precedence="default"
    
  4605.             href="shell/shell render"
    
  4606.           />
    
  4607.           <link
    
  4608.             rel="stylesheet"
    
  4609.             data-precedence="default"
    
  4610.             href="late/shell render"
    
  4611.           />
    
  4612.           <link
    
  4613.             rel="stylesheet"
    
  4614.             data-precedence="default"
    
  4615.             href="shell/late render"
    
  4616.           />
    
  4617.           {/* FROM HERE */}
    
  4618.           <link
    
  4619.             rel="stylesheet"
    
  4620.             data-precedence="default"
    
  4621.             href="late/later render"
    
  4622.           />
    
  4623.           {/** TO HERE:
    
  4624.            * This was hoisted by boundary complete instruction. The preload was already emitted in the
    
  4625.            * shell but we see it below because this was inserted clientside by precedence
    
  4626.            * We don't observe the "late/later preinit" because these do not flush unless they are flushing
    
  4627.            * with the shell
    
  4628.            * */}
    
  4629.           <script async="" src="shell preinit/shell" />
    
  4630.           <script async="" src="shell preinit/shell" type="module" />
    
  4631.           <script async="" src="shell/shell preinit" />
    
  4632.           <script async="" src="shell/shell preinit" type="module" />
    
  4633.           <script async="" src="late/shell preinit" />
    
  4634.           <script async="" src="late/shell preinit" type="module" />
    
  4635.           <script async="" src="shell/shell render" />
    
  4636.           <script async="" src="shell/shell render" type="module" />
    
  4637.           <script async="" src="late/shell render" />
    
  4638.           <script async="" src="late/shell render" type="module" />
    
  4639.           <link rel="preload" as="style" href="shell/late preinit" />
    
  4640.           <link rel="preload" as="script" href="shell/late preinit" />
    
  4641.           <link rel="modulepreload" href="shell/late preinit" />
    
  4642.           <link rel="preload" as="style" href="shell/late render" />
    
  4643.           <link rel="preload" as="script" href="shell/late render" />
    
  4644.           <link rel="modulepreload" href="shell/late render" />
    
  4645.         </head>
    
  4646.         <body>
    
  4647.           {'late...'}
    
  4648.           {'later...'}
    
  4649.           <script async="" src="shell/late preinit" />
    
  4650.           <script async="" src="shell/late preinit" type="module" />
    
  4651.           <script async="" src="shell/late render" />
    
  4652.           <script async="" src="shell/late render" type="module" />
    
  4653.           <link rel="preload" as="style" href="late/later preinit" />
    
  4654.           <link rel="preload" as="script" href="late/later preinit" />
    
  4655.           <link rel="modulepreload" href="late/later preinit" />
    
  4656.           <link rel="preload" as="style" href="late/later render" />
    
  4657.           <link rel="preload" as="script" href="late/later render" />
    
  4658.           <link rel="modulepreload" href="late/later render" />
    
  4659.           {/* FROM HERE */}
    
  4660.           <script async="" src="late/later preinit" />
    
  4661.           <script async="" src="late/later preinit" type="module" />
    
  4662.           <script async="" src="late/later render" />
    
  4663.           <script async="" src="late/later render" type="module" />
    
  4664.           {/** TO HERE:
    
  4665.            * These resources streamed into the body during the boundary flush. Scripts go first then
    
  4666.            * preloads according to our streaming queue priorities
    
  4667.            * */}
    
  4668.         </body>
    
  4669.       </html>,
    
  4670.     );
    
  4671.     loadStylesheets();
    
  4672.     assertLog([
    
  4673.       'load stylesheet: shell preinit/shell',
    
  4674.       'load stylesheet: shell/shell preinit',
    
  4675.       'load stylesheet: late/shell preinit',
    
  4676.       'load stylesheet: shell/shell render',
    
  4677.       'load stylesheet: late/shell render',
    
  4678.       'load stylesheet: shell/late render',
    
  4679.       'load stylesheet: late/later render',
    
  4680.     ]);
    
  4681. 
    
  4682.     ReactDOMClient.hydrateRoot(document, <App />);
    
  4683.     await waitForAll([]);
    
  4684.     expect(getMeaningfulChildren(document)).toEqual(
    
  4685.       <html>
    
  4686.         <head>
    
  4687.           <link
    
  4688.             rel="stylesheet"
    
  4689.             data-precedence="default"
    
  4690.             href="shell preinit/shell"
    
  4691.           />
    
  4692.           <link
    
  4693.             rel="stylesheet"
    
  4694.             data-precedence="default"
    
  4695.             href="shell/shell preinit"
    
  4696.           />
    
  4697.           <link
    
  4698.             rel="stylesheet"
    
  4699.             data-precedence="default"
    
  4700.             href="late/shell preinit"
    
  4701.           />
    
  4702.           <link
    
  4703.             rel="stylesheet"
    
  4704.             data-precedence="default"
    
  4705.             href="shell/shell render"
    
  4706.           />
    
  4707.           <link
    
  4708.             rel="stylesheet"
    
  4709.             data-precedence="default"
    
  4710.             href="late/shell render"
    
  4711.           />
    
  4712.           <link
    
  4713.             rel="stylesheet"
    
  4714.             data-precedence="default"
    
  4715.             href="shell/late render"
    
  4716.           />
    
  4717.           <link
    
  4718.             rel="stylesheet"
    
  4719.             data-precedence="default"
    
  4720.             href="late/later render"
    
  4721.           />
    
  4722.           {/* FROM HERE */}
    
  4723.           <link
    
  4724.             rel="stylesheet"
    
  4725.             data-precedence="default"
    
  4726.             href="shell/late preinit"
    
  4727.           />
    
  4728.           <link
    
  4729.             rel="stylesheet"
    
  4730.             data-precedence="default"
    
  4731.             href="late/later preinit"
    
  4732.           />
    
  4733.           {/** TO HERE:
    
  4734.            * The client render patches in the two missing preinit stylesheets when hydration happens
    
  4735.            * Note that this is only because we repeated the calls to preinit on the client
    
  4736.            * */}
    
  4737.           <script async="" src="shell preinit/shell" />
    
  4738.           <script async="" src="shell preinit/shell" type="module" />
    
  4739.           <script async="" src="shell/shell preinit" />
    
  4740.           <script async="" src="shell/shell preinit" type="module" />
    
  4741.           <script async="" src="late/shell preinit" />
    
  4742.           <script async="" src="late/shell preinit" type="module" />
    
  4743.           <script async="" src="shell/shell render" />
    
  4744.           <script async="" src="shell/shell render" type="module" />
    
  4745.           <script async="" src="late/shell render" />
    
  4746.           <script async="" src="late/shell render" type="module" />
    
  4747.           <link rel="preload" as="style" href="shell/late preinit" />
    
  4748.           <link rel="preload" as="script" href="shell/late preinit" />
    
  4749.           <link rel="modulepreload" href="shell/late preinit" />
    
  4750.           <link rel="preload" as="style" href="shell/late render" />
    
  4751.           <link rel="preload" as="script" href="shell/late render" />
    
  4752.           <link rel="modulepreload" href="shell/late render" />
    
  4753.         </head>
    
  4754.         <body>
    
  4755.           {'Late'}
    
  4756.           {'Later'}
    
  4757.           <script async="" src="shell/late preinit" />
    
  4758.           <script async="" src="shell/late preinit" type="module" />
    
  4759.           <script async="" src="shell/late render" />
    
  4760.           <script async="" src="shell/late render" type="module" />
    
  4761.           <link rel="preload" as="style" href="late/later preinit" />
    
  4762.           <link rel="preload" as="script" href="late/later preinit" />
    
  4763.           <link rel="modulepreload" href="late/later preinit" />
    
  4764.           <link rel="preload" as="style" href="late/later render" />
    
  4765.           <link rel="preload" as="script" href="late/later render" />
    
  4766.           <link rel="modulepreload" href="late/later render" />
    
  4767.           <script async="" src="late/later preinit" />
    
  4768.           <script async="" src="late/later preinit" type="module" />
    
  4769.           <script async="" src="late/later render" />
    
  4770.           <script async="" src="late/later render" type="module" />
    
  4771.         </body>
    
  4772.       </html>,
    
  4773.     );
    
  4774.   });
    
  4775. 
    
  4776.   describe('ReactDOM.prefetchDNS(href)', () => {
    
  4777.     it('creates a dns-prefetch resource when called', async () => {
    
  4778.       function App({url}) {
    
  4779.         ReactDOM.prefetchDNS(url);
    
  4780.         ReactDOM.prefetchDNS(url);
    
  4781.         ReactDOM.prefetchDNS(url, {});
    
  4782.         ReactDOM.prefetchDNS(url, {crossOrigin: 'use-credentials'});
    
  4783.         return (
    
  4784.           <html>
    
  4785.             <body>hello world</body>
    
  4786.           </html>
    
  4787.         );
    
  4788.       }
    
  4789. 
    
  4790.       await expect(async () => {
    
  4791.         await act(() => {
    
  4792.           renderToPipeableStream(<App url="foo" />).pipe(writable);
    
  4793.         });
    
  4794.       }).toErrorDev([
    
  4795.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4796.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4797.       ]);
    
  4798. 
    
  4799.       expect(getMeaningfulChildren(document)).toEqual(
    
  4800.         <html>
    
  4801.           <head>
    
  4802.             <link rel="dns-prefetch" href="foo" />
    
  4803.           </head>
    
  4804.           <body>hello world</body>
    
  4805.         </html>,
    
  4806.       );
    
  4807. 
    
  4808.       const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
    
  4809.       await expect(async () => {
    
  4810.         await waitForAll([]);
    
  4811.       }).toErrorDev([
    
  4812.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4813.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4814.       ]);
    
  4815.       expect(getMeaningfulChildren(document)).toEqual(
    
  4816.         <html>
    
  4817.           <head>
    
  4818.             <link rel="dns-prefetch" href="foo" />
    
  4819.           </head>
    
  4820.           <body>hello world</body>
    
  4821.         </html>,
    
  4822.       );
    
  4823. 
    
  4824.       root.render(<App url="bar" />);
    
  4825.       await expect(async () => {
    
  4826.         await waitForAll([]);
    
  4827.       }).toErrorDev([
    
  4828.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4829.         'ReactDOM.prefetchDNS(): Expected only one argument, `href`, but encountered something with type "object" as a second argument instead. This argument is reserved for future options and is currently disallowed. It looks like the you are attempting to set a crossOrigin property for this DNS lookup hint. Browsers do not perform DNS queries using CORS and setting this attribute on the resource hint has no effect. Try calling ReactDOM.prefetchDNS() with just a single string argument, `href`.',
    
  4830.       ]);
    
  4831.       expect(getMeaningfulChildren(document)).toEqual(
    
  4832.         <html>
    
  4833.           <head>
    
  4834.             <link rel="dns-prefetch" href="foo" />
    
  4835.             <link rel="dns-prefetch" href="bar" />
    
  4836.           </head>
    
  4837.           <body>hello world</body>
    
  4838.         </html>,
    
  4839.       );
    
  4840.     });
    
  4841.   });
    
  4842. 
    
  4843.   describe('ReactDOM.preconnect(href, { crossOrigin })', () => {
    
  4844.     it('creates a preconnect resource when called', async () => {
    
  4845.       function App({url}) {
    
  4846.         ReactDOM.preconnect(url);
    
  4847.         ReactDOM.preconnect(url);
    
  4848.         ReactDOM.preconnect(url, {crossOrigin: true});
    
  4849.         ReactDOM.preconnect(url, {crossOrigin: ''});
    
  4850.         ReactDOM.preconnect(url, {crossOrigin: 'anonymous'});
    
  4851.         ReactDOM.preconnect(url, {crossOrigin: 'use-credentials'});
    
  4852.         return (
    
  4853.           <html>
    
  4854.             <body>hello world</body>
    
  4855.           </html>
    
  4856.         );
    
  4857.       }
    
  4858. 
    
  4859.       await expect(async () => {
    
  4860.         await act(() => {
    
  4861.           renderToPipeableStream(<App url="foo" />).pipe(writable);
    
  4862.         });
    
  4863.       }).toErrorDev(
    
  4864.         'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
    
  4865.       );
    
  4866. 
    
  4867.       expect(getMeaningfulChildren(document)).toEqual(
    
  4868.         <html>
    
  4869.           <head>
    
  4870.             <link rel="preconnect" href="foo" />
    
  4871.             <link rel="preconnect" href="foo" crossorigin="" />
    
  4872.             <link rel="preconnect" href="foo" crossorigin="use-credentials" />
    
  4873.           </head>
    
  4874.           <body>hello world</body>
    
  4875.         </html>,
    
  4876.       );
    
  4877. 
    
  4878.       const root = ReactDOMClient.hydrateRoot(document, <App url="foo" />);
    
  4879.       await expect(async () => {
    
  4880.         await waitForAll([]);
    
  4881.       }).toErrorDev(
    
  4882.         'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
    
  4883.       );
    
  4884.       expect(getMeaningfulChildren(document)).toEqual(
    
  4885.         <html>
    
  4886.           <head>
    
  4887.             <link rel="preconnect" href="foo" />
    
  4888.             <link rel="preconnect" href="foo" crossorigin="" />
    
  4889.             <link rel="preconnect" href="foo" crossorigin="use-credentials" />
    
  4890.           </head>
    
  4891.           <body>hello world</body>
    
  4892.         </html>,
    
  4893.       );
    
  4894. 
    
  4895.       root.render(<App url="bar" />);
    
  4896.       await expect(async () => {
    
  4897.         await waitForAll([]);
    
  4898.       }).toErrorDev(
    
  4899.         'ReactDOM.preconnect(): Expected the `crossOrigin` option (second argument) to be a string but encountered something with type "boolean" instead. Try removing this option or passing a string value instead.',
    
  4900.       );
    
  4901.       expect(getMeaningfulChildren(document)).toEqual(
    
  4902.         <html>
    
  4903.           <head>
    
  4904.             <link rel="preconnect" href="foo" />
    
  4905.             <link rel="preconnect" href="foo" crossorigin="" />
    
  4906.             <link rel="preconnect" href="foo" crossorigin="use-credentials" />
    
  4907.             <link rel="preconnect" href="bar" />
    
  4908.             <link rel="preconnect" href="bar" crossorigin="" />
    
  4909.             <link rel="preconnect" href="bar" crossorigin="use-credentials" />
    
  4910.           </head>
    
  4911.           <body>hello world</body>
    
  4912.         </html>,
    
  4913.       );
    
  4914.     });
    
  4915.   });
    
  4916. 
    
  4917.   describe('ReactDOM.preload(href, { as: ... })', () => {
    
  4918.     // @gate enableFloat
    
  4919.     it('creates a preload resource when called', async () => {
    
  4920.       function App() {
    
  4921.         ReactDOM.preload('foo', {as: 'style'});
    
  4922.         return (
    
  4923.           <html>
    
  4924.             <body>
    
  4925.               <Suspense fallback="loading...">
    
  4926.                 <BlockedOn value="blocked">
    
  4927.                   <Component />
    
  4928.                 </BlockedOn>
    
  4929.               </Suspense>
    
  4930.             </body>
    
  4931.           </html>
    
  4932.         );
    
  4933.       }
    
  4934.       function Component() {
    
  4935.         ReactDOM.preload('bar', {as: 'script'});
    
  4936.         return <div>hello</div>;
    
  4937.       }
    
  4938. 
    
  4939.       await act(() => {
    
  4940.         const {pipe} = renderToPipeableStream(<App />);
    
  4941.         pipe(writable);
    
  4942.       });
    
  4943.       expect(getMeaningfulChildren(document)).toEqual(
    
  4944.         <html>
    
  4945.           <head>
    
  4946.             <link rel="preload" as="style" href="foo" />
    
  4947.           </head>
    
  4948.           <body>loading...</body>
    
  4949.         </html>,
    
  4950.       );
    
  4951. 
    
  4952.       await act(() => {
    
  4953.         resolveText('blocked');
    
  4954.       });
    
  4955.       expect(getMeaningfulChildren(document)).toEqual(
    
  4956.         <html>
    
  4957.           <head>
    
  4958.             <link rel="preload" as="style" href="foo" />
    
  4959.           </head>
    
  4960.           <body>
    
  4961.             <div>hello</div>
    
  4962.             <link rel="preload" as="script" href="bar" />
    
  4963.           </body>
    
  4964.         </html>,
    
  4965.       );
    
  4966. 
    
  4967.       function ClientApp() {
    
  4968.         ReactDOM.preload('foo', {as: 'style'});
    
  4969.         ReactDOM.preload('font', {as: 'font', type: 'font/woff2'});
    
  4970.         React.useInsertionEffect(() => ReactDOM.preload('bar', {as: 'script'}));
    
  4971.         React.useLayoutEffect(() => ReactDOM.preload('baz', {as: 'font'}));
    
  4972.         React.useEffect(() => ReactDOM.preload('qux', {as: 'style'}));
    
  4973.         return (
    
  4974.           <html>
    
  4975.             <body>
    
  4976.               <Suspense fallback="loading...">
    
  4977.                 <div>hello</div>
    
  4978.               </Suspense>
    
  4979.             </body>
    
  4980.           </html>
    
  4981.         );
    
  4982.       }
    
  4983.       ReactDOMClient.hydrateRoot(document, <ClientApp />);
    
  4984.       await waitForAll([]);
    
  4985.       expect(getMeaningfulChildren(document)).toEqual(
    
  4986.         <html>
    
  4987.           <head>
    
  4988.             <link rel="preload" as="style" href="foo" />
    
  4989.             <link
    
  4990.               rel="preload"
    
  4991.               as="font"
    
  4992.               href="font"
    
  4993.               crossorigin=""
    
  4994.               type="font/woff2"
    
  4995.             />
    
  4996.             <link rel="preload" as="font" href="baz" crossorigin="" />
    
  4997.             <link rel="preload" as="style" href="qux" />
    
  4998.           </head>
    
  4999.           <body>
    
  5000.             <div>hello</div>
    
  5001.             <link rel="preload" as="script" href="bar" />
    
  5002.           </body>
    
  5003.         </html>,
    
  5004.       );
    
  5005.     });
    
  5006. 
    
  5007.     // @gate enableFloat
    
  5008.     it('can seed connection props for stylesheet and script resources', async () => {
    
  5009.       function App() {
    
  5010.         ReactDOM.preload('foo', {
    
  5011.           as: 'style',
    
  5012.           crossOrigin: 'use-credentials',
    
  5013.           integrity: 'some hash',
    
  5014.           fetchPriority: 'low',
    
  5015.         });
    
  5016.         return (
    
  5017.           <html>
    
  5018.             <body>
    
  5019.               <div>hello</div>
    
  5020.               <link rel="stylesheet" href="foo" precedence="default" />
    
  5021.             </body>
    
  5022.           </html>
    
  5023.         );
    
  5024.       }
    
  5025. 
    
  5026.       await act(() => {
    
  5027.         const {pipe} = renderToPipeableStream(<App />);
    
  5028.         pipe(writable);
    
  5029.       });
    
  5030. 
    
  5031.       expect(getMeaningfulChildren(document)).toEqual(
    
  5032.         <html>
    
  5033.           <head>
    
  5034.             <link
    
  5035.               rel="stylesheet"
    
  5036.               href="foo"
    
  5037.               data-precedence="default"
    
  5038.               crossorigin="use-credentials"
    
  5039.               integrity="some hash"
    
  5040.             />
    
  5041.           </head>
    
  5042.           <body>
    
  5043.             <div>hello</div>
    
  5044.           </body>
    
  5045.         </html>,
    
  5046.       );
    
  5047.     });
    
  5048. 
    
  5049.     // @gate enableFloat
    
  5050.     it('warns if you do not pass in a valid href argument or options argument', async () => {
    
  5051.       function App() {
    
  5052.         ReactDOM.preload();
    
  5053.         ReactDOM.preload('');
    
  5054.         ReactDOM.preload('foo', null);
    
  5055.         ReactDOM.preload('foo', {});
    
  5056.         ReactDOM.preload('foo', {as: 'foo'});
    
  5057.         return <div>foo</div>;
    
  5058.       }
    
  5059. 
    
  5060.       await expect(async () => {
    
  5061.         await act(() => {
    
  5062.           renderToPipeableStream(<App />).pipe(writable);
    
  5063.         });
    
  5064.       }).toErrorDev([
    
  5065.         'ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `<link rel="preload" as="..." />` tag. The `href` argument encountered was `undefined`. The `options` argument encountered was `undefined`.',
    
  5066.         'ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `<link rel="preload" as="..." />` tag. The `href` argument encountered was an empty string. The `options` argument encountered was `undefined`.',
    
  5067.         'ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `<link rel="preload" as="..." />` tag. The `options` argument encountered was `null`.',
    
  5068.         'ReactDOM.preload(): Expected two arguments, a non-empty `href` string and an `options` object with an `as` property valid for a `<link rel="preload" as="..." />` tag. The `as` option encountered was `undefined`.',
    
  5069.       ]);
    
  5070.     });
    
  5071. 
    
  5072.     it('supports fetchPriority', async () => {
    
  5073.       function Component({isServer}) {
    
  5074.         ReactDOM.preload(isServer ? 'highserver' : 'highclient', {
    
  5075.           as: 'script',
    
  5076.           fetchPriority: 'high',
    
  5077.         });
    
  5078.         ReactDOM.preload(isServer ? 'lowserver' : 'lowclient', {
    
  5079.           as: 'style',
    
  5080.           fetchPriority: 'low',
    
  5081.         });
    
  5082.         ReactDOM.preload(isServer ? 'autoserver' : 'autoclient', {
    
  5083.           as: 'style',
    
  5084.           fetchPriority: 'auto',
    
  5085.         });
    
  5086.         return 'hello';
    
  5087.       }
    
  5088. 
    
  5089.       await act(() => {
    
  5090.         renderToPipeableStream(
    
  5091.           <html>
    
  5092.             <body>
    
  5093.               <Component isServer={true} />
    
  5094.             </body>
    
  5095.           </html>,
    
  5096.         ).pipe(writable);
    
  5097.       });
    
  5098. 
    
  5099.       expect(getMeaningfulChildren(document)).toEqual(
    
  5100.         <html>
    
  5101.           <head>
    
  5102.             <link
    
  5103.               rel="preload"
    
  5104.               as="script"
    
  5105.               href="highserver"
    
  5106.               fetchpriority="high"
    
  5107.             />
    
  5108.             <link
    
  5109.               rel="preload"
    
  5110.               as="style"
    
  5111.               href="lowserver"
    
  5112.               fetchpriority="low"
    
  5113.             />
    
  5114.             <link
    
  5115.               rel="preload"
    
  5116.               as="style"
    
  5117.               href="autoserver"
    
  5118.               fetchpriority="auto"
    
  5119.             />
    
  5120.           </head>
    
  5121.           <body>hello</body>
    
  5122.         </html>,
    
  5123.       );
    
  5124. 
    
  5125.       ReactDOMClient.hydrateRoot(
    
  5126.         document,
    
  5127.         <html>
    
  5128.           <body>
    
  5129.             <Component />
    
  5130.           </body>
    
  5131.         </html>,
    
  5132.       );
    
  5133.       await waitForAll([]);
    
  5134.       expect(getMeaningfulChildren(document)).toEqual(
    
  5135.         <html>
    
  5136.           <head>
    
  5137.             <link
    
  5138.               rel="preload"
    
  5139.               as="script"
    
  5140.               href="highserver"
    
  5141.               fetchpriority="high"
    
  5142.             />
    
  5143.             <link
    
  5144.               rel="preload"
    
  5145.               as="style"
    
  5146.               href="lowserver"
    
  5147.               fetchpriority="low"
    
  5148.             />
    
  5149.             <link
    
  5150.               rel="preload"
    
  5151.               as="style"
    
  5152.               href="autoserver"
    
  5153.               fetchpriority="auto"
    
  5154.             />
    
  5155.             <link
    
  5156.               rel="preload"
    
  5157.               as="script"
    
  5158.               href="highclient"
    
  5159.               fetchpriority="high"
    
  5160.             />
    
  5161.             <link
    
  5162.               rel="preload"
    
  5163.               as="style"
    
  5164.               href="lowclient"
    
  5165.               fetchpriority="low"
    
  5166.             />
    
  5167.             <link
    
  5168.               rel="preload"
    
  5169.               as="style"
    
  5170.               href="autoclient"
    
  5171.               fetchpriority="auto"
    
  5172.             />
    
  5173.           </head>
    
  5174.           <body>hello</body>
    
  5175.         </html>,
    
  5176.       );
    
  5177.     });
    
  5178. 
    
  5179.     it('supports nonce', async () => {
    
  5180.       function App({url}) {
    
  5181.         ReactDOM.preload(url, {as: 'script', nonce: 'abc'});
    
  5182.         return 'hello';
    
  5183.       }
    
  5184. 
    
  5185.       await act(() => {
    
  5186.         renderToPipeableStream(<App url="server" />).pipe(writable);
    
  5187.       });
    
  5188. 
    
  5189.       expect(getMeaningfulChildren(document)).toEqual(
    
  5190.         <html>
    
  5191.           <head />
    
  5192.           <body>
    
  5193.             <div id="container">
    
  5194.               <link rel="preload" as="script" href="server" nonce="abc" />
    
  5195.               hello
    
  5196.             </div>
    
  5197.           </body>
    
  5198.         </html>,
    
  5199.       );
    
  5200. 
    
  5201.       ReactDOMClient.hydrateRoot(container, <App url="client" />);
    
  5202.       await waitForAll([]);
    
  5203.       expect(getMeaningfulChildren(document)).toEqual(
    
  5204.         <html>
    
  5205.           <head>
    
  5206.             <link rel="preload" as="script" href="client" nonce="abc" />
    
  5207.           </head>
    
  5208.           <body>
    
  5209.             <div id="container">
    
  5210.               <link rel="preload" as="script" href="server" nonce="abc" />
    
  5211.               hello
    
  5212.             </div>
    
  5213.           </body>
    
  5214.         </html>,
    
  5215.       );
    
  5216.     });
    
  5217.   });
    
  5218. 
    
  5219.   describe('ReactDOM.preloadModule(href, options)', () => {
    
  5220.     it('preloads scripts as modules', async () => {
    
  5221.       function App({ssr}) {
    
  5222.         const prefix = ssr ? 'ssr ' : 'browser ';
    
  5223.         ReactDOM.preloadModule(prefix + 'plain');
    
  5224.         ReactDOM.preloadModule(prefix + 'default', {as: 'script'});
    
  5225.         ReactDOM.preloadModule(prefix + 'cors', {
    
  5226.           crossOrigin: 'use-credentials',
    
  5227.         });
    
  5228.         ReactDOM.preloadModule(prefix + 'integrity', {integrity: 'some hash'});
    
  5229.         ReactDOM.preloadModule(prefix + 'serviceworker', {as: 'serviceworker'});
    
  5230.         return <div>hello</div>;
    
  5231.       }
    
  5232.       await act(() => {
    
  5233.         renderToPipeableStream(<App ssr={true} />).pipe(writable);
    
  5234.       });
    
  5235.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  5236.         <div id="container">
    
  5237.           <link rel="modulepreload" href="ssr plain" />
    
  5238.           <link rel="modulepreload" href="ssr default" />
    
  5239.           <link
    
  5240.             rel="modulepreload"
    
  5241.             href="ssr cors"
    
  5242.             crossorigin="use-credentials"
    
  5243.           />
    
  5244.           <link
    
  5245.             rel="modulepreload"
    
  5246.             href="ssr integrity"
    
  5247.             integrity="some hash"
    
  5248.           />
    
  5249.           <link
    
  5250.             rel="modulepreload"
    
  5251.             href="ssr serviceworker"
    
  5252.             as="serviceworker"
    
  5253.           />
    
  5254.           <div>hello</div>
    
  5255.         </div>,
    
  5256.       );
    
  5257. 
    
  5258.       ReactDOMClient.hydrateRoot(container, <App />);
    
  5259.       await waitForAll([]);
    
  5260.       expect(getMeaningfulChildren(document)).toEqual(
    
  5261.         <html>
    
  5262.           <head>
    
  5263.             <link rel="modulepreload" href="browser plain" />
    
  5264.             <link rel="modulepreload" href="browser default" />
    
  5265.             <link
    
  5266.               rel="modulepreload"
    
  5267.               href="browser cors"
    
  5268.               crossorigin="use-credentials"
    
  5269.             />
    
  5270.             <link
    
  5271.               rel="modulepreload"
    
  5272.               href="browser integrity"
    
  5273.               integrity="some hash"
    
  5274.             />
    
  5275.             <link
    
  5276.               rel="modulepreload"
    
  5277.               href="browser serviceworker"
    
  5278.               as="serviceworker"
    
  5279.             />
    
  5280.           </head>
    
  5281.           <body>
    
  5282.             <div id="container">
    
  5283.               <link rel="modulepreload" href="ssr plain" />
    
  5284.               <link rel="modulepreload" href="ssr default" />
    
  5285.               <link
    
  5286.                 rel="modulepreload"
    
  5287.                 href="ssr cors"
    
  5288.                 crossorigin="use-credentials"
    
  5289.               />
    
  5290.               <link
    
  5291.                 rel="modulepreload"
    
  5292.                 href="ssr integrity"
    
  5293.                 integrity="some hash"
    
  5294.               />
    
  5295.               <link
    
  5296.                 rel="modulepreload"
    
  5297.                 href="ssr serviceworker"
    
  5298.                 as="serviceworker"
    
  5299.               />
    
  5300.               <div>hello</div>
    
  5301.             </div>
    
  5302.           </body>
    
  5303.         </html>,
    
  5304.       );
    
  5305.     });
    
  5306. 
    
  5307.     it('warns if you provide invalid arguments', async () => {
    
  5308.       function App() {
    
  5309.         ReactDOM.preloadModule();
    
  5310.         ReactDOM.preloadModule(() => {});
    
  5311.         ReactDOM.preloadModule('');
    
  5312.         ReactDOM.preloadModule('1', true);
    
  5313.         ReactDOM.preloadModule('2', {as: true});
    
  5314.         return <div>hello</div>;
    
  5315.       }
    
  5316.       await expect(async () => {
    
  5317.         await act(() => {
    
  5318.           renderToPipeableStream(<App />).pipe(writable);
    
  5319.         });
    
  5320.       }).toErrorDev([
    
  5321.         '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`',
    
  5322.         '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"',
    
  5323.         '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',
    
  5324.         '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"',
    
  5325.         '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"',
    
  5326.       ]);
    
  5327.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  5328.         <div id="container">
    
  5329.           <link rel="modulepreload" href="1" />
    
  5330.           <link rel="modulepreload" href="2" />
    
  5331.           <div>hello</div>
    
  5332.         </div>,
    
  5333.       );
    
  5334. 
    
  5335.       const root = ReactDOMClient.createRoot(
    
  5336.         document.getElementById('container'),
    
  5337.       );
    
  5338.       root.render(<App />);
    
  5339.       await expect(async () => {
    
  5340.         await waitForAll([]);
    
  5341.       }).toErrorDev([
    
  5342.         '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`',
    
  5343.         '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"',
    
  5344.         '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',
    
  5345.         '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"',
    
  5346.         '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"',
    
  5347.       ]);
    
  5348.     });
    
  5349.   });
    
  5350. 
    
  5351.   describe('ReactDOM.preinit(href, { as: ... })', () => {
    
  5352.     // @gate enableFloat
    
  5353.     it('creates a stylesheet resource when ReactDOM.preinit(..., {as: "style" }) is called', async () => {
    
  5354.       function App() {
    
  5355.         ReactDOM.preinit('foo', {as: 'style'});
    
  5356.         return (
    
  5357.           <html>
    
  5358.             <body>
    
  5359.               <Suspense fallback="loading...">
    
  5360.                 <BlockedOn value="bar">
    
  5361.                   <Component />
    
  5362.                 </BlockedOn>
    
  5363.               </Suspense>
    
  5364.             </body>
    
  5365.           </html>
    
  5366.         );
    
  5367.       }
    
  5368. 
    
  5369.       function Component() {
    
  5370.         ReactDOM.preinit('bar', {as: 'style'});
    
  5371.         return <div>hello</div>;
    
  5372.       }
    
  5373. 
    
  5374.       await act(() => {
    
  5375.         const {pipe} = renderToPipeableStream(<App />);
    
  5376.         pipe(writable);
    
  5377.       });
    
  5378.       expect(getMeaningfulChildren(document)).toEqual(
    
  5379.         <html>
    
  5380.           <head>
    
  5381.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  5382.           </head>
    
  5383.           <body>loading...</body>
    
  5384.         </html>,
    
  5385.       );
    
  5386. 
    
  5387.       await act(() => {
    
  5388.         resolveText('bar');
    
  5389.       });
    
  5390.       // The reason we do not see the "bar" stylesheet here is that ReactDOM.preinit is not about
    
  5391.       // encoding a resource dependency but is a hint that a resource will be used in the near future.
    
  5392.       // If we call preinit on the server after the shell has flushed the best we can do is emit a preload
    
  5393.       // because any flushing suspense boundaries are not actually dependent on that resource and we don't
    
  5394.       // want to delay reveal based on when that resource loads.
    
  5395.       expect(getMeaningfulChildren(document)).toEqual(
    
  5396.         <html>
    
  5397.           <head>
    
  5398.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  5399.           </head>
    
  5400.           <body>
    
  5401.             <div>hello</div>
    
  5402.             <link rel="preload" href="bar" as="style" />
    
  5403.           </body>
    
  5404.         </html>,
    
  5405.       );
    
  5406. 
    
  5407.       function ClientApp() {
    
  5408.         ReactDOM.preinit('bar', {as: 'style'});
    
  5409.         return (
    
  5410.           <html>
    
  5411.             <body>
    
  5412.               <Suspense fallback="loading...">
    
  5413.                 <div>hello</div>
    
  5414.               </Suspense>
    
  5415.             </body>
    
  5416.           </html>
    
  5417.         );
    
  5418.       }
    
  5419. 
    
  5420.       ReactDOMClient.hydrateRoot(document, <ClientApp />);
    
  5421.       await waitForAll([]);
    
  5422.       expect(getMeaningfulChildren(document)).toEqual(
    
  5423.         <html>
    
  5424.           <head>
    
  5425.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  5426.             <link rel="stylesheet" href="bar" data-precedence="default" />
    
  5427.           </head>
    
  5428.           <body>
    
  5429.             <div>hello</div>
    
  5430.             <link rel="preload" href="bar" as="style" />
    
  5431.           </body>
    
  5432.         </html>,
    
  5433.       );
    
  5434.     });
    
  5435. 
    
  5436.     // @gate enableFloat
    
  5437.     it('creates a stylesheet resource in the ownerDocument when ReactDOM.preinit(..., {as: "style" }) is called outside of render on the client', async () => {
    
  5438.       function App() {
    
  5439.         React.useEffect(() => {
    
  5440.           ReactDOM.preinit('foo', {as: 'style'});
    
  5441.         }, []);
    
  5442.         return (
    
  5443.           <html>
    
  5444.             <body>foo</body>
    
  5445.           </html>
    
  5446.         );
    
  5447.       }
    
  5448. 
    
  5449.       const root = ReactDOMClient.createRoot(document);
    
  5450.       root.render(<App />);
    
  5451.       await waitForAll([]);
    
  5452.       expect(getMeaningfulChildren(document)).toEqual(
    
  5453.         <html>
    
  5454.           <head>
    
  5455.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  5456.           </head>
    
  5457.           <body>foo</body>
    
  5458.         </html>,
    
  5459.       );
    
  5460.     });
    
  5461. 
    
  5462.     // @gate enableFloat
    
  5463.     it('creates a stylesheet resource in the ownerDocument when ReactDOM.preinit(..., {as: "style" }) is called outside of render on the client', async () => {
    
  5464.       // This is testing behavior, but it shows that it is not a good idea to preinit inside a shadowRoot. The point is we are asserting a behavior
    
  5465.       // you would want to avoid in a real app.
    
  5466.       const shadow = document.body.attachShadow({mode: 'open'});
    
  5467.       function ShadowComponent() {
    
  5468.         ReactDOM.preinit('bar', {as: 'style'});
    
  5469.         return null;
    
  5470.       }
    
  5471.       function App() {
    
  5472.         React.useEffect(() => {
    
  5473.           ReactDOM.preinit('foo', {as: 'style'});
    
  5474.         }, []);
    
  5475.         return (
    
  5476.           <html>
    
  5477.             <body>
    
  5478.               foo
    
  5479.               {ReactDOM.createPortal(
    
  5480.                 <div>
    
  5481.                   <ShadowComponent />
    
  5482.                   shadow
    
  5483.                 </div>,
    
  5484.                 shadow,
    
  5485.               )}
    
  5486.             </body>
    
  5487.           </html>
    
  5488.         );
    
  5489.       }
    
  5490. 
    
  5491.       const root = ReactDOMClient.createRoot(document);
    
  5492.       root.render(<App />);
    
  5493.       await waitForAll([]);
    
  5494.       expect(getMeaningfulChildren(document)).toEqual(
    
  5495.         <html>
    
  5496.           <head>
    
  5497.             <link rel="stylesheet" href="bar" data-precedence="default" />
    
  5498.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  5499.           </head>
    
  5500.           <body>foo</body>
    
  5501.         </html>,
    
  5502.       );
    
  5503.       expect(getMeaningfulChildren(shadow)).toEqual(<div>shadow</div>);
    
  5504.     });
    
  5505. 
    
  5506.     // @gate enableFloat
    
  5507.     it('creates a script resource when ReactDOM.preinit(..., {as: "script" }) is called', async () => {
    
  5508.       function App() {
    
  5509.         ReactDOM.preinit('foo', {as: 'script'});
    
  5510.         return (
    
  5511.           <html>
    
  5512.             <body>
    
  5513.               <Suspense fallback="loading...">
    
  5514.                 <BlockedOn value="bar">
    
  5515.                   <Component />
    
  5516.                 </BlockedOn>
    
  5517.               </Suspense>
    
  5518.             </body>
    
  5519.           </html>
    
  5520.         );
    
  5521.       }
    
  5522. 
    
  5523.       function Component() {
    
  5524.         ReactDOM.preinit('bar', {as: 'script'});
    
  5525.         return <div>hello</div>;
    
  5526.       }
    
  5527. 
    
  5528.       await act(() => {
    
  5529.         const {pipe} = renderToPipeableStream(<App />);
    
  5530.         pipe(writable);
    
  5531.       });
    
  5532.       expect(getMeaningfulChildren(document)).toEqual(
    
  5533.         <html>
    
  5534.           <head>
    
  5535.             <script async="" src="foo" />
    
  5536.           </head>
    
  5537.           <body>loading...</body>
    
  5538.         </html>,
    
  5539.       );
    
  5540. 
    
  5541.       await act(() => {
    
  5542.         resolveText('bar');
    
  5543.       });
    
  5544.       expect(getMeaningfulChildren(document)).toEqual(
    
  5545.         <html>
    
  5546.           <head>
    
  5547.             <script async="" src="foo" />
    
  5548.           </head>
    
  5549.           <body>
    
  5550.             <div>hello</div>
    
  5551.             <script async="" src="bar" />
    
  5552.           </body>
    
  5553.         </html>,
    
  5554.       );
    
  5555. 
    
  5556.       function ClientApp() {
    
  5557.         ReactDOM.preinit('bar', {as: 'script'});
    
  5558.         return (
    
  5559.           <html>
    
  5560.             <body>
    
  5561.               <Suspense fallback="loading...">
    
  5562.                 <div>hello</div>
    
  5563.               </Suspense>
    
  5564.             </body>
    
  5565.           </html>
    
  5566.         );
    
  5567.       }
    
  5568. 
    
  5569.       ReactDOMClient.hydrateRoot(document, <ClientApp />);
    
  5570.       await waitForAll([]);
    
  5571.       expect(getMeaningfulChildren(document)).toEqual(
    
  5572.         <html>
    
  5573.           <head>
    
  5574.             <script async="" src="foo" />
    
  5575.           </head>
    
  5576.           <body>
    
  5577.             <div>hello</div>
    
  5578.             <script async="" src="bar" />
    
  5579.           </body>
    
  5580.         </html>,
    
  5581.       );
    
  5582.     });
    
  5583. 
    
  5584.     // @gate enableFloat
    
  5585.     it('creates a script resource when ReactDOM.preinit(..., {as: "script" }) is called outside of render on the client', async () => {
    
  5586.       function App() {
    
  5587.         React.useEffect(() => {
    
  5588.           ReactDOM.preinit('foo', {as: 'script'});
    
  5589.         }, []);
    
  5590.         return (
    
  5591.           <html>
    
  5592.             <body>foo</body>
    
  5593.           </html>
    
  5594.         );
    
  5595.       }
    
  5596. 
    
  5597.       const root = ReactDOMClient.createRoot(document);
    
  5598.       root.render(<App />);
    
  5599.       await waitForAll([]);
    
  5600.       expect(getMeaningfulChildren(document)).toEqual(
    
  5601.         <html>
    
  5602.           <head>
    
  5603.             <script async="" src="foo" />
    
  5604.           </head>
    
  5605.           <body>foo</body>
    
  5606.         </html>,
    
  5607.       );
    
  5608.     });
    
  5609. 
    
  5610.     // @gate enableFloat
    
  5611.     it('warns if you do not pass in a valid href argument or options argument', async () => {
    
  5612.       function App() {
    
  5613.         ReactDOM.preinit();
    
  5614.         ReactDOM.preinit('');
    
  5615.         ReactDOM.preinit('foo', null);
    
  5616.         ReactDOM.preinit('foo', {});
    
  5617.         ReactDOM.preinit('foo', {as: 'foo'});
    
  5618.         return <div>foo</div>;
    
  5619.       }
    
  5620. 
    
  5621.       await expect(async () => {
    
  5622.         await act(() => {
    
  5623.           renderToPipeableStream(<App />).pipe(writable);
    
  5624.         });
    
  5625.       }).toErrorDev([
    
  5626.         'ReactDOM.preinit(): Expected the `href` argument (first) to be a non-empty string but encountered `undefined` instead',
    
  5627.         'ReactDOM.preinit(): Expected the `href` argument (first) to be a non-empty string but encountered an empty string instead',
    
  5628.         'ReactDOM.preinit(): Expected the `options` argument (second) to be an object with an `as` property describing the type of resource to be preinitialized but encountered `null` instead',
    
  5629.         'ReactDOM.preinit(): Expected the `as` property in the `options` argument (second) to contain a valid value describing the type of resource to be preinitialized but encountered `undefined` instead. Valid values for `as` are "style" and "script".',
    
  5630.         'ReactDOM.preinit(): Expected the `as` property in the `options` argument (second) to contain a valid value describing the type of resource to be preinitialized but encountered "foo" instead. Valid values for `as` are "style" and "script".',
    
  5631.       ]);
    
  5632.     });
    
  5633. 
    
  5634.     it('accepts a `nonce` option for `as: "script"`', async () => {
    
  5635.       function Component({src}) {
    
  5636.         ReactDOM.preinit(src, {as: 'script', nonce: 'R4nD0m'});
    
  5637.         return 'hello';
    
  5638.       }
    
  5639. 
    
  5640.       await act(() => {
    
  5641.         renderToPipeableStream(
    
  5642.           <html>
    
  5643.             <body>
    
  5644.               <Component src="foo" />
    
  5645.             </body>
    
  5646.           </html>,
    
  5647.           {
    
  5648.             nonce: 'R4nD0m',
    
  5649.           },
    
  5650.         ).pipe(writable);
    
  5651.       });
    
  5652. 
    
  5653.       expect(getMeaningfulChildren(document)).toEqual(
    
  5654.         <html>
    
  5655.           <head>
    
  5656.             <script async="" src="foo" nonce="R4nD0m" />
    
  5657.           </head>
    
  5658.           <body>hello</body>
    
  5659.         </html>,
    
  5660.       );
    
  5661. 
    
  5662.       await clientAct(() => {
    
  5663.         ReactDOMClient.hydrateRoot(
    
  5664.           document,
    
  5665.           <html>
    
  5666.             <body>
    
  5667.               <Component src="bar" />
    
  5668.             </body>
    
  5669.           </html>,
    
  5670.         );
    
  5671.       });
    
  5672. 
    
  5673.       expect(getMeaningfulChildren(document)).toEqual(
    
  5674.         <html>
    
  5675.           <head>
    
  5676.             <script async="" src="foo" nonce="R4nD0m" />
    
  5677.             <script async="" src="bar" nonce="R4nD0m" />
    
  5678.           </head>
    
  5679.           <body>hello</body>
    
  5680.         </html>,
    
  5681.       );
    
  5682.     });
    
  5683. 
    
  5684.     it('accepts an `integrity` option for `as: "script"`', async () => {
    
  5685.       function Component({src, hash}) {
    
  5686.         ReactDOM.preinit(src, {as: 'script', integrity: hash});
    
  5687.         return 'hello';
    
  5688.       }
    
  5689. 
    
  5690.       await act(() => {
    
  5691.         renderToPipeableStream(
    
  5692.           <html>
    
  5693.             <body>
    
  5694.               <Component src="foo" hash="foo hash" />
    
  5695.             </body>
    
  5696.           </html>,
    
  5697.           {
    
  5698.             nonce: 'R4nD0m',
    
  5699.           },
    
  5700.         ).pipe(writable);
    
  5701.       });
    
  5702. 
    
  5703.       expect(getMeaningfulChildren(document)).toEqual(
    
  5704.         <html>
    
  5705.           <head>
    
  5706.             <script async="" src="foo" integrity="foo hash" />
    
  5707.           </head>
    
  5708.           <body>hello</body>
    
  5709.         </html>,
    
  5710.       );
    
  5711. 
    
  5712.       await clientAct(() => {
    
  5713.         ReactDOMClient.hydrateRoot(
    
  5714.           document,
    
  5715.           <html>
    
  5716.             <body>
    
  5717.               <Component src="bar" hash="bar hash" />
    
  5718.             </body>
    
  5719.           </html>,
    
  5720.         );
    
  5721.       });
    
  5722. 
    
  5723.       expect(getMeaningfulChildren(document)).toEqual(
    
  5724.         <html>
    
  5725.           <head>
    
  5726.             <script async="" src="foo" integrity="foo hash" />
    
  5727.             <script async="" src="bar" integrity="bar hash" />
    
  5728.           </head>
    
  5729.           <body>hello</body>
    
  5730.         </html>,
    
  5731.       );
    
  5732.     });
    
  5733. 
    
  5734.     it('accepts an `integrity` option for `as: "style"`', async () => {
    
  5735.       function Component({src, hash}) {
    
  5736.         ReactDOM.preinit(src, {as: 'style', integrity: hash});
    
  5737.         return 'hello';
    
  5738.       }
    
  5739. 
    
  5740.       await act(() => {
    
  5741.         renderToPipeableStream(
    
  5742.           <html>
    
  5743.             <body>
    
  5744.               <Component src="foo" hash="foo hash" />
    
  5745.             </body>
    
  5746.           </html>,
    
  5747.           {
    
  5748.             nonce: 'R4nD0m',
    
  5749.           },
    
  5750.         ).pipe(writable);
    
  5751.       });
    
  5752. 
    
  5753.       expect(getMeaningfulChildren(document)).toEqual(
    
  5754.         <html>
    
  5755.           <head>
    
  5756.             <link
    
  5757.               rel="stylesheet"
    
  5758.               href="foo"
    
  5759.               integrity="foo hash"
    
  5760.               data-precedence="default"
    
  5761.             />
    
  5762.           </head>
    
  5763.           <body>hello</body>
    
  5764.         </html>,
    
  5765.       );
    
  5766.       await clientAct(() => {
    
  5767.         ReactDOMClient.hydrateRoot(
    
  5768.           document,
    
  5769.           <html>
    
  5770.             <body>
    
  5771.               <Component src="bar" hash="bar hash" />
    
  5772.             </body>
    
  5773.           </html>,
    
  5774.         );
    
  5775.       });
    
  5776.       expect(getMeaningfulChildren(document)).toEqual(
    
  5777.         <html>
    
  5778.           <head>
    
  5779.             <link
    
  5780.               rel="stylesheet"
    
  5781.               href="foo"
    
  5782.               integrity="foo hash"
    
  5783.               data-precedence="default"
    
  5784.             />
    
  5785.             <link
    
  5786.               rel="stylesheet"
    
  5787.               href="bar"
    
  5788.               integrity="bar hash"
    
  5789.               data-precedence="default"
    
  5790.             />
    
  5791.           </head>
    
  5792.           <body>hello</body>
    
  5793.         </html>,
    
  5794.       );
    
  5795.     });
    
  5796. 
    
  5797.     it('supports fetchPriority', async () => {
    
  5798.       function Component({isServer}) {
    
  5799.         ReactDOM.preinit(isServer ? 'highserver' : 'highclient', {
    
  5800.           as: 'script',
    
  5801.           fetchPriority: 'high',
    
  5802.         });
    
  5803.         ReactDOM.preinit(isServer ? 'lowserver' : 'lowclient', {
    
  5804.           as: 'style',
    
  5805.           fetchPriority: 'low',
    
  5806.         });
    
  5807.         ReactDOM.preinit(isServer ? 'autoserver' : 'autoclient', {
    
  5808.           as: 'style',
    
  5809.           fetchPriority: 'auto',
    
  5810.         });
    
  5811.         return 'hello';
    
  5812.       }
    
  5813. 
    
  5814.       await act(() => {
    
  5815.         renderToPipeableStream(
    
  5816.           <html>
    
  5817.             <body>
    
  5818.               <Component isServer={true} />
    
  5819.             </body>
    
  5820.           </html>,
    
  5821.         ).pipe(writable);
    
  5822.       });
    
  5823. 
    
  5824.       expect(getMeaningfulChildren(document)).toEqual(
    
  5825.         <html>
    
  5826.           <head>
    
  5827.             <link
    
  5828.               rel="stylesheet"
    
  5829.               href="lowserver"
    
  5830.               fetchpriority="low"
    
  5831.               data-precedence="default"
    
  5832.             />
    
  5833.             <link
    
  5834.               rel="stylesheet"
    
  5835.               href="autoserver"
    
  5836.               fetchpriority="auto"
    
  5837.               data-precedence="default"
    
  5838.             />
    
  5839.             <script async="" src="highserver" fetchpriority="high" />
    
  5840.           </head>
    
  5841.           <body>hello</body>
    
  5842.         </html>,
    
  5843.       );
    
  5844.       ReactDOMClient.hydrateRoot(
    
  5845.         document,
    
  5846.         <html>
    
  5847.           <body>
    
  5848.             <Component />
    
  5849.           </body>
    
  5850.         </html>,
    
  5851.       );
    
  5852.       await waitForAll([]);
    
  5853.       expect(getMeaningfulChildren(document)).toEqual(
    
  5854.         <html>
    
  5855.           <head>
    
  5856.             <link
    
  5857.               rel="stylesheet"
    
  5858.               href="lowserver"
    
  5859.               fetchpriority="low"
    
  5860.               data-precedence="default"
    
  5861.             />
    
  5862.             <link
    
  5863.               rel="stylesheet"
    
  5864.               href="autoserver"
    
  5865.               fetchpriority="auto"
    
  5866.               data-precedence="default"
    
  5867.             />
    
  5868.             <link
    
  5869.               rel="stylesheet"
    
  5870.               href="lowclient"
    
  5871.               fetchpriority="low"
    
  5872.               data-precedence="default"
    
  5873.             />
    
  5874.             <link
    
  5875.               rel="stylesheet"
    
  5876.               href="autoclient"
    
  5877.               fetchpriority="auto"
    
  5878.               data-precedence="default"
    
  5879.             />
    
  5880.             <script async="" src="highserver" fetchpriority="high" />
    
  5881.             <script async="" src="highclient" fetchpriority="high" />
    
  5882.           </head>
    
  5883.           <body>hello</body>
    
  5884.         </html>,
    
  5885.       );
    
  5886.     });
    
  5887.   });
    
  5888. 
    
  5889.   describe('ReactDOM.preinitModule(href, options)', () => {
    
  5890.     it('creates a script module resources', async () => {
    
  5891.       function App({ssr}) {
    
  5892.         const prefix = ssr ? 'ssr ' : 'browser ';
    
  5893.         ReactDOM.preinitModule(prefix + 'plain');
    
  5894.         ReactDOM.preinitModule(prefix + 'default', {as: 'script'});
    
  5895.         ReactDOM.preinitModule(prefix + 'cors', {
    
  5896.           crossOrigin: 'use-credentials',
    
  5897.         });
    
  5898.         ReactDOM.preinitModule(prefix + 'integrity', {integrity: 'some hash'});
    
  5899.         ReactDOM.preinitModule(prefix + 'warning', {as: 'style'});
    
  5900.         return <div>hello</div>;
    
  5901.       }
    
  5902.       await expect(async () => {
    
  5903.         await act(() => {
    
  5904.           renderToPipeableStream(<App ssr={true} />).pipe(writable);
    
  5905.         });
    
  5906.       }).toErrorDev([
    
  5907.         '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"',
    
  5908.       ]);
    
  5909.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  5910.         <div id="container">
    
  5911.           <script type="module" src="ssr plain" async="" />
    
  5912.           <script type="module" src="ssr default" async="" />
    
  5913.           <script
    
  5914.             type="module"
    
  5915.             src="ssr cors"
    
  5916.             crossorigin="use-credentials"
    
  5917.             async=""
    
  5918.           />
    
  5919.           <script
    
  5920.             type="module"
    
  5921.             src="ssr integrity"
    
  5922.             integrity="some hash"
    
  5923.             async=""
    
  5924.           />
    
  5925.           <div>hello</div>
    
  5926.         </div>,
    
  5927.       );
    
  5928. 
    
  5929.       ReactDOMClient.hydrateRoot(container, <App />);
    
  5930.       await expect(async () => {
    
  5931.         await waitForAll([]);
    
  5932.       }).toErrorDev([
    
  5933.         '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"',
    
  5934.       ]);
    
  5935.       expect(getMeaningfulChildren(document)).toEqual(
    
  5936.         <html>
    
  5937.           <head>
    
  5938.             <script type="module" src="browser plain" async="" />
    
  5939.             <script type="module" src="browser default" async="" />
    
  5940.             <script
    
  5941.               type="module"
    
  5942.               src="browser cors"
    
  5943.               crossorigin="use-credentials"
    
  5944.               async=""
    
  5945.             />
    
  5946.             <script
    
  5947.               type="module"
    
  5948.               src="browser integrity"
    
  5949.               integrity="some hash"
    
  5950.               async=""
    
  5951.             />
    
  5952.           </head>
    
  5953.           <body>
    
  5954.             <div id="container">
    
  5955.               <script type="module" src="ssr plain" async="" />
    
  5956.               <script type="module" src="ssr default" async="" />
    
  5957.               <script
    
  5958.                 type="module"
    
  5959.                 src="ssr cors"
    
  5960.                 crossorigin="use-credentials"
    
  5961.                 async=""
    
  5962.               />
    
  5963.               <script
    
  5964.                 type="module"
    
  5965.                 src="ssr integrity"
    
  5966.                 integrity="some hash"
    
  5967.                 async=""
    
  5968.               />
    
  5969.               <div>hello</div>
    
  5970.             </div>
    
  5971.           </body>
    
  5972.         </html>,
    
  5973.       );
    
  5974.     });
    
  5975. 
    
  5976.     it('warns if you provide invalid arguments', async () => {
    
  5977.       function App() {
    
  5978.         ReactDOM.preinitModule();
    
  5979.         ReactDOM.preinitModule(() => {});
    
  5980.         ReactDOM.preinitModule('');
    
  5981.         ReactDOM.preinitModule('1', true);
    
  5982.         ReactDOM.preinitModule('2', {as: true});
    
  5983.         return <div>hello</div>;
    
  5984.       }
    
  5985.       await expect(async () => {
    
  5986.         await act(() => {
    
  5987.           renderToPipeableStream(<App />).pipe(writable);
    
  5988.         });
    
  5989.       }).toErrorDev([
    
  5990.         '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`',
    
  5991.         '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"',
    
  5992.         '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',
    
  5993.         '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"',
    
  5994.         '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"',
    
  5995.       ]);
    
  5996.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  5997.         <div id="container">
    
  5998.           <div>hello</div>
    
  5999.         </div>,
    
  6000.       );
    
  6001. 
    
  6002.       const root = ReactDOMClient.createRoot(
    
  6003.         document.getElementById('container'),
    
  6004.       );
    
  6005.       root.render(<App />);
    
  6006.       await expect(async () => {
    
  6007.         await waitForAll([]);
    
  6008.       }).toErrorDev([
    
  6009.         '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`',
    
  6010.         '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"',
    
  6011.         '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',
    
  6012.         '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"',
    
  6013.         '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"',
    
  6014.       ]);
    
  6015.     });
    
  6016.   });
    
  6017. 
    
  6018.   describe('Stylesheet Resources', () => {
    
  6019.     // @gate enableFloat
    
  6020.     it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when server rendering', async () => {
    
  6021.       await act(() => {
    
  6022.         const {pipe} = renderToPipeableStream(
    
  6023.           <html>
    
  6024.             <head />
    
  6025.             <body>
    
  6026.               <link rel="stylesheet" href="aresource" precedence="foo" />
    
  6027.               <div>hello world</div>
    
  6028.             </body>
    
  6029.           </html>,
    
  6030.         );
    
  6031.         pipe(writable);
    
  6032.       });
    
  6033. 
    
  6034.       expect(getMeaningfulChildren(document)).toEqual(
    
  6035.         <html>
    
  6036.           <head>
    
  6037.             <link rel="stylesheet" href="aresource" data-precedence="foo" />
    
  6038.           </head>
    
  6039.           <body>
    
  6040.             <div>hello world</div>
    
  6041.           </body>
    
  6042.         </html>,
    
  6043.       );
    
  6044.     });
    
  6045. 
    
  6046.     // @gate enableFloat
    
  6047.     it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when client rendering', async () => {
    
  6048.       const root = ReactDOMClient.createRoot(document);
    
  6049.       root.render(
    
  6050.         <html>
    
  6051.           <head />
    
  6052.           <body>
    
  6053.             <link rel="stylesheet" href="aresource" precedence="foo" />
    
  6054.             <div>hello world</div>
    
  6055.           </body>
    
  6056.         </html>,
    
  6057.       );
    
  6058.       await waitForAll([]);
    
  6059. 
    
  6060.       expect(getMeaningfulChildren(document)).toEqual(
    
  6061.         <html>
    
  6062.           <head>
    
  6063.             <link rel="stylesheet" href="aresource" data-precedence="foo" />
    
  6064.           </head>
    
  6065.           <body>
    
  6066.             <div>hello world</div>
    
  6067.           </body>
    
  6068.         </html>,
    
  6069.       );
    
  6070.     });
    
  6071. 
    
  6072.     // @gate enableFloat
    
  6073.     it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when hydrating', async () => {
    
  6074.       await act(() => {
    
  6075.         const {pipe} = renderToPipeableStream(
    
  6076.           <html>
    
  6077.             <head />
    
  6078.             <body>
    
  6079.               <link rel="stylesheet" href="aresource" precedence="foo" />
    
  6080.               <div>hello world</div>
    
  6081.             </body>
    
  6082.           </html>,
    
  6083.         );
    
  6084.         pipe(writable);
    
  6085.       });
    
  6086.       ReactDOMClient.hydrateRoot(
    
  6087.         document,
    
  6088.         <html>
    
  6089.           <head />
    
  6090.           <body>
    
  6091.             <link rel="stylesheet" href="aresource" precedence="foo" />
    
  6092.             <div>hello world</div>
    
  6093.           </body>
    
  6094.         </html>,
    
  6095.       );
    
  6096.       await waitForAll([]);
    
  6097. 
    
  6098.       expect(getMeaningfulChildren(document)).toEqual(
    
  6099.         <html>
    
  6100.           <head>
    
  6101.             <link rel="stylesheet" href="aresource" data-precedence="foo" />
    
  6102.           </head>
    
  6103.           <body>
    
  6104.             <div>hello world</div>
    
  6105.           </body>
    
  6106.         </html>,
    
  6107.       );
    
  6108.     });
    
  6109. 
    
  6110.     // @gate enableFloat
    
  6111.     it('hoists stylesheet resources to the correct precedence', async () => {
    
  6112.       await act(() => {
    
  6113.         const {pipe} = renderToPipeableStream(
    
  6114.           <html>
    
  6115.             <head />
    
  6116.             <body>
    
  6117.               <link rel="stylesheet" href="foo1" precedence="foo" />
    
  6118.               <link rel="stylesheet" href="default1" precedence="default" />
    
  6119.               <link rel="stylesheet" href="foo2" precedence="foo" />
    
  6120.               <div>hello world</div>
    
  6121.             </body>
    
  6122.           </html>,
    
  6123.         );
    
  6124.         pipe(writable);
    
  6125.       });
    
  6126.       expect(getMeaningfulChildren(document)).toEqual(
    
  6127.         <html>
    
  6128.           <head>
    
  6129.             <link rel="stylesheet" href="foo1" data-precedence="foo" />
    
  6130.             <link rel="stylesheet" href="foo2" data-precedence="foo" />
    
  6131.             <link rel="stylesheet" href="default1" data-precedence="default" />
    
  6132.           </head>
    
  6133.           <body>
    
  6134.             <div>hello world</div>
    
  6135.           </body>
    
  6136.         </html>,
    
  6137.       );
    
  6138. 
    
  6139.       ReactDOMClient.hydrateRoot(
    
  6140.         document,
    
  6141.         <html>
    
  6142.           <head />
    
  6143.           <body>
    
  6144.             <link rel="stylesheet" href="bar1" precedence="bar" />
    
  6145.             <link rel="stylesheet" href="foo3" precedence="foo" />
    
  6146.             <link rel="stylesheet" href="default2" precedence="default" />
    
  6147.             <div>hello world</div>
    
  6148.           </body>
    
  6149.         </html>,
    
  6150.       );
    
  6151.       await waitForAll([]);
    
  6152.       expect(getMeaningfulChildren(document)).toEqual(
    
  6153.         <html>
    
  6154.           <head>
    
  6155.             <link rel="stylesheet" href="foo1" data-precedence="foo" />
    
  6156.             <link rel="stylesheet" href="foo2" data-precedence="foo" />
    
  6157.             <link rel="stylesheet" href="foo3" data-precedence="foo" />
    
  6158.             <link rel="stylesheet" href="default1" data-precedence="default" />
    
  6159.             <link rel="stylesheet" href="default2" data-precedence="default" />
    
  6160.             <link rel="stylesheet" href="bar1" data-precedence="bar" />
    
  6161.             <link rel="preload" as="style" href="bar1" />
    
  6162.             <link rel="preload" as="style" href="foo3" />
    
  6163.             <link rel="preload" as="style" href="default2" />
    
  6164.           </head>
    
  6165.           <body>
    
  6166.             <div>hello world</div>
    
  6167.           </body>
    
  6168.         </html>,
    
  6169.       );
    
  6170.     });
    
  6171. 
    
  6172.     // @gate enableFloat
    
  6173.     it('retains styles even after the last referring Resource unmounts', async () => {
    
  6174.       // This test is true until a future update where there is some form of garbage collection.
    
  6175.       const root = ReactDOMClient.createRoot(document);
    
  6176. 
    
  6177.       root.render(
    
  6178.         <html>
    
  6179.           <head />
    
  6180.           <body>
    
  6181.             hello world
    
  6182.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  6183.           </body>
    
  6184.         </html>,
    
  6185.       );
    
  6186.       await waitForAll([]);
    
  6187. 
    
  6188.       root.render(
    
  6189.         <html>
    
  6190.           <head />
    
  6191.           <body>hello world</body>
    
  6192.         </html>,
    
  6193.       );
    
  6194.       await waitForAll([]);
    
  6195.       expect(getMeaningfulChildren(document)).toEqual(
    
  6196.         <html>
    
  6197.           <head>
    
  6198.             <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  6199.           </head>
    
  6200.           <body>hello world</body>
    
  6201.         </html>,
    
  6202.       );
    
  6203.     });
    
  6204. 
    
  6205.     // @gate enableFloat && enableHostSingletons && enableClientRenderFallbackOnTextMismatch
    
  6206.     it('retains styles even when a new html, head, and/body mount', async () => {
    
  6207.       await act(() => {
    
  6208.         const {pipe} = renderToPipeableStream(
    
  6209.           <html>
    
  6210.             <head />
    
  6211.             <body>
    
  6212.               <link rel="stylesheet" href="foo" precedence="foo" />
    
  6213.               <link rel="stylesheet" href="bar" precedence="bar" />
    
  6214.               server
    
  6215.             </body>
    
  6216.           </html>,
    
  6217.         );
    
  6218.         pipe(writable);
    
  6219.       });
    
  6220.       const errors = [];
    
  6221.       ReactDOMClient.hydrateRoot(
    
  6222.         document,
    
  6223.         <html>
    
  6224.           <head>
    
  6225.             <link rel="stylesheet" href="qux" precedence="qux" />
    
  6226.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  6227.           </head>
    
  6228.           <body>client</body>
    
  6229.         </html>,
    
  6230.         {
    
  6231.           onRecoverableError(error) {
    
  6232.             errors.push(error.message);
    
  6233.           },
    
  6234.         },
    
  6235.       );
    
  6236.       await expect(async () => {
    
  6237.         await waitForAll([]);
    
  6238.       }).toErrorDev(
    
  6239.         [
    
  6240.           'Warning: Text content did not match. Server: "server" Client: "client"',
    
  6241.           'Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.',
    
  6242.         ],
    
  6243.         {withoutStack: 1},
    
  6244.       );
    
  6245.       expect(getMeaningfulChildren(document)).toEqual(
    
  6246.         <html>
    
  6247.           <head>
    
  6248.             <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  6249.             <link rel="stylesheet" href="bar" data-precedence="bar" />
    
  6250.             <link rel="stylesheet" href="qux" data-precedence="qux" />
    
  6251.           </head>
    
  6252.           <body>client</body>
    
  6253.         </html>,
    
  6254.       );
    
  6255.     });
    
  6256. 
    
  6257.     // @gate enableFloat && !enableHostSingletons
    
  6258.     it('retains styles even when a new html, head, and/body mount - without HostSingleton', async () => {
    
  6259.       await act(() => {
    
  6260.         const {pipe} = renderToPipeableStream(
    
  6261.           <html>
    
  6262.             <head />
    
  6263.             <body>
    
  6264.               <link rel="stylesheet" href="foo" precedence="foo" />
    
  6265.               <link rel="stylesheet" href="bar" precedence="bar" />
    
  6266.               server
    
  6267.             </body>
    
  6268.           </html>,
    
  6269.         );
    
  6270.         pipe(writable);
    
  6271.       });
    
  6272.       const errors = [];
    
  6273.       ReactDOMClient.hydrateRoot(
    
  6274.         document,
    
  6275.         <html>
    
  6276.           <head>
    
  6277.             <link rel="stylesheet" href="qux" precedence="qux" />
    
  6278.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  6279.           </head>
    
  6280.           <body>client</body>
    
  6281.         </html>,
    
  6282.         {
    
  6283.           onRecoverableError(error) {
    
  6284.             errors.push(error.message);
    
  6285.           },
    
  6286.         },
    
  6287.       );
    
  6288.       await expect(async () => {
    
  6289.         await waitForAll([]);
    
  6290.       }).toErrorDev(
    
  6291.         [
    
  6292.           'Warning: Text content did not match. Server: "server" Client: "client"',
    
  6293.           'Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.',
    
  6294.         ],
    
  6295.         {withoutStack: 1},
    
  6296.       );
    
  6297.       expect(getMeaningfulChildren(document)).toEqual(
    
  6298.         <html>
    
  6299.           <head>
    
  6300.             <link rel="stylesheet" href="qux" data-precedence="qux" />
    
  6301.             <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  6302.           </head>
    
  6303.           <body>client</body>
    
  6304.         </html>,
    
  6305.       );
    
  6306.     });
    
  6307. 
    
  6308.     // @gate enableFloat && enableHostSingletons
    
  6309.     it('retains styles in head through head remounts', async () => {
    
  6310.       const root = ReactDOMClient.createRoot(document);
    
  6311.       root.render(
    
  6312.         <html>
    
  6313.           <head key={1} />
    
  6314.           <body>
    
  6315.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  6316.             <link rel="stylesheet" href="bar" precedence="bar" />
    
  6317.             {null}
    
  6318.             hello
    
  6319.           </body>
    
  6320.         </html>,
    
  6321.       );
    
  6322.       await waitForAll([]);
    
  6323.       expect(getMeaningfulChildren(document)).toEqual(
    
  6324.         <html>
    
  6325.           <head>
    
  6326.             <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  6327.             <link rel="stylesheet" href="bar" data-precedence="bar" />
    
  6328.           </head>
    
  6329.           <body>hello</body>
    
  6330.         </html>,
    
  6331.       );
    
  6332. 
    
  6333.       root.render(
    
  6334.         <html>
    
  6335.           <head key={2} />
    
  6336.           <body>
    
  6337.             <link rel="stylesheet" href="foo" precedence="foo" />
    
  6338.             {null}
    
  6339.             <link rel="stylesheet" href="baz" precedence="baz" />
    
  6340.             hello
    
  6341.           </body>
    
  6342.         </html>,
    
  6343.       );
    
  6344.       await waitForAll([]);
    
  6345.       // The reason we do not see preloads in the head is they are inserted synchronously
    
  6346.       // during render and then when the new singleton mounts it resets it's content, retaining only styles
    
  6347.       expect(getMeaningfulChildren(document)).toEqual(
    
  6348.         <html>
    
  6349.           <head>
    
  6350.             <link rel="stylesheet" href="foo" data-precedence="foo" />
    
  6351.             <link rel="stylesheet" href="bar" data-precedence="bar" />
    
  6352.             <link rel="stylesheet" href="baz" data-precedence="baz" />
    
  6353.             <link rel="preload" href="baz" as="style" />
    
  6354.           </head>
    
  6355.           <body>hello</body>
    
  6356.         </html>,
    
  6357.       );
    
  6358.     });
    
  6359.     // @gate enableFloat
    
  6360.     it('can support styles inside portals to a shadowRoot', async () => {
    
  6361.       const shadow = document.body.attachShadow({mode: 'open'});
    
  6362.       const root = ReactDOMClient.createRoot(container);
    
  6363.       root.render(
    
  6364.         <>
    
  6365.           <link rel="stylesheet" href="foo" precedence="default" />
    
  6366.           {ReactDOM.createPortal(
    
  6367.             <div>
    
  6368.               <link
    
  6369.                 rel="stylesheet"
    
  6370.                 href="foo"
    
  6371.                 data-extra-prop="foo"
    
  6372.                 precedence="different"
    
  6373.               />
    
  6374.               shadow
    
  6375.             </div>,
    
  6376.             shadow,
    
  6377.           )}
    
  6378.           container
    
  6379.         </>,
    
  6380.       );
    
  6381.       await waitForAll([]);
    
  6382.       expect(getMeaningfulChildren(document)).toEqual(
    
  6383.         <html>
    
  6384.           <head>
    
  6385.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  6386.             <link rel="preload" href="foo" as="style" />
    
  6387.           </head>
    
  6388.           <body>
    
  6389.             <div id="container">container</div>
    
  6390.           </body>
    
  6391.         </html>,
    
  6392.       );
    
  6393.       expect(getMeaningfulChildren(shadow)).toEqual([
    
  6394.         <link
    
  6395.           rel="stylesheet"
    
  6396.           href="foo"
    
  6397.           data-precedence="different"
    
  6398.           data-extra-prop="foo"
    
  6399.         />,
    
  6400.         <div>shadow</div>,
    
  6401.       ]);
    
  6402.     });
    
  6403.     // @gate enableFloat
    
  6404.     it('can support styles inside portals to an element in shadowRoots', async () => {
    
  6405.       const template = document.createElement('template');
    
  6406.       template.innerHTML =
    
  6407.         "<div><div id='shadowcontainer1'></div><div id='shadowcontainer2'></div></div>";
    
  6408.       const shadow = document.body.attachShadow({mode: 'open'});
    
  6409.       shadow.appendChild(template.content);
    
  6410. 
    
  6411.       const shadowContainer1 = shadow.getElementById('shadowcontainer1');
    
  6412.       const shadowContainer2 = shadow.getElementById('shadowcontainer2');
    
  6413.       const root = ReactDOMClient.createRoot(container);
    
  6414.       root.render(
    
  6415.         <>
    
  6416.           <link rel="stylesheet" href="foo" precedence="default" />
    
  6417.           {ReactDOM.createPortal(
    
  6418.             <div>
    
  6419.               <link rel="stylesheet" href="foo" precedence="one" />
    
  6420.               <link rel="stylesheet" href="bar" precedence="two" />1
    
  6421.             </div>,
    
  6422.             shadow,
    
  6423.           )}
    
  6424.           {ReactDOM.createPortal(
    
  6425.             <div>
    
  6426.               <link rel="stylesheet" href="foo" precedence="one" />
    
  6427.               <link rel="stylesheet" href="baz" precedence="one" />2
    
  6428.             </div>,
    
  6429.             shadowContainer1,
    
  6430.           )}
    
  6431.           {ReactDOM.createPortal(
    
  6432.             <div>
    
  6433.               <link rel="stylesheet" href="bar" precedence="two" />
    
  6434.               <link rel="stylesheet" href="qux" precedence="three" />3
    
  6435.             </div>,
    
  6436.             shadowContainer2,
    
  6437.           )}
    
  6438.           container
    
  6439.         </>,
    
  6440.       );
    
  6441.       await waitForAll([]);
    
  6442.       expect(getMeaningfulChildren(document)).toEqual(
    
  6443.         <html>
    
  6444.           <head>
    
  6445.             <link rel="stylesheet" href="foo" data-precedence="default" />
    
  6446.             <link rel="preload" href="foo" as="style" />
    
  6447.             <link rel="preload" href="bar" as="style" />
    
  6448.             <link rel="preload" href="baz" as="style" />
    
  6449.             <link rel="preload" href="qux" as="style" />
    
  6450.           </head>
    
  6451.           <body>
    
  6452.             <div id="container">container</div>
    
  6453.           </body>
    
  6454.         </html>,
    
  6455.       );
    
  6456.       expect(getMeaningfulChildren(shadow)).toEqual([
    
  6457.         <link rel="stylesheet" href="foo" data-precedence="one" />,
    
  6458.         <link rel="stylesheet" href="baz" data-precedence="one" />,
    
  6459.         <link rel="stylesheet" href="bar" data-precedence="two" />,
    
  6460.         <link rel="stylesheet" href="qux" data-precedence="three" />,
    
  6461.         <div>
    
  6462.           <div id="shadowcontainer1">
    
  6463.             <div>2</div>
    
  6464.           </div>
    
  6465.           <div id="shadowcontainer2">
    
  6466.             <div>3</div>
    
  6467.           </div>
    
  6468.         </div>,
    
  6469.         <div>1</div>,
    
  6470.       ]);
    
  6471.     });
    
  6472. 
    
  6473.     // @gate enableFloat
    
  6474.     it('escapes hrefs when selecting matching elements in the document when rendering Resources', async () => {
    
  6475.       function App() {
    
  6476.         ReactDOM.preload('preload', {as: 'style'});
    
  6477.         ReactDOM.preload('with\nnewline', {as: 'style'});
    
  6478.         return (
    
  6479.           <html>
    
  6480.             <head />
    
  6481.             <body>
    
  6482.               <link rel="stylesheet" href="style" precedence="style" />
    
  6483.               <link rel="stylesheet" href="with\slashes" precedence="style" />
    
  6484.               <div id="container" />
    
  6485.             </body>
    
  6486.           </html>
    
  6487.         );
    
  6488.       }
    
  6489.       await act(() => {
    
  6490.         const {pipe} = renderToPipeableStream(<App />);
    
  6491.         pipe(writable);
    
  6492.       });
    
  6493. 
    
  6494.       container = document.getElementById('container');
    
  6495.       const root = ReactDOMClient.createRoot(container);
    
  6496. 
    
  6497.       function ClientApp() {
    
  6498.         ReactDOM.preload('preload', {as: 'style'});
    
  6499.         ReactDOM.preload('with\nnewline', {as: 'style'});
    
  6500.         return (
    
  6501.           <div>
    
  6502.             <link
    
  6503.               rel="stylesheet"
    
  6504.               href={'style"][rel="stylesheet'}
    
  6505.               precedence="style"
    
  6506.             />
    
  6507.             <link rel="stylesheet" href="with\slashes" precedence="style" />
    
  6508.             foo
    
  6509.           </div>
    
  6510.         );
    
  6511.       }
    
  6512.       root.render(<ClientApp />);
    
  6513.       await waitForAll([]);
    
  6514.       expect(getMeaningfulChildren(document)).toEqual(
    
  6515.         <html>
    
  6516.           <head>
    
  6517.             <link rel="stylesheet" href="style" data-precedence="style" />
    
  6518.             <link
    
  6519.               rel="stylesheet"
    
  6520.               href="with\slashes"
    
  6521.               data-precedence="style"
    
  6522.             />
    
  6523.             <link
    
  6524.               rel="stylesheet"
    
  6525.               href={'style"][rel="stylesheet'}
    
  6526.               data-precedence="style"
    
  6527.             />
    
  6528.             <link rel="preload" as="style" href="preload" />
    
  6529.             <link rel="preload" href={'with\nnewline'} as="style" />
    
  6530.             <link rel="preload" href={'style"][rel="stylesheet'} as="style" />
    
  6531.           </head>
    
  6532.           <body>
    
  6533.             <div id="container">
    
  6534.               <div>foo</div>
    
  6535.             </div>
    
  6536.           </body>
    
  6537.         </html>,
    
  6538.       );
    
  6539.     });
    
  6540. 
    
  6541.     // @gate enableFloat
    
  6542.     it('escapes hrefs when selecting matching elements in the document when using preload and preinit', async () => {
    
  6543.       await act(() => {
    
  6544.         const {pipe} = renderToPipeableStream(
    
  6545.           <html>
    
  6546.             <head />
    
  6547.             <body>
    
  6548.               <link rel="preload" href="preload" as="style" />
    
  6549.               <link rel="stylesheet" href="style" precedence="style" />
    
  6550.               <link rel="stylesheet" href="with\slashes" precedence="style" />
    
  6551.               <link rel="preload" href={'with\nnewline'} as="style" />
    
  6552.               <div id="container" />
    
  6553.             </body>
    
  6554.           </html>,
    
  6555.         );
    
  6556.         pipe(writable);
    
  6557.       });
    
  6558. 
    
  6559.       function App() {
    
  6560.         ReactDOM.preload('preload"][rel="preload', {as: 'style'});
    
  6561.         ReactDOM.preinit('style"][rel="stylesheet', {
    
  6562.           as: 'style',
    
  6563.           precedence: 'style',
    
  6564.         });
    
  6565.         ReactDOM.preinit('with\\slashes', {
    
  6566.           as: 'style',
    
  6567.           precedence: 'style',
    
  6568.         });
    
  6569.         ReactDOM.preload('with\nnewline', {as: 'style'});
    
  6570.         return <div>foo</div>;
    
  6571.       }
    
  6572. 
    
  6573.       container = document.getElementById('container');
    
  6574.       const root = ReactDOMClient.createRoot(container);
    
  6575.       root.render(<App />);
    
  6576.       await waitForAll([]);
    
  6577.       expect(getMeaningfulChildren(document)).toEqual(
    
  6578.         <html>
    
  6579.           <head>
    
  6580.             <link rel="stylesheet" href="style" data-precedence="style" />
    
  6581.             <link
    
  6582.               rel="stylesheet"
    
  6583.               href="with\slashes"
    
  6584.               data-precedence="style"
    
  6585.             />
    
  6586.             <link
    
  6587.               rel="stylesheet"
    
  6588.               href={'style"][rel="stylesheet'}
    
  6589.               data-precedence="style"
    
  6590.             />
    
  6591.             <link rel="preload" as="style" href="preload" />
    
  6592.             <link rel="preload" href={'with\nnewline'} as="style" />
    
  6593.             <link rel="preload" href={'preload"][rel="preload'} as="style" />
    
  6594.           </head>
    
  6595.           <body>
    
  6596.             <div id="container">
    
  6597.               <div>foo</div>
    
  6598.             </div>
    
  6599.           </body>
    
  6600.         </html>,
    
  6601.       );
    
  6602.     });
    
  6603. 
    
  6604.     // @gate enableFloat
    
  6605.     it('does not create stylesheet resources when inside an <svg> context', async () => {
    
  6606.       await act(() => {
    
  6607.         const {pipe} = renderToPipeableStream(
    
  6608.           <html>
    
  6609.             <body>
    
  6610.               <svg>
    
  6611.                 <path>
    
  6612.                   <link rel="stylesheet" href="foo" precedence="default" />
    
  6613.                 </path>
    
  6614.                 <foreignObject>
    
  6615.                   <link rel="stylesheet" href="bar" precedence="default" />
    
  6616.                 </foreignObject>
    
  6617.               </svg>
    
  6618.             </body>
    
  6619.           </html>,
    
  6620.         );
    
  6621.         pipe(writable);
    
  6622.       });
    
  6623.       expect(getMeaningfulChildren(document)).toEqual(
    
  6624.         <html>
    
  6625.           <head>
    
  6626.             <link rel="stylesheet" href="bar" data-precedence="default" />
    
  6627.           </head>
    
  6628.           <body>
    
  6629.             <svg>
    
  6630.               <path>
    
  6631.                 <link rel="stylesheet" href="foo" precedence="default" />
    
  6632.               </path>
    
  6633.               <foreignobject />
    
  6634.             </svg>
    
  6635.           </body>
    
  6636.         </html>,
    
  6637.       );
    
  6638. 
    
  6639.       const root = ReactDOMClient.createRoot(document.body);
    
  6640.       root.render(
    
  6641.         <div>
    
  6642.           <svg>
    
  6643.             <path>
    
  6644.               <link rel="stylesheet" href="foo" precedence="default" />
    
  6645.             </path>
    
  6646.             <foreignObject>
    
  6647.               <link rel="stylesheet" href="bar" precedence="default" />
    
  6648.             </foreignObject>
    
  6649.           </svg>
    
  6650.         </div>,
    
  6651.       );
    
  6652.       await waitForAll([]);
    
  6653.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  6654.         <div>
    
  6655.           <svg>
    
  6656.             <path>
    
  6657.               <link rel="stylesheet" href="foo" precedence="default" />
    
  6658.             </path>
    
  6659.             <foreignobject />
    
  6660.           </svg>
    
  6661.         </div>,
    
  6662.       );
    
  6663.     });
    
  6664. 
    
  6665.     // @gate enableFloat
    
  6666.     it('does not create stylesheet resources when inside a <noscript> context', async () => {
    
  6667.       await act(() => {
    
  6668.         const {pipe} = renderToPipeableStream(
    
  6669.           <html>
    
  6670.             <body>
    
  6671.               <noscript>
    
  6672.                 <link rel="stylesheet" href="foo" precedence="default" />
    
  6673.               </noscript>
    
  6674.             </body>
    
  6675.           </html>,
    
  6676.         );
    
  6677.         pipe(writable);
    
  6678.       });
    
  6679.       expect(getMeaningfulChildren(document)).toEqual(
    
  6680.         <html>
    
  6681.           <head />
    
  6682.           <body>
    
  6683.             <noscript>
    
  6684.               &lt;link rel="stylesheet" href="foo" precedence="default"&gt;
    
  6685.             </noscript>
    
  6686.           </body>
    
  6687.         </html>,
    
  6688.       );
    
  6689. 
    
  6690.       const root = ReactDOMClient.createRoot(document.body);
    
  6691.       root.render(
    
  6692.         <div>
    
  6693.           <noscript>
    
  6694.             <link rel="stylesheet" href="foo" precedence="default" />
    
  6695.           </noscript>
    
  6696.         </div>,
    
  6697.       );
    
  6698.       await waitForAll([]);
    
  6699.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  6700.         <div>
    
  6701.           {/* On the client, <noscript> never renders children */}
    
  6702.           <noscript />
    
  6703.         </div>,
    
  6704.       );
    
  6705.     });
    
  6706. 
    
  6707.     // @gate enableFloat
    
  6708.     it('warns if you provide a `precedence` prop with other props that invalidate the creation of a stylesheet resource', async () => {
    
  6709.       await expect(async () => {
    
  6710.         await act(() => {
    
  6711.           renderToPipeableStream(
    
  6712.             <html>
    
  6713.               <body>
    
  6714.                 <link rel="stylesheet" precedence="default" />
    
  6715.                 <link rel="stylesheet" href="" precedence="default" />
    
  6716.                 <link
    
  6717.                   rel="stylesheet"
    
  6718.                   href="foo"
    
  6719.                   precedence="default"
    
  6720.                   onLoad={() => {}}
    
  6721.                   onError={() => {}}
    
  6722.                 />
    
  6723.                 <link
    
  6724.                   rel="stylesheet"
    
  6725.                   href="foo"
    
  6726.                   precedence="default"
    
  6727.                   onLoad={() => {}}
    
  6728.                 />
    
  6729.                 <link
    
  6730.                   rel="stylesheet"
    
  6731.                   href="foo"
    
  6732.                   precedence="default"
    
  6733.                   onError={() => {}}
    
  6734.                 />
    
  6735.                 <link
    
  6736.                   rel="stylesheet"
    
  6737.                   href="foo"
    
  6738.                   precedence="default"
    
  6739.                   disabled={false}
    
  6740.                 />
    
  6741.               </body>
    
  6742.             </html>,
    
  6743.           ).pipe(writable);
    
  6744.         });
    
  6745.       }).toErrorDev(
    
  6746.         [
    
  6747.           gate(flags => flags.enableFilterEmptyStringAttributesDOM)
    
  6748.             ? 'An empty string ("") was passed to the href attribute. To fix this, either do not render the element at all or pass null to href instead of an empty string.'
    
  6749.             : undefined,
    
  6750.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and expected the `href` prop to be a non-empty string but ecountered `undefined` instead. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop ensure there is a non-empty string `href` prop as well, otherwise remove the `precedence` prop.',
    
  6751.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and expected the `href` prop to be a non-empty string but ecountered an empty string instead. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop ensure there is a non-empty string `href` prop as well, otherwise remove the `precedence` prop.',
    
  6752.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and `onLoad` and `onError` props. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.',
    
  6753.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and `onLoad` prop. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onLoad` prop, otherwise remove the `precedence` prop.',
    
  6754.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and `onError` prop. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onError` prop, otherwise remove the `precedence` prop.',
    
  6755.           'React encountered a `<link rel="stylesheet" .../>` with a `precedence` prop and a `disabled` prop. The presence of the `disabled` prop indicates an intent to manage the stylesheet active state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `disabled` prop, otherwise remove the `precedence` prop.',
    
  6756.         ].filter(Boolean),
    
  6757.       );
    
  6758. 
    
  6759.       ReactDOMClient.hydrateRoot(
    
  6760.         document,
    
  6761.         <html>
    
  6762.           <body>
    
  6763.             <link
    
  6764.               rel="stylesheet"
    
  6765.               href="foo"
    
  6766.               precedence="default"
    
  6767.               onLoad={() => {}}
    
  6768.               onError={() => {}}
    
  6769.             />
    
  6770.           </body>
    
  6771.         </html>,
    
  6772.       );
    
  6773.       await expect(async () => {
    
  6774.         await waitForAll([]);
    
  6775.       }).toErrorDev([
    
  6776.         'React encountered a <link rel="stylesheet" href="foo" ... /> with a `precedence` prop that also included the `onLoad` and `onError` props. The presence of loading and error handlers indicates an intent to manage the stylesheet loading state from your from your Component code and React will not hoist or deduplicate this stylesheet. If your intent was to have React hoist and deduplciate this stylesheet using the `precedence` prop remove the `onLoad` and `onError` props, otherwise remove the `precedence` prop.',
    
  6777.       ]);
    
  6778.     });
    
  6779. 
    
  6780.     // @gate enableFloat
    
  6781.     it('will not block displaying a Suspense boundary on a stylesheet with media that does not match', async () => {
    
  6782.       await act(() => {
    
  6783.         renderToPipeableStream(
    
  6784.           <html>
    
  6785.             <body>
    
  6786.               <Suspense fallback="loading...">
    
  6787.                 <BlockedOn value="block">
    
  6788.                   foo
    
  6789.                   <link
    
  6790.                     rel="stylesheet"
    
  6791.                     href="print"
    
  6792.                     media="print"
    
  6793.                     precedence="print"
    
  6794.                   />
    
  6795.                   <link
    
  6796.                     rel="stylesheet"
    
  6797.                     href="all"
    
  6798.                     media="all"
    
  6799.                     precedence="all"
    
  6800.                   />
    
  6801.                 </BlockedOn>
    
  6802.               </Suspense>
    
  6803.               <Suspense fallback="loading...">
    
  6804.                 <BlockedOn value="block">
    
  6805.                   bar
    
  6806.                   <link
    
  6807.                     rel="stylesheet"
    
  6808.                     href="print"
    
  6809.                     media="print"
    
  6810.                     precedence="print"
    
  6811.                   />
    
  6812.                   <link
    
  6813.                     rel="stylesheet"
    
  6814.                     href="all"
    
  6815.                     media="all"
    
  6816.                     precedence="all"
    
  6817.                   />
    
  6818.                 </BlockedOn>
    
  6819.               </Suspense>
    
  6820.             </body>
    
  6821.           </html>,
    
  6822.         ).pipe(writable);
    
  6823.       });
    
  6824.       expect(getMeaningfulChildren(document)).toEqual(
    
  6825.         <html>
    
  6826.           <head />
    
  6827.           <body>
    
  6828.             {'loading...'}
    
  6829.             {'loading...'}
    
  6830.           </body>
    
  6831.         </html>,
    
  6832.       );
    
  6833. 
    
  6834.       await act(() => {
    
  6835.         resolveText('block');
    
  6836.       });
    
  6837.       expect(getMeaningfulChildren(document)).toEqual(
    
  6838.         <html>
    
  6839.           <head>
    
  6840.             <link
    
  6841.               rel="stylesheet"
    
  6842.               href="print"
    
  6843.               media="print"
    
  6844.               data-precedence="print"
    
  6845.             />
    
  6846.             <link
    
  6847.               rel="stylesheet"
    
  6848.               href="all"
    
  6849.               media="all"
    
  6850.               data-precedence="all"
    
  6851.             />
    
  6852.           </head>
    
  6853.           <body>
    
  6854.             {'loading...'}
    
  6855.             {'loading...'}
    
  6856.             <link rel="preload" href="print" media="print" as="style" />
    
  6857.             <link rel="preload" href="all" media="all" as="style" />
    
  6858.           </body>
    
  6859.         </html>,
    
  6860.       );
    
  6861. 
    
  6862.       await act(() => {
    
  6863.         const allStyle = document.querySelector('link[href="all"]');
    
  6864.         const event = document.createEvent('Events');
    
  6865.         event.initEvent('load', true, true);
    
  6866.         allStyle.dispatchEvent(event);
    
  6867.       });
    
  6868. 
    
  6869.       expect(getMeaningfulChildren(document)).toEqual(
    
  6870.         <html>
    
  6871.           <head>
    
  6872.             <link
    
  6873.               rel="stylesheet"
    
  6874.               href="print"
    
  6875.               media="print"
    
  6876.               data-precedence="print"
    
  6877.             />
    
  6878.             <link
    
  6879.               rel="stylesheet"
    
  6880.               href="all"
    
  6881.               media="all"
    
  6882.               data-precedence="all"
    
  6883.             />
    
  6884.           </head>
    
  6885.           <body>
    
  6886.             {'foo'}
    
  6887.             {'bar'}
    
  6888.             <link rel="preload" href="print" media="print" as="style" />
    
  6889.             <link rel="preload" href="all" media="all" as="style" />
    
  6890.           </body>
    
  6891.         </html>,
    
  6892.       );
    
  6893.     });
    
  6894.   });
    
  6895. 
    
  6896.   describe('Style Resource', () => {
    
  6897.     // @gate enableFloat
    
  6898.     it('treats <style href="..." precedence="..."> elements as a style resource when server rendering', async () => {
    
  6899.       const css = `
    
  6900. body {
    
  6901.   background-color: red;
    
  6902. }`;
    
  6903.       await act(() => {
    
  6904.         renderToPipeableStream(
    
  6905.           <html>
    
  6906.             <body>
    
  6907.               <style href="foo" precedence="foo">
    
  6908.                 {css}
    
  6909.               </style>
    
  6910.             </body>
    
  6911.           </html>,
    
  6912.         ).pipe(writable);
    
  6913.       });
    
  6914. 
    
  6915.       expect(getMeaningfulChildren(document)).toEqual(
    
  6916.         <html>
    
  6917.           <head>
    
  6918.             <style data-href="foo" data-precedence="foo">
    
  6919.               {css}
    
  6920.             </style>
    
  6921.           </head>
    
  6922.           <body />
    
  6923.         </html>,
    
  6924.       );
    
  6925.     });
    
  6926. 
    
  6927.     // @gate enableFloat
    
  6928.     it('can insert style resources as part of a boundary reveal', async () => {
    
  6929.       const cssRed = `
    
  6930. body {
    
  6931.   background-color: red;
    
  6932. }`;
    
  6933.       const cssBlue = `
    
  6934. body {
    
  6935. background-color: blue;
    
  6936. }`;
    
  6937.       const cssGreen = `
    
  6938. body {
    
  6939. background-color: green;
    
  6940. }`;
    
  6941.       await act(() => {
    
  6942.         renderToPipeableStream(
    
  6943.           <html>
    
  6944.             <body>
    
  6945.               <Suspense fallback="loading...">
    
  6946.                 <BlockedOn value="blocked">
    
  6947.                   <style href="foo" precedence="foo">
    
  6948.                     {cssRed}
    
  6949.                   </style>
    
  6950.                   loaded
    
  6951.                 </BlockedOn>
    
  6952.               </Suspense>
    
  6953.             </body>
    
  6954.           </html>,
    
  6955.         ).pipe(writable);
    
  6956.       });
    
  6957. 
    
  6958.       expect(getMeaningfulChildren(document)).toEqual(
    
  6959.         <html>
    
  6960.           <head />
    
  6961.           <body>loading...</body>
    
  6962.         </html>,
    
  6963.       );
    
  6964. 
    
  6965.       await act(() => {
    
  6966.         resolveText('blocked');
    
  6967.       });
    
  6968. 
    
  6969.       expect(getMeaningfulChildren(document)).toEqual(
    
  6970.         <html>
    
  6971.           <head>
    
  6972.             <style data-href="foo" data-precedence="foo">
    
  6973.               {cssRed}
    
  6974.             </style>
    
  6975.           </head>
    
  6976.           <body>loaded</body>
    
  6977.         </html>,
    
  6978.       );
    
  6979. 
    
  6980.       const root = ReactDOMClient.hydrateRoot(
    
  6981.         document,
    
  6982.         <html>
    
  6983.           <body>
    
  6984.             <Suspense fallback="loading...">
    
  6985.               <style href="foo" precedence="foo">
    
  6986.                 {cssRed}
    
  6987.               </style>
    
  6988.               loaded
    
  6989.             </Suspense>
    
  6990.           </body>
    
  6991.         </html>,
    
  6992.       );
    
  6993.       await waitForAll([]);
    
  6994. 
    
  6995.       expect(getMeaningfulChildren(document)).toEqual(
    
  6996.         <html>
    
  6997.           <head>
    
  6998.             <style data-href="foo" data-precedence="foo">
    
  6999.               {cssRed}
    
  7000.             </style>
    
  7001.           </head>
    
  7002.           <body>loaded</body>
    
  7003.         </html>,
    
  7004.       );
    
  7005. 
    
  7006.       root.render(
    
  7007.         <html>
    
  7008.           <body>
    
  7009.             <Suspense fallback="loading...">
    
  7010.               <style href="foo" precedence="foo">
    
  7011.                 {cssRed}
    
  7012.               </style>
    
  7013.               loaded
    
  7014.             </Suspense>
    
  7015.             <style href="bar" precedence="bar">
    
  7016.               {cssBlue}
    
  7017.             </style>
    
  7018.             <style href="baz" precedence="foo">
    
  7019.               {cssGreen}
    
  7020.             </style>
    
  7021.           </body>
    
  7022.         </html>,
    
  7023.       );
    
  7024.       await waitForAll([]);
    
  7025.       expect(getMeaningfulChildren(document)).toEqual(
    
  7026.         <html>
    
  7027.           <head>
    
  7028.             <style data-href="foo" data-precedence="foo">
    
  7029.               {cssRed}
    
  7030.             </style>
    
  7031.             <style data-href="baz" data-precedence="foo">
    
  7032.               {cssGreen}
    
  7033.             </style>
    
  7034.             <style data-href="bar" data-precedence="bar">
    
  7035.               {cssBlue}
    
  7036.             </style>
    
  7037.           </head>
    
  7038.           <body>loaded</body>
    
  7039.         </html>,
    
  7040.       );
    
  7041.     });
    
  7042. 
    
  7043.     // @gate enableFloat
    
  7044.     it('can emit styles early when a partial boundary flushes', async () => {
    
  7045.       const css = 'body { background-color: red; }';
    
  7046.       await act(() => {
    
  7047.         renderToPipeableStream(
    
  7048.           <html>
    
  7049.             <body>
    
  7050.               <Suspense>
    
  7051.                 <BlockedOn value="first">
    
  7052.                   <div>first</div>
    
  7053.                   <style href="foo" precedence="default">
    
  7054.                     {css}
    
  7055.                   </style>
    
  7056.                   <BlockedOn value="second">
    
  7057.                     <div>second</div>
    
  7058.                     <style href="bar" precedence="default">
    
  7059.                       {css}
    
  7060.                     </style>
    
  7061.                   </BlockedOn>
    
  7062.                 </BlockedOn>
    
  7063.               </Suspense>
    
  7064.             </body>
    
  7065.           </html>,
    
  7066.         ).pipe(writable);
    
  7067.       });
    
  7068. 
    
  7069.       expect(getMeaningfulChildren(document)).toEqual(
    
  7070.         <html>
    
  7071.           <head />
    
  7072.           <body />
    
  7073.         </html>,
    
  7074.       );
    
  7075. 
    
  7076.       await act(() => {
    
  7077.         resolveText('first');
    
  7078.       });
    
  7079. 
    
  7080.       expect(getMeaningfulChildren(document)).toEqual(
    
  7081.         <html>
    
  7082.           <head />
    
  7083.           <body>
    
  7084.             <style data-href="foo" data-precedence="default" media="not all">
    
  7085.               {css}
    
  7086.             </style>
    
  7087.           </body>
    
  7088.         </html>,
    
  7089.       );
    
  7090. 
    
  7091.       await act(() => {
    
  7092.         resolveText('second');
    
  7093.       });
    
  7094. 
    
  7095.       expect(getMeaningfulChildren(document)).toEqual(
    
  7096.         <html>
    
  7097.           <head>
    
  7098.             <style data-href="foo" data-precedence="default">
    
  7099.               {css}
    
  7100.             </style>
    
  7101.             <style data-href="bar" data-precedence="default">
    
  7102.               {css}
    
  7103.             </style>
    
  7104.           </head>
    
  7105.           <body>
    
  7106.             <div>first</div>
    
  7107.             <div>second</div>
    
  7108.           </body>
    
  7109.         </html>,
    
  7110.       );
    
  7111.     });
    
  7112. 
    
  7113.     it('can hoist styles flushed early even when no other style dependencies are flushed on completion', async () => {
    
  7114.       await act(() => {
    
  7115.         renderToPipeableStream(
    
  7116.           <html>
    
  7117.             <body>
    
  7118.               <Suspense fallback="loading...">
    
  7119.                 <BlockedOn value="first">
    
  7120.                   <style href="foo" precedence="default">
    
  7121.                     some css
    
  7122.                   </style>
    
  7123.                   <div>first</div>
    
  7124.                   <BlockedOn value="second">
    
  7125.                     <div>second</div>
    
  7126.                   </BlockedOn>
    
  7127.                 </BlockedOn>
    
  7128.               </Suspense>
    
  7129.             </body>
    
  7130.           </html>,
    
  7131.         ).pipe(writable);
    
  7132.       });
    
  7133.       expect(getMeaningfulChildren(document)).toEqual(
    
  7134.         <html>
    
  7135.           <head />
    
  7136.           <body>loading...</body>
    
  7137.         </html>,
    
  7138.       );
    
  7139. 
    
  7140.       // When we resolve first we flush the style tag because it is ready but we aren't yet ready to
    
  7141.       // flush the entire boundary and reveal it.
    
  7142.       await act(() => {
    
  7143.         resolveText('first');
    
  7144.       });
    
  7145.       expect(getMeaningfulChildren(document)).toEqual(
    
  7146.         <html>
    
  7147.           <head />
    
  7148.           <body>
    
  7149.             loading...
    
  7150.             <style data-href="foo" data-precedence="default" media="not all">
    
  7151.               some css
    
  7152.             </style>
    
  7153.           </body>
    
  7154.         </html>,
    
  7155.       );
    
  7156. 
    
  7157.       // When we resolve second we flush the rest of the boundary segments and reveal the boundary. The style tag
    
  7158.       // is hoisted during this reveal process even though no other styles flushed during this tick
    
  7159.       await act(() => {
    
  7160.         resolveText('second');
    
  7161.       });
    
  7162.       expect(getMeaningfulChildren(document)).toEqual(
    
  7163.         <html>
    
  7164.           <head>
    
  7165.             <style data-href="foo" data-precedence="default">
    
  7166.               some css
    
  7167.             </style>
    
  7168.           </head>
    
  7169.           <body>
    
  7170.             <div>first</div>
    
  7171.             <div>second</div>
    
  7172.           </body>
    
  7173.         </html>,
    
  7174.       );
    
  7175.     });
    
  7176. 
    
  7177.     it('can emit multiple style rules into a single style tag for a given precedence', async () => {
    
  7178.       await act(() => {
    
  7179.         renderToPipeableStream(
    
  7180.           <html>
    
  7181.             <body>
    
  7182.               <style href="1" precedence="default">
    
  7183.                 1
    
  7184.               </style>
    
  7185.               <style href="2" precedence="foo">
    
  7186.                 foo2
    
  7187.               </style>
    
  7188.               <style href="3" precedence="default">
    
  7189.                 3
    
  7190.               </style>
    
  7191.               <style href="4" precedence="default">
    
  7192.                 4
    
  7193.               </style>
    
  7194.               <style href="5" precedence="foo">
    
  7195.                 foo5
    
  7196.               </style>
    
  7197.               <div>initial</div>
    
  7198.               <Suspense fallback="loading...">
    
  7199.                 <BlockedOn value="first">
    
  7200.                   <style href="6" precedence="default">
    
  7201.                     6
    
  7202.                   </style>
    
  7203.                   <style href="7" precedence="foo">
    
  7204.                     foo7
    
  7205.                   </style>
    
  7206.                   <style href="8" precedence="default">
    
  7207.                     8
    
  7208.                   </style>
    
  7209.                   <style href="9" precedence="default">
    
  7210.                     9
    
  7211.                   </style>
    
  7212.                   <style href="10" precedence="foo">
    
  7213.                     foo10
    
  7214.                   </style>
    
  7215.                   <div>first</div>
    
  7216.                   <BlockedOn value="second">
    
  7217.                     <style href="11" precedence="default">
    
  7218.                       11
    
  7219.                     </style>
    
  7220.                     <style href="12" precedence="foo">
    
  7221.                       foo12
    
  7222.                     </style>
    
  7223.                     <style href="13" precedence="default">
    
  7224.                       13
    
  7225.                     </style>
    
  7226.                     <style href="14" precedence="default">
    
  7227.                       14
    
  7228.                     </style>
    
  7229.                     <style href="15" precedence="foo">
    
  7230.                       foo15
    
  7231.                     </style>
    
  7232.                     <div>second</div>
    
  7233.                   </BlockedOn>
    
  7234.                 </BlockedOn>
    
  7235.               </Suspense>
    
  7236.             </body>
    
  7237.           </html>,
    
  7238.         ).pipe(writable);
    
  7239.       });
    
  7240.       expect(getMeaningfulChildren(document)).toEqual(
    
  7241.         <html>
    
  7242.           <head>
    
  7243.             <style data-href="1 3 4" data-precedence="default">
    
  7244.               134
    
  7245.             </style>
    
  7246.             <style data-href="2 5" data-precedence="foo">
    
  7247.               foo2foo5
    
  7248.             </style>
    
  7249.           </head>
    
  7250.           <body>
    
  7251.             <div>initial</div>loading...
    
  7252.           </body>
    
  7253.         </html>,
    
  7254.       );
    
  7255. 
    
  7256.       // When we resolve first we flush the style tag because it is ready but we aren't yet ready to
    
  7257.       // flush the entire boundary and reveal it.
    
  7258.       await act(() => {
    
  7259.         resolveText('first');
    
  7260.       });
    
  7261.       await act(() => {
    
  7262.         resolveText('second');
    
  7263.       });
    
  7264. 
    
  7265.       // Some sets of styles were ready before the entire boundary and they got emitted as early as they were
    
  7266.       // ready. The remaining styles were ready when the boundary finished and they got grouped as well
    
  7267.       expect(getMeaningfulChildren(document)).toEqual(
    
  7268.         <html>
    
  7269.           <head>
    
  7270.             <style data-href="1 3 4" data-precedence="default">
    
  7271.               134
    
  7272.             </style>
    
  7273.             <style data-href="6 8 9" data-precedence="default">
    
  7274.               689
    
  7275.             </style>
    
  7276.             <style data-href="11 13 14" data-precedence="default">
    
  7277.               111314
    
  7278.             </style>
    
  7279.             <style data-href="2 5" data-precedence="foo">
    
  7280.               foo2foo5
    
  7281.             </style>
    
  7282.             <style data-href="7 10" data-precedence="foo">
    
  7283.               foo7foo10
    
  7284.             </style>
    
  7285.             <style data-href="12 15" data-precedence="foo">
    
  7286.               foo12foo15
    
  7287.             </style>
    
  7288.           </head>
    
  7289.           <body>
    
  7290.             <div>initial</div>
    
  7291.             <div>first</div>
    
  7292.             <div>second</div>
    
  7293.           </body>
    
  7294.         </html>,
    
  7295.       );
    
  7296. 
    
  7297.       // Client inserted style tags are not grouped together but can hydrate against a grouped set
    
  7298.       ReactDOMClient.hydrateRoot(
    
  7299.         document,
    
  7300.         <html>
    
  7301.           <body>
    
  7302.             <style href="1" precedence="default">
    
  7303.               1
    
  7304.             </style>
    
  7305.             <style href="2" precedence="foo">
    
  7306.               foo2
    
  7307.             </style>
    
  7308.             <style href="16" precedence="default">
    
  7309.               16
    
  7310.             </style>
    
  7311.             <style href="17" precedence="default">
    
  7312.               17
    
  7313.             </style>
    
  7314.           </body>
    
  7315.         </html>,
    
  7316.       );
    
  7317.       await waitForAll([]);
    
  7318.       expect(getMeaningfulChildren(document)).toEqual(
    
  7319.         <html>
    
  7320.           <head>
    
  7321.             <style data-href="1 3 4" data-precedence="default">
    
  7322.               134
    
  7323.             </style>
    
  7324.             <style data-href="6 8 9" data-precedence="default">
    
  7325.               689
    
  7326.             </style>
    
  7327.             <style data-href="11 13 14" data-precedence="default">
    
  7328.               111314
    
  7329.             </style>
    
  7330.             <style data-href="16" data-precedence="default">
    
  7331.               16
    
  7332.             </style>
    
  7333.             <style data-href="17" data-precedence="default">
    
  7334.               17
    
  7335.             </style>
    
  7336.             <style data-href="2 5" data-precedence="foo">
    
  7337.               foo2foo5
    
  7338.             </style>
    
  7339.             <style data-href="7 10" data-precedence="foo">
    
  7340.               foo7foo10
    
  7341.             </style>
    
  7342.             <style data-href="12 15" data-precedence="foo">
    
  7343.               foo12foo15
    
  7344.             </style>
    
  7345.           </head>
    
  7346.           <body>
    
  7347.             <div>initial</div>
    
  7348.             <div>first</div>
    
  7349.             <div>second</div>
    
  7350.           </body>
    
  7351.         </html>,
    
  7352.       );
    
  7353.     });
    
  7354. 
    
  7355.     it('warns if you render a <style> with an href with a space on the server', async () => {
    
  7356.       await expect(async () => {
    
  7357.         await act(() => {
    
  7358.           renderToPipeableStream(
    
  7359.             <html>
    
  7360.               <body>
    
  7361.                 <style href="foo bar" precedence="default">
    
  7362.                   style
    
  7363.                 </style>
    
  7364.               </body>
    
  7365.             </html>,
    
  7366.           ).pipe(writable);
    
  7367.         });
    
  7368.       }).toErrorDev(
    
  7369.         'React expected the `href` prop for a <style> tag opting into hoisting semantics using the `precedence` prop to not have any spaces but ecountered spaces instead. using spaces in this prop will cause hydration of this style to fail on the client. The href for the <style> where this ocurred is "foo bar".',
    
  7370.       );
    
  7371.     });
    
  7372.   });
    
  7373. 
    
  7374.   describe('Script Resources', () => {
    
  7375.     // @gate enableFloat
    
  7376.     it('treats async scripts without onLoad or onError as Resources', async () => {
    
  7377.       await act(() => {
    
  7378.         const {pipe} = renderToPipeableStream(
    
  7379.           <html>
    
  7380.             <head />
    
  7381.             <body>
    
  7382.               <script src="foo" async={true} />
    
  7383.               <script src="bar" async={true} onLoad={() => {}} />
    
  7384.               <script src="baz" data-meaningful="" />
    
  7385.               <script src="qux" defer={true} data-meaningful="" />
    
  7386.               hello world
    
  7387.             </body>
    
  7388.           </html>,
    
  7389.         );
    
  7390.         pipe(writable);
    
  7391.       });
    
  7392.       // The plain async script is converted to a resource and emitted as part of the shell
    
  7393.       // The async script with onLoad is preloaded in the shell but is expecting to be added
    
  7394.       // during hydration. This is novel, the script is NOT a HostHoistable but it also will
    
  7395.       // never hydrate
    
  7396.       // The regular script is just a normal html that should hydrate with a HostComponent
    
  7397.       expect(getMeaningfulChildren(document)).toEqual(
    
  7398.         <html>
    
  7399.           <head>
    
  7400.             <script src="foo" async="" />
    
  7401.           </head>
    
  7402.           <body>
    
  7403.             <script src="bar" async="" />
    
  7404.             <script src="baz" data-meaningful="" />
    
  7405.             <script src="qux" defer="" data-meaningful="" />
    
  7406.             hello world
    
  7407.           </body>
    
  7408.         </html>,
    
  7409.       );
    
  7410. 
    
  7411.       const root = ReactDOMClient.hydrateRoot(
    
  7412.         document,
    
  7413.         <html>
    
  7414.           <head />
    
  7415.           <body>
    
  7416.             <script src="foo" async={true} />
    
  7417.             <script src="bar" async={true} onLoad={() => {}} />
    
  7418.             <script src="baz" data-meaningful="" />
    
  7419.             <script src="qux" defer={true} data-meaningful="" />
    
  7420.             hello world
    
  7421.           </body>
    
  7422.         </html>,
    
  7423.       );
    
  7424.       await waitForAll([]);
    
  7425.       // The async script with onLoad is inserted in the right place but does not cause the hydration
    
  7426.       // to fail.
    
  7427.       expect(getMeaningfulChildren(document)).toEqual(
    
  7428.         <html>
    
  7429.           <head>
    
  7430.             <script src="foo" async="" />
    
  7431.           </head>
    
  7432.           <body>
    
  7433.             <script src="bar" async="" />
    
  7434.             <script src="baz" data-meaningful="" />
    
  7435.             <script src="qux" defer="" data-meaningful="" />
    
  7436.             hello world
    
  7437.           </body>
    
  7438.         </html>,
    
  7439.       );
    
  7440. 
    
  7441.       root.unmount();
    
  7442.       // When we unmount we expect to retain singletons and any content that is not cleared within them.
    
  7443.       // The foo script is a resource so it sticks around. The other scripts are regular HostComponents
    
  7444.       // so they unmount and are removed from the DOM.
    
  7445.       expect(getMeaningfulChildren(document)).toEqual(
    
  7446.         <html>
    
  7447.           <head>
    
  7448.             <script src="foo" async="" />
    
  7449.           </head>
    
  7450.           <body />
    
  7451.         </html>,
    
  7452.       );
    
  7453.     });
    
  7454. 
    
  7455.     // @gate enableFloat
    
  7456.     it('does not create script resources when inside an <svg> context', async () => {
    
  7457.       await act(() => {
    
  7458.         const {pipe} = renderToPipeableStream(
    
  7459.           <html>
    
  7460.             <body>
    
  7461.               <svg>
    
  7462.                 <path>
    
  7463.                   <script async={true} src="foo" />
    
  7464.                 </path>
    
  7465.                 <foreignObject>
    
  7466.                   <script async={true} src="bar" />
    
  7467.                 </foreignObject>
    
  7468.               </svg>
    
  7469.             </body>
    
  7470.           </html>,
    
  7471.         );
    
  7472.         pipe(writable);
    
  7473.       });
    
  7474.       expect(getMeaningfulChildren(document)).toEqual(
    
  7475.         <html>
    
  7476.           <head>
    
  7477.             <script async="" src="bar" />
    
  7478.           </head>
    
  7479.           <body>
    
  7480.             <svg>
    
  7481.               <path>
    
  7482.                 <script async="" src="foo" />
    
  7483.               </path>
    
  7484.               <foreignobject />
    
  7485.             </svg>
    
  7486.           </body>
    
  7487.         </html>,
    
  7488.       );
    
  7489. 
    
  7490.       const root = ReactDOMClient.createRoot(document.body);
    
  7491.       root.render(
    
  7492.         <div>
    
  7493.           <svg>
    
  7494.             <path>
    
  7495.               <script async={true} src="foo" />
    
  7496.             </path>
    
  7497.             <foreignObject>
    
  7498.               <script async={true} src="bar" />
    
  7499.             </foreignObject>
    
  7500.           </svg>
    
  7501.         </div>,
    
  7502.       );
    
  7503.       await waitForAll([]);
    
  7504.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  7505.         <div>
    
  7506.           <svg>
    
  7507.             <path>
    
  7508.               <script async="" src="foo" />
    
  7509.             </path>
    
  7510.             <foreignobject />
    
  7511.           </svg>
    
  7512.         </div>,
    
  7513.       );
    
  7514.     });
    
  7515. 
    
  7516.     // @gate enableFloat
    
  7517.     it('does not create script resources when inside a <noscript> context', async () => {
    
  7518.       await act(() => {
    
  7519.         const {pipe} = renderToPipeableStream(
    
  7520.           <html>
    
  7521.             <body>
    
  7522.               <noscript>
    
  7523.                 <script async={true} src="foo" />
    
  7524.               </noscript>
    
  7525.             </body>
    
  7526.           </html>,
    
  7527.         );
    
  7528.         pipe(writable);
    
  7529.       });
    
  7530.       expect(getMeaningfulChildren(document)).toEqual(
    
  7531.         <html>
    
  7532.           <head />
    
  7533.           <body>
    
  7534.             <noscript>
    
  7535.               &lt;script async="" src="foo"&gt;&lt;/script&gt;
    
  7536.             </noscript>
    
  7537.           </body>
    
  7538.         </html>,
    
  7539.       );
    
  7540. 
    
  7541.       const root = ReactDOMClient.createRoot(document.body);
    
  7542.       root.render(
    
  7543.         <div>
    
  7544.           <noscript>
    
  7545.             <script async={true} src="foo" />
    
  7546.           </noscript>
    
  7547.         </div>,
    
  7548.       );
    
  7549.       await waitForAll([]);
    
  7550.       expect(getMeaningfulChildren(document.body)).toEqual(
    
  7551.         <div>
    
  7552.           {/* On the client, <noscript> never renders children */}
    
  7553.           <noscript />
    
  7554.         </div>,
    
  7555.       );
    
  7556.     });
    
  7557.   });
    
  7558. 
    
  7559.   describe('Hoistables', () => {
    
  7560.     // @gate enableFloat
    
  7561.     it('can hoist meta tags on the server and hydrate them on the client', async () => {
    
  7562.       await act(() => {
    
  7563.         const {pipe} = renderToPipeableStream(
    
  7564.           <html>
    
  7565.             <body>
    
  7566.               <meta name="foo" data-foo="data" content="bar" />
    
  7567.             </body>
    
  7568.           </html>,
    
  7569.         );
    
  7570.         pipe(writable);
    
  7571.       });
    
  7572. 
    
  7573.       expect(getMeaningfulChildren(document)).toEqual(
    
  7574.         <html>
    
  7575.           <head>
    
  7576.             <meta name="foo" data-foo="data" content="bar" />
    
  7577.           </head>
    
  7578.           <body />
    
  7579.         </html>,
    
  7580.       );
    
  7581. 
    
  7582.       const root = ReactDOMClient.hydrateRoot(
    
  7583.         document,
    
  7584.         <html>
    
  7585.           <body>
    
  7586.             <meta name="foo" data-foo="data" content="bar" />
    
  7587.           </body>
    
  7588.         </html>,
    
  7589.       );
    
  7590.       await waitForAll([]);
    
  7591.       expect(getMeaningfulChildren(document)).toEqual(
    
  7592.         <html>
    
  7593.           <head>
    
  7594.             <meta name="foo" data-foo="data" content="bar" />
    
  7595.           </head>
    
  7596.           <body />
    
  7597.         </html>,
    
  7598.       );
    
  7599. 
    
  7600.       root.render(
    
  7601.         <html>
    
  7602.           <body />
    
  7603.         </html>,
    
  7604.       );
    
  7605.       await waitForAll([]);
    
  7606.       expect(getMeaningfulChildren(document)).toEqual(
    
  7607.         <html>
    
  7608.           <head />
    
  7609.           <body />
    
  7610.         </html>,
    
  7611.       );
    
  7612.     });
    
  7613. 
    
  7614.     // @gate enableFloat
    
  7615.     it('can hoist meta tags on the client', async () => {
    
  7616.       const root = ReactDOMClient.createRoot(container);
    
  7617.       await act(() => {
    
  7618.         root.render(
    
  7619.           <div>
    
  7620.             <meta name="foo" data-foo="data" content="bar" />
    
  7621.           </div>,
    
  7622.         );
    
  7623.       });
    
  7624.       await waitForAll([]);
    
  7625. 
    
  7626.       expect(getMeaningfulChildren(document.head)).toEqual(
    
  7627.         <meta name="foo" data-foo="data" content="bar" />,
    
  7628.       );
    
  7629.       expect(getMeaningfulChildren(container)).toEqual(<div />);
    
  7630. 
    
  7631.       root.render(<div />);
    
  7632.       await waitForAll([]);
    
  7633.       expect(getMeaningfulChildren(document.head)).toEqual(undefined);
    
  7634.     });
    
  7635. 
    
  7636.     // @gate enableFloat
    
  7637.     it('can hoist link (non-stylesheet) tags on the server and hydrate them on the client', async () => {
    
  7638.       await act(() => {
    
  7639.         const {pipe} = renderToPipeableStream(
    
  7640.           <html>
    
  7641.             <body>
    
  7642.               <link rel="foo" data-foo="data" href="foo" />
    
  7643.             </body>
    
  7644.           </html>,
    
  7645.         );
    
  7646.         pipe(writable);
    
  7647.       });
    
  7648. 
    
  7649.       expect(getMeaningfulChildren(document)).toEqual(
    
  7650.         <html>
    
  7651.           <head>
    
  7652.             <link rel="foo" data-foo="data" href="foo" />
    
  7653.           </head>
    
  7654.           <body />
    
  7655.         </html>,
    
  7656.       );
    
  7657. 
    
  7658.       const root = ReactDOMClient.hydrateRoot(
    
  7659.         document,
    
  7660.         <html>
    
  7661.           <body>
    
  7662.             <link rel="foo" data-foo="data" href="foo" />
    
  7663.           </body>
    
  7664.         </html>,
    
  7665.       );
    
  7666.       await waitForAll([]);
    
  7667.       expect(getMeaningfulChildren(document)).toEqual(
    
  7668.         <html>
    
  7669.           <head>
    
  7670.             <link rel="foo" data-foo="data" href="foo" />
    
  7671.           </head>
    
  7672.           <body />
    
  7673.         </html>,
    
  7674.       );
    
  7675. 
    
  7676.       root.render(
    
  7677.         <html>
    
  7678.           <body />
    
  7679.         </html>,
    
  7680.       );
    
  7681.       await waitForAll([]);
    
  7682.       expect(getMeaningfulChildren(document)).toEqual(
    
  7683.         <html>
    
  7684.           <head />
    
  7685.           <body />
    
  7686.         </html>,
    
  7687.       );
    
  7688.     });
    
  7689. 
    
  7690.     // @gate enableFloat
    
  7691.     it('can hoist link (non-stylesheet) tags on the client', async () => {
    
  7692.       const root = ReactDOMClient.createRoot(container);
    
  7693.       await act(() => {
    
  7694.         root.render(
    
  7695.           <div>
    
  7696.             <link rel="foo" data-foo="data" href="foo" />
    
  7697.           </div>,
    
  7698.         );
    
  7699.       });
    
  7700.       await waitForAll([]);
    
  7701. 
    
  7702.       expect(getMeaningfulChildren(document.head)).toEqual(
    
  7703.         <link rel="foo" data-foo="data" href="foo" />,
    
  7704.       );
    
  7705.       expect(getMeaningfulChildren(container)).toEqual(<div />);
    
  7706. 
    
  7707.       root.render(<div />);
    
  7708.       await waitForAll([]);
    
  7709.       expect(getMeaningfulChildren(document.head)).toEqual(undefined);
    
  7710.     });
    
  7711. 
    
  7712.     // @gate enableFloat
    
  7713.     it('can hoist title tags on the server and hydrate them on the client', async () => {
    
  7714.       await act(() => {
    
  7715.         const {pipe} = renderToPipeableStream(
    
  7716.           <html>
    
  7717.             <body>
    
  7718.               <title data-foo="foo">a title</title>
    
  7719.             </body>
    
  7720.           </html>,
    
  7721.         );
    
  7722.         pipe(writable);
    
  7723.       });
    
  7724. 
    
  7725.       expect(getMeaningfulChildren(document)).toEqual(
    
  7726.         <html>
    
  7727.           <head>
    
  7728.             <title data-foo="foo">a title</title>
    
  7729.           </head>
    
  7730.           <body />
    
  7731.         </html>,
    
  7732.       );
    
  7733. 
    
  7734.       const root = ReactDOMClient.hydrateRoot(
    
  7735.         document,
    
  7736.         <html>
    
  7737.           <body>
    
  7738.             <title data-foo="foo">a title</title>
    
  7739.           </body>
    
  7740.         </html>,
    
  7741.       );
    
  7742.       await waitForAll([]);
    
  7743.       expect(getMeaningfulChildren(document)).toEqual(
    
  7744.         <html>
    
  7745.           <head>
    
  7746.             <title data-foo="foo">a title</title>
    
  7747.           </head>
    
  7748.           <body />
    
  7749.         </html>,
    
  7750.       );
    
  7751. 
    
  7752.       root.render(
    
  7753.         <html>
    
  7754.           <body />
    
  7755.         </html>,
    
  7756.       );
    
  7757.       await waitForAll([]);
    
  7758.       expect(getMeaningfulChildren(document)).toEqual(
    
  7759.         <html>
    
  7760.           <head />
    
  7761.           <body />
    
  7762.         </html>,
    
  7763.       );
    
  7764.     });
    
  7765. 
    
  7766.     // @gate enableFloat
    
  7767.     it('can hoist title tags on the client', async () => {
    
  7768.       const root = ReactDOMClient.createRoot(container);
    
  7769.       await act(() => {
    
  7770.         root.render(
    
  7771.           <div>
    
  7772.             <title data-foo="foo">a title</title>
    
  7773.           </div>,
    
  7774.         );
    
  7775.       });
    
  7776.       await waitForAll([]);
    
  7777. 
    
  7778.       expect(getMeaningfulChildren(document.head)).toEqual(
    
  7779.         <title data-foo="foo">a title</title>,
    
  7780.       );
    
  7781.       expect(getMeaningfulChildren(container)).toEqual(<div />);
    
  7782. 
    
  7783.       root.render(<div />);
    
  7784.       await waitForAll([]);
    
  7785.       expect(getMeaningfulChildren(document.head)).toEqual(undefined);
    
  7786.     });
    
  7787. 
    
  7788.     // @gate enableFloat
    
  7789.     it('prioritizes ordering for certain hoistables over others when rendering on the server', async () => {
    
  7790.       await act(() => {
    
  7791.         const {pipe} = renderToPipeableStream(
    
  7792.           <html>
    
  7793.             <body>
    
  7794.               <link rel="foo" href="foo" />
    
  7795.               <meta name="bar" />
    
  7796.               <title>a title</title>
    
  7797.               <link rel="preload" href="foo" as="style" />
    
  7798.               <link rel="preconnect" href="bar" />
    
  7799.               <link rel="dns-prefetch" href="baz" />
    
  7800.               <meta charSet="utf-8" />
    
  7801.             </body>
    
  7802.           </html>,
    
  7803.         );
    
  7804.         pipe(writable);
    
  7805.       });
    
  7806. 
    
  7807.       expect(getMeaningfulChildren(document)).toEqual(
    
  7808.         <html>
    
  7809.           <head>
    
  7810.             {/* charset first */}
    
  7811.             <meta charset="utf-8" />
    
  7812.             {/* preconnect links next */}
    
  7813.             <link rel="preconnect" href="bar" />
    
  7814.             <link rel="dns-prefetch" href="baz" />
    
  7815.             {/* preloads next */}
    
  7816.             <link rel="preload" href="foo" as="style" />
    
  7817.             {/* Everything else last */}
    
  7818.             <link rel="foo" href="foo" />
    
  7819.             <meta name="bar" />
    
  7820.             <title>a title</title>
    
  7821.           </head>
    
  7822.           <body />
    
  7823.         </html>,
    
  7824.       );
    
  7825.     });
    
  7826. 
    
  7827.     // @gate enableFloat
    
  7828.     it('emits hoistables before other content when streaming in late', async () => {
    
  7829.       let content = '';
    
  7830.       writable.on('data', chunk => (content += chunk));
    
  7831. 
    
  7832.       await act(() => {
    
  7833.         const {pipe} = renderToPipeableStream(
    
  7834.           <html>
    
  7835.             <body>
    
  7836.               <meta name="early" />
    
  7837.               <Suspense fallback={null}>
    
  7838.                 <BlockedOn value="foo">
    
  7839.                   <div>foo</div>
    
  7840.                   <meta name="late" />
    
  7841.                 </BlockedOn>
    
  7842.               </Suspense>
    
  7843.             </body>
    
  7844.           </html>,
    
  7845.         );
    
  7846.         pipe(writable);
    
  7847.       });
    
  7848. 
    
  7849.       expect(getMeaningfulChildren(document)).toEqual(
    
  7850.         <html>
    
  7851.           <head>
    
  7852.             <meta name="early" />
    
  7853.           </head>
    
  7854.           <body />
    
  7855.         </html>,
    
  7856.       );
    
  7857.       content = '';
    
  7858. 
    
  7859.       await act(() => {
    
  7860.         resolveText('foo');
    
  7861.       });
    
  7862. 
    
  7863.       expect(content.slice(0, 30)).toEqual('<meta name="late"/><div hidden');
    
  7864. 
    
  7865.       expect(getMeaningfulChildren(document)).toEqual(
    
  7866.         <html>
    
  7867.           <head>
    
  7868.             <meta name="early" />
    
  7869.           </head>
    
  7870.           <body>
    
  7871.             <div>foo</div>
    
  7872.             <meta name="late" />
    
  7873.           </body>
    
  7874.         </html>,
    
  7875.       );
    
  7876.     });
    
  7877. 
    
  7878.     // @gate enableFloat
    
  7879.     it('supports rendering hoistables outside of <html> scope', async () => {
    
  7880.       await act(() => {
    
  7881.         const {pipe} = renderToPipeableStream(
    
  7882.           <>
    
  7883.             <meta name="before" />
    
  7884.             <html>
    
  7885.               <body>foo</body>
    
  7886.             </html>
    
  7887.             <meta name="after" />
    
  7888.           </>,
    
  7889.         );
    
  7890.         pipe(writable);
    
  7891.       });
    
  7892. 
    
  7893.       expect(getMeaningfulChildren(document)).toEqual(
    
  7894.         <html>
    
  7895.           <head>
    
  7896.             <meta name="before" />
    
  7897.             <meta name="after" />
    
  7898.           </head>
    
  7899.           <body>foo</body>
    
  7900.         </html>,
    
  7901.       );
    
  7902. 
    
  7903.       const root = ReactDOMClient.hydrateRoot(
    
  7904.         document,
    
  7905.         <>
    
  7906.           <meta name="before" />
    
  7907.           <html>
    
  7908.             <body>foo</body>
    
  7909.           </html>
    
  7910.           <meta name="after" />
    
  7911.         </>,
    
  7912.       );
    
  7913.       await waitForAll([]);
    
  7914.       expect(getMeaningfulChildren(document)).toEqual(
    
  7915.         <html>
    
  7916.           <head>
    
  7917.             <meta name="before" />
    
  7918.             <meta name="after" />
    
  7919.           </head>
    
  7920.           <body>foo</body>
    
  7921.         </html>,
    
  7922.       );
    
  7923. 
    
  7924.       root.render(
    
  7925.         <>
    
  7926.           {null}
    
  7927.           <html>
    
  7928.             <body>foo</body>
    
  7929.           </html>
    
  7930.           {null}
    
  7931.         </>,
    
  7932.       );
    
  7933.       await waitForAll([]);
    
  7934.       expect(getMeaningfulChildren(document)).toEqual(
    
  7935.         <html>
    
  7936.           <head />
    
  7937.           <body>foo</body>
    
  7938.         </html>,
    
  7939.       );
    
  7940.     });
    
  7941. 
    
  7942.     it('can hydrate hoistable tags inside late suspense boundaries', async () => {
    
  7943.       function App() {
    
  7944.         return (
    
  7945.           <html>
    
  7946.             <body>
    
  7947.               <link rel="rel1" href="linkhref" />
    
  7948.               <link rel="rel2" href="linkhref" />
    
  7949.               <meta name="name1" content="metacontent" />
    
  7950.               <meta name="name2" content="metacontent" />
    
  7951.               <Suspense fallback="loading...">
    
  7952.                 <link rel="rel3" href="linkhref" />
    
  7953.                 <link rel="rel4" href="linkhref" />
    
  7954.                 <meta name="name3" content="metacontent" />
    
  7955.                 <meta name="name4" content="metacontent" />
    
  7956.                 <BlockedOn value="release">
    
  7957.                   <link rel="rel5" href="linkhref" />
    
  7958.                   <link rel="rel6" href="linkhref" />
    
  7959.                   <meta name="name5" content="metacontent" />
    
  7960.                   <meta name="name6" content="metacontent" />
    
  7961.                   <div>hello world</div>
    
  7962.                 </BlockedOn>
    
  7963.               </Suspense>
    
  7964.             </body>
    
  7965.           </html>
    
  7966.         );
    
  7967.       }
    
  7968.       await act(() => {
    
  7969.         renderToPipeableStream(<App />).pipe(writable);
    
  7970.       });
    
  7971. 
    
  7972.       expect(getMeaningfulChildren(document)).toEqual(
    
  7973.         <html>
    
  7974.           <head>
    
  7975.             <link rel="rel1" href="linkhref" />
    
  7976.             <link rel="rel2" href="linkhref" />
    
  7977.             <meta name="name1" content="metacontent" />
    
  7978.             <meta name="name2" content="metacontent" />
    
  7979.             <link rel="rel3" href="linkhref" />
    
  7980.             <link rel="rel4" href="linkhref" />
    
  7981.             <meta name="name3" content="metacontent" />
    
  7982.             <meta name="name4" content="metacontent" />
    
  7983.           </head>
    
  7984.           <body>loading...</body>
    
  7985.         </html>,
    
  7986.       );
    
  7987. 
    
  7988.       const root = ReactDOMClient.hydrateRoot(document, <App />);
    
  7989.       await waitForAll([]);
    
  7990.       expect(getMeaningfulChildren(document)).toEqual(
    
  7991.         <html>
    
  7992.           <head>
    
  7993.             <link rel="rel1" href="linkhref" />
    
  7994.             <link rel="rel2" href="linkhref" />
    
  7995.             <meta name="name1" content="metacontent" />
    
  7996.             <meta name="name2" content="metacontent" />
    
  7997.             <link rel="rel3" href="linkhref" />
    
  7998.             <link rel="rel4" href="linkhref" />
    
  7999.             <meta name="name3" content="metacontent" />
    
  8000.             <meta name="name4" content="metacontent" />
    
  8001.           </head>
    
  8002.           <body>loading...</body>
    
  8003.         </html>,
    
  8004.       );
    
  8005. 
    
  8006.       const thirdPartyLink = document.createElement('link');
    
  8007.       thirdPartyLink.setAttribute('href', 'linkhref');
    
  8008.       thirdPartyLink.setAttribute('rel', '3rdparty');
    
  8009.       document.body.prepend(thirdPartyLink);
    
  8010. 
    
  8011.       const thirdPartyMeta = document.createElement('meta');
    
  8012.       thirdPartyMeta.setAttribute('content', 'metacontent');
    
  8013.       thirdPartyMeta.setAttribute('name', '3rdparty');
    
  8014.       document.body.prepend(thirdPartyMeta);
    
  8015. 
    
  8016.       await act(() => {
    
  8017.         resolveText('release');
    
  8018.       });
    
  8019.       await waitForAll([]);
    
  8020.       expect(getMeaningfulChildren(document)).toEqual(
    
  8021.         <html>
    
  8022.           <head>
    
  8023.             <link rel="rel1" href="linkhref" />
    
  8024.             <link rel="rel2" href="linkhref" />
    
  8025.             <meta name="name1" content="metacontent" />
    
  8026.             <meta name="name2" content="metacontent" />
    
  8027.             <link rel="rel3" href="linkhref" />
    
  8028.             <link rel="rel4" href="linkhref" />
    
  8029.             <meta name="name3" content="metacontent" />
    
  8030.             <meta name="name4" content="metacontent" />
    
  8031.           </head>
    
  8032.           <body>
    
  8033.             <meta name="3rdparty" content="metacontent" />
    
  8034.             <link rel="3rdparty" href="linkhref" />
    
  8035.             <div>hello world</div>
    
  8036.             <link rel="rel5" href="linkhref" />
    
  8037.             <link rel="rel6" href="linkhref" />
    
  8038.             <meta name="name5" content="metacontent" />
    
  8039.             <meta name="name6" content="metacontent" />
    
  8040.           </body>
    
  8041.         </html>,
    
  8042.       );
    
  8043. 
    
  8044.       root.unmount();
    
  8045.       expect(getMeaningfulChildren(document)).toEqual(
    
  8046.         <html>
    
  8047.           <head />
    
  8048.           <body>
    
  8049.             <meta name="3rdparty" content="metacontent" />
    
  8050.             <link rel="3rdparty" href="linkhref" />
    
  8051.           </body>
    
  8052.         </html>,
    
  8053.       );
    
  8054.     });
    
  8055. 
    
  8056.     // @gate enableFloat
    
  8057.     it('does not hoist inside an <svg> context', async () => {
    
  8058.       await act(() => {
    
  8059.         const {pipe} = renderToPipeableStream(
    
  8060.           <html>
    
  8061.             <body>
    
  8062.               <svg>
    
  8063.                 <title>svg title</title>
    
  8064.                 <link rel="svg link" href="a" />
    
  8065.                 <meta name="svg meta" />
    
  8066.                 <path>
    
  8067.                   <title>deep svg title</title>
    
  8068.                   <meta name="deep svg meta" />
    
  8069.                   <link rel="deep svg link" href="a" />
    
  8070.                 </path>
    
  8071.                 <foreignObject>
    
  8072.                   <title>hoistable title</title>
    
  8073.                   <meta name="hoistable" />
    
  8074.                   <link rel="hoistable" href="a" />
    
  8075.                 </foreignObject>
    
  8076.               </svg>
    
  8077.             </body>
    
  8078.           </html>,
    
  8079.         );
    
  8080.         pipe(writable);
    
  8081.       });
    
  8082. 
    
  8083.       expect(getMeaningfulChildren(document.head)).toEqual([
    
  8084.         <title>hoistable title</title>,
    
  8085.         <meta name="hoistable" />,
    
  8086.         <link rel="hoistable" href="a" />,
    
  8087.       ]);
    
  8088.     });
    
  8089. 
    
  8090.     // @gate enableFloat
    
  8091.     it('does not hoist inside noscript context', async () => {
    
  8092.       await act(() => {
    
  8093.         const {pipe} = renderToPipeableStream(
    
  8094.           <html>
    
  8095.             <body>
    
  8096.               <title>title</title>
    
  8097.               <link rel="link" href="a" />
    
  8098.               <meta name="meta" />
    
  8099.               <noscript>
    
  8100.                 <title>noscript title</title>
    
  8101.                 <link rel="noscript link" href="a" />
    
  8102.                 <meta name="noscript meta" />
    
  8103.               </noscript>
    
  8104.             </body>
    
  8105.           </html>,
    
  8106.         );
    
  8107.         pipe(writable);
    
  8108.       });
    
  8109. 
    
  8110.       expect(getMeaningfulChildren(document.head)).toEqual([
    
  8111.         <title>title</title>,
    
  8112.         <link rel="link" href="a" />,
    
  8113.         <meta name="meta" />,
    
  8114.       ]);
    
  8115.     });
    
  8116. 
    
  8117.     // @gate enableFloat && enableHostSingletons && (enableClientRenderFallbackOnTextMismatch || !__DEV__)
    
  8118.     it('can render a title before a singleton even if that singleton clears its contents', async () => {
    
  8119.       await act(() => {
    
  8120.         const {pipe} = renderToPipeableStream(
    
  8121.           <>
    
  8122.             <title>foo</title>
    
  8123.             <html>
    
  8124.               <head />
    
  8125.               <body>
    
  8126.                 <div>server</div>
    
  8127.               </body>
    
  8128.             </html>
    
  8129.           </>,
    
  8130.         );
    
  8131.         pipe(writable);
    
  8132.       });
    
  8133. 
    
  8134.       const errors = [];
    
  8135.       ReactDOMClient.hydrateRoot(
    
  8136.         document,
    
  8137.         <>
    
  8138.           <title>foo</title>
    
  8139.           <html>
    
  8140.             <head />
    
  8141.             <body>
    
  8142.               <div>client</div>
    
  8143.             </body>
    
  8144.           </html>
    
  8145.         </>,
    
  8146.         {
    
  8147.           onRecoverableError(err) {
    
  8148.             errors.push(err.message);
    
  8149.           },
    
  8150.         },
    
  8151.       );
    
  8152. 
    
  8153.       await expect(async () => {
    
  8154.         await waitForAll([]);
    
  8155.       }).toErrorDev(
    
  8156.         [
    
  8157.           'Warning: Text content did not match. Server: "server" Client: "client"',
    
  8158.           'Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.',
    
  8159.         ],
    
  8160.         {withoutStack: 1},
    
  8161.       );
    
  8162.       expect(getMeaningfulChildren(document)).toEqual(
    
  8163.         <html>
    
  8164.           <head>
    
  8165.             <title>foo</title>
    
  8166.           </head>
    
  8167.           <body>
    
  8168.             <div>client</div>
    
  8169.           </body>
    
  8170.         </html>,
    
  8171.       );
    
  8172.     });
    
  8173. 
    
  8174.     // @gate enableFloat
    
  8175.     it('can update title tags', async () => {
    
  8176.       const root = ReactDOMClient.createRoot(container);
    
  8177.       await act(() => {
    
  8178.         root.render(<title data-foo="foo">a title</title>);
    
  8179.       });
    
  8180.       await waitForAll([]);
    
  8181. 
    
  8182.       expect(getMeaningfulChildren(document.head)).toEqual(
    
  8183.         <title data-foo="foo">a title</title>,
    
  8184.       );
    
  8185. 
    
  8186.       await act(() => {
    
  8187.         root.render(<title data-foo="bar">another title</title>);
    
  8188.       });
    
  8189.       await waitForAll([]);
    
  8190.       expect(getMeaningfulChildren(document.head)).toEqual(
    
  8191.         <title data-foo="bar">another title</title>,
    
  8192.       );
    
  8193.     });
    
  8194.   });
    
  8195. });