I have just recently started working on integrating a test framework into my AngularJS application, using Protractor do build the test cases & run the tests.
Having never used automated testing before, I am still new to it, and still getting to grips with how it works, how to write the test scripts, etc.
I am currently writing a test to check that the correct 'sub-menu' is displayed when the user hovers the cursor over a button on the main navigation bar. The test currently looks like this:
it('should display the Pages menu', function() {
browser.actions().mouseMove(pagesMenuBtn).perform();
browser.pause();
expect(pageVarBrowser.isDisplayed()).toBeTruthy();
browser.pause();
browser.actions().mouseMove(userCircle).perform();
browser.pause();
expect(pageVarBrowser.isDisplayed()).toBeFalsy();
});
pagesMenuBtn
is the menu button that will display a sub-menu listing the rest of the pages of the application when the user hovers the cursor over it- it has been defined with:
var pagesMenuBtn = element(by.id('.nav-container > model[type=href] > value["#/pages"]'));
pageVarBrowser
is one of the buttons that is displayed on the sub-menu shown when hovering the cursor over pagesMenuBtn
, and is defined with:
var pageVarBrowser = element(by.css('.nav-container > model[type=href] > value["#/pages/varbrowser"]'));
userCircle
is simply another HTML element displayed in a different location on the page (just so that I could move the cursor somewhere off the pagesMenuBtn
), and has been defined with:
var userCircle = element(by.id('icon-user-circle'));
This doesn't appear to be an issue with the syntax/ logic of the tests I've written/ am writing, but when I currently run my tests with the command protractor conf.js
, the script starts up, and starts running through correctly, but when it reaches the above test, I get the following output in the console:
Error: Timeout = Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
Does this mean that my tests have failed because they took too long to execute? If so, how can I fix this? Can I change the 'timeout' variable to a greater value?
In the console where I ran the command protractor conf.js
, I get the following error message about the failure:
A Jasmine spec timed out. Resetting the WebDriver Control Flow
Failures:
1) MyApp should display the Pages menu Message: Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular While waiting for element with locator - Locator: By(css selector, *[id=".nav-container\ >\ model[type\=href]\ >\ value[\"#/pages\"]"]). The following tasks were pending: - $timeout: function () { clearEvents(type); } - $timeout: function setErrorMsg() { // Broadcast system timeout lock event $rootScope.$broadcast('um:LCK_TIMEOUT');
// Save the error message dateObj.error = ( 'Timeout error data last fetched: ' + dateObj.localFormat ); } - $timeout: function clearTags() { // Go through each of the tags angular.forEach(tags, function (tag){ // Clear the value tag.value = null; // If the meta information is set if (tag.meta) { // Clear the meta raw value tag.meta.raw = null; } }); // Empty the active alarms container activeAlarms = {}; // Make sure the observers notice the value change notifyObservers(); }
Anyone have any suggestions as to how I can get this test running correctly?
Edit
So, after removing a couple of the calls to browser.pause();
from my script, I actually got a different error message that says:
Failed: No element found using locator: By(css selector, *[id=".nav-container\ >\ model[type\=href]\ >\ value[\"#/pages\"]"])
So it appears it doesn't like the way I'm trying to get hold of the element from the sub-menu...
Edit
Although the initial error was complaining about a timeout, I'm now not sure that this is the cause of the issue. I removed the calls to browser.pause();
as mentioned in my earlier edit, and then started getting the error message above instead. I suspect that this is due to the location of the element that I'm trying to find/ the structure of the HTML in which it's nested. That HTML is:
<li data-ng-mouseenter="setMenuTop($event)" ng-show="menu.pages.length > 0 || menu.upages.length > 0 || canCreatePage">
<a href="#/pages" id="pagesMenuBtn" target="_self"><i class="ti-layers"></i><span data-i18n="Pages"></span></a>
<ul class="text-capitalize">
<li ng-repeat="page in menu.pages"><a href="#/{{page.location}}" target="_self"><i class="ti-angle-right"></i><span data-i18n="{{page.title}}"></span></a></li>
<li ng-repeat="upage in menu.upages">
<div class="nav-menu-divider" data-ng-if="$index === 0"></div>
<a href="#/{{upage.location}}" target="_self">
<i class="ti-angle-right"></i><span data-i18n="{{upage.title}}"></span>
</a>
</li>
<li data-ng-show="canCreatePage">
<div class="nav-menu-divider"></div>
<a href="#/pages/create" target="_self">
<i class="ti-angle-right"></i><span data-i18n="Create Page"></span>
</a>
</li>
</ul>
</li>
The element that I'm trying to get hold of is actually one of the ones created with the line:
<i class="ti-angle-right"></i><span data-i18n="{{upage.title}}"></span>
inside this block. The element itself is not explicitly written, but is created by the Angular ng-repeat
function, as an element in a list... Anyone know how I would get hold of a specific element from within this list?
browser.pause()
calls - what happens if you remove them? Thanks.browser.pause();
calls are so that the script doesn't execute entirely on its own- it means I have to input 'c' into the command line every time it pauses in order to cause the script to continue. My reason for doing this was to allow me to 'step through' the tests, and see exactly where/ when everything is happening.var pagesMenuBtn = element(by.id('.nav-container > model[type=href] > value["#/pages"]'))
- apparently it can't find the element using that locator...