Storing an array of elements using Cypress - arrays

I want to store an array of strings taken from a page using cypress.
so far I have:
cy.get(".product-name").each(($el) => {
let text = $el.text();
cy.request("POST", "http://localhost:3000/sale-items", {
text
});
cy.wait(1000);
});
As you can see I am having to make separate requests for every item. But I want to store the entire array somehow, and then make one request.
I have read this page on variables and aliases but feel no closer to achieving what I want.
How to store an array of items generated from using Cypress commands?

You can use .then() instead of .each() to retrieve all elements classed 'product-name'. The parameter is an iterable collection that can be converted to an array.
Ref Array.from
cy.get(".product-name").then(($els) => {
const texts = Array.from($els, el => el.innerText);
cy.request("POST", "http://localhost:3000/sale-items", {
texts
});
cy.wait(1000);
});

cypress provide .each($elem, index, $list) method to iterate each
element of the array.
cy.get(".product-name").each(($els, index, $list) => {
// $list itself is collection of element
// $elem is each element of array
// index is postion of element in array
});

function getProductName() {
let countProducts
cy.get('.product-name')
.then((elements) => {
countProducts = elements;
})
return countProducts
}
Cypress.Commands.add('getProductName', getProductName)
To invoke the method from any test:
cy.getProductName().then(element => {
cy.log(`Product names are: ${element.text()} `)
})

Related

Cypress: How to add loop based on the array length?

I have this code where i get 'ul[class="menu"] > li' get there text and convert it to arrays 'list'
it('List to array', () => {
const list = []
cy.get('ul[class="menu"] > li').children()
.each(($ele) => {
list.push($ele.text().toString().trim())
})
.then(() => {
cy.get('ul[class="menu"] > li').should('contain',list[0])
cy.log(list[0])
})
})
Now i want to add a loop until it finished my array in list that will assert (should) based on my last code because the length of list is constantly changing and i don't want a repeated code
How can i achieved this?
Take a look at docs for each(), Cypress passes in each element and also it's index.
Use the index to get the value from the list.
cy.get('ul.menu > li') // same as 'ul[class="menu"] > li'
.each(($el, index) => {
expect($el.text()).to.eq(list[index])
})

Angular Firestore - Map data from nested array of references

I have a collection A and those documents have an array of references to documents in collection B.
In my service I get all my A's but with an array of unusable objects. I but I want to view them too.
getAs() {
this.aService.getAs().subscribe((data) => {
this.aArray = data.map((e) => {
return {
id: e.payload.doc.id,
...(e.payload.doc.data() as {}),
} as A;
});
//TODO some magic to get a nice array of B's inside every A
});
}
It's important to get the array of A objects with arrays of B object inside and not two separate arrays of A's and B's.
I hope I have expressed myself clearly to some extent.
Thanks in advance
As outlined in the Firestore documentation here Firestore Reference a document reference refers to a document location within Firestore and can be used to read, write, or listen to said document. This means that the reference type does not store the document data, and therefore you must query for it.
What you'll have to do is loop over each reference in array_of_bs and use its path to query for the corresponding document. Then, add the document data to a temporary array and combine it with the array being returned by the map() function like so:
async getAs() {
this.aService.getAs().subscribe(async (data) => {
const promises = await data.map(async (e) => {
// temp array to hold b document data
let array_of_bs = [];
// loop over each reference in array_of_bs
for (const path of (e.payload.doc.data() as any).array_of_bs) {
const bObj = await this.afs.doc(path).get().toPromise();
array_of_bs.push(bObj.data());
}
return {
id: e.payload.doc.id,
...(e.payload.doc.data() as {}),
array_of_bs: array_of_bs // this will overwrite the array_of_bs returned in the above line with the document data
} as A;
});
const docValues = await Promise.all(promises);
console.log(docValues);
});
}

React Native: update an Array inside an Object

i currently have an object and inside this object i have multiple objects and Arrays. I want replace an Array inside this object with a new Array, so i thought of making a copy of the entire object and simple replace the Array i wan to change with the updated Array. My problem is i couldnt complete my code, i have the idea of how to do it but cant execute it.
setListings(listings=>
listings.map(item =>{
if(item.id === msg.id){
//console.log(item)
//console.log(item.Message)
const newMessages = [msg,...item.Messages]
//console.log(newMessages)
return console.log([msg,...item.Messages],{...item}) // just for testing purpose i
am returning a console log
to see what it will get me. Not correct.
}
return item;
})
);
So basically listings is my state variable, here console.log(item) prints out the entire object, console.log(item.Messages) prints out the current Messages Array which i want to replace, console.log(newMessages) prints out the new Messages Array which i want to replace the current Messages array with.
cartItem.map((food,index)=> {
if(food.food_id == newFoodItem.food_id && food.id == newFoodItem.id){
const AllFoodData = cartItem
AllFoodData[index] = newFoodItem
AsyncStorage.setItem('#Add_cart_Item', JSON.stringify(AllFoodData))
.then(() => {})
.catch(err => console.log(err))
ToastAndroid.showWithGravityAndOffset('Cart Replace Successfully',ToastAndroid.LONG,ToastAndroid.BOTTOM,25,50 )
}
})
So basically what i want to achieve here is to add the msg object to the existing Messages Array.
Since lsitings is an Array of objects using the .map i can spread through each object and check if the id of that object is each to my msg.id. if that is true then i want to return a copy the that specific listing and edit the Messages Array within [msg, ...item.Messages] otherwise return the existing item.
setListings(listings=> listings.map(item => {
if(item.id === msg.id) {
return {
...item,
Messages: [msg, ...item.Messages]
}
}
return item;
}));
});

