1

I have these browser drivers:

public IWebDriver Browser { get; }
public NgWebDriver NgBrowser { get; }

When I try to find an element with the XPath selector, if Angular is not present it will fail if I use NgBrowser:

var byXpath = By.XPath(exp);
var link = NgBrowser.FindElement(byXpath);

But if I try to find it with Browser and Angular is present it will not find it:

var byXpath = By.XPath(exp);
var link = Browser.FindElement(byXpath);

Should I simply be wrapping the NgBrowser call in a try...catch and retrying with Browser if it throws? Or is there a simpler, more direct method? Perhaps something with built-in fail-over?

.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
    <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
    <PackageReference Include="Protractor" Version="0.12.0" />
    <PackageReference Include="Selenium.Support" Version="3.141.0" />
    <PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
    <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="2.46.0" />
    <PackageReference Include="specflow" Version="3.0.199" />
    <PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.0.199" />
    <PackageReference Include="SpecFlow.MsTest" Version="3.0.199" />
    <PackageReference Include="MSTest.TestFramework" Version="2.0.0-build-20190430-01" />
    <PackageReference Include="MSTest.TestAdapter" Version="2.0.0-build-20190430-01" />
  </ItemGroup>

</Project>

The best I have right now is this:

[Given(@"I go to url (.*)")]
public void GoToUrl(string url)
{
    NgBrowser
        .Navigate()
        .GoToUrl(url, false);
}

While this solves the problem of detecting Angular during a page navigation, it does not answer the question of this post; Namely that simply detecting Angular separately from performing an operation (specifically FindElement) appears to be impossible.

Matt W
  • 9,407
  • 17
  • 83
  • 146

1 Answers1

2

When Angular loads it adds its own classes e.g. ng-untouched ng-pristine ng-valid to elements.

If you are directly matching your class values in XPath, this may be the reason why you are not able to find elements when angular is loaded.

As for the webdriver, you can use this web driver which has a built in method to wait for Angular to load.

If you want to handle it yourself, you can write a class like this:

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

public class AdditionalConditions {
    public static ExpectedCondition<Boolean> angularHasFinishedProcessing() {
        return new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driver) {
                return Boolean.valueOf(((JavascriptExecutor) driver).executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)").toString());
            }
        };
    }
}

It will check the presence of angular in window object to see if angular is loaded or not in your application.

You can use it like this:

WebDriverWait wait = new WebDriverWait(getDriver(), 15, 100);
wait.until(AdditionalConditions.angularHasFinishedProcessing()));

Hope it helps.

asimhashmi
  • 3,715
  • 9
  • 32