Skip to content

Commit

Permalink
Add invariant check for composite components to event simulation test…
Browse files Browse the repository at this point in the history
… utils (#10414)

* Add invariant check for composite components to event simulation test utils

* Change simulate variable names from domComponentOrNode to domNode, language for new simulate invariant, and add space in existing invariant

* Update test name

* Update test for invariant with shallow rendering

* Update text for existing invariant and change comments to reflect change to only domNode usage

* Update text for existing invariant to reflect syntax with new invariant

* Update ReactTestUtilsEntry.js

* Update React element invariant to reflect usage with shallow rendering

* Move Simulate-related tests into Simulate block

* Run prettier
  • Loading branch information
jfo84 authored and gaearon committed Aug 17, 2017
1 parent 149860b commit 072b1d9
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 110 deletions.
34 changes: 17 additions & 17 deletions src/renderers/dom/test/ReactTestUtilsEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,40 +437,40 @@ var ReactTestUtils = {
/**
* Exports:
*
* - `ReactTestUtils.Simulate.click(Element/ReactDOMComponent)`
* - `ReactTestUtils.Simulate.mouseMove(Element/ReactDOMComponent)`
* - `ReactTestUtils.Simulate.change(Element/ReactDOMComponent)`
* - `ReactTestUtils.Simulate.click(Element)`
* - `ReactTestUtils.Simulate.mouseMove(Element)`
* - `ReactTestUtils.Simulate.change(Element)`
* - ... (All keys from event plugin `eventTypes` objects)
*/
function makeSimulator(eventType) {
return function(domComponentOrNode, eventData) {
var node;
return function(domNode, eventData) {
invariant(
!React.isValidElement(domComponentOrNode),
'TestUtils.Simulate expects a component instance and not a ReactElement.' +
'TestUtils.Simulate will not work if you are using shallow rendering.',
!React.isValidElement(domNode),
'TestUtils.Simulate expected a DOM node as the first argument but received ' +
'a React element. Pass the DOM node you wish to simulate the event on instead. ' +
'Note that TestUtils.Simulate will not work if you are using shallow rendering.',
);
invariant(
!ReactTestUtils.isCompositeComponent(domNode),
'TestUtils.Simulate expected a DOM node as the first argument but received ' +
'a component instance. Pass the DOM node you wish to simulate the event on instead.',
);
if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
node = findDOMNode(domComponentOrNode);
} else if (domComponentOrNode.tagName) {
node = domComponentOrNode;
}

var dispatchConfig =
EventPluginRegistry.eventNameDispatchConfigs[eventType];

var fakeNativeEvent = new Event();
fakeNativeEvent.target = node;
fakeNativeEvent.target = domNode;
fakeNativeEvent.type = eventType.toLowerCase();

// We don't use SyntheticEvent.getPooled in order to not have to worry about
// properly destroying any properties assigned from `eventData` upon release
var targetInst = ReactDOMComponentTree.getInstanceFromNode(node);
var targetInst = ReactDOMComponentTree.getInstanceFromNode(domNode);
var event = new SyntheticEvent(
dispatchConfig,
targetInst,
fakeNativeEvent,
node,
domNode,
);

// Since we aren't using pooling, always persist the event. This will make
Expand All @@ -487,7 +487,7 @@ function makeSimulator(eventType) {
ReactDOM.unstable_batchedUpdates(function() {
// Normally extractEvent enqueues a state restore, but we'll just always
// do that since we we're by-passing it here.
ReactControlledComponent.enqueueStateRestore(node);
ReactControlledComponent.enqueueStateRestore(domNode);

EventPluginHub.enqueueEvents(event);
EventPluginHub.processEventQueue(true);
Expand Down
216 changes: 123 additions & 93 deletions src/renderers/dom/test/__tests__/ReactTestUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,127 +187,157 @@ describe('ReactTestUtils', () => {
expect(ReactTestUtils.isDOMComponent(component.refs.body)).toBe(true);
});

it('should change the value of an input field', () => {
const obj = {
handler: function(e) {
e.persist();
},
};
spyOn(obj, 'handler').and.callThrough();
const container = document.createElement('div');
const instance = ReactDOM.render(
<input type="text" onChange={obj.handler} />,
container,
);

const node = ReactDOM.findDOMNode(instance);
node.value = 'giraffe';
ReactTestUtils.Simulate.change(node);

expect(obj.handler).toHaveBeenCalledWith(
jasmine.objectContaining({target: node}),
);
});
it('can scry with stateless components involved', () => {
const Stateless = () => <div><hr /></div>;

it('should change the value of an input field in a component', () => {
class SomeComponent extends React.Component {
render() {
return (
<div>
<input type="text" ref="input" onChange={this.props.handleChange} />
<Stateless />
<hr />
</div>
);
}
}

const obj = {
handler: function(e) {
e.persist();
},
};
spyOn(obj, 'handler').and.callThrough();
const container = document.createElement('div');
const instance = ReactDOM.render(
<SomeComponent handleChange={obj.handler} />,
container,
);
const inst = ReactTestUtils.renderIntoDocument(<SomeComponent />);
const hrs = ReactTestUtils.scryRenderedDOMComponentsWithTag(inst, 'hr');
expect(hrs.length).toBe(2);
});

const node = ReactDOM.findDOMNode(instance.refs.input);
node.value = 'zebra';
ReactTestUtils.Simulate.change(node);
describe('Simulate', () => {
it('should change the value of an input field', () => {
const obj = {
handler: function(e) {
e.persist();
},
};
spyOn(obj, 'handler').and.callThrough();
const container = document.createElement('div');
const instance = ReactDOM.render(
<input type="text" onChange={obj.handler} />,
container,
);

expect(obj.handler).toHaveBeenCalledWith(
jasmine.objectContaining({target: node}),
);
});
const node = ReactDOM.findDOMNode(instance);
node.value = 'giraffe';
ReactTestUtils.Simulate.change(node);

it('should throw when attempting to use ReactTestUtils.Simulate with shallow rendering', () => {
class SomeComponent extends React.Component {
render() {
return (
<div onClick={this.props.handleClick}>
hello, world.
</div>
);
expect(obj.handler).toHaveBeenCalledWith(
jasmine.objectContaining({target: node}),
);
});

it('should change the value of an input field in a component', () => {
class SomeComponent extends React.Component {
render() {
return (
<div>
<input
type="text"
ref="input"
onChange={this.props.handleChange}
/>
</div>
);
}
}
}

const handler = jasmine.createSpy('spy');
const shallowRenderer = createRenderer();
const result = shallowRenderer.render(
<SomeComponent handleClick={handler} />,
);
const obj = {
handler: function(e) {
e.persist();
},
};
spyOn(obj, 'handler').and.callThrough();
const container = document.createElement('div');
const instance = ReactDOM.render(
<SomeComponent handleChange={obj.handler} />,
container,
);

expect(() => ReactTestUtils.Simulate.click(result)).toThrowError(
'TestUtils.Simulate expects a component instance and not a ReactElement.' +
'TestUtils.Simulate will not work if you are using shallow rendering.',
);
expect(handler).not.toHaveBeenCalled();
});
const node = ReactDOM.findDOMNode(instance.refs.input);
node.value = 'zebra';
ReactTestUtils.Simulate.change(node);

it('should not warn when simulating events with extra properties', () => {
spyOn(console, 'error');
expect(obj.handler).toHaveBeenCalledWith(
jasmine.objectContaining({target: node}),
);
});

const CLIENT_X = 100;
it('should throw when attempting to use a React element', () => {
class SomeComponent extends React.Component {
render() {
return (
<div onClick={this.props.handleClick}>
hello, world.
</div>
);
}
}

class Component extends React.Component {
handleClick = e => {
expect(e.clientX).toBe(CLIENT_X);
};
const handler = jasmine.createSpy('spy');
const shallowRenderer = createRenderer();
const result = shallowRenderer.render(
<SomeComponent handleClick={handler} />,
);

render() {
return <div onClick={this.handleClick} />;
expect(() => ReactTestUtils.Simulate.click(result)).toThrowError(
'TestUtils.Simulate expected a DOM node as the first argument but received ' +
'a React element. Pass the DOM node you wish to simulate the event on instead. ' +
'Note that TestUtils.Simulate will not work if you are using shallow rendering.',
);
expect(handler).not.toHaveBeenCalled();
});

it('should throw when attempting to use a component instance', () => {
class SomeComponent extends React.Component {
render() {
return (
<div onClick={this.props.handleClick}>
hello, world.
</div>
);
}
}
}

const element = document.createElement('div');
const instance = ReactDOM.render(<Component />, element);
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance), {
clientX: CLIENT_X,
const handler = jasmine.createSpy('spy');
const container = document.createElement('div');
const instance = ReactDOM.render(
<SomeComponent handleClick={handler} />,
container,
);

expect(() => ReactTestUtils.Simulate.click(instance)).toThrowError(
'TestUtils.Simulate expected a DOM node as the first argument but received ' +
'a component instance. Pass the DOM node you wish to simulate the event on instead.',
);
expect(handler).not.toHaveBeenCalled();
});
expectDev(console.error.calls.count()).toBe(0);
});

it('can scry with stateless components involved', () => {
const Stateless = () => <div><hr /></div>;
it('should not warn when used with extra properties', () => {
spyOn(console, 'error');

class SomeComponent extends React.Component {
render() {
return (
<div>
<Stateless />
<hr />
</div>
);
const CLIENT_X = 100;

class Component extends React.Component {
handleClick = e => {
expect(e.clientX).toBe(CLIENT_X);
};

render() {
return <div onClick={this.handleClick} />;
}
}
}

const inst = ReactTestUtils.renderIntoDocument(<SomeComponent />);
const hrs = ReactTestUtils.scryRenderedDOMComponentsWithTag(inst, 'hr');
expect(hrs.length).toBe(2);
});
const element = document.createElement('div');
const instance = ReactDOM.render(<Component />, element);
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance), {
clientX: CLIENT_X,
});
expectDev(console.error.calls.count()).toBe(0);
});

describe('Simulate', () => {
it('should set the type of the event', () => {
let event;
const stub = jest.genMockFn().mockImplementation(e => {
Expand Down

0 comments on commit 072b1d9

Please sign in to comment.