How to check locators using Playwright

In this article we will talk about what can be checked from a locator (element) and what kind of checking options there are in general. Moreover, in this article I have described exercises that you can do and practice as practice.
Usually my articles were holivar, not technical. But this time I decided to post something really technical and useful. Testers, come on! I really want experienced guys who have been working with playwright for a long time to share their opinion about the examples in the text of the article. Are they informative enough?

Locator checks.

These can be either interactive elements (buttons, input fields, check boxes, …) or statics (pictures, text, icons, etc.).

Each element on the page can give the user feedback: the input field is highlighted in red if you entered invalid data, the “Save” icon is grayed out because you have not yet made changes to the document, the color of the pop-up notification should be red because an error has occurred. Most often, we need to get some property of an element just to immediately check its value. We want to check that the correct text is displayed or the element is assigned the correct CSS class.

On the other hand, sometimes we still need to be able to obtain the properties of elements for intermediate actions. For example, we want to see how many rows are in the table now, delete one and check, that there are one fewer lines. In order to organize such a check, we need to calculate how many lines there were before how we removed the last line. If the table had X lines, then, after pressing, there should be X-1. Find X, is it possible? And here we need a “handle” that we pull and get a number, without any asserts.

In this section we will talk about the possibilities of working with the locator in two planes: we will talk about how to get element property and how to check it.

Element text

Let's start with a simple example – receiving And examination text.

Practice problem

Let's write a script that opens page and takes the text from the first element on the page using the locator [field=descr].

const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => {
await page.goto("<https://inzhenerka.tech/>");
const description = await page.locator("[field=descr]").first().textContent();
console.log(description);
});

The text “We help engineers improve their skills in the labor market and acquire international-level skills” will be displayed in the console. Why did we see it in the console – because the line console.log(description);. Why in the variable description turned out to have a value – because we used the method textContent()which returns us the text of the passed locator.

What else is first()?

You may have noticed that we use some kind of method for the locator first() before requesting the element's text. Do I need to use it every time I want to get the text of an element? Or what happens if this method is not called? Let's explain.

The fact is that, according to our locator [field=descr], 4 elements are detected on the page. Playwright, in such cases, throws an error Error: strict mode violation: locator('[field=descr]') resolved to 4 elements. Which roughly translates to “figure out what you want, then come” “using this locator, 4 elements are determined.” PW does not choose for us which element to work with, but simply stops. If you want the code to be executed, give more precise instructions. After all, the method textContent() works only with one element, but here there is more than one.

So what to do? There are only 2 ways:

  • Way 1: write a more accurate locator. And this is good practice. If you have the opportunity, see what else you can write in the locator to accurately identify the element.

  • Path 2nd and last: explain to PW which of the found elements should be selected. In our case, we ask you to take the first one. By the wayguess what order of elements we will get if we write not .first()A .last() ?

Since we know how to access the first matching element and the last matching element, the question arises – what if I want to access 4 of the 10 elements? Yes, or simply – by the third and I don’t know how many of them there will be in total? Here we have a method .nth(number), which takes as input a number – the serial number of the element. And yes, indexing starts from 0.

It turns out that nth(1) will return me the second in order element? Yeah! And it also turns out that nth(0) – the same as first()? Yeah! It’s just that “first” is somehow easier to read, don’t you agree?

Links to these methods if you are reading them: nth, first And last

So, we know how to get the text of an element. And here, if you have worked with selenium, for example, everything is already clear to you: to write a test, we need to get the text and compare it with the expected one. Well, something like this, for example:

`const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => { await page.goto("https://inzhenerka.tech/");

// saved the element's text into a variable const description = await page.locator(“[field=descr]”).first().textContent(); // checked that the text in the variable is equal to the one we specified expect(description).toEqual( “We help engineers improve their qualifications in the labor market and acquire international-level skills”); } );`

And it will even work.

On the other hand, if you open documentationyou can see this warning:

Untitled

The developers of the tool tell us in plain text that, if you want check text, use a better method toHaveText(). You and I have been on the Internet for a long time and we know that in such situations you need to immediately ask – what is “better”?

First let's see what our test will look like if we use the recommended method:

const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => {
await page.goto("<https://inzhenerka.tech/>");
await expect(page.locator("[field=descr]").first()).toHaveText(
"Помогаем инженерам повысить свою квалификацию на рынке труда и приобрести навыки международного уровня"
);
});

Look, we did without a variable description – they immediately wrote a check, saying that such and such an element should contain such and such text. In the “readability” criterion, we write one point in favor of the second approach. By the way, we noticed that now expect() can I call another set of methods? This is all because we passed no pageas before, and locator. Now suitable methods have appeared.

U toHaveText() There are a couple more tricks in the powder flasks.

Firstly, this method can compare, ignoring case. This will come in handy when you find out that in HTML the text is written in small letters, but the page is displayed in CAPS (ask your front-end developer how this can be done). And so, in order not to collect bumps, selecting the correct register for the expected result, we can simply pass the correct setting:

await expect(page.locator("")).toHaveText("ожидаемый текст", {
  ignoreCase: true,
});

The second interesting feature of the method toHaveText() – it can check the text of a group of elements. How it works: if your locator defines not one element on the page, but a group (for example, a list), then to check the text of the elements we must pass a group (array) of values. The method will correlate received and expected texts 1-to-1. If something doesn't match, it's an error. Examples:

<!-- вот у нас есть вот такой список на странице  -->
<ul>
  <li>Билли</li>
  <li>Вилли</li>
  <li>Дилли</li>
</ul>
// ✓ Вот этот код проверит, что тексты у элементов соответственно равны переданным.
await expect(page.locator("ul > li")).toHaveText(["Билли", "Вилли", "Дилли"]);
// ✖ Вот такая проверка упадет, потому что текстовки идут в другом порядке
await expect(page.locator("ul > li")).toHaveText(["Дилли", "Билли", "Вилли"]);
// ✖ Такой тест тоже упадет, потому что текст одного из элементов не совпадем с ожидаемым
await expect(page.locator("ul > li")).toHaveText([
"Билли",
"Вилли",
"Джонатан?",
]);
// ✖ Вот тут сложнее.
// Тест упадет, потому что локатор собирает не группу элементов (li), а только один (ul).
// Нельзя сравнить текст одного элемента с группой текстов.
await expect(page.locator("ul")).toHaveText(["Text 1", "Text 2", "Text 3"]);

Link to documentation In general, it is indeed more convenient and the code is more readable. Let's do this: if we want to get data, we use the Locator class method. If we want a check, we add the locator to the expect method and call an interesting method.

This is a free demo part of the Playwright simulator lesson from INZHENERKA.TECH, written by Dmitry Eremin. More discussions on the topic are taking place in our Playwright community in telegram

Let me remind you of the purpose of this article: share your opinion about the examples in the text, what do you think? Do you find them informative enough?

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *