Skip to content
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

Expose less internals for TestUtils #13539

Merged
merged 3 commits into from
Sep 3, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,8 @@ describe('ResponderEventPlugin', () => {
beforeEach(() => {
jest.resetModules();

const ReactDOM = require('react-dom');
const ReactDOMUnstableNativeDependencies = require('react-dom/unstable-native-dependencies');
EventPluginHub =
ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.EventPluginHub;
EventPluginHub = require('events/EventPluginHub');
const injectComponentTree =
ReactDOMUnstableNativeDependencies.injectComponentTree;
ResponderEventPlugin =
Expand Down
22 changes: 14 additions & 8 deletions packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -739,14 +739,20 @@ const ReactDOM: Object = {
unstable_flushControlled: DOMRenderer.flushControlled,

__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
// For TapEventPlugin which is popular in open source
EventPluginHub,
Copy link
Collaborator Author

@gaearon gaearon Sep 2, 2018

Choose a reason for hiding this comment

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

Technically this was used by TapEventPlugin. But it's already broken with 16.4 and has been deprecated: https://github.com/zilverline/react-tap-event-plugin#deprecated. So this doesn't matter in practice.

I'll check what's up with our www version but last time I looked at it, there were 5 or so callsites left.

// Used by test-utils
EventPluginRegistry,
EventPropagators,
ReactControlledComponent,
ReactDOMComponentTree,
ReactDOMEventListener,
// Keep in sync with ReactDOMUnstableNativeDependencies.js
// and ReactTestUtils.js:
Copy link
Contributor

@bvaughn bvaughn Sep 3, 2018

Choose a reason for hiding this comment

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

I think we could use Flow to type the Array below to keep these two files in sync for us, e.g.:

Events: [Foo, Bar, Baz] = [ ... ]

Like so

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Not sure how many of these methods are typed but we can try.

Copy link
Collaborator Author

@gaearon gaearon Sep 3, 2018

Choose a reason for hiding this comment

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

That still wouldn’t help if two methods have the same signature but you mess up their order. So I’m not sure it’s that helpful. And if you need to be careful anyway then maybe it’s okay to keep as is.

Copy link
Contributor

Choose a reason for hiding this comment

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

True, it wouldn't be perfect, but even if all the types were the same– it would warn if we added/removed an arg one place and not the other.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As discussed, I tried this but some of those are untyped, and it seemed like more work than it's worth

Events: [
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I could've made the whole thing an array, but our FB bundle puts some additional exports here. We'll need to come back to them and clean them up too.

EventPluginRegistry.eventNameDispatchConfigs,
EventPropagators.accumulateTwoPhaseDispatches,
EventPropagators.accumulateDirectDispatches,
ReactControlledComponent.enqueueStateRestore,
ReactControlledComponent.restoreStateIfNeeded,
ReactDOMEventListener.dispatchEvent,
EventPluginHub.runEventsInBatch,
ReactDOMComponentTree.getFiberCurrentPropsFromNode,
ReactDOMComponentTree.getInstanceFromNode,
ReactDOMComponentTree.getNodeFromInstance,
],
},
};

Expand Down
54 changes: 23 additions & 31 deletions packages/react-dom/src/test-utils/ReactTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ import {ELEMENT_NODE} from '../shared/HTMLNodeType';
import * as DOMTopLevelEventTypes from '../events/DOMTopLevelEventTypes';

const {findDOMNode} = ReactDOM;
const {
EventPluginHub,
EventPluginRegistry,
EventPropagators,
ReactControlledComponent,
ReactDOMComponentTree,
ReactDOMEventListener,
} = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
// Keep in sync with ReactDOMUnstableNativeDependencies.js
// and ReactDOM.js:
const [
eventNameDispatchConfigs,
accumulateTwoPhaseDispatches,
accumulateDirectDispatches,
enqueueStateRestore,
restoreStateIfNeeded,
dispatchEvent,
runEventsInBatch,
// eslint-disable-next-line no-unused-vars
getFiberCurrentPropsFromNode,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried to make this just , but Prettier kept moving my comment so I left it in.

getInstanceFromNode,
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;

function Event(suffix) {}

Expand All @@ -50,7 +56,7 @@ let hasWarnedAboutDeprecatedMockComponent = false;
*/
function simulateNativeEventOnNode(topLevelType, node, fakeNativeEvent) {
fakeNativeEvent.target = node;
ReactDOMEventListener.dispatchEvent(topLevelType, fakeNativeEvent);
dispatchEvent(topLevelType, fakeNativeEvent);
}

/**
Expand Down Expand Up @@ -399,16 +405,15 @@ function makeSimulator(eventType) {
'a component instance. Pass the DOM node you wish to simulate the event on instead.',
);

const dispatchConfig =
EventPluginRegistry.eventNameDispatchConfigs[eventType];
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 = ReactDOMComponentTree.getInstanceFromNode(domNode);
const targetInst = getInstanceFromNode(domNode);
const event = new SyntheticEvent(
dispatchConfig,
targetInst,
Expand All @@ -422,26 +427,26 @@ function makeSimulator(eventType) {
Object.assign(event, eventData);

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

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(domNode);
EventPluginHub.runEventsInBatch(event, true);
enqueueStateRestore(domNode);
runEventsInBatch(event, true);
});
ReactControlledComponent.restoreStateIfNeeded();
restoreStateIfNeeded();
};
}

function buildSimulators() {
ReactTestUtils.Simulate = {};

let eventType;
for (eventType in EventPluginRegistry.eventNameDispatchConfigs) {
for (eventType in eventNameDispatchConfigs) {
/**
* @param {!Element|ReactDOMComponent} domComponentOrNode
* @param {?object} eventData Fake event data to use in SyntheticEvent.
Expand All @@ -450,19 +455,6 @@ function buildSimulators() {
}
}

// Rebuild ReactTestUtils.Simulate whenever event plugins are injected
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Don't need this because we removed injection.

const oldInjectEventPluginOrder =
EventPluginHub.injection.injectEventPluginOrder;
EventPluginHub.injection.injectEventPluginOrder = function() {
oldInjectEventPluginOrder.apply(this, arguments);
buildSimulators();
};
const oldInjectEventPlugins = EventPluginHub.injection.injectEventPluginsByName;
EventPluginHub.injection.injectEventPluginsByName = function() {
oldInjectEventPlugins.apply(this, arguments);
buildSimulators();
};

buildSimulators();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,23 @@ export function injectComponentTree(ComponentTree) {
export {ResponderEventPlugin, ResponderTouchHistoryStore};

// Inject react-dom's ComponentTree into this module.
const {
ReactDOMComponentTree,
} = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
// Keep in sync with ReactDOM.js and ReactTestUtils.js:
const [
/* eslint-disable no-unused-vars */
eventNameDispatchConfigs,
accumulateTwoPhaseDispatches,
accumulateDirectDispatches,
enqueueStateRestore,
restoreStateIfNeeded,
dispatchEvent,
runEventsInBatch,
/* eslint-enable no-unused-vars */
getFiberCurrentPropsFromNode,
getInstanceFromNode,
getNodeFromInstance,
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
EventPluginUtils.setComponentTree(
ReactDOMComponentTree.getFiberCurrentPropsFromNode,
ReactDOMComponentTree.getInstanceFromNode,
ReactDOMComponentTree.getNodeFromInstance,
getFiberCurrentPropsFromNode,
getInstanceFromNode,
getNodeFromInstance,
);