Is there a way in Selenium C# to find a specific update button on a table if all the ids are the same?

Viewed 41

I am writing a selenium test to test a crud application where you can add, update, or delete a user. I have a table that dynamically displays all of the fields. When I add a new user, a new edit button is also added and when clicked edits that particular user. When trying to test this with selenium, I am not sure how to edit a specific user. I would like to edit the 4th user in the list, which would be index 3. I tried this,

var edit = wait.Until((d) => d.FindElements(By.Id("edit")));
edit[3].Click();

but get an index out of range error. If I do this:

var edit = wait.Until((d) => d.FindElement(By.Id("edit")));
edit.Click();

It allows me to edit the first person in the table.

<tr>
    <td>Ray Peterson</td>
    <td>deleted_0_rpeterson@aol.com</td>
    <td>Developer</td>
    <td>
        <div class="pointer">
            <div class="sprk-o-Stack sprk-o-Stack--split@xs" data-id="">
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <div class="updateUser">
                        <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="edit">
                            <use xlink:href="#editable"></use>
                        </svg>
                    </div>
                </div>
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="deleted_0_rpeterson@aol.com">
                        <use xlink:href="#trash"></use>
                    </svg>
                </div>
            </div>
        </div>
    </td>
</tr>
<tr>
    <td>Fredo Corleone</td>
    <td>godfather88@gmail.com</td>
    <td>Developer</td>
    <td>
        <div class="pointer">
            <div class="sprk-o-Stack sprk-o-Stack--split@xs" data-id="">
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <div class="updateUser">
                        <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="edit">
                            <use xlink:href="#editable"></use>
                        </svg>
                    </div>
                </div>
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="godfather88@gmail.com">
                        <use xlink:href="#trash"></use>
                    </svg>
                </div>
            </div>
        </div>
    </td>
</tr>
<tr>
    <td>Try Again</td>
    <td>tryagain@gmail.com</td>
    <td>Developer</td>
    <td>
        <div class="pointer">
            <div class="sprk-o-Stack sprk-o-Stack--split@xs" data-id="">
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <div class="updateUser">
                        <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="edit">
                            <use xlink:href="#editable"></use>
                        </svg>
                    </div>
                </div>
                <div class="sprk-o-Stack__item sprk-o-Stack__item--half@xs sprk-o-Box" data-id="">
                    <svg class="sprk-c-Icon sprk-c-Icon--l" viewBox="0 0 64 64" data-id="" id="tryagain@gmail.com">
                        <use xlink:href="#trash"></use>
                    </svg>
                </div>
            </div>
        </div>
    </td>
</tr>
2 Answers

You can go with the XPath for identifying the specific field Xpath for identifying the input field Xpath for identifying the input field

I hope you have similar page, please try XPath

If you want to edit a specific user, I've found the best way to do this is to create a locator that uses data from the table to find a specific table row and then click the Edit button in that row. Since we are searching the table to find elements based on contained text, our only locator option is XPath.

I can't test this with the current HTML that contains rendering code but I mocked up something based on what you posted and these should work or at least be close.

If you want to search by firstName lastName, you can use

//tr[./td[1][.='John Smith']]//*[name()='svg'][@id='edit']

If you want to search by email, you can use

//tr[./td[2][.='address@email.com']]//*[name()='svg'][@id='edit']

Ideally you would put these into methods and pass in the search criteria and have it click the Edit button for you so that they are reusable.

/// <summary>
/// Finds the user by the supplied email and clicks Edit
/// </summary>
/// <param name="email">The email address of the user to be edited</param>
public void EditUserByEmail(string email)
{
    By locator = By.XPath($"//tr[./td[2][.='{email}']]//*[name()='svg'][@id='edit']");
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    wait.Until(ExpectedConditions.ElementToBeClickable(locator)).Click();
}

/// <summary>
/// Finds the user by the supplied full name and clicks Edit
/// </summary>
/// <param name="fullName">The full name of the user to be edited in the format "firstName lastName"</param>
public void EditUserByName(string fullName)
{
    By locator = By.XPath($"//tr[./td[1][.='{fullName}']]//*[name()='svg'][@id='edit']");
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    wait.Until(ExpectedConditions.ElementToBeClickable(locator)).Click();
}

and you could call it like

EditUserByEmail("pinocchio@aol.com");
Related