138

I have a component library that I'm writing unit tests for using Jest and react-testing-library. Based on certain props or events I want to verify that certain elements aren't being rendered.

getByText, getByTestId, etc throw and error in react-testing-library if the element isn't found causing the test to fail before the expect function fires.

How do you test for something not existing in jest using react-testing-library?

SomethingOn
  • 7,004
  • 17
  • 60
  • 99

7 Answers7

267

From DOM Testing-library Docs - Appearance and Disappearance

Asserting elements are not present

The standard getBy methods throw an error when they can't find an element, so if you want to make an assertion that an element is not present in the DOM, you can use queryBy APIs instead:

const submitButton = screen.queryByText('submit')
expect(submitButton).toBeNull() // it doesn't exist

The queryAll APIs version return an array of matching nodes. The length of the array can be useful for assertions after elements are added or removed from the DOM.

const submitButtons = screen.queryAllByText('submit')
expect(submitButtons).toHaveLength(2) // expect 2 elements

not.toBeInTheDocument

The jest-dom utility library provides the .toBeInTheDocument() matcher, which can be used to assert that an element is in the body of the document, or not. This can be more meaningful than asserting a query result is null.

import '@testing-library/jest-dom/extend-expect'
// use `queryBy` to avoid throwing an error with `getBy`
const submitButton = screen.queryByText('submit')
expect(submitButton).not.toBeInTheDocument()
kentcdodds
  • 20,934
  • 27
  • 99
  • 178
  • 4
    My bad kentcdodds, thank you. I used `getByTestId` and got the same error. And, I didn't check the FAQ, sorry. Great library! Can you modify your answer to include the `.toBeNull(); – SomethingOn Oct 12 '18 at 16:58
  • 3
    I believe the link above was meant to point to the [react-testing-library docs](https://testing-library.com/docs/react-testing-library/faq) – pbre Jan 04 '19 at 16:59
  • 2
    The new docs site was published a few days ago. I should have used a more permanent link. Thanks for the update @pbre! – kentcdodds Jan 04 '19 at 20:18
  • 2
    Another handy resource: https://testing-library.com/docs/react-testing-library/cheatsheet – SomethingOn Apr 08 '19 at 18:50
  • 9
    and `queryByText` for those who want the equivalent to `getByText` that is null safe – S.. Aug 03 '19 at 09:26
  • I really don't want to set a ton of test-id's just to test for the non-existence of certain elements at certain states, it kind of goes against the guidelines of testing-library doesn't it? – Hylle Apr 22 '20 at 22:26
  • 1
    Agreed. You can use the query* variant of any of the queries.https://testing-library.com/docs/dom-testing-library/api-queries – kentcdodds Apr 23 '20 at 02:18
  • It might be worth noting that this works when the `queryBy..` or `getBy..` is de-structured off the render method. I was using the `screen.get..` methods and it throws an error. – Sam Apr 29 '20 at 13:00
  • @Sam, make sure you're on the latest version of Testing Library. The `screen` API is now recommended over destructuring. – kentcdodds Apr 29 '20 at 18:31
  • `not.toBeInTheDocument` is not in `@react-native-community/testing-library` – Dimitri Kopriwa Feb 17 '21 at 11:31
32

Use queryBy / queryAllBy.

As you say, getBy* and getAllBy* throw an error if nothing is found.

However, the equivalent methods queryBy* and queryAllBy* instead return null or []:

queryBy

queryBy* queries return the first matching node for a query, and return null if no elements match. This is useful for asserting an element that is not present. This throws if more than one match is found (use queryAllBy instead).

queryAllBy queryAllBy* queries return an array of all matching nodes for a query, and return an empty array ([]) if no elements match.

https://testing-library.com/docs/dom-testing-library/api-queries#queryby

So for the specific two you mentioned, you'd instead use queryByText and queryByTestId, but these work for all queries, not just those two.

Sam
  • 3,997
  • 4
  • 36
  • 61
  • 2
    This is way better than the accepted answer. Is this API newer? – RubbelDieKatz Nov 25 '19 at 10:13
  • 1
    Thanks for the kind words! This is basically the same functionality as the [accepted answer](https://stackoverflow.com/a/52783201/328817), so I don't think it's a newer API (but I could be wrong). The only real difference between this answer and the accepted one is that the accepted answer says that there's only method which does this (`queryByTestId`) when in fact there are two whole sets of methods, of which `queryByTestId` is one specific example. – Sam Nov 25 '19 at 14:23
  • Thanks I'd much prefer this than setting test-ids – Hylle Apr 22 '20 at 22:27
  • 1
    Thank you for that detailed explanation. It's a such a subtle difference that I didn't see it despite looking at their example here: https://github.com/testing-library/jest-dom#tobeinthedocument :face-palm: – St. John Feb 02 '21 at 16:10
17

You have to use queryByTestId instead of getByTestId.

Here a code example where i want to test if the component with "car" id isn't existing.

 describe('And there is no car', () => {
  it('Should not display car mark', () => {
    const props = {
      ...defaultProps,
      base: null,
    }
    const { queryByTestId } = render(
      <IntlProvider locale="fr" messages={fr}>
        <CarContainer{...props} />
      </IntlProvider>,
    );
    expect(queryByTestId(/car/)).toBeNull();
  });
});
Valentin Garreau
  • 581
  • 1
  • 4
  • 27
12

getBy* throws an error when not finding an elements, so you can check for that

expect(() => getByText('your text')).toThrow('Unable to find an element');
Gabriel Vasile
  • 1,103
  • 7
  • 19
2

You can use react-native-testing-library "getAllByType" and then check to see if the component is null. Has the advantage of not having to set TestID, also should work with third party components

 it('should contain Customer component', () => {
    const component = render(<Details/>);
    const customerComponent = component.getAllByType(Customer);
    expect(customerComponent).not.toBeNull();
  });
Andy Rich
  • 101
  • 1
  • 2
  • 6
1

Another solution: you could also use a try/catch block

expect.assertions(1)
try {
    // if the element is found, the following expect will fail the test
    expect(getByTestId('your-test-id')).not.toBeVisible();
} catch (error) {
    // otherwise, the expect will throw, and the following expect will pass the test
    expect(true).toBeTruthy();
}
Bassem
  • 1,688
  • 1
  • 11
  • 30
0
const submitButton = screen.queryByText('submit')
expect(submitButton).toBeNull() // it doesn't exist

expect(submitButton).not.toBeNull() // it exist