Cypress .each() function only iterating on first instance of element - javascript

I'm attempting to run through a list of dynamic items on my app. Each item is made up of several displayed elements like name, due date, etc. - These are currently entered by users, so I'm stubbing the data in my test via fixtures to verify they're working as expected.
I'm currently using a .each() loop that references the fixture, referred to as patientHealthGoals. Listed below is the relevant portions of the .each() loop.
cy.get('userGoalList')
.each(($el, index) => {
cy.get('userGoalItem')
.within(() => {
cy.get('[data-cy="due-date"]')
.should('have.value', userGoals[index].due_at);
cy.get('[data-cy="comments"]')
.should('have.value', userGoals[index].comment);
});
});
What's strange is that, on each iteration, it correctly checks the [data-cy="due-date"] field. However, on the [data-cy="comments"], it always compares against the first instance of that element, no matter what index it's on. Here is the relevant error I'm getting:
expected [ < textarea.block.-with-updated.ng-untouched.ng-pristine.ng-valid.om-input >, 3 more... ] to have value 'Notes for second item', but the value was 'Notes for first item'
The only difference between the [data-cy="due-date"] and [data-cy="comments"] checks that I can see are the elements themselves. The first one is an input and the latter is a textarea, but I fail to see why Cypress would be treating them completely differently. Any ideas what might be breaking here?

Related

JS <select> listbox not working on click/change

