102

How do I check if a component is not present, i.e. that a specific component has not been rendered?

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
JoeTidee
  • 24,754
  • 25
  • 104
  • 149

8 Answers8

109

.contains receives a React Node or array of Nodes as an argument. Instead, use .find:

expect(wrapper.find('selector').exists()).toBeTruthy()
AdamJB
  • 432
  • 7
  • 10
Artem Kislov
  • 1,101
  • 1
  • 7
  • 3
59

You can use enzymes contains to check if the component was rendered:

expect(component.contains(<ComponentName />)).toBe(false)
lsl
  • 4,371
  • 3
  • 39
  • 54
Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • 29
    The `contains` call always returns `false` in my case. I used `expect(component.find('ComponentName').exists()).toBeFalsy();` instead as suggested by Periback. – Samuel Dec 12 '17 at 11:21
  • @Samuel Your answer works for me. I'm curious why it needs to be "toBeFalsy()" not "toBe(false)". I understand the concept difference between those, however cannot understand why "toBe(false)" is not working in this case. – shinyatk May 27 '19 at 01:07
  • 3
    @shinyatk I believe the `find` and `exists` are the important parts. `toBe(false)` should work just fine. If you use [jest-enzyme matchers](https://github.com/FormidableLabs/enzyme-matchers/tree/master/packages/jest-enzyme#tocontainmatchingelement), you can also just write `expect(component.find('ComponentName')).toExist()` – Samuel May 28 '19 at 06:56
  • @Samuel Thank you for the prompt response. I will look into [jest-enzyme matchers](https://github.com/FormidableLabs/enzyme-matchers/tree/master/packages/jest-enzyme#tocontainmatchingelement) and try with `toExist()` as well :) – shinyatk May 28 '19 at 07:05
  • 1
    @Samuel I believe this is becaus `contains` looks "inside" for the child components. If the component you're testing acts just like a wrapper that renders another component, you might not be able to find it – foxy Feb 27 '20 at 17:33
  • What if there are multiple components with same name? Like a list of items that is rendered by mapping an array? – K4R1 Mar 02 '20 at 22:07
20

If you're using react-testing-library (I know the OP wasn't but I found this question via web search) then this will work:

expect(component.queryByText("Text I care about")).not.toBeInTheDocument();

You can query by Text, Role, and several others. See docs for more info.

Note: queryBy* will return null if it is not found. If you use getBy* then it will error out for elements not found.

Brady Dowling
  • 4,920
  • 3
  • 32
  • 62
8

Providing a slightly updated answer based on the documentation for enzyme-matchers's toExist. This will require you to install the enzyme-matchers package.

function Fixture() {
  return (
    <div>
      <span className="foo" />
      <span className="bar baz" />
    </div>
  );
}

const wrapper = mount(<Fixture />); // mount/render/shallow when applicable

expect(wrapper.find('span')).toExist();
expect(wrapper.find('ul')).not.toExist();
kylieCatt
  • 10,672
  • 5
  • 43
  • 51
Snekse
  • 15,474
  • 10
  • 62
  • 77
  • 4
    This requires `enzyme-matchers` this library. https://github.com/FormidableLabs/enzyme-matchers – smbl Mar 15 '19 at 20:04
  • @smbl This is true. I would hope for most projects, adding a dev dependency for easier testing isn't going to be too much of a problem. – Snekse Mar 19 '19 at 16:17
5

.contains does not expect a selector, unlike find. You can look at the length attribute of the ShallowWrapper

expect(wrapper.find('...')).toHaveLength(0)

I found I needed to use this syntax with Enzyme and Jest to test if a Connected Component existed in the rendered output.

Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70
  • 1
    I think this might be a bit misleading. When we see something with `length` property, we might expect this to be Array or smth. IMO `exists` helps to distinguish these cases more swiftly. – Vladislav Kovechenkov Dec 04 '19 at 12:00
3

We use Jest and Enzyme, and I've found the only good test is to import the sub-component and test this way:

expect(component.find(SubComponent).length).toEqual(0); // or (1) for exists, obvs

I tried all the other answers and none worked reliably.

eon
  • 1,868
  • 1
  • 23
  • 24
0

If you are using react-testing-library, then this also will work:

expect(component.queryByText("Text I care about").toBeNull());
expect(within(component).queryByText("Text I care about")).toBeNull();

Note: In my case, I needed to use queryBy* because it doesn´t error out when the text element (that contains the text: Text I care about) does not exist. Therefore, I could evaluate whether there is an existence of a text component or not.

0

In my case it was rendered then removed later. I needed to wait for it to disappear (because it was hidden by a button):

await waitFor(() => {
  expect(screen.queryByText('some text')).not.toBeInTheDocument()
})
Rimian
  • 36,864
  • 16
  • 117
  • 117