Reputation: 77
I'm trying to get hold of two users in a hideous structure with tables within tables and I'm just not getting it to work... The structure is something like this (inner most table):
<table>
<tbody>
<tr>
<tr>
<tr>
<tr>
<td>
<td>
<td>
<input lotsofuselesstext value="Steve">
<img>
</td>
<td>
</tr>
<tr>
<tr>
<tr>
<td>
<td>
<td>
<input lotsofuselesstext value="Mark">
<img>
</td>
<td>
</tr>
</tbody>
</table>
I'm trying to get hold of Steve and Mark. I can get an xpath that will give me the two input tags, but no matter what I can't get the value fields. I'm using Playwright with C#...
I've tried so many variants that I can't keep track of them, but some that I still have in my code are:
var Planners = await Page.QuerySelectorAllAsync("//*[@summary=\"Planners\"]/tbody/tr/td[3]/input");
var values = await Task.WhenAll(Planners.Select(async element => await element.GetAttributeAsync("value")));
var Planners= await Page.Locator("//*[@summary=\"Planners\"]/tbody/tr/td[3]/input").ElementHandlesAsync();
var Planners = await Page.Locator("//*[@summary=\"Planners\"]/tbody/tr/td[3]/input").AllTextContentsAsync();
And, I'm new to this, as if you couldn't already tell...
Upvotes: 6
Views: 33160
Reputation: 4225
The below code solutions are in JavaScript
await expect(page.locator('.my-table-row').nth(2)).toContainText('Steve');
To get all values from an specific column in an array:(JS)
const textsFromNthColumn = [];
const rows = await page.locator('.table-tbody tr').all();
for (const row of rows) {
const cellText = await row.locator('td').nth(n).innerText();
textsFromNthColumn.push(cellText);
}
console.log(textsFromNthColumn);
Reference: How to get text from a specific column from a table in Playwright
https://github.com/microsoft/playwright/issues/9747
Upvotes: 6
Reputation: 31
I would do something like this
IElementHandle? table = await Page.WaitForSelectorAsync("//*[@summary=\"Planners\"]");
IElementHandle? tableBody = await table.WaitForSelectorAsync("tbody");
var rows = await table?.QuerySelectorAllAsync("tr");
foreach(var row in rows)
{
var cells = await row.QuerySelectorAllAsync("td");
var input = await cells[2].WaitForSelectorAsync("input");
var value = await input.GetAttributeAsync("value");
if(value == "Steve" || value == "Mark")
//Do something
}
Upvotes: 1
Reputation: 11
TLDR:
await Page.GetByRole(AriaRole.Cell, new PageGetByRoleOptions { Name = "Steve" }).GetByRole(AriaRole.Textbox).InputValueAsync();
await Page.GetByRole(AriaRole.Cell, new PageGetByRoleOptions { Name = "Mark" }).GetByRole(AriaRole.Textbox).InputValueAsync();
Here's a breakdown of the code.
Page.GetByRole: This method is used to locate elements based on their ARIA role. In this case, you're looking for cells (AriaRole.Cell) in a table.
new PageGetByRoleOptions { Name = "Steve" }: This part is creating a new instance of a search criterion, specifically looking for a cell that has the accessible name "Steve".
GetByRole(AriaRole.Textbox): Once the specific cell is found, this method is called again to find the textbox within that cell.
InputValueAsync(): This method is called to input a value into the found textbox asynchronously.
Besides write these element locators yourself, codegen
command is also a recommended way to auto generate testing scripts with a relatively high accuracy.
Upvotes: 1
Reputation: 77
I rewrote the xpath and managed to eventually get the names. This is what I ended up with (but I still don't understand why the use of the input tag didn't work):
List<string> textsFromNthColumn = new List<string>();
var rowCount = await Page.Locator("//*[@summary=\"Planners\"]/tbody/tr//td/*[contains(@id,'tdrow_[C:1]_txt-tb')]").CountAsync();
for (int i = 0; i < rowCount; i++)
{
textsFromNthColumn.Add(await Page.Locator("//*[@summary=\"Planners\"]/tbody/tr//td/*[contains(@id,'tdrow_[C:1]_txt-tb')]").Nth(i).GetAttributeAsync("value"));
}
Upvotes: 0