Protractor test timing out waiting for page sync - angularjs

My protractor tests are timing out waiting for page sync. I've checked the console, and no errors are shown, so I'm having trouble debugging. I've tried using allScriptsTimeout as well as defaultTimeoutInterval to no avail. No polling in my app, and the test does seem to log in correctly, it just hangs once logged in even though everything looks fully rendered. My code:
Config file:
var exports;
exports.config = {
// The address of a running selenium server.
seleniumAddress: 'http://localhost:4444/wd/hub',
// Spec patterns are relative to the location of this config.
specs: [
'scenarios/features/portfolio-manager-e2e-local.js'
],
multiCapabilities: [
{
'browserName': 'chrome'
}
],
jasmineNodeOpts: {
onComplete: null,
isVerbose: true,
showColors: true,
includeStackTrace: true,
defaultTimeoutInterval: 20000,
}
};
Test:
I'll just post one for now, the first test that runs and fails:
it('should login user with correct credentials', function () {
browser.get('/#/portfolio');
element(by.model('username')).sendKeys('test');
element(by.model('password')).sendKeys('test');
element(by.css('.btn.btn-md.btn-primary')).click();
expect(element(by.css('.port-header')).getText()).toEqual("Portfolios");
});
Thanks.

I found an ngToast successful login popup had a timeout of 15.5 seconds which was causing the hangup.

You need to wait for angular before making any assertions:
Instruct webdriver to wait until Angular has finished rendering and
has no outstanding $http calls before continuing.
browser.get('/#/portfolio');
browser.waitForAngular()

Related

Protractor Locator Time Out exception for AngularJs application

