Skip to content

Use only public API for ChangeEventPlugin-test.js #11333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 24, 2017
139 changes: 76 additions & 63 deletions packages/react-dom/src/events/__tests__/ChangeEventPlugin-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,72 @@
var React = require('react');
var ReactDOM = require('react-dom');
var ReactTestUtils = require('react-dom/test-utils');
// TODO: can we express this test with only public API?
var ChangeEventPlugin = require('../ChangeEventPlugin').default;
var inputValueTracking = require('../../client/inputValueTracking');

function getTrackedValue(elem) {
var tracker = inputValueTracking._getTrackerFromNode(elem);
return tracker.getValue();
return elem.value;
}

function setTrackedValue(elem, value) {
var tracker = inputValueTracking._getTrackerFromNode(elem);
tracker.setValue(value);
}

function setUntrackedValue(elem, value) {
var tracker = inputValueTracking._getTrackerFromNode(elem);
var current = tracker.getValue();

if (elem.type === 'checkbox' || elem.type === 'radio') {
elem.checked = value;
} else {
elem.value = value;
}
tracker.setValue(current);
var setUntrackedChecked = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
'checked',
).set;

var setUntrackedValue = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
'value',
).set;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this will work since we stub this in the input tracking code...or is that only the instance property that's stubbed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only prototype method I could find that would grant me access to this kind of info. If the value is untracked it won't show up in the Object.getOwnPropertyDescriptor() call. (Hence why I am using the .set method).


function getEvent(type, opts) {
var event = document.createEvent('Event');
event.initEvent(type, true, true);
return event;
}

function dispatchEventOnNode(node, type) {
//console.log(`Dispatch ${type}`, node.checked);
var res = node.dispatchEvent(
new Event( type, {bubbles: true, cancelable: true} ));
}

