I am currently trying to write an utility function that fetches data in a page and returns it using the below code.
The rows of data returned within children().each(()=>{}) is correct and is printed properly. But I am unable to fetch the values of arr_rows outside of the each loop. I am planning to use this fn in tests that requires fetching and comparing a table of data.
I have attached a screenshot of my output below.

To be able to access the value populated into arr_rows within file scope
Current code I am using to fetch data from web page
let arr_rows = [];
function retreive_data_from_UI(){
cy.get(constants.cssCustomerWoListViewTable).children().each(function($rows, ind){
arr_rows[ind] = $rows.text();
cy.log(ind);
cy.log(arr_rows[ind]); // Prints proper output
}).then((arr_rows) => {
cy.wait(1000);
for(var i = 0; i < 5; i++){
cy.log(arr_rows[i]); // does not print expected output
}
});
}
each always passes on its input, it never mutates the values so when you enter the then block you get the elements passed by children.
I see 2 ways of solving this:
text) at some point though.each loop inside a then block. This is the simple, but it's not reusable. See solution below.function retreive_data_from_UI() {
cy.get(constants.cssCustomerWoListViewTable)
.children()
.then(function(rows) {
let arrRows = [];
// Using JQueries `.each`
$(rows).each((i, row) => {
// Add the text of each row to the end of arrRows
arrRows.push(row.text());
});
// Pass arrRows on to the next item in the chain
return arrRows;
})
.then((arr_rows) => {
for(var i = 0; i < 5; i++){
cy.log(arr_rows[i]); // The correct values should be logged here now
}
});
}
A few more things:
I tried the above method 2 but had issues while accessing the elements/rows passed by children() within the then(). But I was able to resolve it by creating and returning a Promise like below.
```js
function retreive_data_from_UI(){
var result = [];
return new Promise(function(resolve){
cy.get(constants.cssCustomerWoListViewTable).children().each(($rows, ind) => {
result.push($rows.text());
}).then(function(){
this.result = result;
for(var i = 0; i < 5; i++){
cy.log(this.result[i])
}
resolve(this.result)
});
});
}
This should be the simplest way
cy
.get(...)
.children()
.then(($rows) => {
// use jquery's map function here
return $rows.map((i, el) => el.textContent).get()
// or use lodash map and avoid the final .get()
return Cypress._.map('textContent')
})
.then((contents = []) => {
// array of text contents
})
The reason your first example wasn't working was because you were overriding the outer arr_rows variable by calling it the same arr_rows in the local scope of your callback function.
arr_rows would then always be the collection that was passed into the .each since .each does not mutate the subject.
In your case since you're pushing into an array in the .each - just reference the array directly and don't yield the current subject in the .then(() => {})
}).then((arr_rows) => { // <-- this is the problem, don't yield this
cy.wait(1000);
for(var i = 0; i < 5; i++){
cy.log(arr_rows[i]); // does not print expected output
}
});
Most helpful comment
This should be the simplest way
The reason your first example wasn't working was because you were overriding the outer
arr_rowsvariable by calling it the samearr_rowsin the local scope of your callback function.arr_rowswould then always be the collection that was passed into the.eachsince.eachdoes not mutate the subject.In your case since you're pushing into an array in the
.each- just reference the array directly and don't yield the current subject in the.then(() => {})