We are trying to automate a publicly accessible website and click on one of the links, but the test fails with TimeOut Exception while locating the element as below:
From: Task: Protractor.waitForAngular() - Locator: By(link text, MY ACCOUNT)
Sample conf and spec file below.
Requesting help on how to solve this issue.
conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
capabilities: {
'browserName': 'chrome'
},
specs: ['test.js']
};
test.js
describe('test', function() {
it('should navigate', function(done) {
browser.get('https://ww2.tracfone.com');
element(by.linkText('MY ACCOUNT')).click();
done();
});
};
Found the root cause for the issue you were seeing for your webPage. Looks like your site continuously polls $timeout or $http, Protractor will wait indefinitely and time out.
I have monitored the http traffic below and see that your app polls at frequent intervals and Protractor just waits. Checkout the screen grab below.(The green marks in the timeline indicating $http calls to - https://ww2.tracfone.com/cgi-bin/tealeaf.pl )
More details on why you are seeing this error is documented here. ok. Coming to the different solutions for this, there are multiple work-arounds for this. I will just talk in brief about the alternatives and leave it to you to choose the best one.
IgnoreSynchronization: Turn this flag - browser.ignoreSynchronization to false before the browser.get() and continue with the test flow and set the flag to true again for other pages
Check here
Interval.js : I am no expert on this but you can explore more here
You should use the $interval for anything that polls continuously
(introduced in Angular 1.2rc3).
Try with different timeOut configurations and see if your app polling stops after some time
allScriptsTimeout: 120000,
getPageTimeout: 120000,
jasmineNodeOpts: {
defaultTimeoutInterval: 120000
}
I setup a sample project based on the items you've posted and this test appears to be working for me.I'm not sure why you are getting the timeout that is usually associated with pages that are not angular but setting browser.ignoreSynchronization = true helped get past this error.
var ec = protractor.ExpectedConditions;
var timeout = 60000;
describe('test', function() {
it('should navigate', function(done) {
browser.ignoreSynchronization = true;
browser.get('https://ww2.tracfone.com')
var myAccount = element(by.linkText('MY ACCOUNT'));
browser.wait(ec.visibilityOf(myAccount)).then(function() {
myAccount.click();
})
done();
});
});

Protractor change rootEl after start when testing angular app

I setup my protractor with this conf file below:
exports.config = {
framework: 'mocha',
rootElement: '#container1',
specs: ['*container1_spec.js'],
capabilities: {
browserName: 'chrome',
version: '',
platform: 'ANY'
},
onPrepare: function() {
// implicit and page load timeouts
browser.manage().timeouts().pageLoadTimeout(40000);
browser.manage().timeouts().implicitlyWait(25000);
}
}
The application is manually bootstrapped in angular and I need to change the root element after some steps when the application transfers the control to another application by doing a window.location.replace. The second application that starts is also an angular app which does manual bootstrapping.
From another thread in SO. I found the code that I could do browser.rootEl = 'div#container2';
WebDriverError: unknown error: [ng:test] no injector found for element argument to getTestability
http://errors.angularjs.org/1.5.8/ng/test
As I mentioned in the question, changing the rootEl did not work. I had to resort to working with the DOM to run the tests.
function getMessage() {
return document.getElementById('msg').textContent;
}
setTimeout(function() {
browser.executeScript(getMessage).then(function (txt) {
chai.expect(txt).to.equal("Error occured");
done();
});
}, 10000);
browser.executeScript is the key function that allowed me to query DOM and workaround. I had to add a timeout for the lag to allow the second application to download and bootstrap.

Getting the Angular Content to load in protractor tests

I have an angular application that I am writing e2e test for using protractor.
Following is my conf.js file setup
var project = require('./package.json');
var HtmlReporter = require('protractor-jasmine2-screenshot-reporter');
var multiCapabilities = [{
'browserName': 'chrome'
}];
multiCapabilities = [{
'browserName': 'chrome',
"platform": "Windows 7",
'build': 'Testing',
'name': project.name + ' tests'
}]
exports.config = {
framework: 'jasmine2',
sauceUser: 'blahblhablah',
sauceKey: 'xyzabcdxyzabac',
multiCapabilities: multiCapabilities,
specs: ['e2e/main.spec.js'],
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
},
onPrepare: function() {
jasmine.getEnv().addReporter(new HtmlReporter({
dest: 'reports/e2e'
}));
}
};
Following is my test spec file
'use strict';
var mainPage = require('./page.js');
describe('Demo', function() {
//Check if title pages are consistent
it('Test 1', function() {
browser.get('http://localhost:3000/');
expect(browser.getTitle()).toEqual('NBA LIVE');
});
});
I am running my test on saucelabs when I run them locally I have no issues. So after I ran this test I got the following error message.
Message:
Failed: Angular could not be found on the page http://localhost:3000/ : retries looking for
angular exceeded
So i did a little more research and realized I can set browser.ignoreSynchronization = true; in my test spec file.
So after doing that I get the following error message:
Message:
Expected 'http://localhost:3000/' to equal 'NBA LIVE'.
So I think maybe the angular or the content is not loading because of me setting ignoring synchronization to true but if i do not then I get the other error. Again none of this is an issue when running my test locally on my laptop but only when doing on saucelab. It is clear I need to add something to make angular content load. Please advice me on what to do.
what might be happening is that it's checking the expect before the page loads so you could try to make it wait till the title says NBA LIVE before you expect it by using the protractor.until statments
browser.wait(protractor.until.titleIs("NBA LIVE"), 5000, "✗ Failed to wait for the NBA LIVE page to load");
expect(browser.getTitle()).toEqual("NBA LIVE");
EDIT:
Since you are using a local app and using saucelabs then you will need to setup sauce connect

Protractor configuration - is there a way to seperate some of the spec files from running asycnronously?

I have some protractor tests for my angular web application (conf.js file at bottom of this post).
There are several tests stored in different .js files and then loaded in.
In addition to the tests, I am using multiple capabilities so that it can test my web site at various resolutions, firing up 5 browsers at once. This works fine.
One of my test suites however, needs not to run at the same time as all of the other capabilities, this is because I have to require the server to change some settings for the tests I am performing to work. I am not able to 'mock' these server calls, as the response from the server is crucial to the test I am running, and I need to see that I called and recieved the expected response from the actual server rather than a mocked up object.
Because of this, if any of the other tests from one of the other capabilities are running at the same time they get the wrong information back from the server.
As a work around I set maxSessions: 1 in my conf file, which stops the above problem, but means my tests take about forever to run!
Is there a way to give the spec declaration two arrays, so it knows to run a certain bunch of tests only when nothing else is running? ( i invented the seperateSpecs property to illustrate what i'm getting at)
For example :
specs: [testCanRunInTandom1.js, testCanRunInTandom2.js, testCanRunInTandom3.js],
seperateSpecs: [MustRunAloneWithoutOtherCapabilities.js, MustRunAloneWithoutOtherCapabilities2.js]
I've had a look about, but can't find anything. An answer of 'no you really cant do that' would be acceptable, but i'm hoping someone knows some secret command you can give to protractor!
Here is my current conf.js file for reference :
var specFiles = ['NavigationTests.js', 'HeaderTests.js', 'TableTypeTests.js', 'DepositTests.js','loginTests.js','userPrefsTests.js', 'progressBarTests.js', 'aboutPageTests.js'];
// multiCapabilities stuff set now near bottom of file to make it easier to add/change/remove capabilities
var HtmlReporter = require('protractor-html-screenshot-reporter');
var request = require('request');
var desktopSpec=
{
// Desktop
'browserName': 'chrome',
'chromeOptions' :
{
args: ['--lang=en', '--window-size=1690,800']
},
specs: specFiles,
};
var iPhone3gSpec=
{
//iphone 3G portrait
'browserName': 'chrome',
'chromeOptions' :
{
args: ['--lang=en',
'--window-size=320,480']
},
specs: specFiles
};
var iPhone3gLandscapeSpec=
{
//iphone 3G landscape
'browserName': 'chrome',
'chromeOptions' :
{
args: ['--lang=en',
'--window-size=480,320']
},
specs: specFiles
};
var iPadSpec=
{
//ipad portrait
'browserName': 'chrome',
'chromeOptions' :
{
args: ['--lang=en',
'--window-size=1024,768']
},
specs: specFiles
};
var iPadLandscapeSpec=
{
//ipad landscape
'browserName': 'chrome',
'chromeOptions' :
{
args: ['--lang=en',
'--window-size=768,1024']
},
specs: specFiles
};
var multiCapabilities=[];
multiCapabilities.push(desktopSpec);
multiCapabilities.push(iPhone3gSpec);
multiCapabilities.push(iPhone3gLandscapeSpec);
multiCapabilities.push(iPadSpec);
multiCapabilities.push(iPadLandscapeSpec);
// Configuration file
exports.config = {
directConnect: true,
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
includeStackTrace: false,
defaultTimeoutInterval: 30000
},
// Run the tests in the different windows sizes
multiCapabilities: multiCapabilities,
onPrepare: function() {
// Add a screenshot reporter and store screenshots to `/tmp/testresults/screnshots`:
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: 'tmp/testresults/screenshots'
}));
},
maxSessions: 1
};