describe('ChangeEventPlugin', () => {
it('should fire change for checkbox input', () => {
it('should fire click for checkbox input', () => {
var called = 0;

function cb(e) {
called = 1;
expect(e.type).toBe('change');
expect(e.type).toBe('click');
}

var input = ReactTestUtils.renderIntoDocument(
<input type="checkbox" onChange={cb} />,
var container = document.createElement('div');

var stub = ReactDOM.render(
<input type="checkbox" onClick={cb}/>,
container
);

setUntrackedValue(input, true);
ReactTestUtils.SimulateNative.click(input);
document.body.appendChild(container);

expect(called).toBe(1);
var node = ReactDOM.findDOMNode(stub);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip: there is no "stub" :-) Old tests are bad, don't copy them.
ReactDOM.render() already returns a DOM node.


setUntrackedChecked.call(node, false); // track and set to false
dispatchEventOnNode(node, 'click'); // make it true

expect(called).toBe(1); // onClick has been called
expect(node.checked).toBe(true); // tracked property is now true

document.body.removeChild(container);
});

it('should catch setting the value programmatically', () => {
var input = ReactTestUtils.renderIntoDocument(
<input type="text" defaultValue="foo" />,
var container = document.createElement('div');
var ref = ReactDOM.render(
<input type="text" defaultValue="foo" />, container
);
var input = ReactDOM.findDOMNode(ref);
setUntrackedValue.call(input, 'bar');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we setting untracked value here? I thought this test verifies that it catches setting value programmatically (and thus through the tracked value property like in the original test).


input.value = 'bar';
expect(getTrackedValue(input)).toBe('bar');
});

Expand All @@ -74,17 +89,20 @@ describe('ChangeEventPlugin', () => {
expect(e.type).toBe('change');
}

var input = ReactTestUtils.renderIntoDocument(
<input type="text" onChange={cb} defaultValue="foo" />,
var container = document.createElement('div');
var ref = ReactDOM.render(
<input type="text" onChange={cb} defaultValue="foo" />, container
);
var input = ReactDOM.findDOMNode(ref);

input.value = 'bar';
ReactTestUtils.SimulateNative.change(input);
dispatchEventOnNode(input, 'change');
expect(called).toBe(0);

setUntrackedValue(input, 'foo');
ReactTestUtils.SimulateNative.change(input);
setUntrackedValue.call(input, 'foo');
expect(input.value).toBe('foo');

dispatchEventOnNode(input, 'change');
expect(called).toBe(1);
});

Expand All @@ -101,12 +119,11 @@ describe('ChangeEventPlugin', () => {
);

input.checked = true;
ReactTestUtils.SimulateNative.click(input);
input.dispatchEvent(getEvent('click'));
expect(called).toBe(0);

input.checked = false;
setTrackedValue(input, undefined);
ReactTestUtils.SimulateNative.click(input);
setUntrackedChecked.call(input, false);
input.dispatchEvent(getEvent('click'));

expect(called).toBe(1);
});
Expand All @@ -128,9 +145,9 @@ describe('ChangeEventPlugin', () => {
var input = ReactTestUtils.renderIntoDocument(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work because it's not actually rendering into document (yes, the naming of that method is pretty bad). That's why reviews in other similar tests added setting up a container and adding it to the body before every test.

<input type="radio" onChange={cb} />,
);
setUntrackedValue(input, true);
ReactTestUtils.SimulateNative.click(input);
ReactTestUtils.SimulateNative.click(input);
setUntrackedChecked.call(input, true);
input.dispatchEvent(getEvent('click'));
input.dispatchEvent(getEvent('click'));
expect(called).toBe(1);
});

Expand All @@ -151,23 +168,23 @@ describe('ChangeEventPlugin', () => {
called = 0;
input = ReactTestUtils.renderIntoDocument(element);

setUntrackedValue(input, '40');
ReactTestUtils.SimulateNative.change(input);
ReactTestUtils.SimulateNative.change(input);
setUntrackedValue.call(input, '40');
input.dispatchEvent(getEvent('change'));
input.dispatchEvent(getEvent('change'));
expect(called).toBe(1);

called = 0;
input = ReactTestUtils.renderIntoDocument(element);
setUntrackedValue(input, '40');
ReactTestUtils.SimulateNative.input(input);
ReactTestUtils.SimulateNative.input(input);
setUntrackedValue.call(input, '40');
input.dispatchEvent(getEvent('input'));
input.dispatchEvent(getEvent('input'));
expect(called).toBe(1);

called = 0;
input = ReactTestUtils.renderIntoDocument(element);
setUntrackedValue(input, '40');
ReactTestUtils.SimulateNative.input(input);
ReactTestUtils.SimulateNative.change(input);
setUntrackedValue.call(input, '40');
input.dispatchEvent(getEvent('input'));
input.dispatchEvent(getEvent('change'));
expect(called).toBe(1);
});
});
Expand All @@ -180,20 +197,16 @@ describe('ChangeEventPlugin', () => {
expect(e.type).toBe('change');
}

if (!ChangeEventPlugin._isInputEventSupported) {
return;
}

var input = ReactTestUtils.renderIntoDocument(
<input type="range" onChange={cb} />,
);
setUntrackedValue(input, 'bar');
setUntrackedValue.call(input, 'bar');

ReactTestUtils.SimulateNative.input(input);
input.dispatchEvent(getEvent('input'));

setUntrackedValue(input, 'foo');
setUntrackedValue.call(input, 'foo');

ReactTestUtils.SimulateNative.change(input);
input.dispatchEvent(getEvent('change'));

expect(called).toBe(2);
});
Expand All @@ -209,14 +222,14 @@ describe('ChangeEventPlugin', () => {
var input = ReactTestUtils.renderIntoDocument(
<input type="range" onChange={cb} />,
);
setUntrackedValue(input, '40');
ReactTestUtils.SimulateNative.input(input);
ReactTestUtils.SimulateNative.change(input);
setUntrackedValue.call(input, '40');
input.dispatchEvent(getEvent('input'));
input.dispatchEvent(getEvent('change'));

setUntrackedValue(input, 'foo');
setUntrackedValue.call(input, 'foo');

ReactTestUtils.SimulateNative.input(input);
ReactTestUtils.SimulateNative.change(input);
input.dispatchEvent(getEvent('input'));
input.dispatchEvent(getEvent('change'));
expect(called).toBe(2);
});
});