6

Consider the following source code,

<div id="groupContainer" class="XXXXXX">

<ul id="GroupContactListWrapper" class="list-wrapper">
    <li class="contactNameItemContainer">

        <div class="contactNameItem">
            <span class="name">Name1</span>
        </div>

    </li>
    <li class="contactNameItemContainer">

        <div class="contactNameItem">
            <span class="name">Name2</span>
        </div>

    </li>
</ul>

</div>

How do i retreive the two names (Name1,Name2) in a list variable ? I tried the following xpath for a "Get Text" keyword, but only returns the first one.

//div[@id='groupContainer']//li[@class='contactNameItemContainer']//span

Please suggest

velapanur
  • 307
  • 3
  • 5
  • 19

6 Answers6

8

You could iterate over the elements as below:

${xpath}=    Set Variable    //div[@id='groupContainer']//li[@class='contactNameItemContainer']//span
${count}=    Get Matching Xpath Count    ${xpath}
${names}=    Create List
:FOR    ${i}    IN RANGE    1    ${count} + 1
\    ${name}=    Get Text    xpath=(${xpath})[${i}]
\    Append To List    ${names}    ${name}

This works but is rather slow when there are many matches.

ombre42
  • 2,344
  • 15
  • 21
  • Can I please ask why you used "${name}" as the list name instead of "@{name}"? – Yu Zhang Aug 02 '15 at 00:59
  • I think there is a typo, **xpath=(${xpath})[${i}]** should have been **xpath=(${xpath})** – Yu Zhang Aug 02 '15 at 03:05
  • That's why I think RF sucks when a test case is a little complex. It creates a new language, but make it more complecated and way less powerful than python. Why doesn't It just let us just use python, and RF, as a framework, just provides functions like machanism of setup, teardown, control test cases scripts running, generator report. That's enough and good. Now it does more but does bad. Keyword development sucks. – Jcyrss May 10 '17 at 03:31
3

You could extend Selenium2Library and write your own keyword for this purpose. Save the following as Selenium2LibraryExt.py

from Selenium2Library import Selenium2Library


class Selenium2LibraryExt(Selenium2Library):

    def get_all_texts(self, locator):
        """Returns the text value of elements identified by `locator`.
        See `introduction` for details about locating elements.
        """
        return self._get_all_texts(locator)

    def _get_all_texts(self, locator):
        elements = self._element_find(locator, False, True)
        texts = []
        for element in elements:
            if element is not None:
                texts.append(element.text)
        return texts if texts else None

Then you can use your new Get All Texts keyword in your tests like this:

*** Settings ***
library     Selenium2LibraryExt


*** Test Cases ***
Get All Texts Test
  Open Browser    http://www.example.com   chrome
  @{texts}        Get All Texts            css=.name
  Log Many        ${texts}
finspin
  • 4,021
  • 6
  • 38
  • 66
3

Though the top-rated answer is fully working - and the most xpath-ish :), let me add an option I don't see proposed yet - using the Get Webelements keyword. E.g.:

@{locators}=     Get Webelements    xpath=//div[@id='groupContainer']//li[@class='contactNameItemContainer']//span
${result}=       Create List

:FOR   ${locator}   in    @{locators}
\       ${name}=    Get Text    ${locator}
\       Append To List  ${result}  ${name}

It'll generate and return a list of all matching elements, on which you just iterate on. It might be a tad faster than xpath's [index] reference because the dom is evaluated once - but don't hold me accountable if that's not fully true :)

Todor Minakov
  • 19,097
  • 3
  • 55
  • 60
2

Get Text will return content of the first element that matches the locator. When using XPATH you can specify the index of the element you want to get, like this:

${name1}    Get Text    xpath=//div[@id='groupContainer']//li[@class='contactNameItemContainer'][0]//span
${name2}    Get Text    xpath=//div[@id='groupContainer']//li[@class='contactNameItemContainer'][1]//span
@{names}    Create List    ${name1}    ${name2}
Harri
  • 2,692
  • 2
  • 21
  • 25
  • This would work for the above case, but i was looking for a more generic one where there could be more than 2 inner LI containers – velapanur Jul 01 '14 at 17:51
2

@Velapanur

I had another similar requirement where in i have to enter the texts into textareas in a page. The below i wrote with the idea in reference to what Todor had suggested, and it worked. Many thanks to Todor, Velapanur

@{Texts}=    Get WebElements    ${AllTextboxes}

    :FOR    ${EachTextarea}    in    @{Texts}

\    Input Text    ${EachTextarea}    ${RandomTextdata}
asha cr
  • 131
  • 3
-1

Here is the logic to get all elements in Java. You can adopt it to your need.

You have to use findElements() and not findElement() to get all elements.

List<WebElement> items = driver.findElements(By.cssSelector("ul#GroupContactListWrapper div.contactNameItem"));

foreach(item in items){
   System.out.println(item.getText();
}

If you want a particular element from the list you can use items.get(1)

Purus
  • 5,701
  • 9
  • 50
  • 89