function makeSimulator(eventType) {
  return function(domNode, eventData) {
    invariant(
      !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.',
    );

    const dispatchConfig = eventNameDispatchConfigs[eventType];

    const fakeNativeEvent = new Event();
    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
    const targetInst = getInstanceFromNode(domNode);
    const event = new SyntheticEvent(
      dispatchConfig,
      targetInst,
      fakeNativeEvent,
      domNode,
    );

    // Since we aren't using pooling, always persist the event. This will make
    // sure it's marked and won't warn when setting additional properties.
    event.persist();
    Object.assign(event, eventData);

    if (dispatchConfig.phasedRegistrationNames) {
      accumulateTwoPhaseDispatches(event);
    } else {
      accumulateDirectDispatches(event);
    }

    ReactDOM.unstable_batchedUpdates(function() {
      // Normally extractEvent enqueues a state restore, but we'll just always
      // do that since we're by-passing it here.
      enqueueStateRestore(domNode);
      runEventsInBatch(event);
    });
    restoreStateIfNeeded();
  };
}
Exports:

- `ReactTestUtils.Simulate.click(Element)`
- `ReactTestUtils.Simulate.mouseMove(Element)`
- `ReactTestUtils.Simulate.change(Element)`
- ... (All keys from event plugin `eventTypes` objects)