Protractor test does not finish, seems to loop until the jasmine timeout error hits - protractor

I feel pretty dumb to not be able to get the most basic protractor test to work. Given protractor 5.4.1 i have a spec.js
describe('my example tests', () => {
const EC = protractor.ExpectedConditions;
it('tests google', async () => {
await browser.waitForAngularEnabled(false);
await browser.get("https://google.com");
await browser.wait(EC.visibilityOf($('input')));
await element(by.css("input")).click();});});
and a conf of
exports.config = {
directConnect: true,
specs: ['tests/**/*.js'],
capabilities: {
browserName: 'chrome',
},
SELENIUM_PROMISE_MANAGER: false,
jasmineNodeOpts: {
defaultTimeoutInterval: 40000
}
};
when running protractor conf.js the browser opens, goes to the page and then nothing happens until the 40s jasmine timeout hits. What I get are ~25 warnings per second
W/element - more than one element found for locator By(css selector, input) - the first result will be used
as if some command is running in an endless loop until I get an error Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. which does not tell me much and is hard to google.
Has anyone experienced this issue?

On the Google page, the locator $('input') matches many elements, which is why you got the warning. The first one was used, but unfortunately, the first one was hidden. so await browser.wait(EC.visibilityOf($('input'))); failed, which gave the timeout error.
Using a locator that locates a unique and not hidden input element on the page, like element(by.name('q')) ought to work better.
I like the Hetzner cloud protractor test helper which provides wrappers like waitToBeDisplayed whose error reporting is less generic, if I recall correctly (it has been a while since I used it).

Related

Protractor not wait for https.request callback

I hit a Protractor issue, if I run this within "ts-node demo.js" it works well and can output the response code and response body.
But if I run this in Protractor it block, then can't get the expected output response code and body, seems like Protractor won't wait for the callback.
In this situation, how can I output the response code and boday?
it(Check manifests V2 api, async() => {
const https = require('https')
const options = {
hostname: 'demo-quayecosystem-quay-quay.com',
port: 443,
path: '/v2/quay/multiarchdemo/manifests/latest',
method: 'GET',
headers: {
'Accept': 'application/vnd.docker.distribution.manifest.list.v2+json'
}
}
https.request(options, res => {
browser.getTitle().then(()=>{
console.log("starting.........");
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
})
})
The function above is an async and when you make your function async, then you should use the await keyword in front of the https.request or return it like this.
return https.request...
And another thing that could lead to problems are...
https.request is making a direct HTTP request, without using a browser
broser.getTitle() is using the browser to interact with the web page.
Be aware - browser uses the browser, and http.request uses direct HTTP from node.js - these are two different things. And it will lead to unpredictable things to mix them. So consider if you want to "test as a user" and then use the browser, or if you want to do the fastest possible test and "test as a website or javascript" and use HTTP.request.
Try reading the async/await page on the Protractor website.
https://www.protractortest.org/#/async-await
If you are puzzled about async/await consider seeing the video from Fun Fun Function on promises https://www.youtube.com/watch?v=568g8hxJJp4&t=251s.

Checking if an element is present in protractor

I have a protractor test that expects a certain panel to be NOT PRESENT after login. My code is below, but every time it is executed, protractor hangs and then fails later on.
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
it('The team overlay page should not be present when another user logs in.', function() {
loginPage.login(user.username, user.password);
expect(element(by.css('div.panel#myPanel')).isPresent()).toBe(false);
});
I also tried using .count() but it also does the same thing. Same error as above.
expect(element.all(by.css('div.panel#myPanel')).count()).toBe(0);
You could try waiting for the element by allowing the browser to fully load with some of the following:
browser.driver.sleep(time in milliseconds)
browser.waitForAngular()
You could increase the timeout interval:
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000
Otherwise:
Make sure your locator via css is working correctly (i.e, test it when the panel should be present), and make sure the webpage you are trying to access supports Angular. My bet is there is something incorrect with the format of your locator, as I don't see what else could be an issue.

Protractor Click function does not work, It throws Time out exception error

Node Version: v6.9.4
Protractor Version: 5.1.1
Angular Version: 1.2.28
Browser(s): Chrome:Version 58.0.3029.96 (64-bit) Chrome WebDriver:Version 2.29
Operating System and Version: MAC OS Siera 10.12.3
protractor configuration file
exports.config = {
directConnect: true,
capabilities: {
'browserName': 'chrome'
},
framework: 'jasmine',
specs: ['./Test/LoginTest.js'],
allScriptsTimeout: 120000,
getPageTimeout: 120000,
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 120000
}
A relevant example test
There is button in the page, when i try to click using protractor , It throws time out error . Unable to click on the element. Same thing work on selenium webdriver.
Step to Reproduce
Step 1: Open website using this URL https://www.neonmob.com/login
Step 2: Enter the user name and password mentioned below and click on Login button
UserName: sharif33332
Password: 1234
Step 3: After login navigate to this URL https://www.neonmob.com/shariftestuser to navigate to exact page where problem occurs.
Issue :Now at this page unable to click on Trade Button and it throws time out exception error.
Same element can be found using jQuery. Please follow the above steps to reproduce this issue.
Used the below code to click on this button
element(by.css("span[id='trade-btn']")).click();
Please let me know if you are not able to follow the steps. I believe there is an issue in protratcor
I found the problem. There is nothing wrong with protractor. There is something wrong with the page. You don't get a timeout on clicking on the button / not finding it. You get an error because the page times out because Angular didn't release the page. There are still open calls or what so ever that keep Angular not ready. This was the log I got
Failures:
1) click on trade button should click on the trade button
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:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
Message:
Failed: Timed out waiting for asynchronous Angular tasks to finish after 30 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, #trade-btn).
The following tasks were pending:
- $timeout: function (){ownershipPromise=artPieceService.syncOwnership()}
If you disable the wait for angular with this it will work
describe('click on trade button', () => {
beforeEach(function () {
browser.get(browser.baseUrl);
$('#field-username').sendKeys('sharif33332');
$('#field-password').sendKeys('1234');
$('#signin-btn').click();
browser.driver.wait(() => browser.getCurrentUrl().then((currentUrl) => currentUrl === 'https://www.neonmob.com/sharif33332'));
browser.get('https://www.neonmob.com/shariftestuser')
});
it('should click on the trade button', () => {
// Disable wait for Angular
browser.ignoreSynchronization = true;
// Wait 2 seconds for the page to be loaded
browser.sleep(2000)
$('#trade-btn').click();
// Wait to verify that the trade button has been clicked.
browser.sleep(5000);
})
});
This will confirm that there is nothing wrong with protractor but you need to dive into Angular on this page / ask a developer to fix this.
#wswebcreation , Are you sure this is not the angular page. If it is not then angular wait will not work. Will be needed to browser.ignoreSynchronization=true .
Anyway I will ask our developer to look onto this and debug it more to fix from application side.
Anyway current solution provided above working fine.
Thank you so much for your help
After checking, your second URL (does not seem) to be an angular page and requires ignoreSynchronization.
Try using the code below:
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get('https://www.neonmob.com/login');
element(by.id('field-username')).sendKeys('sharif33332');
element(by.id('field-password')).sendKeys('1234');
element(by.id('signin-btn')).click();
browser.waitForAngular();
browser.ignoreSynchronization=true
browser.executeScript('this.document.location = "https://www.neonmob.com/shariftestuser"');
element(by.id('trade-btn')).click();
});
});
I did not fix the format, you can do that one. :)
Nothing special on config as well, I only use this:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js'],
jasmineNodeOpts: {defaultTimeoutInterval: 60000}
};

