7

So I am facing a problem interacting with this HTML below. I am unable to open the pop up and close it using different Selenium Webdriver commands. Although I am looking for a specific solution here, any general tips on dealing with Angular JS would also be appreciated. I believe that the root cause of the problem is that I do not know a good way to automate Angular using Selenium Webdriver.

I'm using C#, but I will take any helpful information from any programming language as I can always retrofit the solution.

I am trying to interact with this pop up button, unsuccessfully: uib-popover-template="'/app/student/assessment/directives/templates/shortTextPopupTemplate.html'"

<div class="line ttsBorder">“<span style="font-style:italic;">And be it further enacted</span><span style="display: inline;">, That in all that territory ceded</span><span short-text-popup="" accession-number="VH209006" class="ng-isolate-scope" ng-non-bindable=""><a uib-popover-template="'/app/student/assessment/directives/templates/shortTextPopupTemplate.html'" popover-is-open="ctrl.isVisible" popover-trigger="none" popover-placement="auto top" tabindex="0" title="Shows more information." ng-click="buttonOnClick($event)" ng-keydown="buttonOnKeydown($event)" ng-class="['stpu-button', {disabled: ctrl.isDisabled, active: ctrl.isVisible}]" class="ng-scope stpu-button" style="z-index: 3;"></a></span> by France to the United States&nbsp;.&nbsp;.&nbsp;.&nbsp;which lies north of thirty‑six degrees and thirty minutes north latitude&nbsp;.&nbsp;.&nbsp;.&nbsp;slavery&nbsp;.&nbsp;.&nbsp;.&nbsp;shall be, and is hereby, forever prohibited.”</div>

Here is what I tried unsuccessfully:

//attempt 1
var elements = Driver.FindElements(By.XPath("//*[@class='line ttsBorder']"));

//attempt 2 - UserInteractions = new Actions(Driver);
UserInteractions.MoveToElement(PopUpButton).Click().Perform();


//attempt 3    
    Driver.FindElement(By.XPath("//[@title='Shows more information.']")).Click();

//attempt 4
//Driver.FindElement(By.XPath("//a[@uib-popover-template]"));
    PopUpButton.Click();

//attempt 5
//Working, but seems dirty - JavaExecutor.ExecuteScript("arguments[0].click();", PopUpButton);

I had to result to tabbing through the UI to find the element that I want. I'm really unhappy with such a brittle solution and was hoping that you can offer some advice.

Thanks in advance!

1 Answer 1

3

The quick fix is to create a CssSelector to access your element like this: Driver.FindElement(By.CssSelector("a[ng-click='buttonOnClick($event)']")); A good fix is to create a class for each page you are testing and reach the elements of your page like so:

class LoginPageObject
    {
        public LoginPageObject()
        {
            PageFactory.InitElements(TestBase.driver, this);
        }

        [FindsBy(How = How.Id, Using = "UserName")]
        public IWebElement TxtUsername { get; set; }

        [FindsBy(How = How.Id, Using = "Password")]
        public IWebElement TxtPassword { get; set; }

        [FindsBy(How = How.Id, Using = "submit")]
        public IWebElement BtnLogin { get; set; }
    }

For accessing Angular elements using ng properties, It is better to use Protractor-Net which exposes NgBy class to explore angular elements in the DOM like this:

        var ngDriver = new NgWebDriver(driver);
        ngDriver.Navigate().GoToUrl("http://www.angularjs.org");
        var elements = ngDriver.FindElements(NgBy.Repeater("todo in todoList.todos"));

The complete source code for the code snippet above can be found in here. Also, you can create your own custom decorators for angular elements from protractor API like this:

public class NgByRepeaterFinder : By
    {
        public NgByRepeaterFinder(string locator)
        {
            FindElementsMethod = context => context.FindElements(NgBy.Repeater(locator));
        }
    }

    internal class NgByModelFinder : By
    {
        public NgByModelFinder(string locator)
        {
            FindElementMethod = context => context.FindElement(NgBy.Model(locator));
        }
    }

And then use them in your page class like this:

class YourPageObject
{
    public YourPageObject()
    {
        PageFactory.InitElements(TestBase.ngWebDriver, this);
    }

    [FindsBy(How = How.CssSelector, Using = "a[ng-click='addNewTrack()']")]
    public IWebElement BtnAddNewTrack { get; set; }

    [FindsBy(How = How.Custom, CustomFinderType = typeof(NgByModelFinder), Using = "trackSearch")]
    public IWebElement TxtSearchTrack { get; set; }

    [FindsBy(How = How.Custom, CustomFinderType = typeof(NgByRepeaterFinder), Using = "track in models.tracks | filter: trackSearch")]
    public IList<IWebElement> BtnListTracks { get; set; }
} 

the complete guide for how to create and you custom finder annotators for angularjs can be found in here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.