Find element by id in react-testing-library
Asked Answered
O

8

121

I'm using react-testing-libarary to test my react application. For some reason, I need to be able to find the element by id and not data-testid. There is no way to achieve this in the documentation.

Is there a way to achieve this?

I have the rendered output as follows:

const dom = render(<App />);

I'm looking for something along the lines of:

const input = dom.getElementById('firstinput');
//or 
const input = dom.getById('firstinput');
Organdy answered 26/10, 2018 at 7:27 Comment(1)
This worked for me: document.getElementById('firstinput')Forbidden
O
86

I found a way to do this.

import App from './App';
import { render, queryByAttribute } from 'react-testing-library';

const getById = queryByAttribute.bind(null, 'id');

const dom = render(<App />);
const table = getById(dom.container, 'directory-table');

I hope this helps.

Organdy answered 26/10, 2018 at 7:52 Comment(5)
Why they don't have this by default?? I can't believe it.Electrophone
It's much easier to simply use document.getElementById. But the ID of an element is an implemention detail and I recommend against using it.Ashburn
@Victor Believe it. Users don't fill out elements by ID, so the test shouldn't either (at least according to react-testing-library's philosophy). They fill them out by label, so you should find your elements in the test the same way users will find them: by label or placeholder text or whatever.Humbert
@Imat - Reinstate Monica , well, I discussed some scenarios where the #id solution can be the ideal one. Everything depends on scenarios. A simple example: when using a third-party library (like Kendo), which build their elements by your provided #id, you can create tests relying on the id to access the elements. Using the #id will maintain compatibility with new versions of the third party library and it also doesn't pollute our code with data-test-id's. I explained this more in-depth right here: github.com/testing-library/react-testing-library/issues/…Electrophone
Keep scrolling until @Liran H answer.Flavorful
M
135

I feel like none of the answers really gave a complete solution, so here it is:

const result = render(<SomeComponent />);
const someElement = result.container.querySelector('#some-id');
Munshi answered 12/11, 2020 at 11:8 Comment(2)
did not work for me. but when I logged result.debug() I can clearly see the element with that id. :(Boatload
This initially did not work for me because the id was on the react component and in the component, I ignored the id. I changed it such that the component was wrapped in a div that had the id, annd it worked!Pal
O
86

I found a way to do this.

import App from './App';
import { render, queryByAttribute } from 'react-testing-library';

const getById = queryByAttribute.bind(null, 'id');

const dom = render(<App />);
const table = getById(dom.container, 'directory-table');

I hope this helps.

Organdy answered 26/10, 2018 at 7:52 Comment(5)
Why they don't have this by default?? I can't believe it.Electrophone
It's much easier to simply use document.getElementById. But the ID of an element is an implemention detail and I recommend against using it.Ashburn
@Victor Believe it. Users don't fill out elements by ID, so the test shouldn't either (at least according to react-testing-library's philosophy). They fill them out by label, so you should find your elements in the test the same way users will find them: by label or placeholder text or whatever.Humbert
@Imat - Reinstate Monica , well, I discussed some scenarios where the #id solution can be the ideal one. Everything depends on scenarios. A simple example: when using a third-party library (like Kendo), which build their elements by your provided #id, you can create tests relying on the id to access the elements. Using the #id will maintain compatibility with new versions of the third party library and it also doesn't pollute our code with data-test-id's. I explained this more in-depth right here: github.com/testing-library/react-testing-library/issues/…Electrophone
Keep scrolling until @Liran H answer.Flavorful
O
31

It looks you have DOM node itself as a container. Therefore, you should be able to call .querySelector('#firstinput') with that.

Ogilvy answered 26/10, 2018 at 7:33 Comment(5)
yes this works but the only issue here is now I'm not able to use the react-testing-library helpers on this returned node.Organdy
Nothing wrong with not using the helpers if you don't need themFormality
"I'm not able to use the react-testing-library helpers on this returned node." This is incorrect. What helpers are you talking about? All helpers deal with regular DOM nodes, so it doesn't make a difference how you found it. But either way, finding an element by its ID is not included in the library because that's an implementation detail. Use one of the built-in queries.Ashburn
Liran H's answer is better. Some people might not understand what you mean. Giving a complete example like his is better imo.Pharmacognosy
This is the fastest and easiest means of achieving this. HugsBunyabunya
F
23

There are two ways to do so

  1. Simply use container.getElementById('id'). In the end, all the helpers are doing is making queries like this one under the hood
  2. If you want to have your custom query you can write a custom render. Check the documentation for more info https://github.com/kentcdodds/react-testing-library#getbytestidtext-textmatch-htmlelement

As a final note, if you can avoid looking for elements by id it's better.

Formality answered 26/10, 2018 at 7:55 Comment(6)
I don't think you have access to getElementById on the container.Provencher
This is the correct answer. (I'm the author of testing library).Ashburn
Try to log container my guess is that it's not what you're looking forFormality
@Ashburn I mean, would be nice if that work that way (from 1.), but all i get is TS2339: Property 'getElementById' does not exist on type 'HTMLElement'.Transgress
getElementById is not even present on RTL docs '-' For me the correct way is using the this tool: chrome.google.com/webstore/detail/testing-playground/… I never spent time adding/looking for ids again.Amphibolous
getElementById is not in the docs because it's not an API of RTL, it's a DOM API, supported by all browsers. The error @Transgress and @mihai-zamfir are experiencing is a TypeScript error and has nothing to do with RTL.Formality
B
11

You can set up with testIdAttribute in the configuration.

configure({ testIdAttribute: 'id' })

https://testing-library.com/docs/dom-testing-library/api-configuration


The setting has pros and cons. The benefit of it is that you can set an id for multiple uses. (Test id, marketing analytics, tag manager, ...etc) You don't have to add both id and test-id. It's good for the conciseness of the code.

But be careful, you might accidentally set the same id at two different components on the same page. Remember to add index or identification to a component id for list items.

Bedplate answered 8/10, 2020 at 9:57 Comment(3)
testIdAttribute: The attribute used by getByTestId and related queries. Defaults to data-testid.Bedplate
This is a bad idea because ids are meant to be unique to a single element on an entire page, whereas a test id can be used on more than one element (list items, for example).Neurovascular
Yeah, you're probably right. But there are some benefits for the setting if we need the ids for multiple purposes. (tag manager, for example)Bedplate
A
3

My advice: stop adding and searching by ids, this always takes to much time and effort because you have to add the ids (sometimes test-ids) and then find out the best way to query the element. But even if you really need an id, this tool will save you a lot of time by showing the best way to query any DOM element on your screen: Testing Playground

Amphibolous answered 25/5, 2021 at 14:45 Comment(0)
S
1

If you use TypeScript, and want to get a non-null result, here's a convenience function:

function getById<T extends Element>(container: HTMLElement, id: string): T {
  const element = container.querySelector<T>(`#${id}`);
  assert(element !== null, `Unable to find an element with ID #${id}.`)
  return element;
}

You can then use it like this:

import { render } from '@testing-library/react';

const { container } = render(<App />);
const myInputElement = getById<HTMLInputElement>(container, 'myInputElement');
Siclari answered 11/4, 2022 at 15:1 Comment(0)
A
0

    await waitFor(() => {
            const innerOverlay = queryByAttribute("id", baseElement, "yourId");
            expect(innerOverlay).toBeTruthy();
        });
    

I haven't find anyway to findBy and attribute, however it has queryByAttribute. So we can use it with waitFor to make it similar with findBy

Allowedly answered 12/4, 2024 at 9:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.