Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

WebDriver and AngularJS: Locators and Scripts

DZone's Guide to

WebDriver and AngularJS: Locators and Scripts

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Eighteen months ago I was hypothesizing about new WebDriver (Selenium 2.x) accessors specific to AngularJS. It’s now a reality.

WebDriver Locators for Items in an Angular View

These were pioneered by Julie M Ralph in her Protractor project. There’s a bunch of Angular-centric locators for elements in the DOM supported in Protractor. Specifically:

  • Find by Angular Binding, like ‘cat.name’
  • Find ‘row’ from a ng-repeat list, like ‘cat in cats’ / #3
  • Find ‘cell’ from a ng-repeat list, like ‘cat in cats’ / #3 / ‘cat.color’
  • Find a ‘column’ from a ng-repeat list like ‘cat in cats’ / ‘cat.color’
  • Find inputs and selects in a more idiomatic way for Angular

As well as plural versions of many of the above. See the source for protractor and the first 280 lines at least. These are not compatible (yet) with findElement(s), but I raised it with the rest of the Selenium dev team that they could be with some changes.

WebDriver Scripts for Items in an Angular Model

It’s also possible to retrieve values from the model in $scope, as well as change model value directly.

With The Cookbook’s advanced form, (1/3 down the page) as a testbed, here is example code for that. The source below is in Java, but it shouldn’t be hard to port to other languages:

FirefoxDriver wd = new FirefoxDriver();

wd.get("http://docs.angularjs.org/cookbook/advancedform");

WebElement cityField = wd.findElement(By.cssSelector("input[ng-model='form.address.city']"));
WebElement theForm = wd.findElement(By.cssSelector("div[ng-controller='UserForm']"));

assertThat(cityField.getAttribute("value"), is("Anytown"));

cityField.clear();
cityField.sendKeys("Chicago");

// returns a GoogleCollections Map ordinarily ... note the toString() at the end..
String addr = wd.executeScript("return angular.element(arguments[0]).scope().form.address;", theForm).toString();

// Not JSON, but close enough perhaps:
assertThat(addr, is("{zip=12345, state=AA, line1=123 Main St., city=Chicago}"));

// returns a JSON String:
addr = wd.executeScript("return angular.toJson(angular.element(arguments[0]).scope().form.address);", theForm);

// Turn that back into an Object (via Jackson):
Address address = mapper.readValue(addr, Address.class);
assertThat(address.getZip(), is(12345));

wd.executeScript("angular.element(arguments[0]).scope().form.address.city = 'New York';" +
        "angular.element(document.body).injector().get('$rootScope').$apply();", theForm);

assertThat(cityField.getAttribute("value"), is("New York"));

wd.quit();

Given the potential for nested scopes, it’s important to find an element that’s part of the scope that you are dealing with so that Angular can find the right scope. That’s the only reason I’m locating ‘theForm’ above. It could be any element that’s co-located with the ng-app, as .scope() is smart enough to work out which scope you mean from that.

Using it is slightly less than perfect IMO, as I’d prefer executeScript() to return a string as is, and I do the transformation into an object-model (or not) myself. In some circumstances, I might choose Jackson for deserialization, but can’t because of internal WebDriver choices. Luckily, Angular has a angular.toJson(..) fragment that’ll do the job, meaning the script gets slightly longer to do the right thing and give back a JSON string.

Update: 16th Sep

I’ve released a library for Java that can be used with WebDriver to do more idiomatic locators for Angular apps, as well as interact with models.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Published at DZone with permission of Paul Hammant, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}