what I need to do is to gather some data online via fetch and use the data to give the user infos and such (that I can do). In some cases, the fetch can return multiple results (an array of data), so I decided to create a element in the page to list all the names of the elements in the array (each element in the array is a sub-array with various infos, also a "name", which would be a location name).
I'm working on Chrome. All works, I store the data and this way I created another function to (theoretically) give the user the infos about the selected option in the listbox. If I call the function directly it works fine, meaning it returns all the infos it should. What actually doesn't work is the fact that this function returning infos should trigger on click/selecting any option from the list and it doesn't work. I don't get any error messages, it just does nothing.
What you see in this image is what happens when you click "filter" (it actually filters world locations detected with name similar to "Milano"), the user gets infos in the page and what you see in the right log side in the red square is returning the content of that array I mentioned (it contains data, so it's working), the index selected in the list (the last, so it's 5) and the coordinates of such selected location.
This happens just after the creation of the options because I directly call the function (returning data about the selected option), but if I use manually the list it just does nothing (as you see in the list, there's nothing logged after those coordinates).
I tried to create the options like this:
function createOption(text){
let listOption = new Option(text, text, true, true);
return listOption;
}
What I do directly to create the options in the list is a "for" loop for each element i in the array:
document.getElementById("keyword-results").append(createOption(data.data[i].station.name));
I also tried appendChild instead of append. As I said, this works, but the manual use of the list doesn't. What I declared is:
document.getElementById("keyword-results").addEventListener("onchange", selection());
being "selection()" the function returning the data.
function selection(){
let index = document.getElementById("keyword-results").selectedIndex;
console.log(index);
if (index > -1){
let currentResult = results.data[index];
let aqi = currentResult.aqi;
console.log(aqi);
document.getElementById("answer").innerHTML += `The estimated AQI [...]`;
let far = distance(currentResult.station.geo[0], currentResult.station.geo[1]);
if (far != null || far != undefined) {
document.getElementById("answer").innerHTML += `The estimated distance [...]`;
}
}
}
I also tried "change", "onclick" and "click" as methods to trigger the function but none of them works. Do you have any suggestions? I can't find anything useful here on stackoverflow nor on the web. If you want to check the whole code, this is my GitHub repository https://github.com/leorob88/pollution-forecast-API
document.getElementById("keyword-results").addEventListener("onchange", selection());
addEventListener expects a function as a second parameter, selection() is not a function but selection is.
When you use addEventListener, there is no such event named onchange its actually change
so it becomes:
document.getElementById("keyword-results").addEventListener("change", selection);
Reference.

How can I overwrite an array using Ractive?

I have a componet that updates an array on it's parent. Specifically, it takes additions, and creates an entirely new array that has been sorted, overwriting the original array.
var sortedUpdatedDomainNames = updatedProposedDomainNames.sort(sorts.domainName)
// even though we sort them, after setting the value, getting it returns the unsorted items
debugger;
Typing in the debugger here:
sortedUpdatedDomainNames
(4) ["example.com", "www.example.com", "swag.com", "www.swag.com"]
OK that works. The array items are sorted (using sorts.domainName which puts www immediately after parent domains)
await parentComponent.set('order.proposedDomainNames', sortedUpdatedDomainNames)
Here's the first issue: the DOM doesn't update poroperly, some items are duplicated in the DOM even though they're not duplicated in the data.
Running parentComponent.update fixes these duplications, however:
// Work around odd ractive bug where DOM doesn't update properly
// Trigger an update manually using .update()
// TODO: find proper fix!
await parentComponent.update('order.proposedDomainNames');
Her's the second issue: the values are now unsorted (well, they're sorted alphabetically now, which isn't what I want).
parentComponent.get('order.proposedDomainNames');
(4) ["example.com", "swag.com", "www.example.com", "www.swag.com"]
How can I overwrite an array using Ractive?
Please do not submit answers re: ractive.splice() etc - I do not know in advance the index where the data will be inserted, I simply wish to sort the entire array and update it.
Using the deep option for ractive.set() ensures the DOM updates to match the new array values - even though the array is a simple array of primitives.
await parentComponent.set('order.proposedDomainNames', sortedUpdatedDomainNames, { deep: true })
I also tried shuffle, which was suggested, but this does not work and the DOM is still inconsistent with the array value when using shuffle.
Though the issue is solved, I'm still interested in why deep was needed to make the DOM update correctly, so if you have your own answer to that, add it and I'l; accept it!

Protractor Select Object Which is On Top

I have a test I am trying to create where I change the name of a card. The problem is there is a hidden error card which has the exact same identifiers as what I am trying to edit. The test returns that the object I am trying to work with is unreachable, which makes sense, it is under the one I am working with.
The locator which I have is: textarea[ng-model="ctrl.currentChartTitle"].
Yes, I know that I can do this by model and tried that, but it yields the same results.
Here is a screenshot of the html the yellow is the on top object I am trying to reach:
Not really sure how do to do the selector for this, so it always works.
So I did a bit more searching and found a solution. It looks a like this:
chartTitleTextArea = this.visualizer.all(by.css('textarea[ng-model="ctrl.currentChartTitle"]')).filter((element) => {
return element.isDisplayed().then((isDisplayed) => {
return isDisplayed
})
}).first()
Basically, what this is doing is getting all of the elements which match that locator. Then filtering them on if isDisplayed() is true. Then grabbing the first one.

Remove all elements within a ng-repeat in Angular

I'm working with Angular and part of my page utilizes ng-repeat to display some bug tracker tickets. As part of the site, I also want to provide the ability to search tickets. I'm able to get that part working as I want, and if I'm just appending new tickets they show up fine.
However I would like to be able to, if a user searches, delete all of the currently visible ticket divs and replace them with the search results.
My initial thinking, since I have the ng-repeat set as item in tickets track by item.id, was to just set $scope.tickets equal to the new data. However, this didn't cause Angular to update the DOM.
So, I tried setting $scope.tickets equal to an empty array and then setting it equal to the new data:
$scope.$apply(function() {
$scope.tickets = [];
$scope.tickets = data;
});
Still no update to the DOM, even though console.log($scope.tickets) shows the correct objects.
I'm aware of the method of
$scope.$apply(function() {
array.splice(index, 1);
});
to remove individual elements, but I'm not sure how I would apply that removing all of the elements.
I'll try and get a Plunkr or JSBin added to the Q soon.
What would be the proper way for me to make Angular replace all of the current elements with the new elements created from the data?
try setting array.length = 0
this deletes all elements, while not removing the reference to the array, which actually seems to be the problem in your case.
but another way would be to have a additional data bag.
for example have $scope.data.tickets then you can reasign tickets as usual. important thing is, you have to reference your items using item in data.tickets
Did you test $watch?
$scope.$watch('tickets', function() {
// update data HERE
});

Javascript - removing an element from array

I'm displaying elements from an arraylist in table on the webpage. I want to make sure that once the user press "delete the data", the element in the table is immediately removed so the user does not have to refresh and wait to see the new table. So I'm currently doing it by removing the element from the arraylist, below is the code:
$scope.list= function(Id) {
var position = $scope.list.indexOf(fooCollection.findElementById({Id:Id}));
fooCollection.delete({Id:Id});
if (position>-1) {
$scope.list.splice(position,1);
}
$location.path('/list');
};
But I the position is always -1, so the last item is always removed from the list no matter which element I delete.
I found it strange you we're operating on two different lists to begin with so I assumed you were taking a copy of the initial list. This enabled me to reproduce your bug. On the following line you're trying to find an object that isn't present in your list.
var position = $scope.list.indexOf(fooCollection.findElementById({Id:Id}));
Eventhough we're talking about the same content, these two objects are not the same because:
indexOf compares searchElement to elements of the Array using strict
equality (the same method used by the ===, or triple-equals,
operator).
So there lies your problem. You can see this reproduced on this plunker.
Fixing it the quick way would mean looping over your $scope.list and finding out which element actually has the id that is being passed.
you can use the splice method of javascript which takes two paramete
arrayObject.splice(param1, param2);
param1 -> from this index elements will start removing
param2 -> no of elements will be remove
like if you want to remove only first element and your array object is arrayObject then we can write code as following
arrayObject.splice(0, 1);

Categories