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

mount Suspense and throw promise - Enzyme Internal Error: unknown node with tag 2 #2205

Open
2 of 13 tasks
json2d opened this issue Jul 30, 2019 · 19 comments · May be fixed by #2521
Open
2 of 13 tasks

mount Suspense and throw promise - Enzyme Internal Error: unknown node with tag 2 #2205

json2d opened this issue Jul 30, 2019 · 19 comments · May be fixed by #2521

Comments

@json2d
Copy link

json2d commented Jul 30, 2019

Current behavior

Getting error Enzyme Internal Error: unknown node with tag 2

from mounting Suspense component with child component that throws promise:

import React, { Suspense } from "react";

const Message = props => <div>Hello Enzyme!</div>
const Loading = props => <div>loading...</div>
const Thrower = props => {
  throw new Promise(resolve => {
    setTimeout(resolve, 1000);
  });
};
describe("integration with Suspense component", () => {
  test("should render Message component", () => {
    const wrapper = mount(
      <Suspense fallback={<Loading />}>
        <Message />
      </Suspense>
    );

    expect(wrapper.find(Message)).toExist(); // ✅ passes
  });

  test("should render Loading component", () => {
    const wrapper = mount(
      <Suspense fallback={<Loading />}>
        <Thrower />
      </Suspense>
    );

    expect(wrapper.find(Loading)).toExist(); // ❌ Enzyme Internal Error: unknown node with tag 2
  });
})

trace:

    Enzyme Internal Error: unknown node with tag 2

      20 | 
      21 |   test("should render Loading component", () => {
    > 22 |     const wrapper = mount(
         |                     ^
      23 |       <Suspense fallback={<Loading />}>
      24 |         <Thrower />
      25 |       </Suspense>

      at _toTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:254:13)
      at toTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:267:12)
      at childrenToTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:227:14)
          at Array.map (<anonymous>)
      at map (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:269:27)
      at childrenToTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:248:19)
      at toTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:267:12)
      at childrenToTree (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:169:19)
      at Object.toTree [as getNode] (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:448:11)
      at new getNode (node_modules/enzyme/src/ReactWrapper.js:117:44)
      at mount (node_modules/enzyme/src/mount.js:10:10)
      at Object.mount (__tests__/Suspense.spec.js:22:21)

Expected behavior

No error

Your environment

API

  • shallow
  • mount
  • render

Version

library version
enzyme 3.10.0
jest-enzyme 7.0.2
react 16.8.6
react-dom 16.8.6
react-test-renderer 16.8.6
adapter (below) 1.14.0

Adapter

  • enzyme-adapter-react-16
  • enzyme-adapter-react-16.3
  • enzyme-adapter-react-16.2
  • enzyme-adapter-react-16.1
  • enzyme-adapter-react-15
  • enzyme-adapter-react-15.4
  • enzyme-adapter-react-14
  • enzyme-adapter-react-13
  • enzyme-adapter-react-helper
  • others ( )
@json2d
Copy link
Author

json2d commented Jul 30, 2019

#1917 #1975

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

Looks related to #2125.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

Does this only occur when you throw a promise, as opposed to another kind of exception?

@json2d
Copy link
Author

json2d commented Jul 30, 2019

Yep, throw new Error() instead of a promise doesn't yield this kind of message

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

So you're not using any React.lazy components - which have to be a promise for an object with a default property that's a React component - but I'm not sure you're supposed to be able to throw a promise directly inside Suspense.

Can you link me to the React docs that talk about this? https://reactjs.org/docs/code-splitting.html doesn't seem to.

@json2d
Copy link
Author

json2d commented Jul 30, 2019

Throwing a promise inside Suspense should be the way to implement an async component - afaik.

here's a pretty recent article that talks about it:
https://blog.logrocket.com/the-future-of-react-unfolding-with-suspense/

The part about React.lazy you're referencing from the React docs talks about the import returning a promise that resolves to a module with an export default that's a React component.

@ljharb
Copy link
Member

ljharb commented Jul 30, 2019

hmm, in that case perhaps the "thrown promise" case isn't something we're handling properly.

@CrOrc
Copy link

CrOrc commented Jul 31, 2019

Throwing promise inside render is supported by React Suspense.
See pull request in React repo Accept promise as element type

@OlgaKuksa
Copy link

Hi there, is there any update on the issue? Looking forward for it to be fixed!

@jeffersoneagley
Copy link

Still broken?

@nickpalmer
Copy link

react-lazy-ssr triggers this error because it throws a promise.

While there is a workaround, it would be nice if Enzyme supported it without the workaround.

@rdy
Copy link

rdy commented Sep 13, 2020

I also ran into this issue testing recoil with enzyme and using a value that returns a promise.

It would be nice to be able to use suspense with enzyme.

@ljharb
Copy link
Member

ljharb commented Sep 15, 2020

I'm working on fixing this, but the "detect fiber tags" code we use is having trouble figuring out the 17 (it has to be done dynamically so it doesn't break over time).

@artola
Copy link

artola commented Jun 4, 2021

@ljharb I found this problem using v1.15.6 of the adapter. I am using relay v11 with relay-test-utils. Do you have some hint?

@ljharb
Copy link
Member

ljharb commented Jun 4, 2021

@artola i can reproduce the issue, but i can't figure out yet how to update our internals to handle it.

@artola
Copy link

artola commented Jun 4, 2021

@artola i can reproduce the issue, but i can't figure out yet how to update our internals to handle it.

I will give it a try. Thanks.

@artola
Copy link

artola commented Jun 4, 2021

@ljharb I did some changes and it seems to work for me (at least my test is working), but I have not your experience and broad vision. Does it makes some sense?

// detectFiberTags.js
...
  function LazyFn() {
    throw Promise.resolve();
  }
...
module.exports = function detectFiberTags() {
...
  return {
    FunctionalComponentLazy: supportsLazy ? getLazyFiber(LazyFn).tag : -1,
// reactSixteenAdapter.js
...
    case FiberTags.Lazy:
    case FiberTags.FunctionalComponentLazy:
      return childrenToTree(node.child);

There is also a ClassComponentLazy that should be supported.

@ljharb
Copy link
Member

ljharb commented Jun 4, 2021

@artola if you can make a PR with passing tests, then that sounds awesome.

@artola artola linked a pull request Jun 6, 2021 that will close this issue
@totszwai
Copy link

Failing without any async nor Promise.

it('blah', () => {
  const wrapper = render(
      <I18nextProvider i18n={i18n}>
        <Suspense fallback="Loading...">
          <Test />
        </Suspense>
      </I18nextProvider>
  );

  console.log(wrapper.debug());
});

Enzyme Internal Error: unknown node with tag 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
React 16
  
v16.6+: memo, lazy, suspense
Development

Successfully merging a pull request may close this issue.

9 participants