Protractor: test loading state

I'm setting up protractor for our web app, and all works fine, except one thing: When someone clicks the "login" button, while the HTTP request is running, the button should have class "loading". However, when I try to test this, protractor waits for the HTTP request to finish before it runs the expectation, which then fails, because the loading class is removed again.
How can I assert that the loading class is added?
describe('Authorization', function() {
it('the site loads', () => {
browser.get('/');
expect(browser.getCurrentUrl()).toBe('http://localhost:8000/#/login');
element(by.model('vm.credentials.username')).sendKeys('username');
element(by.model('vm.credentials.password')).sendKeys('password');
element(by.css('#sign-in')).click();
expect(element(by.css('#sign-in')).getAttribute('class')).toMatch(/\bloading\b/);
});
});
I think I found the solution.
The element() function waits for angular to settle in, but browser.driver.findElement() doesn't. So by changing the assertion line to
expect(browser.driver.findElement(by.css('#sign-in')).getAttribute('class')).toMatch(/\bloading\b/);
the tests now pass
As per your problem, protractor is executing your expect statement along with click() function. Protractor is async and fast so it executes everything that it can and then waits for promise/callback to be returned. Try waiting for the click to happen first and then try to assert the class. Here's how you can do it -
element(by.css('#sign-in')).click().then(function(){
expect(element(by.css('#sign-in')).getAttribute('class')).toMatch(/\bloading\b/);
});
Also if the http request is blocking your execution, then try to wait for the element to be displayed. If the element is displayed then it's as good as your element is verified.
browser.wait(protractor.ExpectedConditions.visibilityOf($('.loading')), 10000)
.then(function(){
expect(true).toBe(true);
});
Hope this helps.

How to set the browser name parameter in the protractor script

I have started using protractor and now able to execute same test script on multiple browsers by doing below changes in protractor.conf.js file.
multiCapabilities: [{
'browserName': 'chrome'
}, {
'browserName': 'firefox'
}],
Now, I would like to parameterized my tests to provide browser name on which it should run. For e.g.: I have 2 test cases, 1 should run on chrome and other should run on firefox. This should be handled by providing browser name parameter in the test itself. Below is my first test case. Can you please help me to pass the browser name parameter in it.
'use strict';
/* https://github.com/angular/protractor/blob/master/docs/toc.md */
describe('Login and Logout Test Case', function () {
//before Each unittests case load the login page
beforeEach(function () {
browser.get('#/login');
});
it('unittests the scenario when the user clicks on Dutch', function () {
//The link for Dutch language from the login page is clicked
element(by.id('username')).sendKeys('kaustubhsaxena');
element(by.id('password')).sendKeys('saxena');
element(by.id('login')).click();
browser.quit();
});
});
Thanks in advance for your help
To get the browser name, you can use browser.getCapabilities():
browser.getCapabilities().then(function(capabilities) {
// Outputs 'chrome' when on Chrome
console.log(capabilities.caps_.browserName);
});
If waiting until a promise is resolved isn't good for your use case, then a hackier way that works on my system is to access the resolved/fulfilled session object directly:
// Outputs 'chrome' when on Chrome
console.log(browser.driver.session_.value_.caps_.caps_.browserName);