How do I make expect(stuff).toHaveTextContent(text)
pass only when the text matches exactly?
.toHaveTextContent("1")
counts as a match if the text I'm testing is "100"
How do I make expect(stuff).toHaveTextContent(text)
pass only when the text matches exactly?
.toHaveTextContent("1")
counts as a match if the text I'm testing is "100"
You can do the ff instead:
expect(stuff.textContent).toBe('100')
Use a regex instead expect(stuff).toHaveTextContent(/^100$/);
if you want to match exactly.
As written in the doc (https://github.com/testing-library/jest-dom#tohavetextcontent), it will (just) "check whether the given node has a text content or not"
.toHaveTextContent(/^My name is Joe. Hello, world.$/)
probably doesn't do what you expect (.
is a regex special character matching any character rather than a period, so My name is JoeZ Hello, world0
matches). –
Elagabalus Use getByText
like so,
const { getByText } = render(<YourComponent />)
expect(getByText('text you\'re looking for')).toBeInTheDocument()
This assumes it will be there, so if there's a chance it won't be, use queryByText
.
Get the the text using innerHTML
const element = await waitFor(() => document.querySelector('<YOUR_QUERY>'));
expect(element.innerHTML).toEqual('100')
waitFor
? There's nothing async here yet. Also, just because you're using innerHTML
(probably better to use textContent
) doesn't mean you should stop using RTL selectors. Even if there is an async query, seems best to use screen.findByTestId
or similar, which does the waiting for you. –
Elagabalus As yatrix shows, getByText
offers a non-substring semantic, but running it on the whole component as shown in that answer can lead to false positives. I'd prefer a precise test that checks whether a specific element has certain text:
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import {render, screen, within} from "@testing-library/react";
const {getByTestId} = screen;
describe("Test", () => {
it("should be precise when testing text", () => {
render(
<div>
<div data-testid="test1">10</div>
<div data-testid="test2">100</div>
</div>
);
expect(within(getByTestId("test1")).getByText("10"))
.toBeInTheDocument();
expect(getByTestId("test2")).toHaveTextContent(/^100$/);
});
});
I've also tossed in an assertion using Benjamin's regex approach but I'm wary of this since it's all too easy to forget you're in regex mode and fail to escape a special character like .
.
Note also that
expect(within(getByTestId("test1")).getByText("10"))
.toBeInTheDocument();
can be simply:
within(getByTestId("test1")).getByText("10");
because getBy
will throw if it fails to find a matching element, effectively acting as an expectation/assertion. Kent recommends keeping it explicit, but also says it "really is fine honestly" to skip the assertion. Use queryByText
for assertions for non-existence.
Relevant packages for this post:
{
"@testing-library/dom": "8.11.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "12.1.2",
"@testing-library/react-hooks": "7.0.2",
"@testing-library/user-event": "13.5.0",
"jest": "27.4.5",
"jest-environment-jsdom": "27.4.4",
"react": "17.0.2",
"react-dom": "17.0.2"
}
I think that the best is to use a regular expresion. Let say that you have:
const text = "My exact\ntext";
So the RegExp
should be:
const escapePattern = new RegExp('[.*+?^${}()|[\]\\]', 'g');
const replaceWith = '\\$&';
const textEscaped = text.replace(escapePattern, replaceWith);
const options = {
normalizeWhitespace: false,
};
const regexpToHave = new RegExp(`^${textEscaped}$`, 'm')
expect(stuff).toHaveTextContent(regexpToHave, options);
The m
string means "multiline" and the g "global".
Check the options
and make sure set normalizeWhitespace
to false
to avoid issues.
It is common use in Jest to use getByTestId
, and use data-testid
attribute in the element to be tested. That you ensure that the correct element has the text and not other.
© 2022 - 2024 — McMap. All rights reserved.
toEqual('100')
– Guanidine