testing-library / react-testing-library

🐐 Simple and complete React DOM testing utilities that encourage good testing practices.
https://testing-library.com/react
MIT License
19.01k stars 1.11k forks source link

container.querySelector always returns null #629

Closed mhuggins closed 4 years ago

mhuggins commented 4 years ago

Relevant code or config:

const { container, debug } = render(<FormModal isOpen />);
const el = container.querySelector(selector);

console.log(document.querySelector('div'));
// => HTMLElement< ...snip... >

console.log(el.querySelector('div'));
// => null

debug();
// => <div> ...snip... </div>

What you did:

Using @testing-library/react, I'm attempting to use the container object returned by the render function to query for an ambiguous DOM element.

What happened:

Unfortunately, querySelector always returns null no matter what selector I pass to it. However, if I use document.querySelector, it works as expected.

Reproduction:

Problem description:

The provided documentation doesn't match what is necessary to make this work.

Suggested solution:

Fix it somehow, but I'm not sure why it's not working. The getByXXX functions being returned by the render function work as expected.

eps1lon commented 4 years ago

We'd need the full example to understand the issue. But considering you're rendering a modal the element you want to query is probably inside a react portal. It is expected that querySelector would return null if the element is portaled to another part of the tree.

alexkrolick commented 4 years ago

You probably want to use the screen import which is bound to the document body, instead of the container

kentcdodds commented 4 years ago

And if you really can't use one of the queries exported by screen (it's strongly recommended that you do), then you can use document.querySelector.

With that, I think we can close this. Thanks!

alexkrolick commented 4 years ago

That said, I though container was bound to the document body already? https://github.com/testing-library/react-testing-library/issues/392

kentcdodds commented 4 years ago

It definitely is. It's hard to say whether this is a bug in Testing Library or not without an actual reproduction.

adamchenwei commented 3 years ago

use screen generated by render will receive TypeError: Cannot read property 'querySelector' of undefined Is the suggestion outdated?

Well, the only way works is using document directly inside test execution. in case anyone see this

MatanBobi commented 3 years ago

use screen generated by render will receive TypeError: Cannot read property 'querySelector' of undefined Is the suggestion outdated?

Well, the only way works is using document directly inside test execution. in case anyone see this

@adamchenwei, That's true, as @kentcdodds mentioned here, screen contains our queries and if really can't use them, querySelector is on the document object..

FerhatAvdic commented 3 years ago

Same thing happened to me when i rendered a modal

Hiroki111 commented 2 years ago

Same thing happened to me when I tried to access an element that's rendered via Array.prototype.map().

The component that I'm testing looks like...

export function Component() {
  // other lines here
  function getAvatarContent(staff) {
    if (staff.id === ALL_STAFF.id) {
      return <PeopleIcon className='people-icon'/>;
    }
    // return string based on "staff"
  }

  return (
   <div>
     {staffOptions.map((staff) => (
        {getAvatarContent(staff)}
      ))}
   </div>
  );
}
// "staffOptions" is an array and it always has "ALL_STAFF" object.
// So, "getAvatarContent" function must return PeopleIcon at least once

The test case looks like...

const { container } = render(<Component />);

// This works
await waitFor(() => expect(document.querySelector('.people-icon')).toBeInTheDocument());

// This fails 
await waitFor(() => expect(container.querySelector('.people-icon')).toBeInTheDocument());

PeopleIcon is from @mui/icons-material/Menu. At first, I thought that this icon component had an issue. However, if I render this icon outside the staffOptions.map, container.querySelector('.people-icon') didn't fail.

So, the culprit seems to be container.querySelector to me

dwbra commented 1 year ago

Issue still remains when rendering a Modal.