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

Lines changed: 9 additions & 3 deletions
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

Lines changed: 100 additions & 92 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy