I am trying to test my website which is a non angular website through Protractor. My code is:
describe("Supplier Portal: Login ", function () {
//ui.setSmallScreenSize();
// ui.testLogger(100);
it("test", co.wrap(function* () {
browser.ignoreSynchronization = true;
yield browser.driver.get("https://cit.supplier.ext.here.com/");
yield element(by.xpath("//*[#id=\"rnav\"]/li[2]/a")).click();
var elmOK = element(by.xpath( "//*[#id=\"sign-in-email\"]"));
browser.driver.wait(protractor.until.elementIsVisible(elmOK.getWebElement()))
}));
});
But when I try to execute the code I got the following error:
Failed: No element found using locator: By(xpath, //*[#id="sign-in-email"])
But the element is there on the website.
Please advice what I'm doing wrong
Since you are working on a non-angular site and using browser.ignoreSynchronization = true, Protractor will not wait for the angular variable to become available, so it starts firing tests off because it thinks the app is ready, more info here.
You need to manipulate the Control Flow by using Expected Conditions so Protractor knows that it is waiting for something. This will make your tests more consistent and reliable.
A few examples to guide you:
Wait for an element to be loaded/present in the DOM:
var EC = protractor.ExpectedConditions;
var ele = element(by.css('div.class'));
browser.wait(EC.presenceOf(ele), 5000);
The 5000 parameter value I passed in says wait a maximum of 5 seconds, if not present in 5 seconds then fail.
Wait for an element visible:
browser.wait(EC.visibilityOf(ele), 5000);
Wait for an element to be clickable:
browser.wait(EC.elementToBeClickable(ele), 5000);
Again, it's important to note that these are implicit waits and they will wait a maximum of the time parameter provided. It is not a guaranteed amount of time to wait, they fire off ASAP when they find the element you told it to wait for.
Related
I have this test code:
element(by.cssContainingText('a[ng-click="select()"]', 'Visual')).click()
browser.sleep(1000)
expect(element.all(by.tagName('angular-chart')).count()).toEqual(1);
But it hangs until timeout reach and then shows:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
I suppose I need to wait for the content to load somehow then run the test?
If I replace the expect construct with the one below, it passes:
expect(true).toEqual(true)
Try this:
element(by.cssContainingText('a[ng-click="select()"]', 'Visual')).click().then( function(){
expect(element.all(by.tagName('angular-chart')).count()).toEqual(1);
});
Most calls in protractor returns a promise.
http://www.protractortest.org/#/api?view=webdriver.WebElement.prototype.click
Let's try adding an explicit wait to wait for the angular-chart element to become present:
var EC = protractor.ExpectedConditions;
element(by.cssContainingText('a[ng-click="select()"]', 'Visual')).click()
var chart = element(by.tagName('angular-chart'));
browser.wait(EC.presenceOf(chart), 10000);
You might also look into increasing jasmine timeout intervals.
I am looking for a solution, if it is possible to wait for the data entered by the user in protractor.
I mean test stop for a while and I can enter some value and then these data are used in further tests.
I tried to use javascript prompt, but I did not do much, maybe it is possible to enter data in OS terminal?
Please give me an example if it is possible.
I would not recommend mixing the automatic and manual selenium browser control.
That said, you can use Explicit Waits to wait for certain things to happen on a page, e.g. you can wait for the text to be present in a text input, or an element to become visible, or a page title to be equal to something you expect, there are different ExpectedConditions built-in to protractor and you can easily write your own custom Expected Conditions to wait for. You would have to set a reasonable timeout though.
Alternatively, you can pass the user-defined parameters through browser.params, see:
How can I use command line arguments in Angularjs Protractor?
Example:
protractor my.conf.js --params.login.user=abc --params.login.password=123
Then, you can access the values in your test through browser.params:
var login = element(by.id("login"));
login.sendKeys(browser.params.login.user);
If your data will reside in the console, you can get that data by using the following:
browser.manage().logs().get('browser').then(function(browserLogs) {
// browserLogs is an array which can be filtered by message level
browserLogs.forEach(function(log){
if (log.level.value < 900) { // non-error messages
console.log(log.message);
}
});
});
Then as mentioned in other posts, you can explicitly wait for a condition to be true by using driver.wait():
var started = startTestServer();
driver.wait(started, 5 * 1000,
'Server should start within 5 seconds');
driver.get(getServerUrl());
Or expected conditions if waiting for more than one condition, for example.
I had the same question. After a long search I found a solution with Protractor 5.3.2 that worked:
var EC = protractor.ExpectedConditions;
it('will pause for input...', function() {
browser.ignoreSynchronization = true
browser.waitForAngularEnabled(false);
// open web page that contains an input (in my case it was captchaInput)
browser.driver.get('https://example.com/mywebpagehere');
// waits for 15 sec for the user to enter something. The user shall not click submit
browser.wait(EC.textToBePresentInElementValue(captchaInput, '999'), 15000, "Oops :^(")
.then(function() {
console.log('Hmm... Not supposed to run!');
}, function() {
console.log('Expected timeout, not an issue');
});
browser.sleep(1000);
// submit the user input and execution proceeds (in my case, captchaButton)
captchaButton.click();
// . . .
});
I'm using angular-growl-v2 notifications in my app.
They work ok, the problem comes on my protractor tests. I have to use a TTL (around 6 seconds) as it is a requirement. Then I have the following test:
it('should send a request and notify the user about the result',function(){
detailPage.verifyEmailtButton.click().then(function(){
var expectedDiv = element(by.css('.alert-success'));
expect(expectedDiv).toBeDefined();
});
});
But it is always throwing an error:
NoSuchElementError: No element found using locator: By.cssSelector(".alert-success")
This does not happens when the TLL is -1.
Someone can help here? Thanks in advance.
angular-growl-2 uses $timeout, which doesn't play nicely with protractor: protractor waits for the timeout to end before it completes its sync with angular process.
So by the time it reaches your expect call, the timeout has elapsed and the alert is no longer there. Check out the Waiting for page synchronization section of this doc:
https://github.com/angular/protractor/blob/master/docs/timeouts.md
(This page relates to timeouts, which you don't appear to be experiencing, but since the default timeout is 11 seconds, it could well be that the entire process, including your 6 second TTL, takes place before a timeout happens)
There's a PR to angular-growl-v2 to use $interval instead of $timeout, but its currently waiting for tests:
https://github.com/JanStevens/angular-growl-2/pull/85
Explicitly wait for the alert to be present after clicking the button:
detailPage.verifyEmailtButton.click();
var EC = protractor.ExpectedConditions;
var expectedDiv = element(by.css('.alert-success'));
browser.wait(EC.presenceOf(expectedDiv), 10000, "No alert present");
Why is Protractor running every line of code immediately?
So I have a webpage that is not written in angular. That I need my selenium based automation to hit. I have used selenium webdriver-js code to hit it. Example below. Once you login, you are taken to a page with 3 questions. The order of the questions are randomized each time you login. So you may never get the same questions in the same order each time you login.
Question 1) What is your name?
Question 2) What time is it?
Question 3) Wy are you here?
The answers to each question are the last word of the question.
Answer 1) name
Answer 2) it
Answer 3) here
So what I was thinking an easy way to solve this problem is to create an if conditional statement
var foo = browser.driver.findElement(By.id('question1')).getText();
if(foo == What is your name?) {
browser.driver.findElement(By.id('answer1')).sendKeys('name');
}
else {
blah
}
and so forth... etc...
But the problem I am running into is that Protractor immediately runs the if statement before it gets to that point. In the example below, the console immediately prints out the console log 'this sucks', because it runs through the if statement immediately without going through the first steps to get to the page and then checking.
this.foo_test = function() {
console.log('starting foo test');
browser.driver.get('http://my-test-url.com/');
browser.sleep(3000);
browser.driver.findElement(By.id('login')).click();
browser.sleep(3000);
browser.driver.findElement(By.id('user')).sendKeys('user');
browser.driver.findElement(By.id('login_button')).click();
browser.sleep(3000);
console.log('getting variable');
var foo = browser.driver.findElement(By.id('question1')).getText();
console.log(foo);
if (foo == 'What was the name of your first pet?') {
console.log('this is cool');
}
else{
console.log('this sucks');
}
};
Protractor builds on WebdriverJS, which uses an implicit-promise-queuing style of programming. See:
https://github.com/angular/protractor/blob/master/docs/control-flow.md
What that means is that each statement in a protractor test should be read as enqueuing a promise, not as actually executing. So for example, the line:
browser.driver.findElement(By.id('question1')).getText()
Does not return text, but returns a promise to return text. You must pass this promise to the other promise-expecting APIs, or provide a direct handler with .then().
The expect call you see in Protractor tests has been modified to wait for a promise to resolve. So something like:
expect(name.getText()).toEqual('Jane Doe');
Is actually enqueuing a promise to compare the result of the promise on the left to the value on the right.
I don't know much about Protractor specifically but this sounds like an issue of not recognizing asynchronous code. If the first assignment statement is asynchronous, then the rest of the code will run without waiting for it to complete. Hence, the values you expect will not be there when you try to test for them in the IF statement.
Your best bet is to run the rest of the code in a callback or promise .
It appears your page is still loading even though selenium thinks it is complete. This happens alot with dynamic/asynchronous pages.
browser.sleep() is not really appropriate, you never really know how long you need to wait for.
You can investigate the class WebDriverWait, which allows you to wait for an element to appear, or timeout.
Wait<WebDriver> wait = new WebDriverWait(driver, 50); // timeout is 50 secs
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
return (driver.findElement(By.id('question1'))).isDisplayed();
}
});
You can also try running some javascript to check the document ready status :
Wait<WebDriver> wait = new WebDriverWait(driver, 60); // timeout is 60 secs
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
String docReady = "";
Boolean rc = true;
if (null != ((RemoteWebDriver)driver).getSessionId()) {
docReady = String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"));
rc = docReady.equals("complete");
}
return rc;
}
});
I am doing test-driven development with Qunit: when creating a new function, I write tests for it, create the function, reload the page, and if all the tests pass I move on... Whilst this works fine at the beginning, it starts to become a time consuming process after a while as all the tests take several seconds to run, and that's the time I have to wait for every time I refresh my browser.
In an attempt to workaround that problem, I thought about introducing Zombie.js to perform head-less testing: the idea is to have Zombie.js continuously check the webpage (e.g. $ watch -n1 "node queryTheWebpage.js") and report to me Qunits's results while coding (once in a while, as Zombie.js isn't a "real" browser, I would open up a browser and check the page manually to validate).
So far here is what I have for my node/Zombie piece of code:
browser.visit("http://localhost/mywebpage.html", function () {
var qunit_tests = browser.query('body');
console.log(qunit_tests.innerHTML);
});
In the console output I do see the Qunit tests container <ol id="qunit-tests"></ol> but it is empty which means when the visit callback function is called, the tests haven't run.
I've tried to use the wait function to wait for the tests to run, but unsuccessfully:
function waitForQunitToEnd(window) {
var last = window.document.querySelector('selectorOfMyLastTest');
var first_failed = window.document.querySelector('li.failed');
return (last || first_failed);
}
browser.visit("http://localhost/mywebpage.html", function () {
browser.wait(waitForQunitToEnd, function() {
var qunit_tests = browser.query('body');
console.log(qunit_tests.innerHTML); // still gives me empty <ol id="qunit-tests"></ol>
});
});
I tried to play with the waitFor option (e.g. set to 5000ms) but that didn't help either.
Q1: Is what I'm trying to do making sense, or is there a much simpler way of doing something similar?
Q2: Do you know how I could get Zombie.js to wait for the Qunit tests to run?
I don't know if it will help you but look this : http://api.qunitjs.com/QUnit.done/