diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index da59ac66fa..aa9222adb0 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -10,7 +10,7 @@
'use strict';
import {
- replaceScriptsAndMove,
+ insertNodesAndExecuteScripts,
mergeOptions,
stripExternalRuntimeInNodes,
withLoadingReadyState,
@@ -29,8 +29,6 @@ let useSyncExternalStoreWithSelector;
let use;
let PropTypes;
let textCache;
-let window;
-let document;
let writable;
let CSPnonce = null;
let container;
@@ -43,20 +41,32 @@ let waitForAll;
let assertLog;
let waitForPaint;
let clientAct;
-
-function resetJSDOM(markup) {
- // Test Environment
- const jsdom = new JSDOM(markup, {
- runScripts: 'dangerously',
- });
- window = jsdom.window;
- document = jsdom.window.document;
-}
+let streamingContainer;
describe('ReactDOMFizzServer', () => {
beforeEach(() => {
jest.resetModules();
JSDOM = require('jsdom').JSDOM;
+
+ const jsdom = new JSDOM(
+ '
',
+ {
+ runScripts: 'dangerously',
+ },
+ );
+ // We mock matchMedia. for simplicity it only matches 'all' or '' and misses everything else
+ Object.defineProperty(jsdom.window, 'matchMedia', {
+ writable: true,
+ value: jest.fn().mockImplementation(query => ({
+ matches: query === 'all' || query === '',
+ media: query,
+ })),
+ });
+ streamingContainer = null;
+ global.window = jsdom.window;
+ global.document = jsdom.window.document;
+ container = document.getElementById('container');
+
Scheduler = require('scheduler');
React = require('react');
ReactDOMClient = require('react-dom/client');
@@ -93,9 +103,6 @@ describe('ReactDOMFizzServer', () => {
textCache = new Map();
- resetJSDOM('
');
- container = document.getElementById('container');
-
buffer = '';
hasErrored = false;
@@ -140,6 +147,9 @@ describe('ReactDOMFizzServer', () => {
.join('');
}
+ const bodyStartMatch = /| .*?>)/;
+ const headStartMatch = /| .*?>)/;
+
async function act(callback) {
await callback();
// Await one turn around the event loop.
@@ -153,40 +163,123 @@ describe('ReactDOMFizzServer', () => {
// JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
// We also want to execute any scripts that are embedded.
// We assume that we have now received a proper fragment of HTML.
- const bufferedContent = buffer;
+ let bufferedContent = buffer;
buffer = '';
- const fakeBody = document.createElement('body');
- fakeBody.innerHTML = bufferedContent;
- const parent =
- container.nodeName === '#document' ? container.body : container;
- await withLoadingReadyState(async () => {
- while (fakeBody.firstChild) {
- const node = fakeBody.firstChild;
- await replaceScriptsAndMove(window, CSPnonce, node, parent);
- }
- }, document);
- }
-
- async function actIntoEmptyDocument(callback) {
- await callback();
- // Await one turn around the event loop.
- // This assumes that we'll flush everything we have so far.
- await new Promise(resolve => {
- setImmediate(resolve);
- });
- if (hasErrored) {
- throw fatalError;
+ if (!bufferedContent) {
+ return;
}
- // JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
- // We also want to execute any scripts that are embedded.
- // We assume that we have now received a proper fragment of HTML.
- const bufferedContent = buffer;
- resetJSDOM(bufferedContent);
- container = document;
- buffer = '';
+
await withLoadingReadyState(async () => {
- await replaceScriptsAndMove(window, CSPnonce, document.documentElement);
+ const bodyMatch = bufferedContent.match(bodyStartMatch);
+ const headMatch = bufferedContent.match(headStartMatch);
+
+ if (streamingContainer === null) {
+ // This is the first streamed content. We decide here where to insert it. If we get , , or
+ // we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the
+ // container. This is not really production behavior because you can't correctly stream into a deep div effectively
+ // but it's pragmatic for tests.
+
+ if (
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith(' without a which is almost certainly a bug in React',
+ );
+ }
+
+ if (bufferedContent.startsWith('')) {
+ // we can just use the whole document
+ const tempDom = new JSDOM(bufferedContent);
+
+ // Wipe existing head and body content
+ document.head.innerHTML = '';
+ document.body.innerHTML = '';
+
+ // Copy the attributes over
+ const tempHtmlNode = tempDom.window.document.documentElement;
+ for (let i = 0; i < tempHtmlNode.attributes.length; i++) {
+ const attr = tempHtmlNode.attributes[i];
+ document.documentElement.setAttribute(attr.name, attr.value);
+ }
+
+ if (headMatch) {
+ // We parsed a head open tag. we need to copy head attributes and insert future
+ // content into
+ streamingContainer = document.head;
+ const tempHeadNode = tempDom.window.document.head;
+ for (let i = 0; i < tempHeadNode.attributes.length; i++) {
+ const attr = tempHeadNode.attributes[i];
+ document.head.setAttribute(attr.name, attr.value);
+ }
+ const source = document.createElement('head');
+ source.innerHTML = tempHeadNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
+ }
+
+ if (bodyMatch) {
+ // We parsed a body open tag. we need to copy head attributes and insert future
+ // content into
+ streamingContainer = document.body;
+ const tempBodyNode = tempDom.window.document.body;
+ for (let i = 0; i < tempBodyNode.attributes.length; i++) {
+ const attr = tempBodyNode.attributes[i];
+ document.body.setAttribute(attr.name, attr.value);
+ }
+ const source = document.createElement('body');
+ source.innerHTML = tempBodyNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.body, CSPnonce);
+ }
+
+ if (!headMatch && !bodyMatch) {
+ throw new Error('expected or after ');
+ }
+ } else {
+ // we assume we are streaming into the default container'
+ streamingContainer = container;
+ const div = document.createElement('div');
+ div.innerHTML = bufferedContent;
+ await insertNodesAndExecuteScripts(div, container, CSPnonce);
+ }
+ } else if (streamingContainer === document.head) {
+ bufferedContent = '' + bufferedContent;
+ const tempDom = new JSDOM(bufferedContent);
+
+ const tempHeadNode = tempDom.window.document.head;
+ const source = document.createElement('head');
+ source.innerHTML = tempHeadNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
+
+ if (bodyMatch) {
+ streamingContainer = document.body;
+
+ const tempBodyNode = tempDom.window.document.body;
+ for (let i = 0; i < tempBodyNode.attributes.length; i++) {
+ const attr = tempBodyNode.attributes[i];
+ document.body.setAttribute(attr.name, attr.value);
+ }
+ const bodySource = document.createElement('body');
+ bodySource.innerHTML = tempBodyNode.innerHTML;
+ await insertNodesAndExecuteScripts(
+ bodySource,
+ document.body,
+ CSPnonce,
+ );
+ }
+ } else {
+ const div = document.createElement('div');
+ div.innerHTML = bufferedContent;
+ await insertNodesAndExecuteScripts(div, streamingContainer, CSPnonce);
+ }
}, document);
}
@@ -3467,7 +3560,7 @@ describe('ReactDOMFizzServer', () => {
});
it('accepts an integrity property for bootstrapScripts and bootstrapModules', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -3584,7 +3677,7 @@ describe('ReactDOMFizzServer', () => {
// @gate enableFizzExternalRuntime
it('supports option to load runtime as an external script', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -3631,7 +3724,7 @@ describe('ReactDOMFizzServer', () => {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -3644,7 +3737,7 @@ describe('ReactDOMFizzServer', () => {
});
it('does not send the external runtime for static pages', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -5583,7 +5670,7 @@ describe('ReactDOMFizzServer', () => {
};
try {
- await actIntoEmptyDocument(async () => {
+ await act(async () => {
const {pipe} = renderToPipeableStream(
diff --git a/packages/react-dom/src/__tests__/ReactDOMFloat-test.js b/packages/react-dom/src/__tests__/ReactDOMFloat-test.js
index 28fb79c1a7..728b91564c 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFloat-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFloat-test.js
@@ -10,7 +10,7 @@
'use strict';
import {
- replaceScriptsAndMove,
+ insertNodesAndExecuteScripts,
mergeOptions,
withLoadingReadyState,
} from '../test-utils/FizzTestUtils';
@@ -24,8 +24,6 @@ let ReactDOMFizzServer;
let Suspense;
let textCache;
let loadCache;
-let window;
-let document;
let writable;
const CSPnonce = null;
let container;
@@ -38,28 +36,32 @@ let waitForThrow;
let assertLog;
let Scheduler;
let clientAct;
-
-function resetJSDOM(markup) {
- // Test Environment
- const jsdom = new JSDOM(markup, {
- runScripts: 'dangerously',
- });
- // We mock matchMedia. for simplicity it only matches 'all' or '' and misses everything else
- Object.defineProperty(jsdom.window, 'matchMedia', {
- writable: true,
- value: jest.fn().mockImplementation(query => ({
- matches: query === 'all' || query === '',
- media: query,
- })),
- });
- window = jsdom.window;
- document = jsdom.window.document;
-}
+let streamingContainer;
describe('ReactDOMFloat', () => {
beforeEach(() => {
jest.resetModules();
JSDOM = require('jsdom').JSDOM;
+
+ const jsdom = new JSDOM(
+ '',
+ {
+ runScripts: 'dangerously',
+ },
+ );
+ // We mock matchMedia. for simplicity it only matches 'all' or '' and misses everything else
+ Object.defineProperty(jsdom.window, 'matchMedia', {
+ writable: true,
+ value: jest.fn().mockImplementation(query => ({
+ matches: query === 'all' || query === '',
+ media: query,
+ })),
+ });
+ streamingContainer = null;
+ global.window = jsdom.window;
+ global.document = jsdom.window.document;
+ container = document.getElementById('container');
+
React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
@@ -77,9 +79,6 @@ describe('ReactDOMFloat', () => {
textCache = new Map();
loadCache = new Set();
- resetJSDOM('
');
- container = document.getElementById('container');
-
buffer = '';
hasErrored = false;
@@ -100,6 +99,9 @@ describe('ReactDOMFloat', () => {
}
});
+ const bodyStartMatch = /| .*?>)/;
+ const headStartMatch = /| .*?>)/;
+
async function act(callback) {
await callback();
// Await one turn around the event loop.
@@ -113,44 +115,123 @@ describe('ReactDOMFloat', () => {
// JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
// We also want to execute any scripts that are embedded.
// We assume that we have now received a proper fragment of HTML.
- const bufferedContent = buffer;
+ let bufferedContent = buffer;
buffer = '';
- const fakeBody = document.createElement('body');
- fakeBody.innerHTML = bufferedContent;
- const parent =
- container.nodeName === '#document' ? container.body : container;
- await withLoadingReadyState(async () => {
- while (fakeBody.firstChild) {
- const node = fakeBody.firstChild;
- await replaceScriptsAndMove(
- document.defaultView,
- CSPnonce,
- node,
- parent,
- );
- }
- }, document);
- }
- async function actIntoEmptyDocument(callback) {
- await callback();
- // Await one turn around the event loop.
- // This assumes that we'll flush everything we have so far.
- await new Promise(resolve => {
- setImmediate(resolve);
- });
- if (hasErrored) {
- throw fatalError;
+ if (!bufferedContent) {
+ return;
}
- // JSDOM doesn't support stream HTML parser so we need to give it a proper fragment.
- // We also want to execute any scripts that are embedded.
- // We assume that we have now received a proper fragment of HTML.
- const bufferedContent = buffer;
- resetJSDOM(bufferedContent);
- container = document;
- buffer = '';
+
await withLoadingReadyState(async () => {
- await replaceScriptsAndMove(window, null, document.documentElement);
+ const bodyMatch = bufferedContent.match(bodyStartMatch);
+ const headMatch = bufferedContent.match(headStartMatch);
+
+ if (streamingContainer === null) {
+ // This is the first streamed content. We decide here where to insert it. If we get , , or
+ // we abandon the pre-built document and start from scratch. If we get anything else we assume it goes into the
+ // container. This is not really production behavior because you can't correctly stream into a deep div effectively
+ // but it's pragmatic for tests.
+
+ if (
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith('') ||
+ bufferedContent.startsWith(' without a which is almost certainly a bug in React',
+ );
+ }
+
+ if (bufferedContent.startsWith('')) {
+ // we can just use the whole document
+ const tempDom = new JSDOM(bufferedContent);
+
+ // Wipe existing head and body content
+ document.head.innerHTML = '';
+ document.body.innerHTML = '';
+
+ // Copy the attributes over
+ const tempHtmlNode = tempDom.window.document.documentElement;
+ for (let i = 0; i < tempHtmlNode.attributes.length; i++) {
+ const attr = tempHtmlNode.attributes[i];
+ document.documentElement.setAttribute(attr.name, attr.value);
+ }
+
+ if (headMatch) {
+ // We parsed a head open tag. we need to copy head attributes and insert future
+ // content into
+ streamingContainer = document.head;
+ const tempHeadNode = tempDom.window.document.head;
+ for (let i = 0; i < tempHeadNode.attributes.length; i++) {
+ const attr = tempHeadNode.attributes[i];
+ document.head.setAttribute(attr.name, attr.value);
+ }
+ const source = document.createElement('head');
+ source.innerHTML = tempHeadNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
+ }
+
+ if (bodyMatch) {
+ // We parsed a body open tag. we need to copy head attributes and insert future
+ // content into
+ streamingContainer = document.body;
+ const tempBodyNode = tempDom.window.document.body;
+ for (let i = 0; i < tempBodyNode.attributes.length; i++) {
+ const attr = tempBodyNode.attributes[i];
+ document.body.setAttribute(attr.name, attr.value);
+ }
+ const source = document.createElement('body');
+ source.innerHTML = tempBodyNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.body, CSPnonce);
+ }
+
+ if (!headMatch && !bodyMatch) {
+ throw new Error('expected or after ');
+ }
+ } else {
+ // we assume we are streaming into the default container'
+ streamingContainer = container;
+ const div = document.createElement('div');
+ div.innerHTML = bufferedContent;
+ await insertNodesAndExecuteScripts(div, container, CSPnonce);
+ }
+ } else if (streamingContainer === document.head) {
+ bufferedContent = '' + bufferedContent;
+ const tempDom = new JSDOM(bufferedContent);
+
+ const tempHeadNode = tempDom.window.document.head;
+ const source = document.createElement('head');
+ source.innerHTML = tempHeadNode.innerHTML;
+ await insertNodesAndExecuteScripts(source, document.head, CSPnonce);
+
+ if (bodyMatch) {
+ streamingContainer = document.body;
+
+ const tempBodyNode = tempDom.window.document.body;
+ for (let i = 0; i < tempBodyNode.attributes.length; i++) {
+ const attr = tempBodyNode.attributes[i];
+ document.body.setAttribute(attr.name, attr.value);
+ }
+ const bodySource = document.createElement('body');
+ bodySource.innerHTML = tempBodyNode.innerHTML;
+ await insertNodesAndExecuteScripts(
+ bodySource,
+ document.body,
+ CSPnonce,
+ );
+ }
+ } else {
+ const div = document.createElement('div');
+ div.innerHTML = bufferedContent;
+ await insertNodesAndExecuteScripts(div, streamingContainer, CSPnonce);
+ }
}, document);
}
@@ -350,7 +431,7 @@ describe('ReactDOMFloat', () => {
// @gate enableFloat
it('can hydrate non Resources in head when Resources are also inserted there', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -375,7 +456,7 @@ describe('ReactDOMFloat', () => {
foo
-
<link rel="icon" href="icon"/>
+
<link rel="icon" href="icon">
foo
@@ -406,7 +487,7 @@ describe('ReactDOMFloat', () => {
foo
-
<link rel="icon" href="icon"/>
+
<link rel="icon" href="icon">
@@ -598,7 +679,7 @@ describe('ReactDOMFloat', () => {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
buffer = `${ReactDOMFizzServer.renderToString(
,
)}foo`;
@@ -625,7 +706,7 @@ describe('ReactDOMFloat', () => {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
buffer = `${ReactDOMFizzServer.renderToString(
,
)}foo`;
@@ -649,7 +730,7 @@ describe('ReactDOMFloat', () => {
chunks.push(chunk);
});
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
<>
foo
@@ -681,7 +762,7 @@ describe('ReactDOMFloat', () => {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -703,7 +784,7 @@ describe('ReactDOMFloat', () => {
// @gate enableFloat
it('can avoid inserting a late stylesheet if it already rendered on the client', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -829,7 +910,7 @@ body {
background-color: red;
}`;
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -1125,7 +1206,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
);
pipe(writable);
});
@@ -1211,7 +1292,7 @@ body {
// @gate enableFloat
it('treats stylesheet links with a precedence as a resource', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -1264,7 +1345,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -2659,7 +2740,7 @@ body {
- <meta name="noscript" content="noscript"/>
+ <meta name="noscript" content="noscript">
@@ -2713,7 +2794,7 @@ body {
});
it('does not preload nomodule scripts', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -2839,7 +2920,7 @@ body {
});
it('assumes stylesheets that load in the shell loaded already', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -3321,7 +3402,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream( ).pipe(writable);
});
}).toErrorDev([
@@ -3390,7 +3471,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream( ).pipe(writable);
});
}).toErrorDev(
@@ -3469,7 +3550,7 @@ body {
return hello
;
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -3555,7 +3636,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -3620,7 +3701,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -3645,7 +3726,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -3689,7 +3770,7 @@ body {
return hello
;
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -3799,7 +3880,7 @@ body {
return hello
;
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -3916,7 +3997,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -3952,7 +4033,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -3977,7 +4058,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -4007,7 +4088,7 @@ body {
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -4025,7 +4106,7 @@ body {
describe('Stylesheet Resources', () => {
// @gate enableFloat
it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when server rendering', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4446,7 +4539,7 @@ describe('ReactDOMFizzServer', () => {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4456,17 +4549,13 @@ describe('ReactDOMFizzServer', () => {
);
pipe(writable);
});
- await actIntoEmptyDocument(() => {
+ await act(() => {
resolveText('body');
});
- await actIntoEmptyDocument(() => {
+ await act(() => {
resolveText('nooutput');
});
- // We need to use actIntoEmptyDocument because act assumes that buffered
- // content should be fake streamed into the body which is normally true
- // but in this test the entire shell was delayed and we need the initial
- // construction to be done to get the parsing right
- await actIntoEmptyDocument(() => {
+ await act(() => {
resolveText('head');
});
expect(getVisibleChildren(document)).toEqual(
@@ -4487,7 +4576,7 @@ describe('ReactDOMFizzServer', () => {
chunks.push(chunk);
});
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4953,23 +5042,21 @@ describe('ReactDOMFizzServer', () => {
});
describe('title children', () => {
- function prepareJSDOMForTitle() {
- resetJSDOM('
\u0000');
- container = document.getElementsByTagName('head')[0];
- }
-
it('should accept a single string child', async () => {
// a Single string child
function App() {
- return
hello ;
+ return (
+
+
hello
+
+ );
}
- prepareJSDOMForTitle();
await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
const errors = [];
ReactDOMClient.hydrateRoot(container, , {
@@ -4979,21 +5066,24 @@ describe('ReactDOMFizzServer', () => {
});
await waitForAll([]);
expect(errors).toEqual([]);
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
});
it('should accept children array of length 1 containing a string', async () => {
// a Single string child
function App() {
- return
{['hello']} ;
+ return (
+
+
{['hello']}
+
+ );
}
- prepareJSDOMForTitle();
await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
const errors = [];
ReactDOMClient.hydrateRoot(container, , {
@@ -5003,16 +5093,18 @@ describe('ReactDOMFizzServer', () => {
});
await waitForAll([]);
expect(errors).toEqual([]);
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
});
it('should warn in dev when given an array of length 2 or more', async () => {
function App() {
- return
{['hello1', 'hello2']} ;
+ return (
+
+
{['hello1', 'hello2']}
+
+ );
}
- prepareJSDOMForTitle();
-
await expect(async () => {
await act(() => {
const {pipe} = renderToPipeableStream( );
@@ -5023,15 +5115,15 @@ describe('ReactDOMFizzServer', () => {
]);
if (gate(flags => flags.enableFloat)) {
- expect(getVisibleChildren(container)).toEqual(
);
+ expect(getVisibleChildren(document.head)).toEqual(
);
} else {
- expect(getVisibleChildren(container)).toEqual(
+ expect(getVisibleChildren(document.head)).toEqual(
{'hello1hello2'} ,
);
}
const errors = [];
- ReactDOMClient.hydrateRoot(container, , {
+ ReactDOMClient.hydrateRoot(document.head, , {
onRecoverableError(error) {
errors.push(error.message);
},
@@ -5040,7 +5132,7 @@ describe('ReactDOMFizzServer', () => {
if (gate(flags => flags.enableFloat)) {
expect(errors).toEqual([]);
// with float, the title doesn't render on the client or on the server
- expect(getVisibleChildren(container)).toEqual(
);
+ expect(getVisibleChildren(document.head)).toEqual(
);
} else {
expect(errors).toEqual(
[
@@ -5051,7 +5143,7 @@ describe('ReactDOMFizzServer', () => {
'There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
].filter(Boolean),
);
- expect(getVisibleChildren(container)).toEqual(
+ expect(getVisibleChildren(document.head)).toEqual(
{['hello1', 'hello2']} ,
);
}
@@ -5064,16 +5156,14 @@ describe('ReactDOMFizzServer', () => {
function App() {
return (
- <>
+
- >
+
);
}
- prepareJSDOMForTitle();
-
if (gate(flags => flags.enableFloat)) {
await expect(async () => {
await act(() => {
@@ -5096,15 +5186,15 @@ describe('ReactDOMFizzServer', () => {
if (gate(flags => flags.enableFloat)) {
// object titles are toStringed when float is on
- expect(getVisibleChildren(container)).toEqual(
+ expect(getVisibleChildren(document.head)).toEqual(
{'[object Object]'} ,
);
} else {
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
}
const errors = [];
- ReactDOMClient.hydrateRoot(container, , {
+ ReactDOMClient.hydrateRoot(document.head, , {
onRecoverableError(error) {
errors.push(error.message);
},
@@ -5113,344 +5203,341 @@ describe('ReactDOMFizzServer', () => {
expect(errors).toEqual([]);
if (gate(flags => flags.enableFloat)) {
// object titles are toStringed when float is on
- expect(getVisibleChildren(container)).toEqual(
+ expect(getVisibleChildren(document.head)).toEqual(
{'[object Object]'} ,
);
} else {
- expect(getVisibleChildren(container)).toEqual(
hello );
+ expect(getVisibleChildren(document.head)).toEqual(
hello );
}
});
+ });
- // @gate enableUseHook
- it('basic use(promise)', async () => {
- const promiseA = Promise.resolve('A');
- const promiseB = Promise.resolve('B');
- const promiseC = Promise.resolve('C');
+ // @gate enableUseHook
+ it('basic use(promise)', async () => {
+ const promiseA = Promise.resolve('A');
+ const promiseB = Promise.resolve('B');
+ const promiseC = Promise.resolve('C');
- function Async() {
- return use(promiseA) + use(promiseB) + use(promiseC);
- }
+ function Async() {
+ return use(promiseA) + use(promiseB) + use(promiseC);
+ }
- function App() {
- return (
-
-
-
- );
- }
-
- await act(() => {
- const {pipe} = renderToPipeableStream( );
- pipe(writable);
- });
-
- // TODO: The `act` implementation in this file doesn't unwrap microtasks
- // automatically. We can't use the same `act` we use for Fiber tests
- // because that relies on the mock Scheduler. Doesn't affect any public
- // API but we might want to fix this for our own internal tests.
- //
- // For now, wait for each promise in sequence.
- await act(async () => {
- await promiseA;
- });
- await act(async () => {
- await promiseB;
- });
- await act(async () => {
- await promiseC;
- });
-
- expect(getVisibleChildren(container)).toEqual('ABC');
-
- ReactDOMClient.hydrateRoot(container, );
- await waitForAll([]);
- expect(getVisibleChildren(container)).toEqual('ABC');
- });
-
- // @gate enableUseHook
- it('basic use(context)', async () => {
- const ContextA = React.createContext('default');
- const ContextB = React.createContext('B');
- const ServerContext = React.createServerContext(
- 'ServerContext',
- 'default',
+ function App() {
+ return (
+
+
+
);
- function Client() {
- return use(ContextA) + use(ContextB);
- }
- function ServerComponent() {
- return use(ServerContext);
- }
- function Server() {
- return (
-
-
-
- );
- }
- function App() {
- return (
- <>
-
-
-
-
- >
- );
- }
+ }
- await act(() => {
- const {pipe} = renderToPipeableStream( );
- pipe(writable);
- });
- expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
-
- // Hydration uses a different renderer runtime (Fiber instead of Fizz).
- // We reset _currentRenderer here to not trigger a warning about multiple
- // renderers concurrently using these contexts
- ContextA._currentRenderer = null;
- ServerContext._currentRenderer = null;
- ReactDOMClient.hydrateRoot(container, );
- await waitForAll([]);
- expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
+ await act(() => {
+ const {pipe} = renderToPipeableStream( );
+ pipe(writable);
});
- // @gate enableUseHook
- it('use(promise) in multiple components', async () => {
- const promiseA = Promise.resolve('A');
- const promiseB = Promise.resolve('B');
- const promiseC = Promise.resolve('C');
- const promiseD = Promise.resolve('D');
-
- function Child({prefix}) {
- return prefix + use(promiseC) + use(promiseD);
- }
-
- function Parent() {
- return ;
- }
-
- function App() {
- return (
-
-
-
- );
- }
-
- await act(() => {
- const {pipe} = renderToPipeableStream( );
- pipe(writable);
- });
-
- // TODO: The `act` implementation in this file doesn't unwrap microtasks
- // automatically. We can't use the same `act` we use for Fiber tests
- // because that relies on the mock Scheduler. Doesn't affect any public
- // API but we might want to fix this for our own internal tests.
- //
- // For now, wait for each promise in sequence.
- await act(async () => {
- await promiseA;
- });
- await act(async () => {
- await promiseB;
- });
- await act(async () => {
- await promiseC;
- });
- await act(async () => {
- await promiseD;
- });
-
- expect(getVisibleChildren(container)).toEqual('ABCD');
-
- ReactDOMClient.hydrateRoot(container, );
- await waitForAll([]);
- expect(getVisibleChildren(container)).toEqual('ABCD');
+ // TODO: The `act` implementation in this file doesn't unwrap microtasks
+ // automatically. We can't use the same `act` we use for Fiber tests
+ // because that relies on the mock Scheduler. Doesn't affect any public
+ // API but we might want to fix this for our own internal tests.
+ //
+ // For now, wait for each promise in sequence.
+ await act(async () => {
+ await promiseA;
+ });
+ await act(async () => {
+ await promiseB;
+ });
+ await act(async () => {
+ await promiseC;
});
- // @gate enableUseHook
- it('using a rejected promise will throw', async () => {
- const promiseA = Promise.resolve('A');
- const promiseB = Promise.reject(new Error('Oops!'));
- const promiseC = Promise.resolve('C');
+ expect(getVisibleChildren(container)).toEqual('ABC');
- // Jest/Node will raise an unhandled rejected error unless we await this. It
- // works fine in the browser, though.
- await expect(promiseB).rejects.toThrow('Oops!');
+ ReactDOMClient.hydrateRoot(container, );
+ await waitForAll([]);
+ expect(getVisibleChildren(container)).toEqual('ABC');
+ });
- function Async() {
- return use(promiseA) + use(promiseB) + use(promiseC);
+ // @gate enableUseHook
+ it('basic use(context)', async () => {
+ const ContextA = React.createContext('default');
+ const ContextB = React.createContext('B');
+ const ServerContext = React.createServerContext('ServerContext', 'default');
+ function Client() {
+ return use(ContextA) + use(ContextB);
+ }
+ function ServerComponent() {
+ return use(ServerContext);
+ }
+ function Server() {
+ return (
+
+
+
+ );
+ }
+ function App() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
+
+ await act(() => {
+ const {pipe} = renderToPipeableStream( );
+ pipe(writable);
+ });
+ expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
+
+ // Hydration uses a different renderer runtime (Fiber instead of Fizz).
+ // We reset _currentRenderer here to not trigger a warning about multiple
+ // renderers concurrently using these contexts
+ ContextA._currentRenderer = null;
+ ServerContext._currentRenderer = null;
+ ReactDOMClient.hydrateRoot(container, );
+ await waitForAll([]);
+ expect(getVisibleChildren(container)).toEqual(['AB', 'C']);
+ });
+
+ // @gate enableUseHook
+ it('use(promise) in multiple components', async () => {
+ const promiseA = Promise.resolve('A');
+ const promiseB = Promise.resolve('B');
+ const promiseC = Promise.resolve('C');
+ const promiseD = Promise.resolve('D');
+
+ function Child({prefix}) {
+ return prefix + use(promiseC) + use(promiseD);
+ }
+
+ function Parent() {
+ return ;
+ }
+
+ function App() {
+ return (
+
+
+
+ );
+ }
+
+ await act(() => {
+ const {pipe} = renderToPipeableStream( );
+ pipe(writable);
+ });
+
+ // TODO: The `act` implementation in this file doesn't unwrap microtasks
+ // automatically. We can't use the same `act` we use for Fiber tests
+ // because that relies on the mock Scheduler. Doesn't affect any public
+ // API but we might want to fix this for our own internal tests.
+ //
+ // For now, wait for each promise in sequence.
+ await act(async () => {
+ await promiseA;
+ });
+ await act(async () => {
+ await promiseB;
+ });
+ await act(async () => {
+ await promiseC;
+ });
+ await act(async () => {
+ await promiseD;
+ });
+
+ expect(getVisibleChildren(container)).toEqual('ABCD');
+
+ ReactDOMClient.hydrateRoot(container, );
+ await waitForAll([]);
+ expect(getVisibleChildren(container)).toEqual('ABCD');
+ });
+
+ // @gate enableUseHook
+ it('using a rejected promise will throw', async () => {
+ const promiseA = Promise.resolve('A');
+ const promiseB = Promise.reject(new Error('Oops!'));
+ const promiseC = Promise.resolve('C');
+
+ // Jest/Node will raise an unhandled rejected error unless we await this. It
+ // works fine in the browser, though.
+ await expect(promiseB).rejects.toThrow('Oops!');
+
+ function Async() {
+ return use(promiseA) + use(promiseB) + use(promiseC);
+ }
+
+ class ErrorBoundary extends React.Component {
+ state = {error: null};
+ static getDerivedStateFromError(error) {
+ return {error};
}
-
- class ErrorBoundary extends React.Component {
- state = {error: null};
- static getDerivedStateFromError(error) {
- return {error};
- }
- render() {
- if (this.state.error) {
- return this.state.error.message;
- }
- return this.props.children;
+ render() {
+ if (this.state.error) {
+ return this.state.error.message;
}
+ return this.props.children;
}
+ }
- function App() {
- return (
-
-
-
-
-
- );
- }
+ function App() {
+ return (
+
+
+
+
+
+ );
+ }
- const reportedServerErrors = [];
- await act(() => {
- const {pipe} = renderToPipeableStream( , {
- onError(error) {
- reportedServerErrors.push(error);
- },
- });
- pipe(writable);
- });
-
- // TODO: The `act` implementation in this file doesn't unwrap microtasks
- // automatically. We can't use the same `act` we use for Fiber tests
- // because that relies on the mock Scheduler. Doesn't affect any public
- // API but we might want to fix this for our own internal tests.
- //
- // For now, wait for each promise in sequence.
- await act(async () => {
- await promiseA;
- });
- await act(async () => {
- await expect(promiseB).rejects.toThrow('Oops!');
- });
- await act(async () => {
- await promiseC;
- });
-
- expect(getVisibleChildren(container)).toEqual('Loading...');
- expect(reportedServerErrors.length).toBe(1);
- expect(reportedServerErrors[0].message).toBe('Oops!');
-
- const reportedClientErrors = [];
- ReactDOMClient.hydrateRoot(container, , {
- onRecoverableError(error) {
- reportedClientErrors.push(error);
+ const reportedServerErrors = [];
+ await act(() => {
+ const {pipe} = renderToPipeableStream( , {
+ onError(error) {
+ reportedServerErrors.push(error);
},
});
- await waitForAll([]);
- expect(getVisibleChildren(container)).toEqual('Oops!');
- expect(reportedClientErrors.length).toBe(1);
- if (__DEV__) {
- expect(reportedClientErrors[0].message).toBe('Oops!');
- } else {
- expect(reportedClientErrors[0].message).toBe(
- 'The server could not finish this Suspense boundary, likely due to ' +
- 'an error during server rendering. Switched to client rendering.',
+ pipe(writable);
+ });
+
+ // TODO: The `act` implementation in this file doesn't unwrap microtasks
+ // automatically. We can't use the same `act` we use for Fiber tests
+ // because that relies on the mock Scheduler. Doesn't affect any public
+ // API but we might want to fix this for our own internal tests.
+ //
+ // For now, wait for each promise in sequence.
+ await act(async () => {
+ await promiseA;
+ });
+ await act(async () => {
+ await expect(promiseB).rejects.toThrow('Oops!');
+ });
+ await act(async () => {
+ await promiseC;
+ });
+
+ expect(getVisibleChildren(container)).toEqual('Loading...');
+ expect(reportedServerErrors.length).toBe(1);
+ expect(reportedServerErrors[0].message).toBe('Oops!');
+
+ const reportedClientErrors = [];
+ ReactDOMClient.hydrateRoot(container, , {
+ onRecoverableError(error) {
+ reportedClientErrors.push(error);
+ },
+ });
+ await waitForAll([]);
+ expect(getVisibleChildren(container)).toEqual('Oops!');
+ expect(reportedClientErrors.length).toBe(1);
+ if (__DEV__) {
+ expect(reportedClientErrors[0].message).toBe('Oops!');
+ } else {
+ expect(reportedClientErrors[0].message).toBe(
+ 'The server could not finish this Suspense boundary, likely due to ' +
+ 'an error during server rendering. Switched to client rendering.',
+ );
+ }
+ });
+
+ // @gate enableUseHook
+ it("use a promise that's already been instrumented and resolved", async () => {
+ const thenable = {
+ status: 'fulfilled',
+ value: 'Hi',
+ then() {},
+ };
+
+ // This will never suspend because the thenable already resolved
+ function App() {
+ return use(thenable);
+ }
+
+ await act(() => {
+ const {pipe} = renderToPipeableStream( );
+ pipe(writable);
+ });
+ expect(getVisibleChildren(container)).toEqual('Hi');
+
+ ReactDOMClient.hydrateRoot(container, );
+ await waitForAll([]);
+ expect(getVisibleChildren(container)).toEqual('Hi');
+ });
+
+ // @gate enableUseHook
+ it('unwraps thenable that fulfills synchronously without suspending', async () => {
+ function App() {
+ const thenable = {
+ then(resolve) {
+ // This thenable immediately resolves, synchronously, without waiting
+ // a microtask.
+ resolve('Hi');
+ },
+ };
+ try {
+ return ;
+ } catch {
+ throw new Error(
+ '`use` should not suspend because the thenable resolved synchronously.',
);
}
+ }
+ // Because the thenable resolves synchronously, we should be able to finish
+ // rendering synchronously, with no fallback.
+ await act(() => {
+ const {pipe} = renderToPipeableStream( );
+ pipe(writable);
+ });
+ expect(getVisibleChildren(container)).toEqual('Hi');
+ });
+
+ it('promise as node', async () => {
+ const promise = Promise.resolve('Hi');
+ await act(async () => {
+ const {pipe} = renderToPipeableStream(promise);
+ pipe(writable);
});
- // @gate enableUseHook
- it("use a promise that's already been instrumented and resolved", async () => {
- const thenable = {
- status: 'fulfilled',
- value: 'Hi',
- then() {},
- };
-
- // This will never suspend because the thenable already resolved
- function App() {
- return use(thenable);
- }
-
- await act(() => {
- const {pipe} = renderToPipeableStream( );
- pipe(writable);
- });
- expect(getVisibleChildren(container)).toEqual('Hi');
-
- ReactDOMClient.hydrateRoot(container, );
- await waitForAll([]);
- expect(getVisibleChildren(container)).toEqual('Hi');
+ // TODO: The `act` implementation in this file doesn't unwrap microtasks
+ // automatically. We can't use the same `act` we use for Fiber tests
+ // because that relies on the mock Scheduler. Doesn't affect any public
+ // API but we might want to fix this for our own internal tests.
+ await act(async () => {
+ await promise;
});
- // @gate enableUseHook
- it('unwraps thenable that fulfills synchronously without suspending', async () => {
- function App() {
- const thenable = {
- then(resolve) {
- // This thenable immediately resolves, synchronously, without waiting
- // a microtask.
- resolve('Hi');
- },
- };
- try {
- return ;
- } catch {
- throw new Error(
- '`use` should not suspend because the thenable resolved synchronously.',
- );
- }
- }
- // Because the thenable resolves synchronously, we should be able to finish
- // rendering synchronously, with no fallback.
- await act(() => {
- const {pipe} = renderToPipeableStream( );
- pipe(writable);
- });
- expect(getVisibleChildren(container)).toEqual('Hi');
+ expect(getVisibleChildren(container)).toEqual('Hi');
+ });
+
+ it('context as node', async () => {
+ const Context = React.createContext('Hi');
+ await act(async () => {
+ const {pipe} = renderToPipeableStream(Context);
+ pipe(writable);
+ });
+ expect(getVisibleChildren(container)).toEqual('Hi');
+ });
+
+ it('recursive Usable as node', async () => {
+ const Context = React.createContext('Hi');
+ const promiseForContext = Promise.resolve(Context);
+ await act(async () => {
+ const {pipe} = renderToPipeableStream(promiseForContext);
+ pipe(writable);
});
- it('promise as node', async () => {
- const promise = Promise.resolve('Hi');
- await act(async () => {
- const {pipe} = renderToPipeableStream(promise);
- pipe(writable);
- });
-
- // TODO: The `act` implementation in this file doesn't unwrap microtasks
- // automatically. We can't use the same `act` we use for Fiber tests
- // because that relies on the mock Scheduler. Doesn't affect any public
- // API but we might want to fix this for our own internal tests.
- await act(async () => {
- await promise;
- });
-
- expect(getVisibleChildren(container)).toEqual('Hi');
+ // TODO: The `act` implementation in this file doesn't unwrap microtasks
+ // automatically. We can't use the same `act` we use for Fiber tests
+ // because that relies on the mock Scheduler. Doesn't affect any public
+ // API but we might want to fix this for our own internal tests.
+ await act(async () => {
+ await promiseForContext;
});
- it('context as node', async () => {
- const Context = React.createContext('Hi');
- await act(async () => {
- const {pipe} = renderToPipeableStream(Context);
- pipe(writable);
- });
- expect(getVisibleChildren(container)).toEqual('Hi');
- });
-
- it('recursive Usable as node', async () => {
- const Context = React.createContext('Hi');
- const promiseForContext = Promise.resolve(Context);
- await act(async () => {
- const {pipe} = renderToPipeableStream(promiseForContext);
- pipe(writable);
- });
-
- // TODO: The `act` implementation in this file doesn't unwrap microtasks
- // automatically. We can't use the same `act` we use for Fiber tests
- // because that relies on the mock Scheduler. Doesn't affect any public
- // API but we might want to fix this for our own internal tests.
- await act(async () => {
- await promiseForContext;
- });
-
- expect(getVisibleChildren(container)).toEqual('Hi');
- });
+ expect(getVisibleChildren(container)).toEqual('Hi');
});
describe('useEffectEvent', () => {
@@ -5555,7 +5642,7 @@ describe('ReactDOMFizzServer', () => {
});
it('can render scripts with simple children', async () => {
- await actIntoEmptyDocument(async () => {
+ await act(async () => {
const {pipe} = renderToPipeableStream(
@@ -1302,7 +1383,7 @@ body {
function PresetPrecedence() {
ReactDOM.preinit('preset', {as: 'style', precedence: 'preset'});
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -1584,7 +1665,7 @@ body {
// @gate enableFloat
it('normalizes stylesheet resource precedence for all boundaries inlined as part of the shell flush', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -1668,7 +1749,7 @@ body {
// @gate enableFloat
it('stylesheet resources are inserted according to precedence order on the client', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -1791,7 +1872,7 @@ body {
// @gate enableFloat
it('will include child boundary stylesheet resources in the boundary reveal instruction', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -1910,7 +1991,7 @@ body {
// @gate enableFloat
it('will hoist resources of child boundaries emitted as part of a partial boundary to the parent boundary', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -2132,7 +2213,7 @@ body {
);
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -2218,7 +2299,7 @@ body {
// @gate enableFloat
it('boundary stylesheet resource dependencies hoist to a parent boundary when flushed inline', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -2353,7 +2434,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -2417,7 +2498,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream( ).pipe(writable);
});
@@ -2573,7 +2654,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream( ).pipe(writable);
});
@@ -2593,7 +2674,7 @@ body {
- <meta name="noscript" content="noscript"/>
+ <meta name="noscript" content="noscript">
@@ -4078,7 +4159,7 @@ body {
// @gate enableFloat
it('treats link rel stylesheet elements as a stylesheet resource when it includes a precedence when hydrating', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4116,7 +4197,7 @@ body {
// @gate enableFloat
it('preloads stylesheets without a precedence prop when server rendering', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4144,7 +4225,7 @@ body {
// @gate enableFloat
it('hoists stylesheet resources to the correct precedence', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4239,7 +4320,7 @@ body {
// @gate enableFloat && enableHostSingletons && enableClientRenderFallbackOnTextMismatch
it('retains styles even when a new html, head, and/body mount', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4291,7 +4372,7 @@ body {
// @gate enableFloat && !enableHostSingletons
it('retains styles even when a new html, head, and/body mount - without HostSingleton', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4521,7 +4602,7 @@ body {
);
}
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -4575,7 +4656,7 @@ body {
// @gate enableFloat
it('escapes hrefs when selecting matching elements in the document when using preload and preinit', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4638,7 +4719,7 @@ body {
// @gate enableFloat
it('does not create stylesheet resources when inside an context', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4699,7 +4780,7 @@ body {
// @gate enableFloat
it('does not create stylesheet resources when inside a context', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream(
@@ -4716,7 +4797,7 @@ body {
- <link rel="stylesheet" href="foo" precedence="default"/>
+ <link rel="stylesheet" href="foo" precedence="default">
,
@@ -4742,7 +4823,7 @@ body {
// @gate enableFloat
it('warns if you provide a `precedence` prop with other props that invalidate the creation of a stylesheet resource', async () => {
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -4826,7 +4907,7 @@ body {
);
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -4854,7 +4935,7 @@ body {
);
}
await expect(async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
const {pipe} = renderToPipeableStream( );
pipe(writable);
});
@@ -4865,7 +4946,7 @@ body {
// @gate enableFloat
it('will not block displaying a Suspense boundary on a stylesheet with media that does not match', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -4986,7 +5067,7 @@ body {
body {
background-color: red;
}`;
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -5024,7 +5105,7 @@ background-color: blue;
body {
background-color: green;
}`;
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -5129,7 +5210,7 @@ background-color: green;
// @gate enableFloat
it('can emit styles early when a partial boundary flushes', async () => {
const css = 'body { background-color: red; }';
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -5197,7 +5278,7 @@ background-color: green;
});
it('can hoist styles flushed early even when no other style dependencies are flushed on completion', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -5261,7 +5342,7 @@ background-color: green;
});
it('can emit multiple style rules into a single style tag for a given precedence', async () => {
- await actIntoEmptyDocument(() => {
+ await act(() => {
renderToPipeableStream(
@@ -5440,7 +5521,7 @@ background-color: green;
it('warns if you render a