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

Deprecate undocumented ReactTestUtils.SimulateNative API #13407

Merged
merged 1 commit into from
Apr 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
61 changes: 50 additions & 11 deletions packages/react-dom/src/__tests__/InvalidEventListeners-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,71 @@ jest.mock('../events/isEventSupported');

describe('InvalidEventListeners', () => {
let React;
let ReactTestUtils;
let ReactDOM;
let container;

beforeEach(() => {
jest.resetModules();
React = require('react');
ReactTestUtils = require('react-dom/test-utils');
ReactDOM = require('react-dom');

container = document.createElement('div');
document.body.appendChild(container);
});

afterEach(() => {
document.body.removeChild(container);
container = null;
});

it('should prevent non-function listeners, at dispatch', () => {
let node;
expect(() => {
node = ReactTestUtils.renderIntoDocument(
<div onClick="not a function" />,
);
node = ReactDOM.render(<div onClick="not a function" />, container);
}).toErrorDev(
'Expected `onClick` listener to be a function, instead got a value of `string` type.',
);
expect(() => ReactTestUtils.SimulateNative.click(node)).toThrowError(
'Expected `onClick` listener to be a function, instead got a value of `string` type.',

spyOnProd(console, 'error');

const uncaughtErrors = [];
function handleWindowError(e) {
uncaughtErrors.push(e.error);
}
window.addEventListener('error', handleWindowError);
try {
node.dispatchEvent(
new MouseEvent('click', {
bubbles: true,
}),
);
} finally {
window.removeEventListener('error', handleWindowError);
}
expect(uncaughtErrors.length).toBe(1);
expect(uncaughtErrors[0]).toEqual(
expect.objectContaining({
message:
'Expected `onClick` listener to be a function, ' +
'instead got a value of `string` type.',
}),
);

if (!__DEV__) {
expect(console.error).toHaveBeenCalledTimes(1);
expect(console.error.calls.argsFor(0)[0]).toMatch(
'Expected `onClick` listener to be a function, ' +
'instead got a value of `string` type.',
);
}
});

it('should not prevent null listeners, at dispatch', () => {
const node = ReactTestUtils.renderIntoDocument(<div onClick={null} />);
expect(function() {
ReactTestUtils.SimulateNative.click(node);
}).not.toThrow();
const node = ReactDOM.render(<div onClick={null} />, container);
node.dispatchEvent(
new MouseEvent('click', {
bubbles: true,
}),
);
});
});
16 changes: 16 additions & 0 deletions packages/react-dom/src/__tests__/ReactTestUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ describe('ReactTestUtils', () => {
expect(Object.keys(ReactTestUtils.SimulateNative).sort()).toMatchSnapshot();
});

it('SimulateNative should warn about deprecation', () => {
const container = document.createElement('div');
const node = ReactDOM.render(<div />, container);
expect(() =>
ReactTestUtils.SimulateNative.click(node),
).toWarnDev(
'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
'how the browser dispatches events, and will be removed in a future major ' +
'version of React. If you rely on it for testing, consider attaching the root ' +
'DOM container to the document during the test, and then dispatching native browser ' +
'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
'the `bubbles` flag to `true` when creating the native browser event.',
{withoutStack: true},
);
});

it('gives Jest mocks a passthrough implementation with mockComponent()', () => {
class MockedComponent extends React.Component {
render() {
Expand Down
15 changes: 15 additions & 0 deletions packages/react-dom/src/test-utils/ReactTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const [
function Event(suffix) {}

let hasWarnedAboutDeprecatedMockComponent = false;
let didWarnSimulateNativeDeprecated = false;

/**
* @class ReactTestUtils
Expand Down Expand Up @@ -622,6 +623,20 @@ buildSimulators();

function makeNativeSimulator(eventType, topLevelType) {
return function(domComponentOrNode, nativeEventData) {
if (__DEV__) {
if (!didWarnSimulateNativeDeprecated) {
didWarnSimulateNativeDeprecated = true;
console.warn(
'ReactTestUtils.SimulateNative is an undocumented API that does not match ' +
'how the browser dispatches events, and will be removed in a future major ' +
'version of React. If you rely on it for testing, consider attaching the root ' +
'DOM container to the document during the test, and then dispatching native browser ' +
'events by calling `node.dispatchEvent()` on the DOM nodes. Make sure to set ' +
'the `bubbles` flag to `true` when creating the native browser event.',
);
}
}

const fakeNativeEvent = new Event(eventType);
Object.assign(fakeNativeEvent, nativeEventData);
if (isDOMComponent(domComponentOrNode)) {
Expand Down