Web Tables Navigation | Bondar Academy
Course: Playwright UI Testing with TypeScript
Module: Mastering UI Elements
Instructor: Artem Bondar
Lesson Summary
In this lesson, we explore web tables and techniques for locating web elements within them using Playwright . Navigating tables can be challenging due to their structure, but we will cover effective strategies to identify specific rows and cells. Key Concepts Table Structure: A web table starts with a <table> tag, often containing <thead> and <tbody> sections. Inside the body, rows are defined by <tr> tags, and columns by <td> tags. Locating Rows: To locate a specific row, use getByRow with a unique identifier, such as an email address. Editing Values: When editing a value, such as a user's age, ensure to identify the correct input field, which may not be the same as the displayed text. Automation Steps Identify the target row using a unique identifier (e.g., email). Click the edit button (e.g., pencil icon) to modify the row. Use getByPlaceholder to locate input fields for editing. Submit changes and confirm updates using a checkmark button. Advanced Techniques When dealing with non-unique identifiers, such as IDs that may repeat across pages, use a filter method to narrow down results based on specific columns. This involves: Using page.locator to find elements. Filtering results by column index to ensure accuracy. In summary, to effectively automate interactions with web tables, utilize unique identifiers and appropriate locators, and be mindful of the differences between displayed text and input values. This knowledge will enhance your ability to navigate and manipulate web tables in your tests.
Video Transcript
In this lesson, we will talk about web tables and how to locate web elements inside of the table. So, locating web elements inside of a table of a particular row of the table or cell of the table sometimes can be pretty tricky because of the structure of the web table overall. And in this lesson, I will show you some tricks how using Playwright to locate a specific row of the table or specific cells inside of the table. So, let's get into it. So, for example, let me click on nSpec and I will show you what I mean. So, table always starts with a table tag. When you open this, usually it has table head or table body. Sometimes without the table head, it's just a table body HTML tag. And then inside of table body, we have a table rows, which is tr tag. And each tr has tds. td is table down, which is table column. So, if I hover over each td, you can see that it is highlighted. The tricky part of working with the web tables is identifying the unique enough element to pick up a certain cell from the table or the certain row from the table and making your test table. Or, for example, a tricky part, how to select the entire column in the table. It is pretty difficult task because we know that we have table rows and all columns are within each of the row. So, there is no way how you can select the entire column vertically and just process the values from this column. So, in this lesson, I will show you the tricks how to overcome these difficulties. So, you will be comfortable navigating through the table and automating any scenarios in that. So, in this lesson, let's automate this scenario like this. So, let's say we will take a third user from this row. We will find this user by his email. We know that email is unique for each of this user. This is a unique identifier. So, we're gonna find this row and we will modify age for this user. So, we change 18 to, for example, 35. Let's automate this scenario for the beginning. I'm going back to the framework and creating a new test. From the previous test, I'm gonna copy tables and data in smart table because we already used this page. And the first example I want to show you is how to get the row by any text in this row. We already kind of using this example in the previous lesson when we were automating the dialog box, but I would like to show you this one more time. So, first thing, we need to get the locator for the row. And this is the row that we are interested in. And the unique identifier, we know that this is this email. So, let's do this email as a unique identifier. const targetRow equals to page, getByRow. And the recommended way to get the desired row in the table is to use row, getByRow.type, and then provide the name and provide the text value, which is unique for this particular row. And this is the email address. Here we go. And now we can perform any operations within this row, whatever we want. So, the next step would be we want to click on this pencil to edit the details in this row. So, right-click, inspect, and the pencil class is nbEdit. Await targetRow, locator, and perform a click. That's it. So, let's run this real quick to make sure that it is working as expected. Yeah, you can see the click was performed and our row right now is an edit mode. Moving on. So, the next thing we want to click on this pencil button, right, and modify the age for this user. And the first thing that you may think is let's navigate just to this row by using this locator that we already have and update this age. So, sounds simple, right? But look what we actually have. So, if I make a right-click on this email and navigate, we can see that this email is displayed as a text inside of this row when this row is not edited. But if I click on the pencil, you see that the DOM has changed. And if I will try to inspect the same cell one more time, this value does not exist here anymore. This is not a text anymore. This is a property right now. And we can see only that ng-reflect model has this value and it became an input field. And remember, I mentioned before that inside of the input fields, very often the text that you see is not the actually HTML text. This is a property value. And this is our case. That's why this locator will not work because getByRow and name, name referring to exact HTML text reflected in the row. Since this is not a text anymore, this is a property value. We cannot reuse this locator. We need to do something different. So, what we can do? We can build a new locator, take this input editor, HTML tag, and take some other property, which is unique for the field. And since we want to update the age, we can take, inspect, input editor, and we can take a placeholder age. So, let's do this. Await page locator. First, we need to take this input editor tag, and then within getByPlaceholder, and we can use age. First thing, we need to clear the existing value. Clear input field. And then we want to type inside of the same cell, field 35. And after we type the value, we need to confirm that this has happened. Right-click on this icon, inspect, and this is NB checkmark. Await page locator.nbcheckmarkclass.click. All right, so, let's run this test. All right, you can see that age was successful. All right, you can see that age was successfully updated for our user. Right now, it's 35. If I will show the screenshots before, so we made a click. Edit 18, clear. Now, it's 35, and we confirm this. So, everything is working fine. So, one more time, real quick. So, everything is working fine. So, one more time, real quick. You can always get any row in the web table by using getByRow, row, and providing the text that exists in this row. But keep in mind that sometimes text in the table can be reflected as an input value. In this case, you will not be able to use the locator like that. You will need to use something different. For example, we use the placeholder age to identify the right cell in our table. Moving on. So, let's make it a little bit more complex scenario. For example, we want to select a row by the ID column. So, if we look into this table, we see that ID is unique. And if we are going to next pages, all the ID numbers is unique. So, we can technically use the ID column to select whatever user we want from this table. But here is a difficulty. For example, if we go to the second page, we may have a situation when the ID is the same as the age. For example, ID 11. And here we have a different column, age is 11. Or here, 19 ID and age 19 as well. So, if we follow approach from the previous example, like getByRow with this text, it will not work. Because PlayWrite will find for us two rows with the same text. But how can we tell a PlayWrite to find the row only by the specific column in the table? So, let me show you how to do that as well. So, let's make this scenario. We will navigate to the second page of this table. And then we update a user with ID 11. So, PlayWrite should find just this table, ignoring this one. And we want to update, let's say, this email to some new value. So, let's gonna do this. So, the first thing what we need to do is to navigate on the second page. So, how to do that? Let's do inspect. We can take the text too. But we need something more unique about this specific area. And we can, for example, take this class. Or no, let's take this one, ng-smart-pagination-nav. It sounds like unique. So, we can take this class. And then within this class, we can find a text that has two. And we will be able successfully to click on this particular page. So, let's create a new page. Await page.locator. We provide the class. And then getByText to dot click. Okay, so, let's run this really quick to see if it's actually clicking on the second page. Yes, it's navigated to the second page. Moving on. Let's create a locator for this, navigate to page two, for this row by ID 11. How are we gonna do this? Const, let me call it target row by ID equals. And it starts with similar approach. Page dot getByRow, row, and I provide the name 11. So, let me run it. And I will show you that it will actually try to find add two elements. Let me make this quick demo. Yeah, and you can see we have an error. Let me make it bigger. So, yeah, two rows were found. One is Mark Otto, and the second one is Francisco Brady. And this is exactly how it's supposed to work. So, this is our Francisco Brady with the age 11. And first guy is this Mark Otto with ID 11. So, now we have two rows found. And out of those two rows, right now we need to find only a single row, which is the first one for this particular guy by the ID column. And how to do that? We need to use a filter method. So, we will filter our output of two rows. And we will provide the filter as a locator. Has, and locator will be a column with the desired value. So, we type page dot locator. We are looking for column TD. And the index of this column is one. So, if we go back to application. So, first column is actions, which is index zero. And we are interested in the second column. So, index should be one. And it should be a number, not a string. Okay, and once we found this first column, we want to get by text and 11. So, one more time what's going to happen here. So, this locator will return us two rows in the table. Then this filter will return us all columns for each of those rows. Then we want to take only first column for the two rows. And then that result, we want to find only text 11 as part of the first column. And because text 11 exists only in one of the rows in the first column, this entire expression will return us a row that has text 11 in the first column. So, this is how it works. And right now I can do with this row, whatever I need. I need to click on NB edit button. And let's see if this actually works. Yeah, you can see we successfully selected the first row. And right now it's in edit mode. And the rest is pretty simple. So, we can speed up this process. I can copy the previous two lines. And we are looking instead of age, we're looking for email. Email clear, email one, email two, email three, email four, email five. And we want to fill a value test at test.com. And we can run this test one more time. Okay, test at test.com sounds good. Now we need to submit the NB check mark click to confirm our update. And let's say we want to add the assertion that we successfully made the change. So, I type expect. Now I need to find this column and make an assertion that this text was updated. So, now I can use this row again because it is not in the edit mode anymore. And I can reuse this locator, locator td. I need to find all the columns in my row. And the column index would be 0, 1, 2, 3, 4, 5. So, email is the fifth column in this row. And five, and it should to have text. And we are expecting this test at test.com to be there, running it again. Okay, it worked successfully. We have assertion, assertion is passed. And let's quickly summarize what we did in this lesson. If you want to locate any row in the table and your table has a unique text, you can use this form, getByRow, and provide the text that is displayed in the table. Keep in mind, the text that displayed in the table, not always HTML text. It sometimes can be a value. In this case, you will not be able to use this construction. You will need to use a different identifier, such as getByPlaceholder or something else. If the text that you are looking for in the row is not unique, but unique for the certain column, you can use a filter narrowing down the output of your row by a specific column using the constructions like that, using allocator filter. Then when you want to make the assertion, you can always navigate into the desired column by the index of this column and make an assertion. All right, that's it, guys, and see you in the next lesson.