Selecting hidden elements when using protractorjs with phantomjs

In a recent post of mine I had an issue with hideen elements (see Here). Since then I have moved from chrome driver to phantomjs for headless testing.
My issue is this.
Since the move selecting hidden elements causes the error below,
UnknownError: Error Message => ''undefined' is not a function (evaluating 'arguments[0].click()')'
Running in chrome (webdriver) is fine and all test pass but phantomjs doesn't seem to like this method. Is there another way round this issue that will run in under test using phantomjs and protractorjs.
EDIT
The test below is what I am having issues
it('should redirect to addresses', function () {
var hiddenWebElement = ptor.driver.findElement(by.css('ul#myaccount li:nth-child(2) a'));
ptor.driver.executeScript("arguments[0].click()",hiddenWebElement).then(function() {
expect(ptor.driver.getCurrentUrl()).toContain('#/addresses');
});
}, 15000);
my config file is
// An example configuration file.
exports.config = {
// The address of a running selenium server.
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:52254',
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'phantomjs'
},
// Spec patterns are relative to the current working directly when
// protractor is called.
specs: [
'Scenarios/account_spec.js',
'Scenarios/add_address_spec.js'
],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
A point to notice is that all tests above this run expect the one below which again has an issue when trying to find the element
it('should redirect to login', function () {
ptor.driver.findElement(by.id('headerLoginBtn')).click().then(function () {
expect(ptor.driver.getCurrentUrl()).toContain('/Account/Login');
});
}, 15000);
which throws an exception of element is not visible. Also my tests in this scenario use ptor.driver because the pages contain c# ASP.NET code.
i found a workaround which looks like the only possible way to me. I removed the css that hide the element and then clicked on it and it worked. I am using selenium but it should be similar solution for you
executeJavaScript("$('.log-out').removeClass('hide');");
driver.findElement(By.className("log-out")).click();

Resources