I was recently tasked with implementing some automated testing for an AngularJS application developed by my company. After doing some research into the different testing frameworks available, I decided to use Protractor as it seems to provide all of the functionality that we will need, and appears to be well documented & maintained.
When I started designing & writing the tests, I noticed that most of the HTML elements in the code had not been given ID attributes- so I started assigning ID attributes to the various elements that would be used in the tests, so that I could access them using functions such as element(by.id('abc'));
to assign them to variables for use within the test scripts.
However, I have just been informed that not giving the HTML elements ID attributes was a deliberate design choice in order to make the source code easier to compress for distribution to our customers. So this means that I now need to re-write my tests so that they no longer use ID attributes to get hold of the elements, but I'm not sure quite how to do this...
When I inspect those menu item in the browser, it shows the following HTML structure:
<ul id="nav" class="nav" data-slim-scroll ... >
<li data-ng-mouseenter="setMenuTop($event)" ...
<a href="#/pages" id="pagesMenuBtn" ... >
...
<a href="#/alarms" id="alarmsMenuBtn" ... >
...
...
</li>
...
</ul>
The goal is to be able to remove the id
attributes from the tags above, but still be able to access those HTML elements to run tests on them.
For example, where I previously had:
describe('myApp', function() {
var alarmsMenuBtn = element(by.id('alarmsMenuBtn'));
var chartsMenuBtn = element(by.id('chartsMenuBtn'));
...
it('should navigate to the Charts page', function(){
browser.waitForAngularEnabled(false);
browser.actions().mouseMove(chartsMenuBtn).perform();
chartsMenuBtn.click();
browser.waitForAngularEnabled(true);
browser.call(closeDlg).then(function(){
expect(browser.getCurrentUrl()).toBe('chartsURL');
});
I now have:
describe('myApp', function() {
var menuItems = $(".slimScrollDiv").$(".nav").$$("li");
var alarmsMenuBtn = menuItems.get(1).$("a");
var chartsMenuBtn = menuItems.get(2).$("a");
But when I run this with the same tests, my tests now fail, giving me messages such as:
Failures: 1) App should navigate to the Alarms page Message: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. Stack: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. at ontimeout (timers.js:386:11) at tryOnTimeout (timers.js:250:5) at Timer.listOnTimeout (timers.js:214:5) Message: Failed: element not visible (Session info: chrome=61.0.3163.100) (Driver info: chromedriver=2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.15063 x86_64) Stack: ...
and:
2) App should navigate to the Charts page Message: Failed: element not visible (Session info: chrome=61.0.3163.100) (Driver info: chromedriver=2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.15063 x86_64)
The HTML for these elements is:
<li><a href="#/alarms" id="alarmsMenuBtn" target="_self"><i class="ti-alert"></i><span data-i18n="Alarms"></span></a></li>
<li><a href="#/charts" id="chartsMenuBtn" target="_self"><i class="ti-bar-chart"></i><span data-i18n="Charts"></span></a></li>
So my question is, how can I access these (or any other) HTML elements using something other than ID attributes to get them?