Protractor wait for all elements to have changed text - protractor

I want to wait till first element gets updated to rate same as monthlyRate variable and second element gets updated to rate same as annualRate.
With below code I get:
Failed: Wait timed out after 9008ms
public waitForSubscriptionRates = (rateselector: string, monthlyRate: string, annualRate: string) => {
browser.wait(function(){
element.all(by.css(rateselector)).filter(function(elem, index) {
return elem.getText().then(function(text) {
console.log('text=' + text);
console.log('monthlyRate=' + monthlyRate);
console.log('annualrate=' + annualRate);
return (text === monthlyRate || text === annualRate);
});
}).first().click();
},9000);
}

I'm not sure do I understand your code well.
I assume that there are two selectors - first may contain text of monthlyRate and second annualRate. They can not be mixed, isn't it?
I don't get what you want to click.
Anyway, you can chain ExpectedConditions with or keyword.
See the example in the documentation: http://www.protractortest.org/#/api?view=ProtractorExpectedConditions.prototype.or

Related

AG-Grid: updateRowData({update: ItemsArray}) affecting all rows instead of selected rows

I'm using Ag-Grid and Angular for this project, and what I'm trying to do is set up shortcut keys to change the 'Status' value of selected rows by pressing associated keys('1'= 'status complete', etc.). There is a built in function called onCellKeyPress() that listens for keystrokes after a row, or rows, has been selected. That's working great, I have a switch case that sends off a value depending on which key is pressed like so:
onCellKeyPress = (e: any) => {
switch(e.event.key) {
case '0': this.rowUpdates('New'); break;
case '1': this.rowUpdates('Completed'); break;
case '2': this.rowUpdates('Needs Attention'); break;
case '3': this.rowUpdates('Rejected'); break;
}
}
It sends a string to my custom function rowUpdates(), that takes the value, goes though the existing Nodes, looks for any that are selected, sets the value on those selected, and pushes them to an array.
Now here's where the trouble starts. updateRowData takes 2 params, first is the type of updating it's doing(add, remove, update), in my case I'm using the latter, and an array of rows to change.
rowUpdates = (value: String) => {
let itemsToUpdate = [];
this.gridOptions.api.forEachNode(rowNode => {
if(rowNode.isSelected() === true) {
const selected = rowNode.data;
selected.status.name = value;
itemsToUpdate.push(selected);
console.log(itemsToUpdate);
}
});
this.gridOptions.api.updateRowData({update: itemsToUpdate});
}
However when I press a key to change the row value it updates every row in my grid. What's extra strange is that I have a method that adds a class to the row depending on the 'Status' value, and only the rows I intended to change receive that class.
I'm stumped. I've console.logged everything in this function and they all return with their intended values. The array always contains the nodes that have been selected and the return value of updateRowData is always that same array. I've tried switching out 'forEachNode' with getSelectedNodes and getSelectedRows to no avail. Any ideas?
Please try this.
updateItems(value: String) {
var itemsToUpdate = [];
this.gridApi.forEachNodeAfterFilterAndSort(function(rowNode, index) {
if (!rowNode.selected) {
return;
}
var data = rowNode.data;
data.status.name = value;
itemsToUpdate.push(data);
});
var res = this.gridApi.updateRowData({ update: itemsToUpdate });
this.gridApi.deselectAll();//optional
}

How can you create a timer that works on a List in Rx?

