React: Bug - Upgrading `react-dom` from 16.8.6 to 16.9.0 breaks tests (await Promise.all not supported)

Created on 20 Aug 2019  Â·  10Comments  Â·  Source: facebook/react

When upgrading to react-dom 16.9.0, I have several jest tests break.

The first failure is pasted below. There are other failures to do with missing elements on the page (renders in the browser fine) but they feel less informative so are being omitted for now.

What is the expected behavior?
Tests pass!

I'm unsure of whether this is a bug with react or whether it's just something else that this upgrade has revealed. Could also be an issue with something else in the test setup (my code, React Testing Library, Jest, babel compilation)

I also suspect there might be something wrong with my usage of the async loading of polyfills in componentDidMount but I'm not sure if this is the case. If this is the case it would still mean that other tests were breaking in the upgrade.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Only occurs with 16.9.0. Was working with 16.8.6

Failing Test Message

● <CustomApp /> › renders the error page with a 500 error if there is an unknown error

    Not supported

      26 | async function loadIntlPolyfills(locale: string) {
      27 |   const lang = localeToLang(locale);
    > 28 |   await Promise.all([
         |                 ^
      29 |     import('intl-pluralrules'),
      30 |     import('@formatjs/intl-relativetimeformat/polyfill'),
      31 |     import(`@formatjs/intl-relativetimeformat/dist/locale-data/${lang}`),

      at all (pages/_app.tsx:28:17)
      at CustomApp.loadIntlPolyfills (pages/_app.tsx:153:5)
      at commitLifeCycles (node_modules/react-dom/cjs/react-dom.development.js:20049:22)
      at commitLayoutEffects (node_modules/react-dom/cjs/react-dom.development.js:22813:7)
      at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:347:14)
      at invokeEventListeners (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:193:27)
      at HTMLUnknownElementImpl._dispatch (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:119:9)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:82:17)
      at HTMLUnknownElementImpl.dispatchEvent (node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js:30:27)
      at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:157:21)
      at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:397:16)
      at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:454:31)
      at commitRootImpl (node_modules/react-dom/cjs/react-dom.development.js:22585:9)
      at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:643:12)
      at runWithPriority$2 (node_modules/react-dom/cjs/react-dom.development.js:11305:10)
      at commitRoot (node_modules/react-dom/cjs/react-dom.development.js:22414:3)
      at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21421:20)
      at scheduleRootUpdate (node_modules/react-dom/cjs/react-dom.development.js:24319:3)
      at updateContainerAtExpirationTime (node_modules/react-dom/cjs/react-dom.development.js:24347:10)
      at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:24436:10)
      at node_modules/react-dom/cjs/react-dom.development.js:24963:7
      at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:21687:12)
      at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:24962:5)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:25042:12)
      at node_modules/@testing-library/react/dist/pure.js:86:25
      at batchedUpdates$1 (node_modules/react-dom/cjs/react-dom.development.js:21643:12)
      at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1002:14)
      at act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1418:12)
      at render (node_modules/@testing-library/react/dist/pure.js:82:26)
      at Object.it (__tests__/pages/_app.test.tsx:68:27)

Custom _app.tsx (Next component, see docs here)

// _app.tsx

async function loadIntlPolyfills(locale: string) {
  const lang = localeToLang(locale);
  await Promise.all([
    import('intl-pluralrules'),
    import('@formatjs/intl-relativetimeformat/polyfill'),
    import(`@formatjs/intl-relativetimeformat/dist/locale-data/${lang}`),
  ]);
}

export default class CustomApp extends App<Props, State> {
  // ...

  componentDidMount(): void {
    const { locale } = this.props;
    loadIntlPolyfills(locale);
    // ...
  }

  // ...
}

Failing Test

  let mockedRouter;

  it('renders the error page with a 500 error if there is an unknown error', async () => {
    const props = await CustomApp.getInitialProps({
      Component: TestComponent, // some mocked component with getInitialProps
      ctx: {
        req: reqMock,
      },
    });

    mockedRouter = { pathname: '/web-client-test/' };
    Router.router = mockedRouter;
    jest.spyOn(global.console, 'error').mockImplementation(() => {});
    const pageProps = {
      throwWebErrorInInitialProps: false,
      throwWebErrorInRender: false,
    };

    const app = (
      <CustomApp
        {...props}
        Component={TestComponent}
        router={Router.router}
        pageProps={pageProps}
      />
    );

    const { getByText } = rtlRender(app);
    expect(
      getByText('A 500 error occurred on the server.'),
    ).toBeInTheDocument();
  });

Complete diff between version of our app that had passing tests and version with failing tests

(apologies for b&w diff; +s and -s should show changes)

