My script failed at the expected conditions at this line:
let condition = EC.presenceOf (title_css);
The error message:
Failed: Cannot read property 'bind' of undefined
I tried an equivalent script in selenium Java and it works. But I am wonder why this fails in Protractor. I am new to Protractor and wonder if ExpectedConditions do not work for non angular.
var title_css = "h1[ng-bind='::$ctrl.primaryText']"
describe ("Protractor test demo", function(){
it ("testing site", function (){
browser.get('https://www.eat24.com/')
let EC = ExpectedConditions;
var title_css = by.css (title_css);
let condition = EC.presenceOf (title_css);
browser.wait(condition, 30000)
})
})
ExpectedConditions in Protractor should accept css like in Selenium / Java?
change the EC to EC = protractor.ExpectedConditions;
then the presenceOf part browser.wait(EC.presenceOf(element));
Also this condition will return a promise that needs resolving
I suggest you to read protractor API documentation first. you'll see protractor has different syntax
A few problems I noticed in your code
let title_css = "h1[ng-bind='::$ctrl.primaryText']" // I assume you verified it works
describe("Protractor test demo", function() {
it("testing site", function () {
browser.get('https://www.eat24.com/')
let EC = protractor.ExpectedConditions; // ExpectedConditions may be available as a global variable, may not, so to be safe do it this way...
let title_element = element(by.css(title_css)); // syntax is element(by.strategy(locator))
let condition = EC.presenceOf(title_element);
browser.wait(condition, 30000)
})
})
If you solve your problem, your next problem will be Promises, I can guarantee you that. So read how to handle them
Related
I wrote a pack of tests and separately each of them works correctly (for each test I created separate file - it important for my case) , but when I try to run them all together I have some problems:
At the first I tried to restart browser after each test with “restartBrowserBetweenTests: true” option but as a result I receive next error:
Failed: This driver instance does not have a valid session ID (did you
call WebDriver.quit()?) and may no longer be used.
I read some advice for this situation, but nothing helped me.
Basically, I can get without restarting browser but in this case I want to close all active tabs after each test and I also don’t know ho to do it. With the help of this function:
browser.getAllWindowHandles().then((handles) => {
browser.driver.switchTo().window(handles[1]);
browser.driver.close();
browser.driver.switchTo().window(handles[0]);
});
I can close active tab and return for the previous but the function works only if I place this code in the test spec, that's not comfortable for me (copy it for each test) and if I call it from special file with functions it works incorrectly due to the
“Failed: no such window: target window already closed
from unknown error: web view not found”
errors (a consequence of a lost context).
https://www.protractortest.org/#/api?view=ProtractorBrowser.prototype.restart
use instead:
browser.restart()
also try to use await
it('Test Puppeteer screenshot', async function() {
await browser.get('https://www.google.com')
let current = await browser.getWindowHandle()
await browser.executeScript("window.open('https://www.indiatoday.com')")
handles = await browser.getAllWindowHandles()
await browser.switchTo().window(handles[1]);
await browser.close();
await browser.switchTo().window(handles[0]);
});
Note if you are using page object the nyou have to reinitialize modules:
if you are using javascript object notation for page then
https://www.npmjs.com/package/decache
const decache = require('decache');
let stage1 = require('../pageobjects/stage1.js');
beforeEach(async function () {
decache('../pageobjects/stage1.js');
stage1 = require('../pageobjects/stage1.js');
elements = stage1.elements;
});
If you are using nodejs class:
let stage1 = require('../pageobjects/stage1.js');
beforeEach(async function () {
stage1 = new PageObjects.stage1();
});
This because the reference for elements have changed you have to reinitialize them
I have executing some protractor script in a function and that function is calling in a for loop.So if any of the error occurring like element not found, element not intractable,WebDriverError: unknown error occur: Element is not clickable, then i need to skip for that loop count and need to execute next loop count.I have tried with isPresent(),isDisplayed() for catching the error but its not working then i tried below code for that.
for(i=0; i<count; i++){
post(post_details[i].MediaUrl,post_details[i].CallToActionType,post_details[i].LPAID,post_details[i].CallToActionUrl);
}
post((MediaUrl,CallToActionType,LPAID,CallToActionUrl){
element(by.css(locators.locator_post_description)).sendKeys(Summary).then (function(){
if(MediaUrl!=null){
var path = require('path');
var type=MediaUrl.split("/");
var fileToUpload = '../files/' + (type[type.length-1]) ;
var absolutePath = path.resolve(__dirname, fileToUpload);
browser.sleep(3000);
element(by.css(locators.locator_post_img)).sendKeys(absolutePath);
browser.sleep(6000);
}
if(CallToActionType!=null){
browser.sleep(1000);
element(by.css(locators.locator_post_eventPostButton)).click();
browser.sleep(2000);
element(by.cssContainingText(locators.locator_post_buttonType,CallToActionType)).click();
browser.sleep(1000);
element(by.css(locators.locator_post_eventPostButtonLInk)).sendKeys(CallToActionUrl);
}
element(by.xpath(locators.locator_post_publishBtn)).click().then (function(){
browser.sleep(3000);
updatedb(LPAID);
});
},function(err) {
console.log("no summary...."+err);
return true;
});
}
Here i am getting values(MediaUrl,CallToActionType,LPAID) form DB and i am checking its value is not null.By using the above code, i am able to catch the error associated with description element and then exiting from that loop count and executing next loop count.But i am not able to use this error catching method for image element,button type element,button link element.So how can i catch error(if any) associated with each of the locator elements and if error occurred, then to skip that loop count.Thanks in advance.
Protractor has inbuilt Expected Conditions using which with browser.wait() you can handle the your issues. Refer to below code and link:
var EC = protractor.ExpectedConditions;
var button = $('#xyz');
var isClickable = EC.elementToBeClickable(button);
browser.get(URL);
browser.wait(isClickable, 5000); //wait for an element to become clickable
button.click();
Documentation - https://www.protractortest.org/#/api?view=ProtractorExpectedConditions
var express = require('express');
var app = express();
var bodyparser = require('body-parser');
var mongoose = require('mongoose');
books = require('./models/books.js');
mongoose.connect('mongodb://localhost/books');
var db = mongoose.connection;
app.get('/api/authors', function (req, res) {
books.getBooks(function (books,err) {
if(err){
throw err;
}
res.json(books);
});
});
Why we cannot use the function(err, books) as function(books, error).
I want to know what principle it violates.
When query is executed, results are passed as parameters to callback function. If If there is any error in executing the query, the error is passed as first argument and the results are passed as second parameter to the callback function. And this is how it works.
So, you can't use it interchangeably.
In your case books.getBooks(function (books,err) {.. if there is any error books will be the one containing in it. And if not, there will be results in err params.
And I assume your query is working OK and you are throwing error checking on err value that's why you see the error.
May be you are getting confused with the names of the params. Remember, they are just the variable names, results are there according to the position of variables in callback.
To answer your question on:
Why we cannot use the function(err, books) as function(books,
error).
Most npm modules follow the Continuation-passing style(CPS) design pattern, which uses:
cb(null, data) to pass on a successful result.
cb(err) to pass on an error and exit the function.
and, the function has only one outcome.
For example:
function getBooks(cb) {
let books, error;
// .... Perform the operations
// .... If all goes well store
// .... the results in books
if (books) {
cb(null, result);
} else {
error = "There was an error loading books"
cb(error)
}
}
This is not a complete example, but shows the essence of it.
TL;DR: That, my friend, is convention.
The only thing that I can think of without knowing the error is that you might want to use:
let books = mongoose.model ('Books');
And your model should be called Books.
Is it possible to include the Error message and Model so we could have some more info about the problem?
I'm trying to wait for a promise resolution using Cucumber, Chai, and Protractor. Is there a way using Chai to wait for something (like a pageload) to occur before sending the callback?
I want something like:
browser.get(url).then(callback)
which I thought would be in Chai:
browser.get(url).should.be.fulfilled.and.notify(callback);
although when I do that, I'm just getting a timeout, but I see the page has loaded.
I already have it setup with:
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
var should = chai.should;
I don't want to check for something, I just want to make sure the page loads. From what I've seen most people just do:
browser.get(url);
callback();
and only use an assert or expect in a Gherkins Then clause, but I want to wait for the page to load in a Given or When.
What I understand with your question is you want the asynchronous Given, When, Then's in CucumberJS to behave as synchronous execution, So that once your step with browser.get(url) is completed then the next step definition is executed. If that is what your question is then Yes we can do that-
You need to either return a promise or use the done callback in your step definitions. Otherwise cucumber doesn't know when your asynchronous actions are complete.
I prefer to return promises when I am performing some actions on the results with .then function and use .done callback function when I am not, Also you don't need callbacks now CucumberJS supports promises. So your step file should look like -
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var expect = chai.expect;
module.exports = function () {
this.Given(/^I launch the protractor demo page$/, function () {
return browser.get('http://juliemr.github.io/protractor-demo/');
});
});
this.When(/^I check the title of the page$/, function () {
return browser.getTitle().then(function(text){
console.log('title is - ' + text);
expect(text).to.equal('Super Calculator');
});
});
There's a troncated code of a page Object in protractor
that code is working :
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function(){
return this.publishedShows.first();
}
};
this one is not :
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function(){
return this.publishedShows.get(0);
}
};
I get this error :
Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator by.repeater("show in showsHomePage")
Anyone can inlight me?
It is not about get(0) vs first() - they are absolutely the same in terms of implementation. It is probably about the timing, wait for the presence of the element before making any action with it:
var elm = myPageObject.getFirstShow();
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(elm), 5000);
// do smth with elm
alecxe does have a point about waiting for the element to be present and so you may want to the wait as mentioned or browser.waitForAngular();
What I have seen is that if you resolve a finder to a variable then this can get left in the unfulfilled promise state (even though the internals have resolved the query). What needs to be done is to resolve the promise and then you should be able to get the element you require:
So from your code:
`this.publishedShows = element.all(by.repeater('show in showsHomePage'));`
Will still be a promise and not publishedShows.
This returns items when I try your code (I have a slightly different repeater).
var HomePage = function() {
this.publishedShows = element.all(by.repeater('show in showsHomePage'));
this.getFirstShow = function() {
return this.publishedShows.then(function(items){
=>return items[0].getText();
});
}
};
var hp = new HomePage();
=>expect(hp.getFirstShow()).toEqual('hello');
Obviously change your expect to what you want to check for and also the return too. Marked with =>
Ensure also that if you use any track by statement then you should look at the by.exactRepeater command to have an exact match on only the repeater part.
This worked for me, note the resolved promise returns an array of finders.