I want to look for an entire list of items to be found before I complete and if that entire list isn't found, then an exception (a Timeout or custom one) is to be thrown. Like the built in Observable.timer() but instead of the test passing once the first item is emitted, I want it to require all of the items in a list to be found.
Here is an example. Let's say I have some test function that emits Observable<FoundNumber>. It looks like this:
var emittedList: List<String?> = listOf(null, "202", "302", "400")
data class FoundNumber(val numberId: String?)
fun scanNumbers(): Observable<FoundNumber> = Observable
.intervalRange(0,
emittedList.size.toLong(),
0,
1,
TimeUnit.SECONDS).map { index ->
FoundNumber(emittedList[index.toInt()]) }
That function will then be called to get numbers that will be compared to a list of expected numbers. It doesn't matter if there are additional numbers coming from scanForNumbers that aren't in the "target" list. They will just be ignored. Something like this:
val expectedNumbers = listOf("202", "302","999")
scanForNumbers(expectedNumbers)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe { value -> Log.d(TAG, "Was returned a $value") }
So, the expected numbers (202, 302, and 999) don't exactly match with the numbers that will be emitted (202, 302, and 400). So, a timeout SHOULD occur, but with the built in version of Observable.timer(), it will not time out since at least one item was observed.
Here is kind of what I'd like to have. Anyone know how to code this up in RxJava/RxKotlin?
fun scanForNumbers(targets: List<String>): Observable<FoundNumber> {
val accumulator: Pair<Set<Any>, FoundNumber?> = targets.toSet() to null
return scanNumbers()
.SPECIAL_TIMEOUT_FOR_LIST(5, TimeUnit.SECONDS, List)
.scan(accumulator) { acc, next ->
val (set, previous) = acc
val stringSet:MutableSet<String> = hashSetOf()
set.forEach { stringSet.add(it.toString()) }
val item = if (next.numberId in stringSet) {
next
} else null
(set - next) to item // return set and nullable item
}
.filter { Log.d(TAG, "Filtering on ${it.second}")
it.second != null } // item not null
.take(targets.size.toLong()) // limit to the number of items
.map { it.second } // unwrap the item from the pair
.map { FoundController(it.numberId) } // wrap in your class
}
How do you code, hopefully using RxJava/Kotlin, a means to timeout on a list as mentioned?
I think I get it now, you want the timeout to begin counting from the moment you subscribe, not after you observe items.
If this is what you need, then the takeUntil operator could help you:
return scanNumbers()
.takeUntil(Observable.timer(5, TimeUnit.SECONDS))
.scan(accumulator) { acc, next -> ...
In this case, the timer will begin counting as soon as you subscribe. If the main observable completes before then great, if not, then the timer will complete the main observable anyways.
But takeUntil by itself will not throw an error, it will just complete. If you need it to end with an error, then you could use the following combination:
return scanNumbers()
.takeUntil(
Observable
.error<Void>(new TimeoutError("timeout!"))
.delay(5, TimeUnit.SECONDS, true))
.scan(accumulator) { acc, next -> ...

How to wait for item to be removed from list

I am trying to delete and Item from the list, it takes long time in application to delete this element, so I want to wait until this element is deleted and then verify that this item is not present on the page.
this.GroupList = element.all(by.repeater("Group in GroupList | orderBy: order"));
Now I delete an element from the above list based on its Name getAttribute('aria-label'), How can I use ExpectedConditions.stalenessOf OR ExpectedConditions.invisibilityOf to wait till one element from the list is removed from DOM.
If you have a reference to this specific repeater item, you can use stalenessOf Expected Condition, for instance:
// page object
this.GroupList = element.all(by.repeater("Group in GroupList"));
// test
var itemToBeDeleted = pageObject.GroupList.get(5);
// delete an item here
browser.wait(EC.stalenessOf(itemToBeDeleted), 5000);
Note that you don't need the "orderBy" part in the repeater locator.
Another idea would be to wait for the count to decrease by one with a custom expected condition:
function waitForCount(elementArrayFinder, count) {
return function () {
return elementArrayFinder.count(function (actualCount) {
return actualCount === count;
});
};
}
Usage:
pageObject.GroupList.count().then(function (countBefore) {
// delete item here
browser.wait(waitForCount(pageObject.GroupList, countBefore - 1));
});

Filter getElementsByTagName list by option values

I'm using getElementsByTagName to return all the select lists on a page - is it possible to then filter these based upon an option value, ie of the first or second item in the list?
The reason is that for reasons I won't go into here there are a block of select lists with number values (1,2,3,4,5 etc) and others which have text values (Blue and Black, Red and Black etc) and I only want the scripting I have to run on the ones with numerical values. I can't add a class to them which would more easily let me do this however I can be certain that the first option value in the list will be "1".
Therefore is there a way to filter the returned list of selects on the page by only those whose first option value is "1"?
I am pretty sure that there is a better solution, but for the moment you can try something like:
var allSelect = document.getElementsByTagName("select");
var result = filterBy(allSelect, 0/*0 == The first option*/, "1"/* 1 == the value of the first option*/);
function filterBy(allSelect, index, theValue) {
var result = [];
for (var i = 0; i < allSelect.length; i++) {
if(allSelect[i].options[index].value == theValue ) {
result.push(allSelect[i]);
}
}
return result;
}
I managed to get this working by wrapping a simple IF statement around the action to be performed (in this case, disabling options) as follows:
inputs = document.getElementsByTagName('select');
for (i = 0; i < inputs.length; i++) {
if (inputs[i].options[1].text == 1) {
// perform action required
}
}
No doubt there is a slicker or more economic way to do this but the main thing is it works for me.

tinymce.dom.replace throws an exception concerning parentNode

I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.