Adding SSR test for form fields.
Sasha Aickin committed
Mar 26, 2017 at 20:51 UTC
14863c9a8722281b6bf1d0d9fc7b95b44e189354
4 files changed
+670
-15
scripts/fiber/tests-failing.txt
+36
@@ -102,6 +102,42 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
102
* renders >,<, and & as single child with client render on top of good server markup
103
* renders >,<, and & as multiple children with server string render
104
* renders >,<, and & as multiple children with client render on top of good server markup
105
+* renders an input with a value and an onChange with client render on top of good server markup
106
+* renders an input with a value and readOnly with client render on top of good server markup
107
+* renders an input with a value and no onChange/readOnly with client render on top of good server markup
108
+* renders an input with a defaultValue with client render on top of good server markup
109
+* renders an input value overriding defaultValue with client render on top of good server markup
110
+* renders an input value overriding defaultValue no matter the prop order with client render on top of good server markup
111
+* renders a checkbox that is checked with an onChange with client render on top of good server markup
112
+* renders a checkbox that is checked with readOnly with client render on top of good server markup
113
+* renders a checkbox that is checked and no onChange/readOnly with client render on top of good server markup
114
+* renders a checkbox with defaultChecked with client render on top of good server markup
115
+* renders a checkbox checked overriding defaultChecked with client render on top of good server markup
116
+* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of good server markup
117
+* renders a textarea with a value and an onChange with client render on top of good server markup
118
+* renders a textarea with a value and readOnly with client render on top of good server markup
119
+* renders a textarea with a value and no onChange/readOnly with client render on top of good server markup
120
+* renders a textarea with a defaultValue with client render on top of good server markup
121
+* renders a textarea value overriding defaultValue with client render on top of good server markup
122
+* renders a textarea value overriding defaultValue no matter the prop order with client render on top of good server markup
123
+* renders a select with a value and an onChange with client render on top of good server markup
124
+* renders a select with a value and readOnly with client render on top of good server markup
125
+* renders a select with a multiple values and an onChange with client render on top of good server markup
126
+* renders a select with a multiple values and readOnly with client render on top of good server markup
127
+* renders a select with a value and no onChange/readOnly with client render on top of good server markup
128
+* renders a select with a defaultValue with client render on top of good server markup
129
+* renders a select value overriding defaultValue with client render on top of good server markup
130
+* renders a select value overriding defaultValue no matter the prop order with client render on top of good server markup
131
+* renders a controlled text input with client render on top of good server markup
132
+* renders a controlled textarea with client render on top of good server markup
133
+* renders a controlled checkbox with client render on top of good server markup
134
+* renders a controlled select with client render on top of good server markup
135
+* should not blow away user-entered text on successful reconnect to an uncontrolled input
136
+* should not blow away user-entered text on successful reconnect to a controlled input
137
+* should not blow away user-entered text on successful reconnect to an uncontrolled checkbox
138
+* should not blow away user-entered text on successful reconnect to a controlled checkbox
139
+* should not blow away user-selected value on successful reconnect to an uncontrolled select
140
+* should not blow away user-selected value on successful reconnect to an controlled select
141
* renders class child with context with client render on top of good server markup
142
* renders stateless child with context with client render on top of good server markup
143
* renders class child without context with client render on top of good server markup
scripts/fiber/tests-passing-except-dev.txt
+30
@@ -95,6 +95,36 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
95
* throws when rendering an undefined component with client render on top of bad server markup
96
* throws when rendering a number component with clean client render
97
* throws when rendering a number component with client render on top of bad server markup
98
+* renders an input with a value and an onChange with client render on top of bad server markup
99
+* renders an input with a value and readOnly with client render on top of bad server markup
100
+* renders an input with a value and no onChange/readOnly with client render on top of bad server markup
101
+* renders an input with a defaultValue with client render on top of bad server markup
102
+* renders an input value overriding defaultValue with client render on top of bad server markup
103
+* renders an input value overriding defaultValue no matter the prop order with client render on top of bad server markup
104
+* renders a checkbox that is checked with an onChange with client render on top of bad server markup
105
+* renders a checkbox that is checked with readOnly with client render on top of bad server markup
106
+* renders a checkbox that is checked and no onChange/readOnly with client render on top of bad server markup
107
+* renders a checkbox with defaultChecked with client render on top of bad server markup
108
+* renders a checkbox checked overriding defaultChecked with client render on top of bad server markup
109
+* renders a checkbox checked overriding defaultChecked no matter the prop order with client render on top of bad server markup
110
+* renders a textarea with a value and an onChange with client render on top of bad server markup
111
+* renders a textarea with a value and readOnly with client render on top of bad server markup
112
+* renders a textarea with a value and no onChange/readOnly with client render on top of bad server markup
113
+* renders a textarea with a defaultValue with client render on top of bad server markup
114
+* renders a textarea value overriding defaultValue with client render on top of bad server markup
115
+* renders a textarea value overriding defaultValue no matter the prop order with client render on top of bad server markup
116
+* renders a select with a value and an onChange with client render on top of bad server markup
117
+* renders a select with a value and readOnly with client render on top of bad server markup
118
+* renders a select with a multiple values and an onChange with client render on top of bad server markup
119
+* renders a select with a multiple values and readOnly with client render on top of bad server markup
120
+* renders a select with a value and no onChange/readOnly with client render on top of bad server markup
121
+* renders a select with a defaultValue with client render on top of bad server markup
122
+* renders a select value overriding defaultValue with client render on top of bad server markup
123
+* renders a select value overriding defaultValue no matter the prop order with client render on top of bad server markup
124
+* renders a controlled text input with client render on top of bad server markup
125
+* renders a controlled textarea with client render on top of bad server markup
126
+* renders a controlled checkbox with client render on top of bad server markup
127
+* renders a controlled select with client render on top of bad server markup
128
* renders class child with context with client render on top of bad server markup
129
* renders stateless child with context with client render on top of bad server markup
130
* renders class child without context with client render on top of bad server markup
scripts/fiber/tests-passing.txt
+56
-1
@@ -1154,6 +1154,62 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
1154
* throws when rendering string with server string render
1155
* throws when rendering string with clean client render
1156
* throws when rendering string with client render on top of bad server markup
1157
+* renders an input with a value and an onChange with server string render
1158
+* renders an input with a value and an onChange with clean client render
1159
+* renders an input with a value and readOnly with server string render
1160
+* renders an input with a value and readOnly with clean client render
1161
+* renders an input with a value and no onChange/readOnly with server string render
1162
+* renders an input with a value and no onChange/readOnly with clean client render
1163
+* renders an input with a defaultValue with server string render
1164
+* renders an input with a defaultValue with clean client render
1165
+* renders an input value overriding defaultValue with server string render
1166
+* renders an input value overriding defaultValue with clean client render
1167
+* renders an input value overriding defaultValue no matter the prop order with server string render
1168
+* renders an input value overriding defaultValue no matter the prop order with clean client render
1169
+* renders a checkbox that is checked with an onChange with server string render
1170
+* renders a checkbox that is checked with an onChange with clean client render
1171
+* renders a checkbox that is checked with readOnly with server string render
1172
+* renders a checkbox that is checked with readOnly with clean client render
1173
+* renders a checkbox that is checked and no onChange/readOnly with server string render
1174
+* renders a checkbox that is checked and no onChange/readOnly with clean client render
1175
+* renders a checkbox with defaultChecked with server string render
1176
+* renders a checkbox with defaultChecked with clean client render
1177
+* renders a checkbox checked overriding defaultChecked with server string render
1178
+* renders a checkbox checked overriding defaultChecked with clean client render
1179
+* renders a checkbox checked overriding defaultChecked no matter the prop order with server string render
1180
+* renders a checkbox checked overriding defaultChecked no matter the prop order with clean client render
1181
+* renders a textarea with a value and an onChange with server string render
1182
+* renders a textarea with a value and an onChange with clean client render
1183
+* renders a textarea with a value and readOnly with server string render
1184
+* renders a textarea with a value and readOnly with clean client render
1185
+* renders a textarea with a value and no onChange/readOnly with server string render
1186
+* renders a textarea with a value and no onChange/readOnly with clean client render
1187
+* renders a textarea with a defaultValue with server string render
1188
+* renders a textarea with a defaultValue with clean client render
1189
+* renders a textarea value overriding defaultValue with server string render
1190
+* renders a textarea value overriding defaultValue with clean client render
1191
+* renders a textarea value overriding defaultValue no matter the prop order with server string render
1192
+* renders a textarea value overriding defaultValue no matter the prop order with clean client render
1193
+* renders a select with a value and an onChange with server string render
1194
+* renders a select with a value and an onChange with clean client render
1195
+* renders a select with a value and readOnly with server string render
1196
+* renders a select with a value and readOnly with clean client render
1197
+* renders a select with a multiple values and an onChange with server string render
1198
+* renders a select with a multiple values and an onChange with clean client render
1199
+* renders a select with a multiple values and readOnly with server string render
1200
+* renders a select with a multiple values and readOnly with clean client render
1201
+* renders a select with a value and no onChange/readOnly with server string render
1202
+* renders a select with a value and no onChange/readOnly with clean client render
1203
+* renders a select with a defaultValue with server string render
1204
+* renders a select with a defaultValue with clean client render
1205
+* renders a select value overriding defaultValue with server string render
1206
+* renders a select value overriding defaultValue with clean client render
1207
+* renders a select value overriding defaultValue no matter the prop order with server string render
1208
+* renders a select value overriding defaultValue no matter the prop order with clean client render
1209
+* renders a controlled text input with clean client render
1210
+* renders a controlled textarea with clean client render
1211
+* renders a controlled checkbox with clean client render
1212
+* renders a controlled select with clean client render
1213
* renders class child with context with server string render
1214
* renders class child with context with clean client render
1215
* renders stateless child with context with server string render
@@ -1193,7 +1249,6 @@ src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
1249
* should reconnect Pure Component to Bare Element
1250
* should reconnect Bare Element to Bare Element
1251
* should reconnect a div with a number and string version of number
1196
-* should reconnect if component trees differ but resulting markup is the same
1252
1253
src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
1254
* updates a mounted text component in place
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
+548
-14
@@ -16,6 +16,7 @@ let React;
16
let ReactDOM;
17
let ReactDOMServer;
18
let ReactDOMFeatureFlags;
19
+let ReactTestUtils;
20
21
// Helper functions for rendering tests
22
// ====================================
@@ -209,6 +210,7 @@ function resetModules() {
210
ReactDOM = require('ReactDOM');
211
ReactDOMServer = require('ReactDOMServer');
212
ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
213
+ ReactTestUtils = require('ReactTestUtils');
214
ExecutionEnvironment = require('ExecutionEnvironment');
215
}
216
@@ -1022,6 +1024,552 @@ describe('ReactDOMServerIntegration', () => {
1024
});
1025
});
1026
1027
+ describe('form controls', function() {
1028
+ describe('inputs', function() {
1029
+ itRenders('an input with a value and an onChange', async render => {
1030
+ const e = await render(<input value="foo" onChange={() => {}} />);
1031
+ expect(e.value).toBe('foo');
1032
+ });
1033
+
1034
+ itRenders('an input with a value and readOnly', async render => {
1035
+ const e = await render(<input value="foo" readOnly={true} />);
1036
+ expect(e.value).toBe('foo');
1037
+ });
1038
+
1039
+ itRenders(
1040
+ 'an input with a value and no onChange/readOnly',
1041
+ async render => {
1042
+ // this configuration should raise a dev warning that value without
1043
+ // onChange or readOnly is a mistake.
1044
+ const e = await render(<input value="foo" />, 1);
1045
+ expect(e.value).toBe('foo');
1046
+ },
1047
+ );
1048
+
1049
+ itRenders('an input with a defaultValue', async render => {
1050
+ const e = await render(<input defaultValue="foo" />);
1051
+ expect(e.value).toBe('foo');
1052
+ expect(e.getAttribute('defaultValue')).toBe(null);
1053
+ });
1054
+
1055
+ itRenders('an input value overriding defaultValue', async render => {
1056
+ const e = await render(
1057
+ <input value="foo" defaultValue="bar" readOnly={true} />,
1058
+ 1,
1059
+ );
1060
+ expect(e.value).toBe('foo');
1061
+ expect(e.getAttribute('defaultValue')).toBe(null);
1062
+ });
1063
+
1064
+ itRenders(
1065
+ 'an input value overriding defaultValue no matter the prop order',
1066
+ async render => {
1067
+ const e = await render(
1068
+ <input defaultValue="bar" value="foo" readOnly={true} />,
1069
+ 1,
1070
+ );
1071
+ expect(e.value).toBe('foo');
1072
+ expect(e.getAttribute('defaultValue')).toBe(null);
1073
+ },
1074
+ );
1075
+ });
1076
+
1077
+ describe('checkboxes', function() {
1078
+ itRenders('a checkbox that is checked with an onChange', async render => {
1079
+ const e = await render(
1080
+ <input type="checkbox" checked={true} onChange={() => {}} />,
1081
+ );
1082
+ expect(e.checked).toBe(true);
1083
+ });
1084
+
1085
+ itRenders('a checkbox that is checked with readOnly', async render => {
1086
+ const e = await render(
1087
+ <input type="checkbox" checked={true} readOnly={true} />,
1088
+ );
1089
+ expect(e.checked).toBe(true);
1090
+ });
1091
+
1092
+ itRenders(
1093
+ 'a checkbox that is checked and no onChange/readOnly',
1094
+ async render => {
1095
+ // this configuration should raise a dev warning that checked without
1096
+ // onChange or readOnly is a mistake.
1097
+ const e = await render(<input type="checkbox" checked={true} />, 1);
1098
+ expect(e.checked).toBe(true);
1099
+ },
1100
+ );
1101
+
1102
+ itRenders('a checkbox with defaultChecked', async render => {
1103
+ const e = await render(<input type="checkbox" defaultChecked={true} />);
1104
+ expect(e.checked).toBe(true);
1105
+ expect(e.getAttribute('defaultChecked')).toBe(null);
1106
+ });
1107
+
1108
+ itRenders(
1109
+ 'a checkbox checked overriding defaultChecked',
1110
+ async render => {
1111
+ const e = await render(
1112
+ <input
1113
+ type="checkbox"
1114
+ checked={true}
1115
+ defaultChecked={false}
1116
+ readOnly={true}
1117
+ />,
1118
+ 1,
1119
+ );
1120
+ expect(e.checked).toBe(true);
1121
+ expect(e.getAttribute('defaultChecked')).toBe(null);
1122
+ },
1123
+ );
1124
+
1125
+ itRenders(
1126
+ 'a checkbox checked overriding defaultChecked no matter the prop order',
1127
+ async render => {
1128
+ const e = await render(
1129
+ <input
1130
+ type="checkbox"
1131
+ defaultChecked={false}
1132
+ checked={true}
1133
+ readOnly={true}
1134
+ />,
1135
+ 1,
1136
+ );
1137
+ expect(e.checked).toBe(true);
1138
+ expect(e.getAttribute('defaultChecked')).toBe(null);
1139
+ },
1140
+ );
1141
+ });
1142
+
1143
+ describe('textareas', function() {
1144
+ // textareas
1145
+ // ---------
1146
+ itRenders('a textarea with a value and an onChange', async render => {
1147
+ const e = await render(<textarea value="foo" onChange={() => {}} />);
1148
+ // textarea DOM elements don't have a value **attribute**, the text is
1149
+ // a child of the element and accessible via the .value **property**.
1150
+ expect(e.getAttribute('value')).toBe(null);
1151
+ expect(e.value).toBe('foo');
1152
+ });
1153
+
1154
+ itRenders('a textarea with a value and readOnly', async render => {
1155
+ const e = await render(<textarea value="foo" readOnly={true} />);
1156
+ // textarea DOM elements don't have a value **attribute**, the text is
1157
+ // a child of the element and accessible via the .value **property**.
1158
+ expect(e.getAttribute('value')).toBe(null);
1159
+ expect(e.value).toBe('foo');
1160
+ });
1161
+
1162
+ itRenders(
1163
+ 'a textarea with a value and no onChange/readOnly',
1164
+ async render => {
1165
+ // this configuration should raise a dev warning that value without
1166
+ // onChange or readOnly is a mistake.
1167
+ const e = await render(<textarea value="foo" />, 1);
1168
+ expect(e.getAttribute('value')).toBe(null);
1169
+ expect(e.value).toBe('foo');
1170
+ },
1171
+ );
1172
+
1173
+ itRenders('a textarea with a defaultValue', async render => {
1174
+ const e = await render(<textarea defaultValue="foo" />);
1175
+ expect(e.getAttribute('value')).toBe(null);
1176
+ expect(e.getAttribute('defaultValue')).toBe(null);
1177
+ expect(e.value).toBe('foo');
1178
+ });
1179
+
1180
+ itRenders('a textarea value overriding defaultValue', async render => {
1181
+ const e = await render(
1182
+ <textarea value="foo" defaultValue="bar" readOnly={true} />,
1183
+ 1,
1184
+ );
1185
+ expect(e.getAttribute('value')).toBe(null);
1186
+ expect(e.getAttribute('defaultValue')).toBe(null);
1187
+ expect(e.value).toBe('foo');
1188
+ });
1189
+
1190
+ itRenders(
1191
+ 'a textarea value overriding defaultValue no matter the prop order',
1192
+ async render => {
1193
+ const e = await render(
1194
+ <textarea defaultValue="bar" value="foo" readOnly={true} />,
1195
+ 1,
1196
+ );
1197
+ expect(e.getAttribute('value')).toBe(null);
1198
+ expect(e.getAttribute('defaultValue')).toBe(null);
1199
+ expect(e.value).toBe('foo');
1200
+ },
1201
+ );
1202
+ });
1203
+
1204
+ describe('selects', function() {
1205
+ var options;
1206
+ beforeEach(function() {
1207
+ options = [
1208
+ <option key={1} value="foo" id="foo">Foo</option>,
1209
+ <option key={2} value="bar" id="bar">Bar</option>,
1210
+ <option key={3} value="baz" id="baz">Baz</option>,
1211
+ ];
1212
+ });
1213
+
1214
+ // a helper function to test the selected value of a <select> element.
1215
+ // takes in a <select> DOM element (element) and a value or array of
1216
+ // values that should be selected (selected).
1217
+ const expectSelectValue = (element, selected) => {
1218
+ if (!Array.isArray(selected)) {
1219
+ selected = [selected];
1220
+ }
1221
+ // the select DOM element shouldn't ever have a value or defaultValue
1222
+ // attribute; that is not how select values are expressed in the DOM.
1223
+ expect(element.getAttribute('value')).toBe(null);
1224
+ expect(element.getAttribute('defaultValue')).toBe(null);
1225
+
1226
+ ['foo', 'bar', 'baz'].forEach(value => {
1227
+ const expectedValue = selected.indexOf(value) !== -1;
1228
+ var option = element.querySelector(`#${value}`);
1229
+ expect(option.selected).toBe(expectedValue);
1230
+ });
1231
+ };
1232
+
1233
+ itRenders('a select with a value and an onChange', async render => {
1234
+ const e = await render(
1235
+ <select value="bar" onChange={() => {}}>{options}</select>,
1236
+ );
1237
+ expectSelectValue(e, 'bar');
1238
+ });
1239
+
1240
+ itRenders('a select with a value and readOnly', async render => {
1241
+ const e = await render(
1242
+ <select value="bar" readOnly={true}>{options}</select>,
1243
+ );
1244
+ expectSelectValue(e, 'bar');
1245
+ });
1246
+
1247
+ itRenders(
1248
+ 'a select with a multiple values and an onChange',
1249
+ async render => {
1250
+ const e = await render(
1251
+ <select value={['bar', 'baz']} multiple={true} onChange={() => {}}>
1252
+ {options}
1253
+ </select>,
1254
+ );
1255
+ expectSelectValue(e, ['bar', 'baz']);
1256
+ },
1257
+ );
1258
+
1259
+ itRenders(
1260
+ 'a select with a multiple values and readOnly',
1261
+ async render => {
1262
+ const e = await render(
1263
+ <select value={['bar', 'baz']} multiple={true} readOnly={true}>
1264
+ {options}
1265
+ </select>,
1266
+ );
1267
+ expectSelectValue(e, ['bar', 'baz']);
1268
+ },
1269
+ );
1270
+
1271
+ itRenders(
1272
+ 'a select with a value and no onChange/readOnly',
1273
+ async render => {
1274
+ // this configuration should raise a dev warning that value without
1275
+ // onChange or readOnly is a mistake.
1276
+ const e = await render(<select value="bar">{options}</select>, 1);
1277
+ expectSelectValue(e, 'bar');
1278
+ },
1279
+ );
1280
+
1281
+ itRenders('a select with a defaultValue', async render => {
1282
+ const e = await render(<select defaultValue="bar">{options}</select>);
1283
+ expectSelectValue(e, 'bar');
1284
+ });
1285
+
1286
+ itRenders('a select value overriding defaultValue', async render => {
1287
+ const e = await render(
1288
+ <select value="bar" defaultValue="baz" readOnly={true}>
1289
+ {options}
1290
+ </select>,
1291
+ 1,
1292
+ );
1293
+ expectSelectValue(e, 'bar');
1294
+ });
1295
+
1296
+ itRenders(
1297
+ 'a select value overriding defaultValue no matter the prop order',
1298
+ async render => {
1299
+ const e = await render(
1300
+ <select defaultValue="baz" value="bar" readOnly={true}>
1301
+ {options}
1302
+ </select>,
1303
+ 1,
1304
+ );
1305
+ expectSelectValue(e, 'bar');
1306
+ },
1307
+ );
1308
+ });
1309
+
1310
+ describe('user interaction', function() {
1311
+ let ControlledInput,
1312
+ ControlledTextArea,
1313
+ ControlledCheckbox,
1314
+ ControlledSelect;
1315
+ beforeEach(() => {
1316
+ ControlledInput = class extends React.Component {
1317
+ constructor() {
1318
+ super();
1319
+ this.state = {value: 'Hello'};
1320
+ }
1321
+ handleChange(event) {
1322
+ if (this.props.onChange) {
1323
+ this.props.onChange(event);
1324
+ }
1325
+ this.setState({value: event.target.value});
1326
+ }
1327
+ render() {
1328
+ return (
1329
+ <input
1330
+ value={this.state.value}
1331
+ onChange={this.handleChange.bind(this)}
1332
+ />
1333
+ );
1334
+ }
1335
+ };
1336
+ ControlledTextArea = class extends React.Component {
1337
+ constructor() {
1338
+ super();
1339
+ this.state = {value: 'Hello'};
1340
+ }
1341
+ handleChange(event) {
1342
+ if (this.props.onChange) {
1343
+ this.props.onChange(event);
1344
+ }
1345
+ this.setState({value: event.target.value});
1346
+ }
1347
+ render() {
1348
+ return (
1349
+ <textarea
1350
+ value={this.state.value}
1351
+ onChange={this.handleChange.bind(this)}
1352
+ />
1353
+ );
1354
+ }
1355
+ };
1356
+ ControlledCheckbox = class extends React.Component {
1357
+ constructor() {
1358
+ super();
1359
+ this.state = {value: true};
1360
+ }
1361
+ handleChange(event) {
1362
+ if (this.props.onChange) {
1363
+ this.props.onChange(event);
1364
+ }
1365
+ this.setState({value: event.target.checked});
1366
+ }
1367
+ render() {
1368
+ return (
1369
+ <input
1370
+ type="checkbox"
1371
+ checked={this.state.value}
1372
+ onChange={this.handleChange.bind(this)}
1373
+ />
1374
+ );
1375
+ }
1376
+ };
1377
+ ControlledSelect = class extends React.Component {
1378
+ constructor() {
1379
+ super();
1380
+ this.state = {value: 'Hello'};
1381
+ }
1382
+ handleChange(event) {
1383
+ if (this.props.onChange) {
1384
+ this.props.onChange(event);
1385
+ }
1386
+ this.setState({value: event.target.value});
1387
+ }
1388
+ render() {
1389
+ return (
1390
+ <select
1391
+ value={this.state.value}
1392
+ onChange={this.handleChange.bind(this)}>
1393
+ <option key="1" value="Hello">Hello</option>
1394
+ <option key="2" value="Goodbye">Goodbye</option>
1395
+ </select>
1396
+ );
1397
+ }
1398
+ };
1399
+ });
1400
+
1401
+ describe('user interaction with controlled inputs', function() {
1402
+ itClientRenders('a controlled text input', async render => {
1403
+ let changeCount = 0;
1404
+ const e = await render(
1405
+ <ControlledInput onChange={() => changeCount++} />,
1406
+ );
1407
+ expect(changeCount).toBe(0);
1408
+ expect(e.value).toBe('Hello');
1409
+
1410
+ // simulate a user typing.
1411
+ e.value = 'Goodbye';
1412
+ ReactTestUtils.Simulate.change(e);
1413
+
1414
+ expect(changeCount).toBe(1);
1415
+ expect(e.value).toBe('Goodbye');
1416
+ });
1417
+
1418
+ itClientRenders('a controlled textarea', async render => {
1419
+ let changeCount = 0;
1420
+ const e = await render(
1421
+ <ControlledTextArea onChange={() => changeCount++} />,
1422
+ );
1423
+ expect(changeCount).toBe(0);
1424
+ expect(e.value).toBe('Hello');
1425
+
1426
+ // simulate a user typing.
1427
+ e.value = 'Goodbye';
1428
+ ReactTestUtils.Simulate.change(e);
1429
+
1430
+ expect(changeCount).toBe(1);
1431
+ expect(e.value).toBe('Goodbye');
1432
+ });
1433
+
1434
+ itClientRenders('a controlled checkbox', async render => {
1435
+ let changeCount = 0;
1436
+ const e = await render(
1437
+ <ControlledCheckbox onChange={() => changeCount++} />,
1438
+ );
1439
+ expect(changeCount).toBe(0);
1440
+ expect(e.checked).toBe(true);
1441
+
1442
+ // simulate a user typing.
1443
+ e.checked = false;
1444
+ ReactTestUtils.Simulate.change(e);
1445
+
1446
+ expect(changeCount).toBe(1);
1447
+ expect(e.checked).toBe(false);
1448
+ });
1449
+
1450
+ itClientRenders('a controlled select', async render => {
1451
+ let changeCount = 0;
1452
+ const e = await render(
1453
+ <ControlledSelect onChange={() => changeCount++} />,
1454
+ );
1455
+ expect(changeCount).toBe(0);
1456
+ expect(e.value).toBe('Hello');
1457
+
1458
+ // simulate a user typing.
1459
+ e.value = 'Goodbye';
1460
+ ReactTestUtils.Simulate.change(e);
1461
+
1462
+ expect(changeCount).toBe(1);
1463
+ expect(e.value).toBe('Goodbye');
1464
+ });
1465
+ });
1466
+
1467
+ describe('user interaction with inputs before client render', function() {
1468
+ // renders the element and changes the value **before** the client
1469
+ // code has a chance to render; this simulates what happens when a
1470
+ // user starts to interact with a server-rendered form before
1471
+ // ReactDOM.render is called. the client render should NOT blow away
1472
+ // the changes the user has made.
1473
+ const testUserInteractionBeforeClientRender = async (
1474
+ element,
1475
+ initialValue = 'Hello',
1476
+ changedValue = 'Goodbye',
1477
+ valueKey = 'value',
1478
+ ) => {
1479
+ const field = await serverRender(element);
1480
+ expect(field[valueKey]).toBe(initialValue);
1481
+
1482
+ // simulate a user typing in the field **before** client-side reconnect happens.
1483
+ field[valueKey] = changedValue;
1484
+
1485
+ resetModules();
1486
+ // client render on top of the server markup.
1487
+ const clientField = await renderIntoDom(element, field.parentNode);
1488
+ // verify that the input field was not replaced.
1489
+ // Note that we cannot use expect(clientField).toBe(field) because
1490
+ // of jest bug #1772
1491
+ expect(clientField === field).toBe(true);
1492
+ // confirm that the client render has not changed what the user typed.
1493
+ expect(clientField[valueKey]).toBe(changedValue);
1494
+ };
1495
+
1496
+ it('should not blow away user-entered text on successful reconnect to an uncontrolled input', () =>
1497
+ testUserInteractionBeforeClientRender(
1498
+ <input defaultValue="Hello" />,
1499
+ ));
1500
+
1501
+ it('should not blow away user-entered text on successful reconnect to a controlled input', async () => {
1502
+ let changeCount = 0;
1503
+ await testUserInteractionBeforeClientRender(
1504
+ <ControlledInput onChange={() => changeCount++} />,
1505
+ );
1506
+ // note that there's a strong argument to be made that the DOM revival
1507
+ // algorithm should notice that the user has changed the value and fire
1508
+ // an onChange. however, it does not now, so that's what this tests.
1509
+ expect(changeCount).toBe(0);
1510
+ });
1511
+
1512
+ it('should not blow away user-entered text on successful reconnect to an uncontrolled checkbox', () =>
1513
+ testUserInteractionBeforeClientRender(
1514
+ <input type="checkbox" defaultChecked={true} />,
1515
+ true,
1516
+ false,
1517
+ 'checked',
1518
+ ));
1519
+
1520
+ it('should not blow away user-entered text on successful reconnect to a controlled checkbox', async () => {
1521
+ let changeCount = 0;
1522
+ await testUserInteractionBeforeClientRender(
1523
+ <ControlledCheckbox onChange={() => changeCount++} />,
1524
+ true,
1525
+ false,
1526
+ 'checked',
1527
+ );
1528
+ expect(changeCount).toBe(0);
1529
+ });
1530
+
1531
+ // skipping this test because React 15 does the wrong thing. it blows
1532
+ // away the user's typing in the textarea.
1533
+ xit(
1534
+ 'should not blow away user-entered text on successful reconnect to an uncontrolled textarea',
1535
+ () =>
1536
+ testUserInteractionBeforeClientRender(
1537
+ <textarea defaultValue="Hello" />,
1538
+ ),
1539
+ );
1540
+
1541
+ // skipping this test because React 15 does the wrong thing. it blows
1542
+ // away the user's typing in the textarea.
1543
+ xit(
1544
+ 'should not blow away user-entered text on successful reconnect to a controlled textarea',
1545
+ async () => {
1546
+ let changeCount = 0;
1547
+ await testUserInteractionBeforeClientRender(
1548
+ <ControlledTextArea onChange={() => changeCount++} />,
1549
+ );
1550
+ expect(changeCount).toBe(0);
1551
+ },
1552
+ );
1553
+
1554
+ it('should not blow away user-selected value on successful reconnect to an uncontrolled select', () =>
1555
+ testUserInteractionBeforeClientRender(
1556
+ <select defaultValue="Hello">
1557
+ <option key="1" value="Hello">Hello</option>
1558
+ <option key="2" value="Goodbye">Goodbye</option>
1559
+ </select>,
1560
+ ));
1561
+
1562
+ it('should not blow away user-selected value on successful reconnect to an controlled select', async () => {
1563
+ let changeCount = 0;
1564
+ await testUserInteractionBeforeClientRender(
1565
+ <ControlledSelect onChange={() => changeCount++} />,
1566
+ );
1567
+ expect(changeCount).toBe(0);
1568
+ });
1569
+ });
1570
+ });
1571
+ });
1572
+
1573
describe('context', function() {
1574
let PurpleContext, RedContext;
1575
beforeEach(() => {
@@ -1442,20 +1990,6 @@ describe('ReactDOMServerIntegration', () => {
1990
1991
it('can distinguish an empty component from an empty text component', () =>
1992
expectMarkupMismatch(<div><EmptyComponent /></div>, <div>{''}</div>));
1445
-
1446
- it('should reconnect if component trees differ but resulting markup is the same', () => {
1447
- class Component1 extends React.Component {
1448
- render() {
1449
- return <span id="foobar" />;
1450
- }
1451
- }
1452
- class Component2 extends React.Component {
1453
- render() {
1454
- return <span id="foobar" />;
1455
- }
1456
- }
1457
- return expectMarkupMatch(<Component1 />, <Component2 />);
1458
- });
1993
});
1994
1995
// Markup Mismatches: misc