diff --git a/web_client/package.json b/web_client/package.json
index e8f0aebdf3..bdb47345fa 100644
--- a/web_client/package.json
+++ b/web_client/package.json
@@ -41,7 +41,7 @@
     "postcss-flexbugs-fixes": "^4.1.0",
     "query-string": "5",
     "react": "^16.9.0",
-    "react-dom": "^16.8.6",
+    "react-dom": "^16.9.0",
     "react-intl": "^3.1.8",
     "react-stripe-elements": "^4.0.1",
     "store": "^2.0.12",
diff --git a/web_client/yarn.lock b/web_client/yarn.lock
index 3658d6ccfc..900e0caa5a 100644
--- a/web_client/yarn.lock
+++ b/web_client/yarn.lock
@@ -7959,15 +7959,15 @@ rc@^1.2.7:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"

-react-dom@^16.8.6:
-  version "16.8.6"
-  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f"
-  integrity sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==
+react-dom@^16.9.0:
+  version "16.9.0"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962"
+  integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==
   dependencies:
     loose-envify "^1.1.0"
     object-assign "^4.1.1"
     prop-types "^15.6.2"
-    scheduler "^0.13.6"
+    scheduler "^0.15.0"

 [email protected]:
   version "5.1.6"
@@ -8505,10 +8505,10 @@ sax@^1.2.4, sax@~1.2.1:
   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
   integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==

-scheduler@^0.13.6:
-  version "0.13.6"
-  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
-  integrity sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==
+scheduler@^0.15.0:
+  version "0.15.0"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.15.0.tgz#6bfcf80ff850b280fed4aeecc6513bc0b4f17f8e"
+  integrity sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==
   dependencies:
     loose-envify "^1.1.0"
     object-assign "^4.1.1"
(END)

Most helpful comment

@mulholio It appears the problem isn't with React, but Next 9.0 (ref: https://github.com/zeit/next.js/issues/7872, https://github.com/zeit/next.js/issues/5416) The reason that 16.9.0 exposed this issue, is that with async act properly working, react-testing-library flushes the possible async work correctly now, actually running loadIntlPolyfills as expected. The linked issues have some workarounds that should work for you. Marking this closed.

All 10 comments

Could you also try upgrading react testing library? Older versions had a bug. If that doesn’t help, I’ll have a look tomorrow.

(I don’t know what the “not supported” error is about, but I’m afk atm)

Unfortunately, that doesn't seem to have done anything

Tch, too bad. In which case, I’m going to need a repro on either codesandbox or a git repo, because honestly I’ve never seen that error before, but I’d be happy to help you debug. It feels like a build issue, but I really can’t be sure without looking further.

No problem! Here you go: https://github.com/mulholio/react-dom-upgrade-bug-reproduction

Running yarn test shows the error

My tests also got broken after updating to 16.9.0.
Test file:
```
const defaultDateForTesting = new Date(2018, 6, 11);

// Date object has to be mocked for tests, otherwise "today" would change every day.
// This way we can be sure this date is always same and tests do not break every day
const RealDate = Date;

describe('DatePicker', () => {
let component;
let onChangeMock;

beforeEach(() => {
global.Date = jest.fn((...props) =>
props.length
? new RealDate(...props)
: new RealDate(defaultDateForTesting)
);
Object.assign(Date, RealDate);
});

afterEach(() => {
global.Date = RealDate;
});

it('renders', () => {
component = mount(
label="Select date"
dayPickerProps={{ initialMonth: defaultDateForTesting }}
onChange={() => {}}
/>
);
expect(component).toMatchHtmlSnapshot();
});
`` Error: DatePicker › renders

TypeError: Date.now is not a function`

Using shallow instead of mount solves the issue, but then I can't access the children

@Dizotoff please file a separate issue and tag me, that looks like a different issue. Please also make a codesandbox reproduction, or a git repo.

@mulholio It appears the problem isn't with React, but Next 9.0 (ref: https://github.com/zeit/next.js/issues/7872, https://github.com/zeit/next.js/issues/5416) The reason that 16.9.0 exposed this issue, is that with async act properly working, react-testing-library flushes the possible async work correctly now, actually running loadIntlPolyfills as expected. The linked issues have some workarounds that should work for you. Marking this closed.

Thanks for your help!

For others finding this, adding babel-plugin-dynamic-import-node to my .babelrc fixed this for me

Was this page helpful?
0 / 5 - 0 ratings

Related issues

framerate picture framerate  Â·  3Comments

zpao picture zpao  Â·  3Comments

varghesep picture varghesep  Â·  3Comments

UnbearableBear picture UnbearableBear  Â·  3Comments

Prinzhorn picture Prinzhorn  Â·  3Comments