Skip to content
Permalink
Browse files

make testing builds for React/ReactDOM (#17915)

This PR introduces adds `react/testing` and `react-dom/testing`.
- changes infra to generate these builds
- exports act on ReactDOM in these testing builds
- uses the new test builds in fixtures/dom

In the next PR -

- I'll use the new builds for all our own tests
- I'll replace usages of TestUtils.act with ReactDOM.act.
  • Loading branch information
threepointone committed Feb 3, 2020
1 parent ace9e81 commit 3e9251d605692e6db6103e4fca9771ac30a62247
@@ -8,18 +8,23 @@
*/

let React;
let TestUtils;
let ReactDOM;
let TestRenderer;

global.__DEV__ = process.env.NODE_ENV !== 'production';

jest.mock('react-dom', () =>
require.requireActual('react-dom/cjs/react-dom-testing.development.js')
);
// we'll replace the above with react/testing and react-dom/testing right before the next minor

expect.extend(require('../toWarnDev'));

describe('unmocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
TestUtils = require('react-dom/test-utils');
ReactDOM = require('react-dom');
TestRenderer = require('react-test-renderer');
});

@@ -33,7 +38,7 @@ describe('unmocked scheduler', () => {
}
// in legacy mode, this tests whether an act only flushes its own effects
TestRenderer.act(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual([]);
@@ -42,7 +47,7 @@ describe('unmocked scheduler', () => {

log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.act(() => {
TestRenderer.create(<Effecty />);
});
@@ -59,7 +64,7 @@ describe('mocked scheduler', () => {
require.requireActual('scheduler/unstable_mock')
);
React = require('react');
TestUtils = require('react-dom/test-utils');
ReactDOM = require('react-dom');
TestRenderer = require('react-test-renderer');
});

@@ -77,7 +82,7 @@ describe('mocked scheduler', () => {
}
// with a mocked scheduler, this tests whether it flushes all work only on the outermost act
TestRenderer.act(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.create(<Effecty />);
});
expect(log).toEqual([]);
@@ -86,7 +91,7 @@ describe('mocked scheduler', () => {

log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.act(() => {
TestRenderer.create(<Effecty />);
});
@@ -12,13 +12,17 @@ let ReactDOM;
let ReactART;
let ARTSVGMode;
let ARTCurrentMode;
let TestUtils;
let TestRenderer;
let ARTTest;

global.__DEV__ = process.env.NODE_ENV !== 'production';
global.__EXPERIMENTAL__ = process.env.RELEASE_CHANNEL === 'experimental';

jest.mock('react-dom', () =>
require.requireActual('react-dom/cjs/react-dom-testing.development.js')
);
// we'll replace the above with react/testing and react-dom/testing right before the next minor

expect.extend(require('../toWarnDev'));

function App(props) {
@@ -32,7 +36,6 @@ beforeEach(() => {
ReactART = require('react-art');
ARTSVGMode = require('art/modes/svg');
ARTCurrentMode = require('art/modes/current');
TestUtils = require('react-dom/test-utils');
TestRenderer = require('react-test-renderer');

ARTCurrentMode.setCurrent(ARTSVGMode);
@@ -70,8 +73,8 @@ beforeEach(() => {
});

it("doesn't warn when you use the right act + renderer: dom", () => {
TestUtils.act(() => {
TestUtils.renderIntoDocument(<App />);
ReactDOM.act(() => {
ReactDOM.render(<App />, document.createElement('div'));
});
});

@@ -86,7 +89,7 @@ it('resets correctly across renderers', () => {
React.useEffect(() => {}, []);
return null;
}
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.act(() => {});
expect(() => {
TestRenderer.create(<Effecty />);
@@ -99,7 +102,7 @@ it('resets correctly across renderers', () => {
it('warns when using the wrong act version - test + dom: render', () => {
expect(() => {
TestRenderer.act(() => {
TestUtils.renderIntoDocument(<App />);
ReactDOM.render(<App />, document.createElement('div'));
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
@@ -113,7 +116,7 @@ it('warns when using the wrong act version - test + dom: updates', () => {
setCtr = _setCtr;
return ctr;
}
TestUtils.renderIntoDocument(<Counter />);
ReactDOM.render(<Counter />, document.createElement('div'));
expect(() => {
TestRenderer.act(() => {
setCtr(1);
@@ -123,7 +126,7 @@ it('warns when using the wrong act version - test + dom: updates', () => {

it('warns when using the wrong act version - dom + test: .create()', () => {
expect(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.create(<App />);
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
@@ -134,7 +137,7 @@ it('warns when using the wrong act version - dom + test: .create()', () => {
it('warns when using the wrong act version - dom + test: .update()', () => {
const root = TestRenderer.create(<App key="one" />);
expect(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
root.update(<App key="two" />);
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
@@ -151,15 +154,15 @@ it('warns when using the wrong act version - dom + test: updates', () => {
}
TestRenderer.create(<Counter />);
expect(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
setCtr(1);
});
}).toWarnDev(["It looks like you're using the wrong act()"]);
});

it('does not warn when nesting react-act inside react-dom', () => {
TestUtils.act(() => {
TestUtils.renderIntoDocument(<ARTTest />);
ReactDOM.act(() => {
ReactDOM.render(<ARTTest />, document.createElement('div'));
});
});

@@ -171,7 +174,7 @@ it('does not warn when nesting react-act inside react-test-renderer', () => {

it("doesn't warn if you use nested acts from different renderers", () => {
TestRenderer.act(() => {
TestUtils.act(() => {
ReactDOM.act(() => {
TestRenderer.create(<App />);
});
});
@@ -0,0 +1,38 @@
'use strict';

function checkDCE() {
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' ||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function'
) {
return;
}
if (process.env.NODE_ENV !== 'production') {
// This branch is unreachable because this function is only called
// in production, but the condition is true only in development.
// Therefore if the branch is still here, dead code elimination wasn't
// properly applied.
// Don't change the message. React DevTools relies on it. Also make sure
// this message doesn't occur elsewhere in this function, or it will cause
// a false positive.
throw new Error('^_^');
}
try {
// Verify that the code above has been dead code eliminated (DCE'd).
__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE);
} catch (err) {
// DevTools shouldn't crash React, no matter what.
// We should still report in case we break this code.
console.error(err);
}
}

if (process.env.NODE_ENV === 'production') {
// DCE check should happen before ReactDOM bundle executes so that
// DevTools can report bad minification during injection.
checkDCE();
module.exports = require('./cjs/react-dom-testing.production.min.js');
} else {
module.exports = require('./cjs/react-dom-testing.development.js');
}
@@ -722,6 +722,7 @@ function runActTests(label, render, unmount, rerender) {

describe('suspense', () => {
if (__DEV__ && __EXPERIMENTAL__) {
// todo - remove __DEV__ check once we start using testing builds
it('triggers fallbacks if available', async () => {
let resolved = false;
let resolve;
@@ -35,6 +35,7 @@ import {
attemptUserBlockingHydration,
attemptContinuousHydration,
attemptHydrationAtCurrentPriority,
act,
} from 'react-reconciler/inline.dom';
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -58,6 +59,7 @@ import {
disableUnstableCreatePortal,
disableUnstableRenderSubtreeIntoContainer,
warnUnstableRenderSubtreeIntoContainer,
isTestEnvironment,
} from 'shared/ReactFeatureFlags';

import {
@@ -251,4 +253,8 @@ if (__DEV__) {
}
}

if (isTestEnvironment) {
ReactDOM.act = act;
}

export default ReactDOM;
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

'use strict';

const ReactDOM = require('./src/client/ReactDOM');

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
module.exports = ReactDOM.default || ReactDOM;

0 comments on commit 3e9251d

Please sign in to comment.
You can’t perform that action at this time.