Skip to content

Commit 9aef5d2

Browse files
authored
Use modern rendering APIs for attribute-behavior fixture (#27883)
The attribute-behavior fixture now uses `createRoot().render()` and `renderToReadableStream` instead of depdrecated APIs. This revealed some changes to the snapshots that I annotated for discussion. I also added some new tests related to upcoming changes for easier future diffing. Also adds support for running the attribute-behavior fixture using Apple Silicon chips (Apple MBP M-series).
1 parent 60f190a commit 9aef5d2

File tree

6 files changed

+180
-203
lines changed

6 files changed

+180
-203
lines changed

fixtures/attribute-behavior/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/build
1111
/public/react.development.js
1212
/public/react-dom.development.js
13-
/public/react-dom-server-legacy.browser.development.js
13+
/public/react-dom-server.browser.development.js
1414

1515
# misc
1616
.DS_Store

fixtures/attribute-behavior/AttributeTableSnapshot.md

+91-41
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@
294294
| `action=(string 'on')`| (changed)| `"http://localhost:3000/on"` |
295295
| `action=(string 'off')`| (changed)| `"http://localhost:3000/off"` |
296296
| `action=(symbol)`| (initial, warning)| `"http://localhost:3000/"` |
297-
| `action=(function)`| (initial, warning)| `"http://localhost:3000/"` |
297+
| `action=(function)`| (changed, ssr error, ssr mismatch)| `"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')"` |
298298
| `action=(null)`| (initial)| `"http://localhost:3000/"` |
299299
| `action=(undefined)`| (initial)| `"http://localhost:3000/"` |
300300

@@ -648,6 +648,31 @@
648648
| `aria-=(null)`| (initial, warning)| `<null>` |
649649
| `aria-=(undefined)`| (initial, warning)| `<null>` |
650650

651+
## `aria-hidden` (on `<div>` inside `<div>`)
652+
| Test Case | Flags | Result |
653+
| --- | --- | --- |
654+
| `aria-hidden=(string)`| (changed)| `"a string"` |
655+
| `aria-hidden=(empty string)`| (changed)| `<empty string>` |
656+
| `aria-hidden=(array with string)`| (changed)| `"string"` |
657+
| `aria-hidden=(empty array)`| (changed)| `<empty string>` |
658+
| `aria-hidden=(object)`| (changed)| `"result of toString()"` |
659+
| `aria-hidden=(numeric string)`| (changed)| `"42"` |
660+
| `aria-hidden=(-1)`| (changed)| `"-1"` |
661+
| `aria-hidden=(0)`| (changed)| `"0"` |
662+
| `aria-hidden=(integer)`| (changed)| `"1"` |
663+
| `aria-hidden=(NaN)`| (changed)| `"NaN"` |
664+
| `aria-hidden=(float)`| (changed)| `"99.99"` |
665+
| `aria-hidden=(true)`| (changed)| `"true"` |
666+
| `aria-hidden=(false)`| (changed)| `"false"` |
667+
| `aria-hidden=(string 'true')`| (changed)| `"true"` |
668+
| `aria-hidden=(string 'false')`| (changed)| `"false"` |
669+
| `aria-hidden=(string 'on')`| (changed)| `"on"` |
670+
| `aria-hidden=(string 'off')`| (changed)| `"off"` |
671+
| `aria-hidden=(symbol)`| (initial)| `<null>` |
672+
| `aria-hidden=(function)`| (initial)| `<null>` |
673+
| `aria-hidden=(null)`| (initial)| `<null>` |
674+
| `aria-hidden=(undefined)`| (initial)| `<null>` |
675+
651676
## `aria-invalidattribute` (on `<div>` inside `<div>`)
652677
| Test Case | Flags | Result |
653678
| --- | --- | --- |
@@ -2568,8 +2593,8 @@
25682593
| `defaultChecked=(string 'false')`| (changed)| `<boolean: true>` |
25692594
| `defaultChecked=(string 'on')`| (changed)| `<boolean: true>` |
25702595
| `defaultChecked=(string 'off')`| (changed)| `<boolean: true>` |
2571-
| `defaultChecked=(symbol)`| (changed, ssr mismatch)| `<boolean: true>` |
2572-
| `defaultChecked=(function)`| (changed, ssr mismatch)| `<boolean: true>` |
2596+
| `defaultChecked=(symbol)`| (initial)| `<boolean: false>` |
2597+
| `defaultChecked=(function)`| (initial)| `<boolean: false>` |
25732598
| `defaultChecked=(null)`| (initial)| `<boolean: false>` |
25742599
| `defaultChecked=(undefined)`| (initial)| `<boolean: false>` |
25752600

@@ -4176,25 +4201,25 @@
41764201
## `formAction` (on `<input>` inside `<div>`)
41774202
| Test Case | Flags | Result |
41784203
| --- | --- | --- |
4179-
| `formAction=(string)`| (changed)| `"https://reactjs.com/"` |
4180-
| `formAction=(empty string)`| (initial)| `"http://localhost:3000/"` |
4181-
| `formAction=(array with string)`| (changed)| `"https://reactjs.com/"` |
4182-
| `formAction=(empty array)`| (initial)| `"http://localhost:3000/"` |
4183-
| `formAction=(object)`| (changed)| `"http://localhost:3000/result%20of%20toString()"` |
4184-
| `formAction=(numeric string)`| (changed)| `"http://localhost:3000/42"` |
4185-
| `formAction=(-1)`| (changed)| `"http://localhost:3000/-1"` |
4186-
| `formAction=(0)`| (changed)| `"http://localhost:3000/0"` |
4187-
| `formAction=(integer)`| (changed)| `"http://localhost:3000/1"` |
4204+
| `formAction=(string)`| (changed, warning)| `"https://reactjs.com/"` |
4205+
| `formAction=(empty string)`| (initial, warning)| `"http://localhost:3000/"` |
4206+
| `formAction=(array with string)`| (changed, warning)| `"https://reactjs.com/"` |
4207+
| `formAction=(empty array)`| (initial, warning)| `"http://localhost:3000/"` |
4208+
| `formAction=(object)`| (changed, warning)| `"http://localhost:3000/result%20of%20toString()"` |
4209+
| `formAction=(numeric string)`| (changed, warning)| `"http://localhost:3000/42"` |
4210+
| `formAction=(-1)`| (changed, warning)| `"http://localhost:3000/-1"` |
4211+
| `formAction=(0)`| (changed, warning)| `"http://localhost:3000/0"` |
4212+
| `formAction=(integer)`| (changed, warning)| `"http://localhost:3000/1"` |
41884213
| `formAction=(NaN)`| (changed, warning)| `"http://localhost:3000/NaN"` |
4189-
| `formAction=(float)`| (changed)| `"http://localhost:3000/99.99"` |
4214+
| `formAction=(float)`| (changed, warning)| `"http://localhost:3000/99.99"` |
41904215
| `formAction=(true)`| (initial, warning)| `"http://localhost:3000/"` |
41914216
| `formAction=(false)`| (initial, warning)| `"http://localhost:3000/"` |
4192-
| `formAction=(string 'true')`| (changed)| `"http://localhost:3000/true"` |
4193-
| `formAction=(string 'false')`| (changed)| `"http://localhost:3000/false"` |
4194-
| `formAction=(string 'on')`| (changed)| `"http://localhost:3000/on"` |
4195-
| `formAction=(string 'off')`| (changed)| `"http://localhost:3000/off"` |
4217+
| `formAction=(string 'true')`| (changed, warning)| `"http://localhost:3000/true"` |
4218+
| `formAction=(string 'false')`| (changed, warning)| `"http://localhost:3000/false"` |
4219+
| `formAction=(string 'on')`| (changed, warning)| `"http://localhost:3000/on"` |
4220+
| `formAction=(string 'off')`| (changed, warning)| `"http://localhost:3000/off"` |
41964221
| `formAction=(symbol)`| (initial, warning)| `"http://localhost:3000/"` |
4197-
| `formAction=(function)`| (initial, warning)| `"http://localhost:3000/"` |
4222+
| `formAction=(function)`| (changed, warning, ssr error, ssr mismatch)| `"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')"` |
41984223
| `formAction=(null)`| (initial)| `"http://localhost:3000/"` |
41994224
| `formAction=(undefined)`| (initial)| `"http://localhost:3000/"` |
42004225

@@ -5052,7 +5077,7 @@
50525077
| Test Case | Flags | Result |
50535078
| --- | --- | --- |
50545079
| `href=(string)`| (changed)| `"https://reactjs.com/"` |
5055-
| `href=(empty string)`| (changed)| `"http://localhost:3000/"` |
5080+
| `href=(empty string)`| (initial, warning)| `<empty string>` |
50565081
| `href=(array with string)`| (changed)| `"https://reactjs.com/"` |
50575082
| `href=(empty array)`| (changed)| `"http://localhost:3000/"` |
50585083
| `href=(object)`| (changed)| `"http://localhost:3000/result%20of%20toString()"` |
@@ -5398,6 +5423,31 @@
53985423
| `in=(null)`| (initial)| `<null>` |
53995424
| `in=(undefined)`| (initial)| `<null>` |
54005425

5426+
## `inert` (on `<div>` inside `<div>`)
5427+
| Test Case | Flags | Result |
5428+
| --- | --- | --- |
5429+
| `inert=(string)`| (changed)| `<boolean: true>` |
5430+
| `inert=(empty string)`| (changed)| `<boolean: true>` |
5431+
| `inert=(array with string)`| (changed)| `<boolean: true>` |
5432+
| `inert=(empty array)`| (changed)| `<boolean: true>` |
5433+
| `inert=(object)`| (changed)| `<boolean: true>` |
5434+
| `inert=(numeric string)`| (changed)| `<boolean: true>` |
5435+
| `inert=(-1)`| (changed)| `<boolean: true>` |
5436+
| `inert=(0)`| (changed)| `<boolean: true>` |
5437+
| `inert=(integer)`| (changed)| `<boolean: true>` |
5438+
| `inert=(NaN)`| (changed, warning)| `<boolean: true>` |
5439+
| `inert=(float)`| (changed)| `<boolean: true>` |
5440+
| `inert=(true)`| (initial, warning)| `<boolean: false>` |
5441+
| `inert=(false)`| (initial, warning)| `<boolean: false>` |
5442+
| `inert=(string 'true')`| (changed)| `<boolean: true>` |
5443+
| `inert=(string 'false')`| (changed)| `<boolean: true>` |
5444+
| `inert=(string 'on')`| (changed)| `<boolean: true>` |
5445+
| `inert=(string 'off')`| (changed)| `<boolean: true>` |
5446+
| `inert=(symbol)`| (initial, warning)| `<boolean: false>` |
5447+
| `inert=(function)`| (initial, warning)| `<boolean: false>` |
5448+
| `inert=(null)`| (initial)| `<boolean: false>` |
5449+
| `inert=(undefined)`| (initial)| `<boolean: false>` |
5450+
54015451
## `in2` (on `<feBlend>` inside `<svg>`)
54025452
| Test Case | Flags | Result |
54035453
| --- | --- | --- |
@@ -5501,27 +5551,27 @@
55015551
## `inputMode` (on `<input>` inside `<div>`)
55025552
| Test Case | Flags | Result |
55035553
| --- | --- | --- |
5504-
| `inputMode=(string)`| (changed)| `"a string"` |
5505-
| `inputMode=(empty string)`| (changed)| `<empty string>` |
5506-
| `inputMode=(array with string)`| (changed)| `"string"` |
5507-
| `inputMode=(empty array)`| (changed)| `<empty string>` |
5508-
| `inputMode=(object)`| (changed)| `"result of toString()"` |
5509-
| `inputMode=(numeric string)`| (changed)| `"42"` |
5510-
| `inputMode=(-1)`| (changed)| `"-1"` |
5511-
| `inputMode=(0)`| (changed)| `"0"` |
5512-
| `inputMode=(integer)`| (changed)| `"1"` |
5513-
| `inputMode=(NaN)`| (changed, warning)| `"NaN"` |
5514-
| `inputMode=(float)`| (changed)| `"99.99"` |
5515-
| `inputMode=(true)`| (initial, warning)| `<null>` |
5516-
| `inputMode=(false)`| (initial, warning)| `<null>` |
5517-
| `inputMode=(string 'true')`| (changed)| `"true"` |
5518-
| `inputMode=(string 'false')`| (changed)| `"false"` |
5519-
| `inputMode=(string 'on')`| (changed)| `"on"` |
5520-
| `inputMode=(string 'off')`| (changed)| `"off"` |
5521-
| `inputMode=(symbol)`| (initial, warning)| `<null>` |
5522-
| `inputMode=(function)`| (initial, warning)| `<null>` |
5523-
| `inputMode=(null)`| (initial)| `<null>` |
5524-
| `inputMode=(undefined)`| (initial)| `<null>` |
5554+
| `inputMode=(string)`| (initial)| `<empty string>` |
5555+
| `inputMode=(empty string)`| (initial)| `<empty string>` |
5556+
| `inputMode=(array with string)`| (initial)| `<empty string>` |
5557+
| `inputMode=(empty array)`| (initial)| `<empty string>` |
5558+
| `inputMode=(object)`| (initial)| `<empty string>` |
5559+
| `inputMode=(numeric string)`| (initial)| `<empty string>` |
5560+
| `inputMode=(-1)`| (initial)| `<empty string>` |
5561+
| `inputMode=(0)`| (initial)| `<empty string>` |
5562+
| `inputMode=(integer)`| (initial)| `<empty string>` |
5563+
| `inputMode=(NaN)`| (initial, warning)| `<empty string>` |
5564+
| `inputMode=(float)`| (initial)| `<empty string>` |
5565+
| `inputMode=(true)`| (initial, warning)| `<empty string>` |
5566+
| `inputMode=(false)`| (initial, warning)| `<empty string>` |
5567+
| `inputMode=(string 'true')`| (initial)| `<empty string>` |
5568+
| `inputMode=(string 'false')`| (initial)| `<empty string>` |
5569+
| `inputMode=(string 'on')`| (initial)| `<empty string>` |
5570+
| `inputMode=(string 'off')`| (initial)| `<empty string>` |
5571+
| `inputMode=(symbol)`| (initial, warning)| `<empty string>` |
5572+
| `inputMode=(function)`| (initial, warning)| `<empty string>` |
5573+
| `inputMode=(null)`| (initial)| `<empty string>` |
5574+
| `inputMode=(undefined)`| (initial)| `<empty string>` |
55255575

55265576
## `integrity` (on `<script>` inside `<div>`)
55275577
| Test Case | Flags | Result |
@@ -9877,7 +9927,7 @@
98779927
| Test Case | Flags | Result |
98789928
| --- | --- | --- |
98799929
| `src=(string)`| (changed)| `"https://reactjs.com/"` |
9880-
| `src=(empty string)`| (changed)| `"http://localhost:3000/"` |
9930+
| `src=(empty string)`| (initial, warning)| `<empty string>` |
98819931
| `src=(array with string)`| (changed)| `"https://reactjs.com/"` |
98829932
| `src=(empty array)`| (changed)| `"http://localhost:3000/"` |
98839933
| `src=(object)`| (changed)| `"http://localhost:3000/result%20of%20toString()"` |

fixtures/attribute-behavior/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
"react-scripts": "1.0.11",
1111
"react-virtualized": "^9.9.0"
1212
},
13+
"resolutions": {
14+
"fsevents": "1.2.13"
15+
},
1316
"scripts": {
1417
"predev":
15-
"cp ../../build/oss-experimental/react/umd/react.development.js public/ && cp ../../build/oss-experimental/react-dom/umd/react-dom.development.js public/ && cp ../../build/oss-experimental/react-dom/umd/react-dom-server-legacy.browser.development.js public/",
18+
"cp ../../build/oss-experimental/react/umd/react.development.js public/ && cp ../../build/oss-experimental/react-dom/umd/react-dom.development.js public/ && cp ../../build/oss-experimental/react-dom/umd/react-dom-server.browser.development.js public/",
1619
"dev": "react-scripts start",
1720
"build": "react-scripts build",
1821
"test": "react-scripts test --env=jsdom",

fixtures/attribute-behavior/src/App.js

+50-18
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,32 @@ function getCanonicalizedValue(value) {
213213

214214
let _didWarn = false;
215215
function warn(str) {
216-
if (str.includes('ReactDOM.render is no longer supported')) {
217-
return;
218-
}
219216
_didWarn = true;
220217
}
218+
219+
/**
220+
* @param {import('react-dom/server')} serverRenderer
221+
*/
222+
async function renderToString(serverRenderer, element) {
223+
let didError = false;
224+
const stream = await serverRenderer.renderToReadableStream(element, {
225+
onError(error) {
226+
didError = true;
227+
console.error(error);
228+
},
229+
});
230+
await stream.allReady;
231+
232+
if (didError) {
233+
throw new Error('The above error occurred while rendering to string.');
234+
}
235+
236+
const response = new Response(stream);
237+
return response.text();
238+
}
239+
221240
const UNKNOWN_HTML_TAGS = new Set(['keygen', 'time', 'command']);
222-
function getRenderedAttributeValue(
241+
async function getRenderedAttributeValue(
223242
react,
224243
renderer,
225244
serverRenderer,
@@ -283,12 +302,21 @@ function getRenderedAttributeValue(
283302
_didWarn = false;
284303
try {
285304
let container = createContainer();
286-
renderer.render(react.createElement(tagName, baseProps), container);
305+
renderer.flushSync(() => {
306+
renderer
307+
.createRoot(container)
308+
.render(react.createElement(tagName, baseProps));
309+
});
287310
defaultValue = read(container.lastChild);
288311
canonicalDefaultValue = getCanonicalizedValue(defaultValue);
289312

290313
container = createContainer();
291-
renderer.render(react.createElement(tagName, props), container);
314+
315+
renderer.flushSync(() => {
316+
renderer
317+
.createRoot(container)
318+
.render(react.createElement(tagName, props));
319+
});
292320
result = read(container.lastChild);
293321
canonicalResult = getCanonicalizedValue(result);
294322
didWarn = _didWarn;
@@ -305,19 +333,22 @@ function getRenderedAttributeValue(
305333
try {
306334
let container;
307335
if (containerTagName === 'document') {
308-
const html = serverRenderer.renderToString(
336+
const html = await renderToString(
337+
serverRenderer,
309338
react.createElement(tagName, props)
310339
);
311340
container = createContainer();
312341
container.innerHTML = html;
313342
} else if (containerTagName === 'head') {
314-
const html = serverRenderer.renderToString(
343+
const html = await renderToString(
344+
serverRenderer,
315345
react.createElement(tagName, props)
316346
);
317347
container = createContainer();
318348
container.innerHTML = html;
319349
} else {
320-
const html = serverRenderer.renderToString(
350+
const html = await renderToString(
351+
serverRenderer,
321352
react.createElement(
322353
containerTagName,
323354
null,
@@ -326,7 +357,8 @@ function getRenderedAttributeValue(
326357
);
327358
const outerContainer = document.createElement('div');
328359
outerContainer.innerHTML = html;
329-
container = outerContainer.firstChild;
360+
// Float may prepend `<link />`
361+
container = outerContainer.lastChild;
330362
}
331363

332364
if (
@@ -396,8 +428,8 @@ function getRenderedAttributeValue(
396428
};
397429
}
398430

399-
function prepareState(initGlobals) {
400-
function getRenderedAttributeValues(attribute, type) {
431+
async function prepareState(initGlobals) {
432+
async function getRenderedAttributeValues(attribute, type) {
401433
const {
402434
ReactStable,
403435
ReactDOMStable,
@@ -406,14 +438,14 @@ function prepareState(initGlobals) {
406438
ReactDOMNext,
407439
ReactDOMServerNext,
408440
} = initGlobals(attribute, type);
409-
const reactStableValue = getRenderedAttributeValue(
441+
const reactStableValue = await getRenderedAttributeValue(
410442
ReactStable,
411443
ReactDOMStable,
412444
ReactDOMServerStable,
413445
attribute,
414446
type
415447
);
416-
const reactNextValue = getRenderedAttributeValue(
448+
const reactNextValue = await getRenderedAttributeValue(
417449
ReactNext,
418450
ReactDOMNext,
419451
ReactDOMServerNext,
@@ -451,7 +483,7 @@ function prepareState(initGlobals) {
451483
let hasSameBehaviorForAll = true;
452484
let rowPatternHash = '';
453485
for (let type of types) {
454-
const result = getRenderedAttributeValues(attribute, type);
486+
const result = await getRenderedAttributeValues(attribute, type);
455487
results.set(type.name, result);
456488
if (!result.hasSameBehavior) {
457489
hasSameBehaviorForAll = false;
@@ -772,10 +804,10 @@ class App extends React.Component {
772804
ReactDOMStable:
773805
'https://unpkg.com/react-dom@latest/umd/react-dom.development.js',
774806
ReactDOMServerStable:
775-
'https://unpkg.com/react-dom@latest/umd/react-dom-server-legacy.browser.development.js',
807+
'https://unpkg.com/react-dom@latest/umd/react-dom-server.browser.development.js',
776808
ReactNext: '/react.development.js',
777809
ReactDOMNext: '/react-dom.development.js',
778-
ReactDOMServerNext: '/react-dom-server-legacy.browser.development.js',
810+
ReactDOMServerNext: '/react-dom-server.browser.development.js',
779811
};
780812
const codePromises = Object.values(sources).map(src =>
781813
fetch(src).then(res => res.text())
@@ -820,7 +852,7 @@ class App extends React.Component {
820852
return globals;
821853
}
822854

823-
const {table, rowPatternHashes} = prepareState(initGlobals);
855+
const {table, rowPatternHashes} = await prepareState(initGlobals);
824856
document.title = 'Ready';
825857

826858
this.setState({

0 commit comments

Comments
 (0)