19
tags = [...tags];
20
warnings = [...warnings];
21
22
+ document.removeChild(document.documentElement);
23
+ document.appendChild(document.createElement('html'));
24
+ document.documentElement.innerHTML = '<head></head><body></body>';
25
+
26
let element = null;
27
const containerTag = tags.shift();
24
- const container =
25
- containerTag === 'svg'
26
- ? document.createElementNS('http://www.w3.org/2000/svg', containerTag)
27
- : document.createElement(containerTag);
28
+ let container;
29
+ switch (containerTag) {
30
+ case '#document':
31
+ container = document;
32
+ break;
33
+ case 'html':
34
+ container = document.documentElement;
35
+ break;
36
+ case 'body':
37
+ container = document.body;
38
+ break;
39
+ case 'head':
40
+ container = document.head;
41
+ break;
42
+ case 'svg':
43
+ container = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
44
+ break;
45
+ default:
46
+ container = document.createElement(containerTag);
47
+ break;
48
+ }
49
50
while (tags.length) {
51
const Tag = tags.pop();
31
- element = <Tag>{element}</Tag>;
52
+ if (Tag === '#text') {
53
+ element = 'text';
54
+ } else {
55
+ element = <Tag>{element}</Tag>;
56
+ }
57
}
58
59
const root = ReactDOMClient.createRoot(container);
60
+ ReactDOM.flushSync(() => {
61
+ root.render(element);
62
+ });
63
if (warnings.length) {
36
- ReactDOM.flushSync(() => {
37
- root.render(element);
38
- });
64
assertConsoleErrorDev(
65
warnings,
66
withoutStack > 0 ? {withoutStack} : undefined,
67
);
68
}
69
+ root.unmount();
70
}
71
72
describe('validateDOMNesting', () => {
166
' in body (at **)',
167
],
168
);
169
+ expectWarnings(
170
+ ['head', 'body'],
171
+ [
172
+ 'In HTML, <body> cannot be a child of <head>.\n' +
173
+ 'This will cause a hydration error.\n' +
174
+ ' in body (at **)',
175
+ ],
176
+ );
177
+ expectWarnings(
178
+ ['head', 'head'],
179
+ [
180
+ 'In HTML, <head> cannot be a child of <head>.\n' +
181
+ 'This will cause a hydration error.\n' +
182
+ ' in head (at **)',
183
+ ],
184
+ );
185
+ expectWarnings(
186
+ ['html', 'html'],
187
+ [
188
+ 'In HTML, <html> cannot be a child of <html>.\n' +
189
+ 'This will cause a hydration error.\n' +
190
+ ' in html (at **)',
191
+ ],
192
+ );
193
+ expectWarnings(
194
+ ['body', 'html'],
195
+ [
196
+ 'In HTML, <html> cannot be a child of <body>.\n' +
197
+ 'This will cause a hydration error.\n' +
198
+ ' in html (at **)',
199
+ ],
200
+ );
201
+ expectWarnings(
202
+ ['head', 'html'],
203
+ [
204
+ 'In HTML, <html> cannot be a child of <head>.\n' +
205
+ 'This will cause a hydration error.\n' +
206
+ ' in html (at **)',
207
+ ],
208
+ );
209
expectWarnings(
210
['svg', 'foreignObject', 'body', 'p'],
211
gate(flags => flags.enableOwnerStacks)
218
'> <body>\n' +
219
'\n' +
220
' in body (at **)',
155
- 'You are mounting a new body component when a previous one has not first unmounted. It is an error to render more than one body component at a time and attributes and children of these components will likely fail in unpredictable ways. Please only render a single instance of <body> and if you need to mount a new one, ensure any previous ones have unmounted first.\n' +
156
- ' in body (at **)',
221
]
222
: [
223
// TODO, this should say "In SVG",
229
'\n' +
230
' in body (at **)\n' +
231
' in foreignObject (at **)',
168
- 'You are mounting a new body component when a previous one has not first unmounted. It is an error to render more than one body component at a time and attributes and children of these components will likely fail in unpredictable ways. Please only render a single instance of <body> and if you need to mount a new one, ensure any previous ones have unmounted first.\n' +
169
- ' in body (at **)\n' +
170
- ' in foreignObject (at **)',
232
],
233
);
234
});
235
+
236
+ it('relaxes the nesting rules at the root when the container is a singleton', () => {
237
+ expectWarnings(['#document', 'html']);
238
+ expectWarnings(['#document', 'body']);
239
+ expectWarnings(['#document', 'head']);
240
+ expectWarnings(['#document', 'div']);
241
+ expectWarnings(['#document', 'meta']);
242
+ expectWarnings(['#document', '#text']);
243
+ expectWarnings(['html', 'body']);
244
+ expectWarnings(['html', 'head']);
245
+ expectWarnings(['html', 'div']);
246
+ expectWarnings(['html', 'meta']);
247
+ expectWarnings(['html', '#text']);
248
+ expectWarnings(['body', 'head']);
249
+ expectWarnings(['body', 'div']);
250
+ expectWarnings(['body', 'meta']);
251
+ expectWarnings(['body', '#text']);
252
+ });
253
});