@samitouri / QOS-React-2 / commits / a1dbb852c2

warn if you try to use act() in prod (#16282)

We have behaviour divergence for act() between prod and dev (specifically, act() + concurrent mode does not flush fallbacks in prod. This doesn't affect anyone in OSS yet) We also don't have a good story for writing tests in prod (and what from what I gather, nobody really writes tests in prod mode). We could have wiped out act() in prod builds, except that _we_ ourselves use act() for our tests when we run them in prod mode. This PR is a compromise to all of this. We will log a warning if you try to use act() in prod mode, and we silence it in our test suites.

Sunil Pai committed Aug 5, 2019 at 21:01 UTC a1dbb852c29d23d5d0b76a0171eb59df4bebf684
5 files changed +60 -2
packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+23 -2
@@ -27,7 +27,7 @@ function sleep(period) {
27
28 describe('ReactTestUtils.act()', () => {
29 // first we run all the tests with concurrent mode
30 - let concurrentRoot;
30 + let concurrentRoot = null;
31 function renderConcurrent(el, dom) {
32 concurrentRoot = ReactDOM.unstable_createRoot(dom);
33 concurrentRoot.render(el);
@@ -71,7 +71,7 @@ describe('ReactTestUtils.act()', () => {
71 runActTests('legacy sync mode', renderSync, unmountSync, rerenderSync);
72
73 // and then in batched mode
74 - let batchedRoot;
74 + let batchedRoot = null;
75 function renderBatched(el, dom) {
76 batchedRoot = ReactDOM.unstable_createSyncRoot(dom);
77 batchedRoot.render(el);
@@ -791,5 +791,26 @@ function runActTests(label, render, unmount, rerender) {
791 });
792 }
793 });
794 + describe('warn in prod mode', () => {
795 + it('warns if you try to use act() in prod mode', () => {
796 + const spy = spyOnDevAndProd(console, 'error');
797 +
798 + act(() => {});
799 +
800 + if (!__DEV__) {
801 + expect(console.error).toHaveBeenCalledTimes(1);
802 + expect(console.error.calls.argsFor(0)[0]).toContain(
803 + 'act(...) is not supported in production builds of React',
804 + );
805 + } else {
806 + expect(console.error).toHaveBeenCalledTimes(0);
807 + }
808 +
809 + spy.calls.reset();
810 + // does not warn twice
811 + act(() => {});
812 + expect(console.error).toHaveBeenCalledTimes(0);
813 + });
814 + });
815 });
816 }
packages/react-dom/src/test-utils/ReactTestUtilsAct.js
+9
@@ -74,8 +74,17 @@ function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
74 // so we can tell if any async act() calls try to run in parallel.
75
76 let actingUpdatesScopeDepth = 0;
77 +let didWarnAboutUsingActInProd = false;
78
79 function act(callback: () => Thenable) {
80 + if (!__DEV__) {
81 + if (didWarnAboutUsingActInProd === false) {
82 + didWarnAboutUsingActInProd = true;
83 + console.error(
84 + 'act(...) is not supported in production builds of React, and might not behave as expected.',
85 + );
86 + }
87 + }
88 let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
89 let previousIsSomeRendererActing;
90 let previousIsThisRendererActing;
packages/react-noop-renderer/src/createReactNoop.js
+9
@@ -630,8 +630,17 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
630 // so we can tell if any async act() calls try to run in parallel.
631
632 let actingUpdatesScopeDepth = 0;
633 + let didWarnAboutUsingActInProd = false;
634
635 function act(callback: () => Thenable) {
636 + if (!__DEV__) {
637 + if (didWarnAboutUsingActInProd === false) {
638 + didWarnAboutUsingActInProd = true;
639 + console.error(
640 + 'act(...) is not supported in production builds of React, and might not behave as expected.',
641 + );
642 + }
643 + }
644 let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
645 let previousIsSomeRendererActing;
646 let previousIsThisRendererActing;
packages/react-test-renderer/src/ReactTestRendererAct.js
+9
@@ -55,8 +55,17 @@ function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
55 // so we can tell if any async act() calls try to run in parallel.
56
57 let actingUpdatesScopeDepth = 0;
58 +let didWarnAboutUsingActInProd = false;
59
60 function act(callback: () => Thenable) {
61 + if (!__DEV__) {
62 + if (didWarnAboutUsingActInProd === false) {
63 + didWarnAboutUsingActInProd = true;
64 + console.error(
65 + 'act(...) is not supported in production builds of React, and might not behave as expected.',
66 + );
67 + }
68 + }
69 let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
70 let previousIsSomeRendererActing;
71 let previousIsThisRendererActing;
scripts/jest/shouldIgnoreConsoleError.js
+10
@@ -25,6 +25,16 @@ module.exports = function shouldIgnoreConsoleError(format, args) {
25 // They are noisy too so we'll try to ignore them.
26 return true;
27 }
28 + if (
29 + format.indexOf(
30 + 'act(...) is not supported in production builds of React'
31 + ) === 0
32 + ) {
33 + // We don't yet support act() for prod builds, and warn for it.
34 + // But we'd like to use act() ourselves for prod builds.
35 + // Let's ignore the warning and #yolo.
36 + return true;
37 + }
38 }
39 // Looks legit
40 return false;