Skip to content

Commit 69fd78f

Browse files
authored
Update Float tests to check for specific errors (#26367)
I updated some of the Float tests that intentionally trigger an error to assert on the specific error message, rather than swallow any errors that may or may not happen.
1 parent 93c10df commit 69fd78f

File tree

2 files changed

+109
-95
lines changed

2 files changed

+109
-95
lines changed

packages/internal-test-utils/ReactInternalTestUtils.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ ${diff(expectedLog, actualLog)}
104104
throw error;
105105
}
106106

107-
export async function waitForThrow(expectedError: mixed) {
107+
export async function waitForThrow(expectedError: mixed): mixed {
108108
assertYieldsWereCleared(SchedulerMock);
109109

110110
// Create the error object before doing any async work, to get a better
@@ -123,8 +123,14 @@ export async function waitForThrow(expectedError: mixed) {
123123
try {
124124
SchedulerMock.unstable_flushAllWithoutAsserting();
125125
} catch (x) {
126+
if (expectedError === undefined) {
127+
// If no expected error was provided, then assume the caller is OK with
128+
// any error being thrown. We're returning the error so they can do
129+
// their own checks, if they wish.
130+
return x;
131+
}
126132
if (equals(x, expectedError)) {
127-
return;
133+
return x;
128134
}
129135
if (
130136
typeof expectedError === 'string' &&
@@ -133,7 +139,7 @@ export async function waitForThrow(expectedError: mixed) {
133139
typeof x.message === 'string' &&
134140
x.message.includes(expectedError)
135141
) {
136-
return;
142+
return x;
137143
}
138144
error.message = `
139145
Expected error was not thrown.

packages/react-dom/src/__tests__/ReactDOMFloat-test.js

+100-92
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717

1818
let JSDOM;
1919
let Stream;
20-
let Scheduler;
2120
let React;
2221
let ReactDOM;
2322
let ReactDOMClient;
@@ -34,7 +33,7 @@ let hasErrored = false;
3433
let fatalError = undefined;
3534
let renderOptions;
3635
let waitForAll;
37-
let assertLog;
36+
let waitForThrow;
3837

3938
function resetJSDOM(markup) {
4039
// Test Environment
@@ -57,7 +56,6 @@ describe('ReactDOMFloat', () => {
5756
beforeEach(() => {
5857
jest.resetModules();
5958
JSDOM = require('jsdom').JSDOM;
60-
Scheduler = require('scheduler');
6159
React = require('react');
6260
ReactDOM = require('react-dom');
6361
ReactDOMClient = require('react-dom/client');
@@ -67,7 +65,7 @@ describe('ReactDOMFloat', () => {
6765

6866
const InternalTestUtils = require('internal-test-utils');
6967
waitForAll = InternalTestUtils.waitForAll;
70-
assertLog = InternalTestUtils.assertLog;
68+
waitForThrow = InternalTestUtils.waitForThrow;
7169

7270
textCache = new Map();
7371

@@ -261,23 +259,6 @@ describe('ReactDOMFloat', () => {
261259
);
262260
}
263261

264-
function renderSafelyAndExpect(root, children) {
265-
root.render(children);
266-
return expect(() => {
267-
try {
268-
// TODO: Migrate this to waitForAll()
269-
Scheduler.unstable_flushAll();
270-
assertLog([]);
271-
} catch (e) {
272-
try {
273-
// TODO: Migrate this to waitForAll()
274-
Scheduler.unstable_flushAll();
275-
assertLog([]);
276-
} catch (f) {}
277-
}
278-
});
279-
}
280-
281262
// @gate enableFloat
282263
it('can render resources before singletons', async () => {
283264
const root = ReactDOMClient.createRoot(document);
@@ -382,94 +363,127 @@ describe('ReactDOMFloat', () => {
382363
it('warns if you render resource-like elements above <head> or <body>', async () => {
383364
const root = ReactDOMClient.createRoot(document);
384365

385-
renderSafelyAndExpect(
386-
root,
387-
<>
388-
<noscript>foo</noscript>
389-
<html>
390-
<body>foo</body>
391-
</html>
392-
</>,
393-
).toErrorDev(
366+
await expect(async () => {
367+
root.render(
368+
<>
369+
<noscript>foo</noscript>
370+
<html>
371+
<body>foo</body>
372+
</html>
373+
</>,
374+
);
375+
const aggregateError = await waitForThrow();
376+
expect(aggregateError.errors.length).toBe(2);
377+
expect(aggregateError.errors[0].message).toContain(
378+
'Invalid insertion of NOSCRIPT',
379+
);
380+
expect(aggregateError.errors[1].message).toContain(
381+
'The node to be removed is not a child of this node',
382+
);
383+
}).toErrorDev(
394384
[
395385
'Cannot render <noscript> outside the main document. Try moving it into the root <head> tag.',
396386
'Warning: validateDOMNesting(...): <noscript> cannot appear as a child of <#document>.',
397387
],
398388
{withoutStack: 1},
399389
);
400390

401-
renderSafelyAndExpect(
402-
root,
403-
<html>
404-
<template>foo</template>
405-
<body>foo</body>
406-
</html>,
407-
).toErrorDev([
391+
await expect(async () => {
392+
root.render(
393+
<html>
394+
<template>foo</template>
395+
<body>foo</body>
396+
</html>,
397+
);
398+
await waitForAll([]);
399+
}).toErrorDev([
408400
'Cannot render <template> outside the main document. Try moving it into the root <head> tag.',
409401
'Warning: validateDOMNesting(...): <template> cannot appear as a child of <html>.',
410402
]);
411403

412-
renderSafelyAndExpect(
413-
root,
414-
<html>
415-
<body>foo</body>
416-
<style>foo</style>
417-
</html>,
418-
).toErrorDev([
404+
await expect(async () => {
405+
root.render(
406+
<html>
407+
<body>foo</body>
408+
<style>foo</style>
409+
</html>,
410+
);
411+
await waitForAll([]);
412+
}).toErrorDev([
419413
'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.',
420414
'Warning: validateDOMNesting(...): <style> cannot appear as a child of <html>.',
421415
]);
422416

423-
renderSafelyAndExpect(
424-
root,
425-
<>
426-
<html>
427-
<body>foo</body>
428-
</html>
429-
<link rel="stylesheet" href="foo" />
430-
</>,
431-
).toErrorDev(
417+
await expect(async () => {
418+
root.render(
419+
<>
420+
<html>
421+
<body>foo</body>
422+
</html>
423+
<link rel="stylesheet" href="foo" />
424+
</>,
425+
);
426+
const aggregateError = await waitForThrow();
427+
expect(aggregateError.errors.length).toBe(2);
428+
expect(aggregateError.errors[0].message).toContain(
429+
'Invalid insertion of LINK',
430+
);
431+
expect(aggregateError.errors[1].message).toContain(
432+
'The node to be removed is not a child of this node',
433+
);
434+
}).toErrorDev(
432435
[
433436
'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.',
434437
'Warning: validateDOMNesting(...): <link> cannot appear as a child of <#document>.',
435438
],
436439
{withoutStack: 1},
437440
);
438441

439-
renderSafelyAndExpect(
440-
root,
441-
<>
442-
<html>
443-
<body>foo</body>
444-
<script href="foo" />
445-
</html>
446-
</>,
447-
).toErrorDev([
442+
await expect(async () => {
443+
root.render(
444+
<>
445+
<html>
446+
<body>foo</body>
447+
<script href="foo" />
448+
</html>
449+
</>,
450+
);
451+
await waitForAll([]);
452+
}).toErrorDev([
448453
'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.',
449454
'Warning: validateDOMNesting(...): <script> cannot appear as a child of <html>.',
450455
]);
451456

452-
renderSafelyAndExpect(
453-
root,
454-
<>
457+
await expect(async () => {
458+
root.render(
455459
<html>
456460
<script async={true} onLoad={() => {}} href="bar" />
457461
<body>foo</body>
458-
</html>
459-
</>,
460-
).toErrorDev([
462+
</html>,
463+
);
464+
await waitForAll([]);
465+
}).toErrorDev([
461466
'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>.',
462467
]);
463468

464-
renderSafelyAndExpect(
465-
root,
466-
<>
467-
<link rel="foo" onLoad={() => {}} href="bar" />
468-
<html>
469-
<body>foo</body>
470-
</html>
471-
</>,
472-
).toErrorDev(
469+
await expect(async () => {
470+
root.render(
471+
<>
472+
<link rel="foo" onLoad={() => {}} href="bar" />
473+
<html>
474+
<body>foo</body>
475+
</html>
476+
</>,
477+
);
478+
const aggregateError = await waitForThrow();
479+
expect(aggregateError.errors.length).toBe(2);
480+
expect(aggregateError.errors[0].message).toContain(
481+
'Invalid insertion of LINK',
482+
);
483+
expect(aggregateError.errors[1].message).toContain(
484+
'The node to be removed is not a child of this node',
485+
);
486+
}).toErrorDev(
473487
[
474488
'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>.',
475489
],
@@ -5638,22 +5652,16 @@ background-color: green;
56385652
},
56395653
},
56405654
);
5641-
try {
5642-
await expect(async () => {
5643-
await waitForAll([]);
5644-
}).toErrorDev(
5645-
[
5646-
'Warning: Text content did not match. Server: "server" Client: "client"',
5647-
'Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.',
5648-
],
5649-
{withoutStack: 1},
5650-
);
5651-
} catch (e) {
5652-
// When gates are false this test fails on a DOMException if you don't clear the scheduler after catching.
5653-
// When gates are true this branch should not be hit
5655+
5656+
await expect(async () => {
56545657
await waitForAll([]);
5655-
throw e;
5656-
}
5658+
}).toErrorDev(
5659+
[
5660+
'Warning: Text content did not match. Server: "server" Client: "client"',
5661+
'Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.',
5662+
],
5663+
{withoutStack: 1},
5664+
);
56575665
expect(getMeaningfulChildren(document)).toEqual(
56585666
<html>
56595667
<head>

0 commit comments

Comments
 (0)