6

There's been other questions like these, but I feel like I'm missing some of the basics, so I'll try asking a potential duplicate question:

How do I get/list the contents of each row in a table like this?

<div class="entity-body list-entity-body entity-content-payload">
   <div class="table-holder l-height-full" style="overflow-y: scroll; flex: 1 1 auto" data-bind="fullHeight: 'leave-space-for-following-elements'">
      <content-placeholder class="l-height-full jsx-component-rendered" content-id="list-page-list">
         <content-placeholder class=" jsx-component-rendered" content-id="standard-list-page-list">
            <section class=" jsx-component-rendered" data-bind="component: { name: listCustomElementName, params: listParams }">
               <table class="table-default" cellspacing="0" style="width: 100%">
                  <thead>
                     <tr>
                        ...
                     </tr>
                  </thead>
                  <tbody>
                     <tr data-bind="css: { selected: $parent.selected.indexOf(href) != -1 }, loadRelated: $parent.fieldsFromRelated">>
                        <td class="fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                        <td class="keyColumn fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                        <td class="keyColumn fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                        <td class="keyColumn fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                        <td class="keyColumn fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                        <td class="fit-cell-content">
                           <a data-bind="clientHref: href" href="#/Customers/149999/Locations/000" data-server-href="/Api/Customers/149999/Locations/000">
                        </td>
                     </tr>   

There are other things on the page, and this code is nested quite a but down in the tags, but it should be possible. However, one thing is finding the rows and contens (which I need hints for doing) - another is storing it and using it.

UPDATE: kirbycope has a great answer below. Building on that, how do check each row for a specific name and then click it?

UPDATE2: Using kirbycope's examples below, here's what I've got so far:

(I search the table for an row containing a specific text - "Bergen" in a td)

var table = GCDriver.Instance.FindElement(By.TagName("table"));
var rows = table.FindElements(By.TagName("tr"));

foreach (var row in rows) {
    if (row.Text.Contains("Bergen")) {
    //Console.WriteLine(row.Text);

    var tds = row.FindElements(By.TagName("a"));
    foreach (var entry in tds) {
        Console.WriteLine(entry.Text);
        entry.Click();
    }
}

The Console.WriteLine line works fine, printing this:

149999-002
Bergen
0
0
13
Branch Office

However, the entry.Click() line does not, resulting in this error:

OpenQA.Selenium.StaleElementReferenceException: stale element reference:     
element is not attached to the page document
  (Session info: chrome=56.0.2924.87)
  (Driver info: chromedriver=2.28.455520     
(cc17746adff54984afff480136733114c6b3704b),platform=Windows NT 10.0.14393 x86_64)

Most of what I can find on that exception is that people seem to think it's because an element is not loaded, not accessible etc. on the web page, and to implement a wait or similar. But this is not the case here; I can add a timeout of 10 hours and the exception is still there. Also, if I just use the XPath of a specific row and add .Click() to that, it works fine.

UPDATE 3: As per ChatuD's help below, I'm trying this to get all the elements of a specific row (tr):

var rows = table.FindElements(By.TagName("tr"));
    foreach (var row in rows) {
        if (row.Text.Contains("Bergen")) {
            IList<IWebElement> List = row.FindElements(By.TagName("a"));
            List<String> NewList = new List<String>();

            foreach (var item in List) {
                NewList.Add(item.Text);
            }

            Actions action3 = new Actions(GCDriver.Instance);
            action3.MoveToElement(NewList[<Index number >]).Perform();
        }

But - and pardon my lack of both C# and VS knowledge - how do I access the row element in NewList in the last line above? It doesn't work just typing the index number, and "ElementAt" doesn't exist as a method.

2 Answers 2

10

Get the table, then its rows, then each row's TDs, then each TD's anchor:

var table = driver.FindElement(By.TagName("table"));
var rows = table.FindElements(By.TagName("tr"));
foreach (var row in rows)
{
     var rowTds = row.FindElements(By.TagName("td"));
     foreach (var td in rowTds)
     {
         var a = td.FindElement(By.TagName("a"));
         Console.WriteLine("HREF: " + a.GetAttribute("href"));
     }
}

Or, if you just want each of the TDs anchors you could:

var tds = driver.FindElements(By.TagName("td"));
foreach (var td in tds)
{
    var a = td.FindElement(By.TagName("a"));
    var href = a.GetAttribute("href"));
    if(href.Contains("Customer1234"))
    {
        a.Click();
        break;
    }
}

The takeaway here is that *.FindElements() returns a collection of elements that you can parse. In much the same way as document.querySelectorAll() does in JavaScript.

9
  • That simple, eh? :-)
    – Hfrav
    Commented Mar 21, 2017 at 15:08
  • 1
    Hm. What if you wanted to search each row for a specific name and click it? (I notice the contents are links...)
    – Frank H.
    Commented Mar 21, 2017 at 15:09
  • Yes, or check the td(-s) inside the rows for specific names.
    – Hfrav
    Commented Mar 21, 2017 at 15:11
  • 1
    I updated my answer. You can just grab all TDs or get all rows, then for each row, get its TDs, then for each TD get the Anchor. It all depends on what makes the most sense for you test case.
    – kirbycope
    Commented Mar 21, 2017 at 15:17
  • The line "var a = td.FindElement(By.TagName("a"));" throws this exception: "threw exception: OpenQA.Selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"tag name","selector":"a"}"
    – Hfrav
    Commented Mar 22, 2017 at 9:10
2

As every line start with a '<a' tag

IList<IWebElement> List = driver.FindElements(By.TagName("a"));
List<String> NewList = new List<String>();
foreach (var item in List)
            {
                NewList.Add(item.Text);
            }

The you will get all the list of items in the table as NewList.

So for clicking on an element dont directly use NewList[<Index number>]. Use Actions.

Actions action3 = new Actions(Setup.driver);
            action3.MoveToElement(NewList[<Index number>]).Perform();

            Thread.Sleep(4000);
            action3.Click(NewList[<Index number>]).Perform();
7
  • Well, this is basically what I'm doing, and I'm able to find a specific row based on the content of one of the tds. However, when I try CLICKING it (in your example, with item.Click()), I get this error: "OpenQA.Selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document". Which I don't understand, because if I use FirePath to get the XPath for a specific row in the list, I can click it without problems.
    – Hfrav
    Commented Mar 22, 2017 at 15:09
  • simple matter.I will update my answer
    – ChathuD
    Commented Mar 22, 2017 at 17:03
  • Hm. What on earth goes into the [<Index number>] space? Nothing I try is accepted...
    – Hfrav
    Commented Mar 23, 2017 at 12:34
  • index number means the item number of that returning NewList.Just debug the code and see how the NewLine List will looks like after it gose thru the Foreach loop
    – ChathuD
    Commented Mar 23, 2017 at 15:53
  • Sorry for the silly questions, but I'm very new at both C# and VS. I was thinking to step through the code, but that doesn't seem too easy with a unit test and not an executable project. Anyway, what I don't understand is: NewList.Add(item.Text); <--- here we just add the textual items in the list, right? For the row in question. Then, why shouldn't I be able to do action3.MoveToElement(NewList[0]).Perform(); to access a specific element?
    – Hfrav
    Commented Mar 27, 2017 at 8:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.