How to sort how you want the the data from firestore

I have a firestore with lessons, see the picture below, I get from the firestore the title property from each object and display it in the browser, but everytime I refresh the website the lessons are sorted by how they want, why is that happening? I want to sort them how I want, I want to start with 'Introduction' and so on, how can I do that? I think the orderBy() is not working here.
As you see in the image above, the order in the firestore is alphabetical, but in my page is sorted by its own, see the picture below.
I want the result to be by in a specific order, for example we have the following titles, these titles are from the firestore: "Display", "Introduction", "Alignment", my problem is that these 3 titles are in a new order every time I refresh the website, I want them to be: "Introduction", "Alignment", "Display". In my case I have more titles but this is what's happening, I don't know how to align them how I want or even alphabetical if is possible.
Below is the code that I used to get the data from firestore:
useEffect(() => {
db.collection("users")
.doc(`${user.uid}`)
.get()
.then((doc) => {
const allData = { ...doc.data(), id: doc.id };
const intoArray = Object.entries(allData);
intoArray.sort(); // I used sort here because I had the same problem
// (every time a new order) with the
// data when I converted it to an array
const getCSSLessons = intoArray[0][1];
const cssData = Object.values(getCSSLessons);
setCss(cssData);
const getHTMLLessons = intoArray[1][1];
const htmlData = Object.values(getHTMLLessons);
setHtml(htmlData);
const getResLessons = intoArray[3][1];
const resData = Object.values(getResLessons);
setRes(resData);
})
.catch((error) => console.log(error));
}, [user]);
I tried using sort(), for a variable (htmlData) but its not working.
Also, I use map() to display them, if this helps you to answer to my question.
If you use sort without any argument, it will sort array elements alphabetically. It looks like your array elements are arrays, which will end with unexpected behaviors. Use sort argument to ensure it uses your own sorting rules. For example:
const intoArray = Object
.entries(allData)
// I don't know what should be the sorting algorithm
// As an example, I consider each element (`a` and `b`) to
// be arrays and compare both first element as a Number
.sort( (a, b) => a[0] - b[0])
Edit
A more secure way to find elements in an array is to use find:
const getCSSLessons = intoArray[0]
.find( element => element.name === 'CSS Lessons');
I was doing something unnecessary as you see in the first picture I had a main object css and in that object I had sub-objects like alignment and in the sub object I had the properties that I want to display, that sub object was unncessary, istead of sub objects with a pre defined name, I let the firebase to count the sub objects and add as a name a number and the order is the same as I wanted to be.
The code that I used to add data to firebase:
fire
.auth()
.createUserWithEmailAndPassword(email, password)
.then((cred) => {
return db
.collection("users")
.doc(cred.user.uid)
.set({
css: [
{
title: "Introduction",
path: "/css3/introduction",
},
{
title: "Priority",
path: "/css3/priority",
},
],
});

Is it possible to make ng-repeat delay a bit redrawing of array content

I'm using ng-repeat to (guess) put array content in table.
Content is drawn dynamically, and it works well, when I'm modifying single elements of an array. But when I reload a whole array, there is this moment, when array is reassigned with new value, and ng-repeat draws blank table (which is actually logically correct). Is there a way to delay redrawing of content that way, the ng-repeat ignores the moment when the array is empty? Like the content is switched to new content without the 'clear' time.
I'm assigning new elements to array this way:
items = newItems;
where items is the array ng-repeat uses and newItems is an array of items freshly downloaded from database. The newItems is complete, when the assignment occurres. I'm not doing items = []; before the assignemt.
I'm usign angular 1.3
EDIT:
the ng-repeat:
<tr ng-repeat="order in submittedOrders">
stuff
<\tr>
js:
`$scope.reloadView = function() {
$scope.submittedOrders = OrdersService.getOrdersByStatus(ORDER_STATUS.submitted);
};`
Can it be the that the table is cleared in the first place, before call to database(service takes data from database) and during the wait, the table is cleared?
You may have to make use of Observables and async pipe of Angular.
Here are few steps you can take:
Convert your newItems to a rxjs Subject.
newItems$ = new Subject();
Whenever you get new values for your array, emit them via subject.
this.newItems$.next(newItems);
Make the items an observable of newItems$, and filter out empty arrays.
items = this.newItems$.pipe(
filter((a:any[]) => {
return a.length != 0;
})
);
In your template, use async pipe to iterate over array.
*ngFor="item of items | async"
Below is relevant parts of code that can get you started.
import { Observable, of, from, Subject } from 'rxjs';
import { filter, mapTo } from 'rxjs/operators';
...
newItems$ = new Subject();
items = this.newItems$.pipe(
filter((a:any[]) => {
return a.length != 0;
})
);
...
// A test method - link it to (click) handler of any div/button in your template
// This method will emit a non-empty array first, then, after 1 second emit an empty
// array, and then, after 2 seconds it will emit a non-empty array again with updated
// values.
testMethod() {
this.newItems$.next([3,4,5]);
setTimeout((v) => {
console.log("Emptying the array - should not be displayed browser");
this.newItems$.next([]);
}, 1000);
setTimeout((v) => {
console.log("Updating the array - should be displayed in browser");
this.newItems$.next([3,4,4,5]);
}, 2000);
}

Resources