How to check for some text on a webpage using playwright?
Asked Answered
P

5

10

I want to check if the text QUEUED appears on a website. I tried the following commands

await expect(page1).toContainText('[QUEUED]');
await expect(page1.locator('span')).toContainText('[QUEUED]');

but in the first example it says a "locator" is expected, and for the second one it says

Error: strict mode violation: "span" resolved to 108 elements:

I am not interested in the exact element, I just want to check if the text QUEUED appears at least once on the page.

I also tried to select the exact element which in the HTML DOM looks like

<span data-v-729cd282="" class="">QUEUED</span>

using the expression

await expect(page1.locator('(//span[@data-v-729cd282])[6]')).toHaveText('[QUEUED]');

but here I also get an error

waiting for selector "(//span[@data-v-729cd282])[6]"

So how to do this right?

Psychoneurotic answered 14/11, 2022 at 7:44 Comment(0)
I
9

In the first case you need a locator, in the second case your locator found too many elements.

You do need to be interested in the exact elements (even if it can be any element on page), how will you else locate them and assert if the text is visible ?
You should find an element on the page by using the text as locator, and check if its present, thereby knowing the text is on page e.g.

UPDATE

comments are correct and i found that there's more correct ways to implement this, you should do as following instead - above reasoning still persists.

const element = await expect(page.getByText('QUEUED')).toBeVisible();

so you should care about finding a element regardless of what element it is, as long as you'r trying to verify its presence on the page.

Imbrication answered 14/11, 2022 at 8:29 Comment(4)
On my machine, element is a Locator@internal:text="QUEUED"i, which therefore is never undefined -- it's always true.Posterity
Yes, this always returns true for me as well on "@playwright/test": "1.38.0". Better to use .first() and .toBeVisible() I reckon.Boycie
toBeVisible returns a Promise<void> - so element is a void? 🤔Kite
@GrimmTheOpiner Playwrights .getBy locators will throw an error if(0||many) matches, and the element found if exactly one element. That element is then matched on a truthy matcher .toBeVisible. .toBeVisible ensures that the locator getByText points at a visible and attached DOM node.Imbrication
A
2

Don't verify just text on page without any other contextual details.

... as it may verify it on an unexpected place where the intended verification does not apply.

Always locate an desired place (a locator) and verify the text within the context of that element to make the verification meaningful.

Example:

On performing an action on an page, it queues an order on the page. Upon having done that successfully, it shows that as status in front of that order number in the same row but in next column within an table as 'queued'.

So maybe it can be verified as:

await page.locator('tr')
            .filter({ hasText: orderID }) //orderID in variable
            .getByRole('span', { hasText: 'Queued' })
            .isVisible() 

This will be guaranteed to be unique unless the orderID itself is not unique. This is the correct way to validate something.

Armstead answered 19/6, 2023 at 19:0 Comment(0)
E
0

You could combine a locator check with a filter on the text like so:

const queueIsVisible =
  await page.locator('span')
            .filter({ hasText: "QUEUED" })
            .first()
            .isVisible()

This grabs the first one, so it doesn't matter how many are on the page as long as there is at least one match. And then it checks if it is visible.

Emotive answered 19/6, 2023 at 18:8 Comment(0)
B
0

As others have said you should use .getByText(). To the best of my knowledge playwright does not have an assertion that can do freetext/regex matching against a whole page so this is the only way.

However, you always need to be mindful of how many matches might be returned. Some of Playwright's expect methods can handle multiple results, but many can't, and those methods will fail when the selector you pass them isn't specific enough to only select one thing.

If you expect a particular number of results, and only that number, then use .toHaveCount(x) e.g.

const element = await page.getByText(/my search term/i)
await expect(element).toHaveCount(1)

However if don't care if there's more than one, then make sure to qualify the statement with .first(), otherwise Playwright will fail your test if it finds more than one match. You can then use .toBeVisible() to wait for that element to become visible e.g.

const element = await page.getByText(/QUEUED/i).first()
await expect(element).toBeVisible()

Also, note that .getByText() is not a "locator" as such, it return a static DOM element. If you need to monitor the results "live", as you are expecting them to change over time, or as a result of your actions, then you can use locator() with Playwright's custom pseudo-element 'has-text', albeit without the ability to use regex...

page.locator(`:has-text('QUEUED')`)

If you don't need a live DOM reference I would prefer the first way though.

Boycie answered 21/9, 2023 at 12:15 Comment(0)
L
0

You can check the text anywhere on the page like this:

await expect(
    page.getByRole('main').filter({hasText: "Lorem ipsum, bla, bla, bla"}),
  ).toBeTruthy();
Lodged answered 30/7, 2024 at 9:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.