Click an element based on a comparison in protractor - protractor

In my e2e testing using protractor,I am taking data from a file and checking whether that data is present in the UI. If present,then click it.
There are about 10 chapters in the page and my file has 2 chapters(indicated as chapterName).I want to check whether the chapterNames in my file are there in the UI and if so,then click one by one.I am working with the below code,but dont know how to do the looping
How to do that in protractor?
element.all(by.repeater('chapter in chapters')).filter(function (ele,index) {
return ele.getText().then(function(text){
return text === chapterName;
});
}).click();

You need to use closure function to achieve looping inside a promise. look at the below example code.
function clickChapterByName(){
var chapterNames= ['chapter-1','chapter-2','chapter-3','chapter-4','chapter-5']
for(i=0;i<chapterNames.length;i++){
function closure(chapterName) {
element.all(by.repeater('chapter in chapters')).filter(function (ele,index) {
return ele.getText().then(function(text){
return text === chapterName;
});
}).click();
}
closure(chapterNames[i])
}
}

Not quite sure that i am correct, but i think you are almost there:
element.all(by.repeater('chapter in chapters')).filter(element=> {
return ele.getText().then(text=> text === chapterName);
});
}).map(element=> element.click());
Result of .filter will be only elements that match condition, so you will get new ArrayElementFinder, and you can iterate thru it with .map()

For your requirement, you need to do loop operation.So you can achieve this by each() method which is available in protractor api.
Code Snippet:
element.all(by.repeater('chapter in chapters')).
each(function (ele, index) {//for looping purpose
ele.getText().then(function(text){
if(text == inputChapterName){
ele.click();//click chapter is
}
});
})

Related

Select features with click AND double-click in Openlayers 3

I would like to click and double-click select features at the same time in openlayers 3. The condition option when creating ol.interaction.Select takes only one function, so a workaround is necessary
I tried writing my own custom condition function that calls the appropriate function, I was thinking of something like...
this.selectType = (feature) => {
if (feature){
if(feature.onclick){
return ol.events.condition.singleClick
} else {
return ol.events.condition.doubleClick
}
}
}
this.selectInteraction = new ol.interaction.Select({
condition: this.selectType(),
toggleCondition: ol.events.condition.shiftKeyOnly,
layers: this.layerFilter,
features: this.features,
style: this.selectStyle,
});
...but without success.
I realize, I could create two separate interactions for selecting features, but would rather not because that would involve replicating a lot of code depending on the Select interaction.
Does anyone know if this is even possible in openlayers and how to handle a situation like this?
Thanx a lot
The condition is a function which takes a map browser event and returns a boolean. Based on Alt+Cick in the OpenLayers example https://openlayers.org/en/v4.6.5/examples/select-features.html to select on either single or double click you will need something like
this.selectType = (mapBrowserEvent) => {
return ol.events.condition.singleClick(mapBrowserEvent) ||
ol.events.condition.doubleClick(mapBrowserEvent);
}
this.selectInteraction = new ol.interaction.Select({
condition: this.selectType, // pass the function, don't call it!
toggleCondition: ol.events.condition.shiftKeyOnly,
layers: this.layerFilter,
features: this.features,
style: this.selectStyle,
});

Protractor: Failed: stale element reference: element is not attached to the page document after click()

I am facing above issue when i am trying to click on the dropdown element which matches with given text. All the options of dropdown are as in the image with span having the text.
I tried things given as in the link here,but no success. Protractor: Failed: stale element reference: element is not attached to the page document. Reference of tags are as given here in this pic below.
My code looks something like this
element.all(by.css('ul[class='ui-dropdown-items ui']>li')).each(function(element) {
element.getText().then(function (text) {
if (text.includes("Bag")){
element.click();
}
});
});
Though the click action gets performed by above statement, still error is thrown.
Also when i try to click on any index as hard coded it works with no error.
element.all().get(4), where 4 being index of the element.
My application is in angular 5.
Can someone help me out on this! This is blocking my project.
element.all().each() execute iteration on each element, even you add if condition to only click one element of all, But the getText() in each iteration still be executed.
After you click on the matched element, the page redirected or refreshed. Then call getText() on next element on "new" page, that's why report stale reference exception
You need to filter the matched element, then click on it.
// approach 1
element
.all(by.css('ul[class='ui-dropdown-items ui']>li'))
.filter(function(ele) {
return ele.getText().then(function (text) {
return text.includes("Bag");
});
})
.then(function(eles){
if (eles && eles.length > 0) {
eles[0].click()
}
})
// approach 2
let options = element.all(by.css('ul[class='ui-dropdown-items ui']>li'))
options.getText(function(txts) {
return txts.findIndex(function(txt){
return txt.includes('Bag');
})
})
.then(function(index){
return index !== -1 && options.get(index).click();
})

Protractor element handling

