Remove event simulation of onChange events (#13176)
* Remove event simulation of onChange events It’s time to get rid of even more `ReactTestUtils.Simulate`s. In this PR we remove the event simulation from all onChange tests. To do this, we have to get a setter to the untracked value/checked props. All remaining `ReactTestUtils.Simulate` calls are either testing ReactTestUtils or assert that they do/don't throw. * Use input instead of change event for all but checkbox, radio, and select
Philipp Spieß committed
Jul 12, 2018 at 13:11 UTC
32f6f258bad524ec3886901a5b132887f8dd7553
4 files changed
+257
-223
packages/react-dom/src/__tests__/ReactDOMInput-test.js
+149
-186
@@ -15,8 +15,9 @@ describe('ReactDOMInput', () => {
15
let React;
16
let ReactDOM;
17
let ReactDOMServer;
18
- let ReactTestUtils;
18
let setUntrackedValue;
19
+ let setUntrackedChecked;
20
+ let container;
21
22
function dispatchEventOnNode(node, type) {
23
node.dispatchEvent(new Event(type, {bubbles: true, cancelable: true}));
@@ -29,15 +30,24 @@ describe('ReactDOMInput', () => {
30
HTMLInputElement.prototype,
31
'value',
32
).set;
33
+ setUntrackedChecked = Object.getOwnPropertyDescriptor(
34
+ HTMLInputElement.prototype,
35
+ 'checked',
36
+ ).set;
37
38
React = require('react');
39
ReactDOM = require('react-dom');
40
ReactDOMServer = require('react-dom/server');
36
- ReactTestUtils = require('react-dom/test-utils');
41
+
42
+ container = document.createElement('div');
43
+ document.body.appendChild(container);
44
+ });
45
+
46
+ afterEach(() => {
47
+ document.body.removeChild(container);
48
});
49
50
it('should properly control a value even if no event listener exists', () => {
40
- const container = document.createElement('div');
51
let node;
52
53
expect(() => {
@@ -46,19 +56,13 @@ describe('ReactDOMInput', () => {
56
'Failed prop type: You provided a `value` prop to a form field without an `onChange` handler.',
57
);
58
49
- document.body.appendChild(container);
50
-
51
- try {
52
- setUntrackedValue.call(node, 'giraffe');
59
+ setUntrackedValue.call(node, 'giraffe');
60
54
- // This must use the native event dispatching. If we simulate, we will
55
- // bypass the lazy event attachment system so we won't actually test this.
56
- dispatchEventOnNode(node, 'change');
61
+ // This must use the native event dispatching. If we simulate, we will
62
+ // bypass the lazy event attachment system so we won't actually test this.
63
+ dispatchEventOnNode(node, 'input');
64
58
- expect(node.value).toBe('lion');
59
- } finally {
60
- document.body.removeChild(container);
61
- }
65
+ expect(node.value).toBe('lion');
66
});
67
68
it('should control a value in reentrant events', () => {
@@ -72,7 +76,7 @@ describe('ReactDOMInput', () => {
76
// Calling focus here will blur the text box which causes a native
77
// change event. Ideally we shouldn't have to fire this ourselves.
78
// Don't remove unless you've verified the fix in #8240 is still covered.
75
- dispatchEventOnNode(this.a, 'change');
79
+ dispatchEventOnNode(this.a, 'input');
80
this.b.focus();
81
}
82
blur(currentValue) {
@@ -97,25 +101,19 @@ describe('ReactDOMInput', () => {
101
}
102
}
103
100
- const container = document.createElement('div');
104
const instance = ReactDOM.render(<ControlledInputs />, container);
105
103
- // We need it to be in the body to test native event dispatching.
104
- document.body.appendChild(container);
105
-
106
// Focus the field so we can later blur it.
107
// Don't remove unless you've verified the fix in #8240 is still covered.
108
instance.a.focus();
109
setUntrackedValue.call(instance.a, 'giraffe');
110
// This must use the native event dispatching. If we simulate, we will
111
// bypass the lazy event attachment system so we won't actually test this.
112
- dispatchEventOnNode(instance.a, 'change');
112
+ dispatchEventOnNode(instance.a, 'input');
113
dispatchEventOnNode(instance.a, 'blur');
114
115
expect(instance.a.value).toBe('giraffe');
116
expect(instance.switchedFocus).toBe(true);
117
-
118
- document.body.removeChild(container);
117
});
118
119
it('should control values in reentrant events with different targets', () => {
@@ -150,12 +148,8 @@ describe('ReactDOMInput', () => {
148
}
149
}
150
153
- const container = document.createElement('div');
151
const instance = ReactDOM.render(<ControlledInputs />, container);
152
156
- // We need it to be in the body to test native event dispatching.
157
- document.body.appendChild(container);
158
-
153
setUntrackedValue.call(instance.a, 'giraffe');
154
// This must use the native event dispatching. If we simulate, we will
155
// bypass the lazy event attachment system so we won't actually test this.
@@ -163,18 +157,16 @@ describe('ReactDOMInput', () => {
157
158
expect(instance.a.value).toBe('lion');
159
expect(instance.b.checked).toBe(true);
166
-
167
- document.body.removeChild(container);
160
});
161
162
describe('switching text inputs between numeric and string numbers', () => {
163
it('does change the number 2 to "2.0" with no change handler', () => {
164
const stub = <input type="text" value={2} onChange={jest.fn()} />;
173
- const node = ReactTestUtils.renderIntoDocument(stub);
165
+ const node = ReactDOM.render(stub, container);
166
175
- node.value = '2.0';
167
+ setUntrackedValue.call(node, '2.0');
168
177
- ReactTestUtils.Simulate.change(node);
169
+ dispatchEventOnNode(node, 'input');
170
171
expect(node.getAttribute('value')).toBe('2');
172
expect(node.value).toBe('2');
@@ -182,11 +174,11 @@ describe('ReactDOMInput', () => {
174
175
it('does change the string "2" to "2.0" with no change handler', () => {
176
const stub = <input type="text" value={'2'} onChange={jest.fn()} />;
185
- const node = ReactTestUtils.renderIntoDocument(stub);
177
+ const node = ReactDOM.render(stub, container);
178
187
- node.value = '2.0';
179
+ setUntrackedValue.call(node, '2.0');
180
189
- ReactTestUtils.Simulate.change(node);
181
+ dispatchEventOnNode(node, 'input');
182
183
expect(node.getAttribute('value')).toBe('2');
184
expect(node.value).toBe('2');
@@ -207,12 +199,12 @@ describe('ReactDOMInput', () => {
199
}
200
}
201
210
- const stub = ReactTestUtils.renderIntoDocument(<Stub />);
202
+ const stub = ReactDOM.render(<Stub />, container);
203
const node = ReactDOM.findDOMNode(stub);
204
213
- node.value = '2.0';
205
+ setUntrackedValue.call(node, '2.0');
206
215
- ReactTestUtils.Simulate.change(node);
207
+ dispatchEventOnNode(node, 'input');
208
209
expect(node.getAttribute('value')).toBe('2.0');
210
expect(node.value).toBe('2.0');
@@ -231,7 +223,7 @@ describe('ReactDOMInput', () => {
223
224
let stub;
225
expect(() => {
234
- stub = ReactTestUtils.renderIntoDocument(<Stub />);
226
+ stub = ReactDOM.render(<Stub />, container);
227
}).toWarnDev(
228
'You provided a `value` prop to a form field ' +
229
'without an `onChange` handler.',
@@ -252,7 +244,7 @@ describe('ReactDOMInput', () => {
244
}
245
}
246
255
- const stub = ReactTestUtils.renderIntoDocument(<Stub />);
247
+ const stub = ReactDOM.render(<Stub />, container);
248
const node = ReactDOM.findDOMNode(stub);
249
stub.setState({value: 0});
250
@@ -260,7 +252,6 @@ describe('ReactDOMInput', () => {
252
});
253
254
it('updates the value on radio buttons from "" to 0', function() {
263
- const container = document.createElement('div');
255
ReactDOM.render(
256
<input type="radio" value="" onChange={function() {}} />,
257
container,
@@ -274,7 +265,6 @@ describe('ReactDOMInput', () => {
265
});
266
267
it('updates the value on checkboxes from "" to 0', function() {
277
- const container = document.createElement('div');
268
ReactDOM.render(
269
<input type="checkbox" value="" onChange={function() {}} />,
270
container,
@@ -300,7 +290,7 @@ describe('ReactDOMInput', () => {
290
let stub;
291
292
expect(() => {
303
- stub = ReactTestUtils.renderIntoDocument(<Stub />);
293
+ stub = ReactDOM.render(<Stub />, container);
294
}).toWarnDev(
295
'You provided a `value` prop to a form field ' +
296
'without an `onChange` handler.',
@@ -313,7 +303,7 @@ describe('ReactDOMInput', () => {
303
304
it('should display `defaultValue` of number 0', () => {
305
let stub = <input type="text" defaultValue={0} />;
316
- const node = ReactTestUtils.renderIntoDocument(stub);
306
+ const node = ReactDOM.render(stub, container);
307
308
expect(node.getAttribute('value')).toBe('0');
309
expect(node.value).toBe('0');
@@ -326,7 +316,7 @@ describe('ReactDOMInput', () => {
316
}
317
}
318
329
- const component = ReactTestUtils.renderIntoDocument(<Test />);
319
+ const component = ReactDOM.render(<Test />, container);
320
const node = ReactDOM.findDOMNode(component);
321
322
Object.defineProperty(node, 'defaultValue', {
@@ -345,21 +335,19 @@ describe('ReactDOMInput', () => {
335
336
it('should display "true" for `defaultValue` of `true`', () => {
337
let stub = <input type="text" defaultValue={true} />;
348
- const node = ReactTestUtils.renderIntoDocument(stub);
338
+ const node = ReactDOM.render(stub, container);
339
340
expect(node.value).toBe('true');
341
});
342
343
it('should display "false" for `defaultValue` of `false`', () => {
344
let stub = <input type="text" defaultValue={false} />;
355
- const node = ReactTestUtils.renderIntoDocument(stub);
345
+ const node = ReactDOM.render(stub, container);
346
347
expect(node.value).toBe('false');
348
});
349
350
it('should update `defaultValue` for uncontrolled input', () => {
361
- const container = document.createElement('div');
362
-
351
const node = ReactDOM.render(
352
<input type="text" defaultValue="0" />,
353
container,
@@ -374,8 +362,6 @@ describe('ReactDOMInput', () => {
362
});
363
364
it('should update `defaultValue` for uncontrolled date/time input', () => {
377
- const container = document.createElement('div');
378
-
365
const node = ReactDOM.render(
366
<input type="date" defaultValue="1980-01-01" />,
367
container,
@@ -392,7 +378,6 @@ describe('ReactDOMInput', () => {
378
});
379
380
it('should take `defaultValue` when changing to uncontrolled input', () => {
395
- const container = document.createElement('div');
381
const node = ReactDOM.render(
382
<input type="text" value="0" readOnly="true" />,
383
container,
@@ -427,7 +412,6 @@ describe('ReactDOMInput', () => {
412
});
413
414
it('should render name attribute if it is supplied', () => {
430
- const container = document.createElement('div');
415
const node = ReactDOM.render(<input type="text" name="name" />, container);
416
expect(node.name).toBe('name');
417
expect(container.firstChild.getAttribute('name')).toBe('name');
@@ -442,7 +426,6 @@ describe('ReactDOMInput', () => {
426
});
427
428
it('should not render name attribute if it is not supplied', () => {
445
- const container = document.createElement('div');
429
ReactDOM.render(<input type="text" />, container);
430
expect(container.firstChild.getAttribute('name')).toBe(null);
431
});
@@ -463,20 +446,19 @@ describe('ReactDOMInput', () => {
446
};
447
448
const stub = <input type="text" defaultValue={objToString} />;
466
- const node = ReactTestUtils.renderIntoDocument(stub);
449
+ const node = ReactDOM.render(stub, container);
450
451
expect(node.value).toBe('foobar');
452
});
453
454
it('should display `value` of number 0', () => {
455
const stub = <input type="text" value={0} />;
473
- const node = ReactTestUtils.renderIntoDocument(stub);
456
+ const node = ReactDOM.render(stub, container);
457
458
expect(node.value).toBe('0');
459
});
460
461
it('should allow setting `value` to `true`', () => {
479
- const container = document.createElement('div');
462
let stub = <input type="text" value="yolo" onChange={emptyFunction} />;
463
const node = ReactDOM.render(stub, container);
464
@@ -490,7 +472,6 @@ describe('ReactDOMInput', () => {
472
});
473
474
it('should allow setting `value` to `false`', () => {
493
- const container = document.createElement('div');
475
let stub = <input type="text" value="yolo" onChange={emptyFunction} />;
476
const node = ReactDOM.render(stub, container);
477
@@ -504,7 +485,6 @@ describe('ReactDOMInput', () => {
485
});
486
487
it('should allow setting `value` to `objToString`', () => {
507
- const container = document.createElement('div');
488
let stub = <input type="text" value="foo" onChange={emptyFunction} />;
489
const node = ReactDOM.render(stub, container);
490
@@ -523,7 +503,6 @@ describe('ReactDOMInput', () => {
503
});
504
505
it('should not incur unnecessary DOM mutations', () => {
526
- const container = document.createElement('div');
506
ReactDOM.render(<input value="a" onChange={() => {}} />, container);
507
508
const node = container.firstChild;
@@ -546,7 +525,6 @@ describe('ReactDOMInput', () => {
525
});
526
527
it('should not incur unnecessary DOM mutations for numeric type conversion', () => {
549
- const container = document.createElement('div');
528
ReactDOM.render(<input value="0" onChange={() => {}} />, container);
529
530
const node = container.firstChild;
@@ -566,7 +544,6 @@ describe('ReactDOMInput', () => {
544
});
545
546
it('should not incur unnecessary DOM mutations for the boolean type conversion', () => {
569
- const container = document.createElement('div');
547
ReactDOM.render(<input value="true" onChange={() => {}} />, container);
548
549
const node = container.firstChild;
@@ -587,34 +564,32 @@ describe('ReactDOMInput', () => {
564
565
it('should properly control a value of number `0`', () => {
566
const stub = <input type="text" value={0} onChange={emptyFunction} />;
590
- const node = ReactTestUtils.renderIntoDocument(stub);
567
+ const node = ReactDOM.render(stub, container);
568
592
- node.value = 'giraffe';
593
- ReactTestUtils.Simulate.change(node);
569
+ setUntrackedValue.call(node, 'giraffe');
570
+ dispatchEventOnNode(node, 'input');
571
expect(node.value).toBe('0');
572
});
573
574
it('should properly control 0.0 for a text input', () => {
575
const stub = <input type="text" value={0} onChange={emptyFunction} />;
599
- const node = ReactTestUtils.renderIntoDocument(stub);
576
+ const node = ReactDOM.render(stub, container);
577
601
- node.value = '0.0';
602
- ReactTestUtils.Simulate.change(node, {target: {value: '0.0'}});
578
+ setUntrackedValue.call(node, '0.0');
579
+ dispatchEventOnNode(node, 'input');
580
expect(node.value).toBe('0');
581
});
582
583
it('should properly control 0.0 for a number input', () => {
584
const stub = <input type="number" value={0} onChange={emptyFunction} />;
608
- const node = ReactTestUtils.renderIntoDocument(stub);
585
+ const node = ReactDOM.render(stub, container);
586
610
- node.value = '0.0';
611
- ReactTestUtils.Simulate.change(node, {target: {value: '0.0'}});
587
+ setUntrackedValue.call(node, '0.0');
588
+ dispatchEventOnNode(node, 'input');
589
expect(node.value).toBe('0.0');
590
});
591
592
it('should properly transition from an empty value to 0', function() {
616
- const container = document.createElement('div');
617
-
593
ReactDOM.render(<input type="text" value="" />, container);
594
ReactDOM.render(<input type="text" value={0} />, container);
595
@@ -625,8 +600,6 @@ describe('ReactDOMInput', () => {
600
});
601
602
it('should properly transition from 0 to an empty value', function() {
628
- const container = document.createElement('div');
629
-
603
ReactDOM.render(<input type="text" value={0} />, container);
604
ReactDOM.render(<input type="text" value="" />, container);
605
@@ -637,8 +610,6 @@ describe('ReactDOMInput', () => {
610
});
611
612
it('should properly transition a text input from 0 to an empty 0.0', function() {
640
- const container = document.createElement('div');
641
-
613
ReactDOM.render(<input type="text" value={0} />, container);
614
ReactDOM.render(<input type="text" value="0.0" />, container);
615
@@ -649,8 +620,6 @@ describe('ReactDOMInput', () => {
620
});
621
622
it('should properly transition a number input from "" to 0', function() {
652
- const container = document.createElement('div');
653
-
623
ReactDOM.render(<input type="number" value="" />, container);
624
ReactDOM.render(<input type="number" value={0} />, container);
625
@@ -661,8 +630,6 @@ describe('ReactDOMInput', () => {
630
});
631
632
it('should properly transition a number input from "" to "0"', function() {
664
- const container = document.createElement('div');
665
-
633
ReactDOM.render(<input type="number" value="" />, container);
634
ReactDOM.render(<input type="number" value="0" />, container);
635
@@ -679,21 +646,18 @@ describe('ReactDOMInput', () => {
646
handled = true;
647
};
648
const stub = <input type="text" value={0} onChange={handler} />;
682
- const container = document.createElement('div');
649
const node = ReactDOM.render(stub, container);
650
651
setUntrackedValue.call(node, 'giraffe');
652
687
- ReactTestUtils.SimulateNative.input(node, {
688
- path: [node, container],
689
- });
653
+ dispatchEventOnNode(node, 'input');
654
655
expect(handled).toBe(true);
656
});
657
658
it('should not set a value for submit buttons unnecessarily', () => {
659
const stub = <input type="submit" />;
696
- const node = ReactTestUtils.renderIntoDocument(stub);
660
+ const node = ReactDOM.render(stub, container);
661
662
// The value shouldn't be '', or else the button will have no text; it
663
// should have the default "Submit" or "Submit Query" label. Most browsers
@@ -733,7 +697,7 @@ describe('ReactDOMInput', () => {
697
}
698
}
699
736
- const stub = ReactTestUtils.renderIntoDocument(<RadioGroup />);
700
+ const stub = ReactDOM.render(<RadioGroup />, container);
701
const aNode = stub.refs.a;
702
const bNode = stub.refs.b;
703
const cNode = stub.refs.c;
@@ -746,11 +710,8 @@ describe('ReactDOMInput', () => {
710
expect(cNode.checked).toBe(true);
711
expect(cNode.hasAttribute('checked')).toBe(true);
712
749
- bNode.checked = true;
750
- // This next line isn't necessary in a proper browser environment, but
751
- // jsdom doesn't uncheck the others in a group (which makes this whole test
752
- // a little less effective)
753
- aNode.checked = false;
713
+ setUntrackedChecked.call(bNode, true);
714
+ expect(aNode.checked).toBe(false);
715
expect(cNode.checked).toBe(true);
716
717
// The original 'checked' attribute should be unchanged
@@ -759,7 +720,7 @@ describe('ReactDOMInput', () => {
720
expect(cNode.hasAttribute('checked')).toBe(true);
721
722
// Now let's run the actual ReactDOMInput change event handler
762
- ReactTestUtils.Simulate.change(bNode);
723
+ dispatchEventOnNode(bNode, 'click');
724
725
// The original state should have been restored
726
expect(aNode.checked).toBe(true);
@@ -797,16 +758,16 @@ describe('ReactDOMInput', () => {
758
}
759
}
760
800
- const stub = ReactTestUtils.renderIntoDocument(<App />);
761
+ const stub = ReactDOM.render(<App />, container);
762
const buttonNode = ReactDOM.findDOMNode(stub).childNodes[0];
763
const firstRadioNode = ReactDOM.findDOMNode(stub).childNodes[1];
764
expect(firstRadioNode.checked).toBe(false);
804
- ReactTestUtils.Simulate.click(buttonNode);
765
+ dispatchEventOnNode(buttonNode, 'click');
766
expect(firstRadioNode.checked).toBe(true);
767
});
768
769
it('should control radio buttons if the tree updates during render', () => {
809
- const sharedParent = document.createElement('div');
770
+ const sharedParent = container;
771
const container1 = document.createElement('div');
772
const container2 = document.createElement('div');
773
@@ -815,6 +776,15 @@ describe('ReactDOMInput', () => {
776
let aNode;
777
let bNode;
778
class ComponentA extends React.Component {
779
+ state = {changed: false};
780
+ handleChange = () => {
781
+ this.setState({
782
+ changed: true,
783
+ });
784
+ };
785
+ componentDidUpdate() {
786
+ sharedParent.appendChild(container2);
787
+ }
788
componentDidMount() {
789
ReactDOM.render(<ComponentB />, container2);
790
}
@@ -825,8 +795,8 @@ describe('ReactDOMInput', () => {
795
ref={n => (aNode = n)}
796
type="radio"
797
name="fruit"
828
- checked={true}
829
- onChange={emptyFunction}
798
+ checked={false}
799
+ onChange={this.handleChange}
800
/>
801
A
802
</div>
@@ -835,15 +805,6 @@ describe('ReactDOMInput', () => {
805
}
806
807
class ComponentB extends React.Component {
838
- state = {changed: false};
839
- handleChange = () => {
840
- this.setState({
841
- changed: true,
842
- });
843
- };
844
- componentDidUpdate() {
845
- sharedParent.appendChild(container2);
846
- }
808
render() {
809
return (
810
<div>
@@ -851,8 +812,8 @@ describe('ReactDOMInput', () => {
812
ref={n => (bNode = n)}
813
type="radio"
814
name="fruit"
854
- checked={false}
855
- onChange={this.handleChange}
815
+ checked={true}
816
+ onChange={emptyFunction}
817
/>
818
B
819
</div>
@@ -862,31 +823,34 @@ describe('ReactDOMInput', () => {
823
824
ReactDOM.render(<ComponentA />, container1);
825
865
- expect(aNode.checked).toBe(true);
866
- expect(bNode.checked).toBe(false);
826
+ expect(aNode.checked).toBe(false);
827
+ expect(bNode.checked).toBe(true);
828
868
- bNode.checked = true;
829
+ setUntrackedChecked.call(aNode, true);
830
// This next line isn't necessary in a proper browser environment, but
870
- // jsdom doesn't uncheck the others in a group (which makes this whole test
871
- // a little less effective)
872
- aNode.checked = false;
831
+ // jsdom doesn't uncheck the others in a group (because they are not yet
832
+ // sharing a parent), which makes this whole test a little less effective.
833
+ setUntrackedChecked.call(bNode, false);
834
835
// Now let's run the actual ReactDOMInput change event handler
875
- ReactTestUtils.Simulate.change(bNode);
836
+ dispatchEventOnNode(aNode, 'click');
837
838
// The original state should have been restored
878
- expect(aNode.checked).toBe(true);
879
- expect(bNode.checked).toBe(false);
839
+ expect(aNode.checked).toBe(false);
840
+ expect(bNode.checked).toBe(true);
841
});
842
843
it('should warn with value and no onChange handler and readOnly specified', () => {
883
- ReactTestUtils.renderIntoDocument(
844
+ ReactDOM.render(
845
<input type="text" value="zoink" readOnly={true} />,
846
+ container,
847
);
848
+ ReactDOM.unmountComponentAtNode(container);
849
850
expect(() =>
888
- ReactTestUtils.renderIntoDocument(
851
+ ReactDOM.render(
852
<input type="text" value="zoink" readOnly={false} />,
853
+ container,
854
),
855
).toWarnDev(
856
'Warning: Failed prop type: You provided a `value` prop to a form ' +
@@ -898,24 +862,29 @@ describe('ReactDOMInput', () => {
862
});
863
864
it('should have a this value of undefined if bind is not used', () => {
865
+ expect.assertions(1);
866
const unboundInputOnChange = function() {
867
expect(this).toBe(undefined);
868
};
869
905
- let instance = <input type="text" onChange={unboundInputOnChange} />;
906
- instance = ReactTestUtils.renderIntoDocument(instance);
870
+ const stub = <input type="text" onChange={unboundInputOnChange} />;
871
+ const node = ReactDOM.render(stub, container);
872
908
- ReactTestUtils.Simulate.change(instance);
873
+ setUntrackedValue.call(node, 'giraffe');
874
+ dispatchEventOnNode(node, 'input');
875
});
876
877
it('should warn with checked and no onChange handler with readOnly specified', () => {
912
- ReactTestUtils.renderIntoDocument(
878
+ ReactDOM.render(
879
<input type="checkbox" checked="false" readOnly={true} />,
880
+ container,
881
);
882
+ ReactDOM.unmountComponentAtNode(container);
883
884
expect(() =>
917
- ReactTestUtils.renderIntoDocument(
885
+ ReactDOM.render(
886
<input type="checkbox" checked="false" readOnly={false} />,
887
+ container,
888
),
889
).toWarnDev(
890
'Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler. ' +
@@ -925,7 +894,6 @@ describe('ReactDOMInput', () => {
894
});
895
896
it('should update defaultValue to empty string', () => {
928
- const container = document.createElement('div');
897
ReactDOM.render(<input type="text" defaultValue={'foo'} />, container);
898
ReactDOM.render(<input type="text" defaultValue={''} />, container);
899
expect(container.firstChild.defaultValue).toBe('');
@@ -933,25 +901,27 @@ describe('ReactDOMInput', () => {
901
902
it('should warn if value is null', () => {
903
expect(() =>
936
- ReactTestUtils.renderIntoDocument(<input type="text" value={null} />),
904
+ ReactDOM.render(<input type="text" value={null} />, container),
905
).toWarnDev(
906
'`value` prop on `input` should not be null. ' +
907
'Consider using an empty string to clear the component or `undefined` ' +
908
'for uncontrolled components.',
909
);
910
+ ReactDOM.unmountComponentAtNode(container);
911
943
- ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
912
+ ReactDOM.render(<input type="text" value={null} />, container);
913
});
914
915
it('should warn if checked and defaultChecked props are specified', () => {
916
expect(() =>
948
- ReactTestUtils.renderIntoDocument(
917
+ ReactDOM.render(
918
<input
919
type="radio"
920
checked={true}
921
defaultChecked={true}
922
readOnly={true}
923
/>,
924
+ container,
925
),
926
).toWarnDev(
927
'A component contains an input of type radio with both checked and defaultChecked props. ' +
@@ -961,21 +931,24 @@ describe('ReactDOMInput', () => {
931
'element and remove one of these props. More info: ' +
932
'https://fb.me/react-controlled-components',
933
);
934
+ ReactDOM.unmountComponentAtNode(container);
935
965
- ReactTestUtils.renderIntoDocument(
936
+ ReactDOM.render(
937
<input
938
type="radio"
939
checked={true}
940
defaultChecked={true}
941
readOnly={true}
942
/>,
943
+ container,
944
);
945
});
946
947
it('should warn if value and defaultValue props are specified', () => {
948
expect(() =>
977
- ReactTestUtils.renderIntoDocument(
949
+ ReactDOM.render(
950
<input type="text" value="foo" defaultValue="bar" readOnly={true} />,
951
+ container,
952
),
953
).toWarnDev(
954
'A component contains an input of type text with both value and defaultValue props. ' +
@@ -985,9 +958,11 @@ describe('ReactDOMInput', () => {
958
'element and remove one of these props. More info: ' +
959
'https://fb.me/react-controlled-components',
960
);
961
+ ReactDOM.unmountComponentAtNode(container);
962
989
- ReactTestUtils.renderIntoDocument(
963
+ ReactDOM.render(
964
<input type="text" value="foo" defaultValue="bar" readOnly={true} />,
965
+ container,
966
);
967
});
968
@@ -995,7 +970,6 @@ describe('ReactDOMInput', () => {
970
const stub = (
971
<input type="text" value="controlled" onChange={emptyFunction} />
972
);
998
- const container = document.createElement('div');
973
ReactDOM.render(stub, container);
974
expect(() => ReactDOM.render(<input type="text" />, container)).toWarnDev(
975
'Warning: A component is changing a controlled input of type text to be uncontrolled. ' +
@@ -1010,7 +984,6 @@ describe('ReactDOMInput', () => {
984
const stub = (
985
<input type="text" value="controlled" onChange={emptyFunction} />
986
);
1013
- const container = document.createElement('div');
987
ReactDOM.render(stub, container);
988
expect(() =>
989
ReactDOM.render(<input type="text" value={null} />, container),
@@ -1029,7 +1002,6 @@ describe('ReactDOMInput', () => {
1002
const stub = (
1003
<input type="text" value="controlled" onChange={emptyFunction} />
1004
);
1032
- const container = document.createElement('div');
1005
ReactDOM.render(stub, container);
1006
expect(() =>
1007
ReactDOM.render(
@@ -1047,7 +1019,6 @@ describe('ReactDOMInput', () => {
1019
1020
it('should warn if uncontrolled input (value is undefined) switches to controlled', () => {
1021
const stub = <input type="text" />;
1050
- const container = document.createElement('div');
1022
ReactDOM.render(stub, container);
1023
expect(() =>
1024
ReactDOM.render(<input type="text" value="controlled" />, container),
@@ -1062,7 +1033,6 @@ describe('ReactDOMInput', () => {
1033
1034
it('should warn if uncontrolled input (value is null) switches to controlled', () => {
1035
const stub = <input type="text" value={null} />;
1065
- const container = document.createElement('div');
1036
expect(() => ReactDOM.render(stub, container)).toWarnDev(
1037
'`value` prop on `input` should not be null. ' +
1038
'Consider using an empty string to clear the component or `undefined` for uncontrolled components.',
@@ -1082,7 +1052,6 @@ describe('ReactDOMInput', () => {
1052
const stub = (
1053
<input type="checkbox" checked={true} onChange={emptyFunction} />
1054
);
1085
- const container = document.createElement('div');
1055
ReactDOM.render(stub, container);
1056
expect(() =>
1057
ReactDOM.render(<input type="checkbox" />, container),
@@ -1099,7 +1068,6 @@ describe('ReactDOMInput', () => {
1068
const stub = (
1069
<input type="checkbox" checked={true} onChange={emptyFunction} />
1070
);
1102
- const container = document.createElement('div');
1071
ReactDOM.render(stub, container);
1072
expect(() =>
1073
ReactDOM.render(<input type="checkbox" checked={null} />, container),
@@ -1116,7 +1084,6 @@ describe('ReactDOMInput', () => {
1084
const stub = (
1085
<input type="checkbox" checked={true} onChange={emptyFunction} />
1086
);
1119
- const container = document.createElement('div');
1087
ReactDOM.render(stub, container);
1088
expect(() =>
1089
ReactDOM.render(
@@ -1134,7 +1101,6 @@ describe('ReactDOMInput', () => {
1101
1102
it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', () => {
1103
const stub = <input type="checkbox" />;
1137
- const container = document.createElement('div');
1104
ReactDOM.render(stub, container);
1105
expect(() =>
1106
ReactDOM.render(<input type="checkbox" checked={true} />, container),
@@ -1149,7 +1115,6 @@ describe('ReactDOMInput', () => {
1115
1116
it('should warn if uncontrolled checkbox (checked is null) switches to controlled', () => {
1117
const stub = <input type="checkbox" checked={null} />;
1152
- const container = document.createElement('div');
1118
ReactDOM.render(stub, container);
1119
expect(() =>
1120
ReactDOM.render(<input type="checkbox" checked={true} />, container),
@@ -1164,7 +1129,6 @@ describe('ReactDOMInput', () => {
1129
1130
it('should warn if controlled radio switches to uncontrolled (checked is undefined)', () => {
1131
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1167
- const container = document.createElement('div');
1132
ReactDOM.render(stub, container);
1133
expect(() => ReactDOM.render(<input type="radio" />, container)).toWarnDev(
1134
'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' +
@@ -1177,7 +1141,6 @@ describe('ReactDOMInput', () => {
1141
1142
it('should warn if controlled radio switches to uncontrolled (checked is null)', () => {
1143
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1180
- const container = document.createElement('div');
1144
ReactDOM.render(stub, container);
1145
expect(() =>
1146
ReactDOM.render(<input type="radio" checked={null} />, container),
@@ -1192,7 +1155,6 @@ describe('ReactDOMInput', () => {
1155
1156
it('should warn if controlled radio switches to uncontrolled with defaultChecked', () => {
1157
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1195
- const container = document.createElement('div');
1158
ReactDOM.render(stub, container);
1159
expect(() =>
1160
ReactDOM.render(<input type="radio" defaultChecked={true} />, container),
@@ -1207,7 +1169,6 @@ describe('ReactDOMInput', () => {
1169
1170
it('should warn if uncontrolled radio (checked is undefined) switches to controlled', () => {
1171
const stub = <input type="radio" />;
1210
- const container = document.createElement('div');
1172
ReactDOM.render(stub, container);
1173
expect(() =>
1174
ReactDOM.render(<input type="radio" checked={true} />, container),
@@ -1222,7 +1183,6 @@ describe('ReactDOMInput', () => {
1183
1184
it('should warn if uncontrolled radio (checked is null) switches to controlled', () => {
1185
const stub = <input type="radio" checked={null} />;
1225
- const container = document.createElement('div');
1186
ReactDOM.render(stub, container);
1187
expect(() =>
1188
ReactDOM.render(<input type="radio" checked={true} />, container),
@@ -1236,7 +1196,6 @@ describe('ReactDOMInput', () => {
1196
});
1197
1198
it('should not warn if radio value changes but never becomes controlled', () => {
1239
- const container = document.createElement('div');
1199
ReactDOM.render(<input type="radio" value="value" />, container);
1200
ReactDOM.render(<input type="radio" />, container);
1201
ReactDOM.render(
@@ -1251,7 +1210,6 @@ describe('ReactDOMInput', () => {
1210
});
1211
1212
it('should not warn if radio value changes but never becomes uncontrolled', () => {
1254
- const container = document.createElement('div');
1213
ReactDOM.render(
1214
<input type="radio" checked={false} onChange={() => null} />,
1215
container,
@@ -1269,7 +1227,6 @@ describe('ReactDOMInput', () => {
1227
});
1228
1229
it('should warn if radio checked false changes to become uncontrolled', () => {
1272
- const container = document.createElement('div');
1230
ReactDOM.render(
1231
<input
1232
type="radio"
@@ -1314,7 +1271,7 @@ describe('ReactDOMInput', () => {
1271
return el;
1272
});
1273
1317
- ReactTestUtils.renderIntoDocument(
1274
+ ReactDOM.render(
1275
<input
1276
value="0"
1277
onChange={() => {}}
@@ -1323,6 +1280,7 @@ describe('ReactDOMInput', () => {
1280
max="100"
1281
step="1"
1282
/>,
1283
+ container,
1284
);
1285
expect(log).toEqual([
1286
'set attribute type',
@@ -1336,9 +1294,7 @@ describe('ReactDOMInput', () => {
1294
});
1295
1296
it('sets value properly with type coming later in props', () => {
1339
- const input = ReactTestUtils.renderIntoDocument(
1340
- <input value="hi" type="radio" />,
1341
- );
1297
+ const input = ReactDOM.render(<input value="hi" type="radio" />, container);
1298
expect(input.value).toBe('hi');
1299
});
1300
@@ -1352,7 +1308,7 @@ describe('ReactDOMInput', () => {
1308
}
1309
}
1310
1355
- const input = ReactTestUtils.renderIntoDocument(<Input />);
1311
+ const input = ReactDOM.render(<Input />, container);
1312
const node = ReactDOM.findDOMNode(input);
1313
1314
// If the value is set before the type, a validation warning will raise and
@@ -1388,9 +1344,7 @@ describe('ReactDOMInput', () => {
1344
return el;
1345
});
1346
1391
- ReactTestUtils.renderIntoDocument(
1392
- <input type="date" defaultValue="1980-01-01" />,
1393
- );
1347
+ ReactDOM.render(<input type="date" defaultValue="1980-01-01" />, container);
1348
expect(log).toEqual([
1349
'node.setAttribute("type", "date")',
1350
'node.value = "1980-01-01"',
@@ -1419,61 +1373,68 @@ describe('ReactDOMInput', () => {
1373
1374
it('always sets the attribute when values change on text inputs', function() {
1375
const Input = getTestInput();
1422
- const stub = ReactTestUtils.renderIntoDocument(<Input type="text" />);
1376
+ const stub = ReactDOM.render(<Input type="text" />, container);
1377
const node = ReactDOM.findDOMNode(stub);
1378
1425
- ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
1379
+ setUntrackedValue.call(node, '2');
1380
+ dispatchEventOnNode(node, 'input');
1381
1382
expect(node.getAttribute('value')).toBe('2');
1383
});
1384
1385
it('does not set the value attribute on number inputs if focused', () => {
1386
const Input = getTestInput();
1432
- const stub = ReactTestUtils.renderIntoDocument(
1387
+ const stub = ReactDOM.render(
1388
<Input type="number" value="1" />,
1389
+ container,
1390
);
1391
const node = ReactDOM.findDOMNode(stub);
1392
1393
node.focus();
1394
1439
- ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
1395
+ setUntrackedValue.call(node, '2');
1396
+ dispatchEventOnNode(node, 'input');
1397
1398
expect(node.getAttribute('value')).toBe('1');
1399
});
1400
1401
it('sets the value attribute on number inputs on blur', () => {
1402
const Input = getTestInput();
1446
- const stub = ReactTestUtils.renderIntoDocument(
1403
+ const stub = ReactDOM.render(
1404
<Input type="number" value="1" />,
1405
+ container,
1406
);
1407
const node = ReactDOM.findDOMNode(stub);
1408
1451
- ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
1452
- ReactTestUtils.SimulateNative.blur(node);
1409
+ setUntrackedValue.call(node, '2');
1410
+ dispatchEventOnNode(node, 'input');
1411
+ dispatchEventOnNode(node, 'blur');
1412
1413
expect(node.getAttribute('value')).toBe('2');
1414
});
1415
1416
it('an uncontrolled number input will not update the value attribute on blur', () => {
1458
- const node = ReactTestUtils.renderIntoDocument(
1417
+ const node = ReactDOM.render(
1418
<input type="number" defaultValue="1" />,
1419
+ container,
1420
);
1421
1462
- node.value = 4;
1422
+ setUntrackedValue.call(node, 4);
1423
1464
- ReactTestUtils.SimulateNative.blur(node);
1424
+ dispatchEventOnNode(node, 'blur');
1425
1426
expect(node.getAttribute('value')).toBe('1');
1427
});
1428
1429
it('an uncontrolled text input will not update the value attribute on blur', () => {
1470
- const node = ReactTestUtils.renderIntoDocument(
1430
+ const node = ReactDOM.render(
1431
<input type="text" defaultValue="1" />,
1432
+ container,
1433
);
1434
1474
- node.value = 4;
1435
+ setUntrackedValue.call(node, 4);
1436
1476
- ReactTestUtils.SimulateNative.blur(node);
1437
+ dispatchEventOnNode(node, 'blur');
1438
1439
expect(node.getAttribute('value')).toBe('1');
1440
});
@@ -1483,7 +1444,12 @@ describe('ReactDOMInput', () => {
1444
let input;
1445
1446
function renderInputWithStringThenWithUndefined() {
1447
+ let setValueToUndefined;
1448
class Input extends React.Component {
1449
+ constructor() {
1450
+ super();
1451
+ setValueToUndefined = () => this.setState({value: undefined});
1452
+ }
1453
state = {value: 'first'};
1454
render() {
1455
return (
@@ -1495,10 +1461,11 @@ describe('ReactDOMInput', () => {
1461
}
1462
}
1463
1498
- const stub = ReactTestUtils.renderIntoDocument(<Input />);
1464
+ const stub = ReactDOM.render(<Input />, container);
1465
input = ReactDOM.findDOMNode(stub);
1500
- ReactTestUtils.Simulate.change(input, {target: {value: 'latest'}});
1501
- ReactTestUtils.Simulate.change(input, {target: {value: undefined}});
1466
+ setUntrackedValue.call(input, 'latest');
1467
+ dispatchEventOnNode(input, 'input');
1468
+ setValueToUndefined();
1469
}
1470
1471
it('reverts the value attribute to the initial value', () => {
@@ -1522,7 +1489,12 @@ describe('ReactDOMInput', () => {
1489
let input;
1490
1491
function renderInputWithStringThenWithNull() {
1492
+ let setValueToNull;
1493
class Input extends React.Component {
1494
+ constructor() {
1495
+ super();
1496
+ setValueToNull = () => this.setState({value: null});
1497
+ }
1498
state = {value: 'first'};
1499
render() {
1500
return (
@@ -1534,10 +1506,11 @@ describe('ReactDOMInput', () => {
1506
}
1507
}
1508
1537
- const stub = ReactTestUtils.renderIntoDocument(<Input />);
1509
+ const stub = ReactDOM.render(<Input />, container);
1510
input = ReactDOM.findDOMNode(stub);
1539
- ReactTestUtils.Simulate.change(input, {target: {value: 'latest'}});
1540
- ReactTestUtils.Simulate.change(input, {target: {value: null}});
1511
+ setUntrackedValue.call(input, 'latest');
1512
+ dispatchEventOnNode(input, 'input');
1513
+ setValueToNull();
1514
}
1515
1516
it('reverts the value attribute to the initial value', () => {
@@ -1565,7 +1538,6 @@ describe('ReactDOMInput', () => {
1538
1539
describe('When given a Symbol value', function() {
1540
it('treats initial Symbol value as an empty string', function() {
1568
- const container = document.createElement('div');
1541
expect(() =>
1542
ReactDOM.render(
1543
<input value={Symbol('foobar')} onChange={() => {}} />,
@@ -1579,7 +1551,6 @@ describe('ReactDOMInput', () => {
1551
});
1552
1553
it('treats updated Symbol value as an empty string', function() {
1582
- const container = document.createElement('div');
1554
ReactDOM.render(<input value="foo" onChange={() => {}} />, container);
1555
expect(() =>
1556
ReactDOM.render(
@@ -1594,7 +1565,6 @@ describe('ReactDOMInput', () => {
1565
});
1566
1567
it('treats initial Symbol defaultValue as an empty string', function() {
1597
- const container = document.createElement('div');
1568
ReactDOM.render(<input defaultValue={Symbol('foobar')} />, container);
1569
const node = container.firstChild;
1570
@@ -1604,7 +1574,6 @@ describe('ReactDOMInput', () => {
1574
});
1575
1576
it('treats updated Symbol defaultValue as an empty string', function() {
1607
- const container = document.createElement('div');
1577
ReactDOM.render(<input defaultValue="foo" />, container);
1578
ReactDOM.render(<input defaultValue={Symbol('foobar')} />, container);
1579
const node = container.firstChild;
@@ -1617,7 +1586,6 @@ describe('ReactDOMInput', () => {
1586
1587
describe('When given a function value', function() {
1588
it('treats initial function value as an empty string', function() {
1620
- const container = document.createElement('div');
1589
expect(() =>
1590
ReactDOM.render(
1591
<input value={() => {}} onChange={() => {}} />,
@@ -1631,7 +1599,6 @@ describe('ReactDOMInput', () => {
1599
});
1600
1601
it('treats updated function value as an empty string', function() {
1634
- const container = document.createElement('div');
1602
ReactDOM.render(<input value="foo" onChange={() => {}} />, container);
1603
expect(() =>
1604
ReactDOM.render(
@@ -1646,7 +1613,6 @@ describe('ReactDOMInput', () => {
1613
});
1614
1615
it('treats initial function defaultValue as an empty string', function() {
1649
- const container = document.createElement('div');
1616
ReactDOM.render(<input defaultValue={() => {}} />, container);
1617
const node = container.firstChild;
1618
@@ -1656,7 +1622,6 @@ describe('ReactDOMInput', () => {
1622
});
1623
1624
it('treats updated function defaultValue as an empty string', function() {
1659
- const container = document.createElement('div');
1625
ReactDOM.render(<input defaultValue="foo" />, container);
1626
ReactDOM.render(<input defaultValue={() => {}} />, container);
1627
const node = container.firstChild;
@@ -1673,7 +1638,6 @@ describe('ReactDOMInput', () => {
1638
// value in order to "dettach" it from defaultValue. This had the unfortunate
1639
// side-effect of assigning value="on" to radio and checkboxes
1640
it('does not add "on" in absence of value on a checkbox', function() {
1676
- const container = document.createElement('div');
1641
ReactDOM.render(
1642
<input type="checkbox" defaultChecked={true} />,
1643
container,
@@ -1685,7 +1649,6 @@ describe('ReactDOMInput', () => {
1649
});
1650
1651
it('does not add "on" in absence of value on a radio', function() {
1688
- const container = document.createElement('div');
1652
ReactDOM.render(<input type="radio" defaultChecked={true} />, container);
1653
const node = container.firstChild;
1654
packages/react-dom/src/__tests__/ReactDOMSelect-test.js
+12
-3
@@ -615,11 +615,20 @@ describe('ReactDOMSelect', () => {
615
<option value="gorilla">A gorilla!</option>
616
</select>
617
);
618
- const node = ReactTestUtils.renderIntoDocument(stub);
618
+ const container = document.createElement('div');
619
+ document.body.appendChild(container);
620
620
- ReactTestUtils.Simulate.change(node);
621
+ try {
622
+ const node = ReactDOM.render(stub, container);
623
622
- expect(node.value).toBe('giraffe');
624
+ node.dispatchEvent(
625
+ new Event('change', {bubbles: true, cancelable: false}),
626
+ );
627
+
628
+ expect(node.value).toBe('giraffe');
629
+ } finally {
630
+ document.body.removeChild(container);
631
+ }
632
});
633
634
it('should warn if value and defaultValue props are specified', () => {
packages/react-dom/src/__tests__/ReactDOMServerIntegrationForms-test.js
+78
-30
@@ -14,14 +14,12 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
14
let React;
15
let ReactDOM;
16
let ReactDOMServer;
17
-let ReactTestUtils;
17
18
function initModules() {
19
// Reset warning cache.
20
jest.resetModuleRegistry();
21
React = require('react');
22
ReactDOM = require('react-dom');
24
- ReactTestUtils = require('react-dom/test-utils');
23
ReactDOMServer = require('react-dom/server');
24
25
// Make them available to the helpers.
@@ -519,35 +517,63 @@ describe('ReactDOMServerIntegration', () => {
517
518
describe('user interaction with controlled inputs', function() {
519
itClientRenders('a controlled text input', async render => {
520
+ const setUntrackedValue = Object.getOwnPropertyDescriptor(
521
+ HTMLInputElement.prototype,
522
+ 'value',
523
+ ).set;
524
+
525
let changeCount = 0;
526
const e = await render(
527
<ControlledInput onChange={() => changeCount++} />,
528
);
526
- expect(changeCount).toBe(0);
527
- expect(e.value).toBe('Hello');
529
+ const container = e.parentNode;
530
+ document.body.appendChild(container);
531
529
- // simulate a user typing.
530
- e.value = 'Goodbye';
531
- ReactTestUtils.Simulate.change(e);
532
+ try {
533
+ expect(changeCount).toBe(0);
534
+ expect(e.value).toBe('Hello');
535
533
- expect(changeCount).toBe(1);
534
- expect(e.value).toBe('Goodbye');
536
+ // simulate a user typing.
537
+ setUntrackedValue.call(e, 'Goodbye');
538
+ e.dispatchEvent(
539
+ new Event('input', {bubbles: true, cancelable: false}),
540
+ );
541
+
542
+ expect(changeCount).toBe(1);
543
+ expect(e.value).toBe('Goodbye');
544
+ } finally {
545
+ document.body.removeChild(container);
546
+ }
547
});
548
549
itClientRenders('a controlled textarea', async render => {
550
+ const setUntrackedValue = Object.getOwnPropertyDescriptor(
551
+ HTMLTextAreaElement.prototype,
552
+ 'value',
553
+ ).set;
554
+
555
let changeCount = 0;
556
const e = await render(
557
<ControlledTextArea onChange={() => changeCount++} />,
558
);
542
- expect(changeCount).toBe(0);
543
- expect(e.value).toBe('Hello');
559
+ const container = e.parentNode;
560
+ document.body.appendChild(container);
561
545
- // simulate a user typing.
546
- e.value = 'Goodbye';
547
- ReactTestUtils.Simulate.change(e);
562
+ try {
563
+ expect(changeCount).toBe(0);
564
+ expect(e.value).toBe('Hello');
565
549
- expect(changeCount).toBe(1);
550
- expect(e.value).toBe('Goodbye');
566
+ // simulate a user typing.
567
+ setUntrackedValue.call(e, 'Goodbye');
568
+ e.dispatchEvent(
569
+ new Event('input', {bubbles: true, cancelable: false}),
570
+ );
571
+
572
+ expect(changeCount).toBe(1);
573
+ expect(e.value).toBe('Goodbye');
574
+ } finally {
575
+ document.body.removeChild(container);
576
+ }
577
});
578
579
itClientRenders('a controlled checkbox', async render => {
@@ -555,31 +581,53 @@ describe('ReactDOMServerIntegration', () => {
581
const e = await render(
582
<ControlledCheckbox onChange={() => changeCount++} />,
583
);
558
- expect(changeCount).toBe(0);
559
- expect(e.checked).toBe(true);
584
+ const container = e.parentNode;
585
+ document.body.appendChild(container);
586
561
- // simulate a user typing.
562
- e.checked = false;
563
- ReactTestUtils.Simulate.change(e);
587
+ try {
588
+ expect(changeCount).toBe(0);
589
+ expect(e.checked).toBe(true);
590
565
- expect(changeCount).toBe(1);
566
- expect(e.checked).toBe(false);
591
+ // simulate a user clicking.
592
+ e.dispatchEvent(
593
+ new Event('click', {bubbles: true, cancelable: true}),
594
+ );
595
+
596
+ expect(changeCount).toBe(1);
597
+ expect(e.checked).toBe(false);
598
+ } finally {
599
+ document.body.removeChild(container);
600
+ }
601
});
602
603
itClientRenders('a controlled select', async render => {
604
+ const setUntrackedValue = Object.getOwnPropertyDescriptor(
605
+ HTMLSelectElement.prototype,
606
+ 'value',
607
+ ).set;
608
+
609
let changeCount = 0;
610
const e = await render(
611
<ControlledSelect onChange={() => changeCount++} />,
612
);
574
- expect(changeCount).toBe(0);
575
- expect(e.value).toBe('Hello');
613
+ const container = e.parentNode;
614
+ document.body.appendChild(container);
615
577
- // simulate a user typing.
578
- e.value = 'Goodbye';
579
- ReactTestUtils.Simulate.change(e);
616
+ try {
617
+ expect(changeCount).toBe(0);
618
+ expect(e.value).toBe('Hello');
619
581
- expect(changeCount).toBe(1);
582
- expect(e.value).toBe('Goodbye');
620
+ // simulate a user typing.
621
+ setUntrackedValue.call(e, 'Goodbye');
622
+ e.dispatchEvent(
623
+ new Event('change', {bubbles: true, cancelable: false}),
624
+ );
625
+
626
+ expect(changeCount).toBe(1);
627
+ expect(e.value).toBe('Goodbye');
628
+ } finally {
629
+ document.body.removeChild(container);
630
+ }
631
});
632
});
633
packages/react-dom/src/__tests__/ReactDOMTextarea-test.js
+18
-4
@@ -237,11 +237,25 @@ describe('ReactDOMTextarea', () => {
237
238
it('should properly control a value of number `0`', () => {
239
const stub = <textarea value={0} onChange={emptyFunction} />;
240
- const node = renderTextarea(stub);
240
+ const setUntrackedValue = Object.getOwnPropertyDescriptor(
241
+ HTMLTextAreaElement.prototype,
242
+ 'value',
243
+ ).set;
244
242
- node.value = 'giraffe';
243
- ReactTestUtils.Simulate.change(node);
244
- expect(node.value).toBe('0');
245
+ const container = document.createElement('div');
246
+ document.body.appendChild(container);
247
+
248
+ try {
249
+ const node = renderTextarea(stub, container);
250
+
251
+ setUntrackedValue.call(node, 'giraffe');
252
+ node.dispatchEvent(
253
+ new Event('input', {bubbles: true, cancelable: false}),
254
+ );
255
+ expect(node.value).toBe('0');
256
+ } finally {
257
+ document.body.removeChild(container);
258
+ }
259
});
260
261
it('should treat children like `defaultValue`', () => {