I have a question regarding how protractor handles the locating of elements.
I am using page-objects just like I did in Webdriver.
The big difference with Webdriver is that locating the element only happens when a function is called on that element.
When using page-objects, it is advised to instantiate your objects before your tests. But then I was wondering, if you instantiate your object and the page changes, what happens to the state of the elements?
I shall demonstrate with an example
it('Change service', function() {
servicePage.clickChangeService();
serviceForm.selectService(1);
serviceForm.save();
expect(servicePage.getService()).toMatch('\bNo service\b');
});
When debugging servicePage.getService() returns undefined.
Is this because serviceForm is another page and the state of servicePage has been changed?
This is my pageobject:
var servicePage = function() {
this.changeServiceLink = element(by.id('serviceLink'));
this.service = element(by.id('service'));
this.clickChangeService = function() {
this.changeServiceLink.click();
};
this.getService = function() {
return this.service.getAttribute('value');
};
};
module.exports = servicePage;
Thank you in advance.
Regards
Essentially, element() is an 'elementFinder' which doesn't do any work unless you call some action like getAttribute().
So you can think of element(by.id('service')) as a placeholder.
When you want to actually find the element and do some action, then you combine it like element(by.id('service')).getAttribute('value'), but this in itself isn't the value that you are looking for, it's a promise to get the value. You can read all about how to deal with promises elsewhere.
The other thing that protractor does specifically is to patch in a waitForAngular() when it applies an action so that it will wait for any outstanding http calls and timeouts before actually going out to find the element and apply the action. So when you call .getAttribute() it really looks like
return browser.waitForAngular().then(function() {
return element(by.id('service')).getAttribute('value');
});
So, in your example, if your angular pages aren't set up correctly or depending on the controls you are using, you might be trying to get the value before the page has settled with the new value in the element.
To debug your example you should be doing something like
it('Change service', function() {
servicePage.getService().then(function(originalService) {
console.log('originalService: ' + originalService);
});
servicePage.clickChangeService();
serviceForm.selectService(1);
serviceForm.save();
servicePage.getService().then(function(newService) {
console.log('newService: ' + newService);
});
expect(servicePage.getService()).toMatch('\bNo service\b');
});
The other thing that I'm seeing is that your pageObject appears to be a constructor when you could just use an object instead:
// name this file servicePage.js, and use as 'var servicePage = require('./servicePage.js');'
module.exports = {
changeServiceLink: element(by.id('serviceLink')),
service: element(by.id('service')),
clickChangeService: function() {
this.changeServiceLink.click();
},
getService: function() {
return this.service.getAttribute('value');
}
};
Otherwise you would have to do something like module.exports = new servicePage(); or instantiate it in your test file.
When you navigate another page, the web elements will be clear, that you selected. So you have to select again. You can select all elements that is in a page of HTML. You can click that you see. So the protactor + Selenium can decide what is displayed.
You have a mistake in your code, try this:
expect(servicePage.getService()).toMatch('\bNo service\b');

Protractor unable to select dropdown option

Hi I have been doing protractor test and I'm having a problem with my tests. My ionic app do have a drop down having a model name and I tried to access it using the model name and it works but the problem is it can not select the exact option that i need to select from that dropdown option. It selects only the first one? I wrote the protractor syntax like this.
element(by.model('generalPowerOfAttorney.grantorGeneralPowerOfAttorneyForm.region')).$('[value="59"]').click();
But this code selects not the value 59 rather value 0 which is the default option. Is there anyone who could help me?
You should add the html source to facilitate the answer.
You can use the filter method in order to get the correct element clicked.
var elements = element.all(by.model('generalPowerOfAttorney.grantorGeneralPowerOfAttorneyForm.region'));
elements.filter(function(elem, index) {
return elem.getText().then(function(text) {
return text === 'value="59"';
});
}).then(function(filteredElem){
if(filteredElem[0] !== undefined){
filteredElem[0].click();
}
else {
throw 'element not found'
}
});

infinite scroll manual trigger callback

I'm using Infinite Scroll plugin in a (I know it is unrecommended http://isotope.metafizzy.co/docs/help.html#infinite_scroll_with_filtering_or_sorting), Infinite Scroll + Isotipe Filtering combination.
Now sometimes happend that after i run my filter, if I get an empty list i manually trigger infinite scroll to load more elements.
$('.items').isotope({ filter: filter }, function( $items ) {
var id = this.attr('class'),
len = $items.length;
if (len == 0){getElement();}
});
Here is my function that load elements, but it seems that the callback is not working.
function getElement(){
$('.items').infinitescroll('retrieve',function(items){
console.log('callback');
console.log(items);
});
}
Unfortunally Infinite Scroll documentation is not the best for manual trigger (it suggest a not-working way to call it - $(document).trigger('retrieve.infscr'); i found the solution here: infinite scroll manual trigger) so I'm a little bit stucked here.
Any suggestion?
I know it is a very old post. But I find it over Google as I searched for the self problem. But I also find the solution for this. Perhaps it helps somebody...
You must put the callback not to the main function. Because manual function only push the main function.
jQuery(document).ready(function($) {
var $infinitecontainer = $(".infinite-content").infinitescroll({
navSelector: ".nav-links",
nextSelector: ".nav-links a:first",
itemSelector: ".infinite-post",
errorCallback: function(){ $(".inf-more-but").css("display", "none") }
}, function() { // callback
alert("Manual click load finished");
});
$(window).unbind(".infscr");
$(".inf-more-but").click(function(e){
e.preventDefault();
var infinite_scroll = $(".infinite-content").infinitescroll("retrieve");
return false;
});