How to check many urls in one test? - javascript

I have a list of urls and need to check the same element on every of them.
But there are 2 conditions:
all must be done in 1 it()
test must not fail after the first wrong url, but must check all of them and show result only after list finishing
I tried to do it by loop and try-catch (because there is not soft asserting by default), but then the test always was passed, even when text from element was wrong (as I undestand it's because of asynchronicing).
let errorUrls = []
for (let url in data.PRODUCTS_PAGES) {
cy.visit(url)
cy.get('div.configurator-controls span').invoke('text')
.then(text => {
try {
expect(text).to.equal(data.PRODUCTS_PAGES[url])
} catch (e) {
errorUrls.push(e.message)
}
})
}
expect(errorUrls).to.be.empty
How can I do this?

If you don't want to fail, don't use the expect() in the loop.
Note, all URL's must be same-origin.
let errorUrls = []
for (let url in data.PRODUCTS_PAGES) {
cy.visit(data.PRODUCTS_PAGES[url])
cy.get('div.configurator-controls span').invoke('text')
.then(text => {
if (text !== data.PRODUCTS_PAGES[url]) {
errorUrls.push(e.message)
}
})
}
cy.then(() => {
cy.log(errorUrls)
expect(errorUrls).to.have.length(0)
})

You can do something like this:
let errorUrls = []
for (let url in data.PRODUCTS_PAGES) {
cy.visit(data.PRODUCTS_PAGES[url])
cy.get('div.configurator-controls span').then(($ele) => {
if ($ele.text() == data.PRODUCTS_PAGES[url]) {
expect($ele.text()).to.equal(data.PRODUCTS_PAGES[url])
} else {
errorUrls.push(data.PRODUCTS_PAGES[url])
}
})
}
cy.then(() => {
expect(errorUrls).to.be.empty
})

Related

React Child Component Is Not Rerendering When Props Are Updated

My parent component takes input from a form and the state changes when the value goes out of focus via onBlur.
useEffect(() => {
let duplicate = false;
const findHierarchy = () => {
duplicationSearchParam
.filter(
(object, index) =>
index ===
duplicationSearchParam.findIndex(
(obj) => JSON.stringify(obj.name) === JSON.stringify(object.name)
)
)
.map((element) => {
DuplicateChecker(element.name).then((data) => {
if (data.status > 200) {
element.hierarchy = [];
} else {
element.hierarchy = data;
}
});
if (duplicate) {
} else {
duplicate = element?.hierarchy?.length !== 0;
}
});
return duplicate;
};
let dupe = findHierarchy();
if (dupe) {
setConfirmationProps({
retrievedData: formData,
duplicate: true,
responseHierarchy: [...duplicationSearchParam],
});
} else {
setConfirmationProps({
retrievedData: formData,
duplicate: false,
responseHierarchy: [],
});
}
}, [duplicationSearchParam]);
I have a child component also uses a useeffect hook to check for any state changes of the confirmationProps prop.
the issue is that the event gets triggered onblur, and if the user clicks on the next button. this function gets processes
const next = (data) => {
if (inProgress === true) {
return;
}
inProgress = true;
let countryLabels = [];
formData.addresses?.map((address) => {
fetch(`/api/ref/country/${address?.country}`)
.then((data) => {
countryLabels.push(data.label);
return countryLabels;
})
.then((countries) => {
let clean = MapCleanse(data, countries);
fetch("/api/v1/organization/cleanse", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(clean),
})
.then((data) => {
if (data.status > 200) {
console.log(data.message);
message.error(getErrorCode(data.message.toString()));
} else {
Promise.all([confirmationProps, duplicationSearchParam]).then(
(values) => {
console.log(values);
console.log(data);
setCleansed(data);
**setCurrent(current + 1);**
inProgress = false;
}
);
}
})
.catch((err) => {
console.log(err);
inProgress = false;
});
})
.catch((err) => {
console.log(err);
inProgress = false;
});
});
console.log(confirmationProps);
};
The important part in the above code snippet is the setCurrent(current + 1) as this is what directs our code to render the child component
in the child component, i have a use effect hook that is watching [props.duplicateData.responseHierarchy]
I do output the values of props.duplicateData.responsehierarchy to the console to see if the updated information gets passed to the child component and it does. the values are present.
I have a conditional render statement that looks like this
{cleansedTree?.length > 0 || treeDuplicate ? (...)}
so although the data is present and is processed and massaged in the child component. it still will not re render or display properly. unless the user goes back to the previous screen and proceeds to the next screen again... which forces a re-render of the child component.
I have boiled it down and am assuming that the conditional rendering of the HTML is to blame. Or maybe when the promise resolves and the state gets set for the confirmation props that the data somehow gets lost or the useefect doesn't pick it up.
I have tried the useefect dependency array to contain the props object itself and other properties that arent directly related
UPDATE: this is a code snippet of the processing that gets done in the childs useeffect
useEffect(() => {
console.log(props.duplicate);
console.log(props.duplicateData);
console.log(props.confirmationProps);
let newArray = props.duplicateData.filter((value) => value);
let duplicateCheck = newArray.map((checker) =>
checker?.hierarchy?.find((Qstring) =>
Qstring?.highlightedId?.includes(UUIDToString(props?.rawEdit?.id))
)
);
duplicateCheck = duplicateCheck.filter((value) => value);
console.log(newArray, "new array");
console.log(duplicateCheck, "duplicate check");
if (newArray?.length > 0 && duplicateCheck?.length === 0) {
let list = [];
newArray.map((dupeData) => {
if (dupeData !== []) {
let clean = dupeData.hierarchy?.filter(
(hierarchy) => !hierarchy.queryString
);
let queryParam = dupeData.hierarchy?.filter(
(hierarchy) => hierarchy.queryString
);
setSelectedKeys([queryParam?.[0]?.highlightedId]);
let treeNode = {};
if (clean?.length > 0) {
console.log("clean", clean);
Object.keys(clean).map(function (key) {
treeNode = buildDuplicate(clean[key]);
list.push(treeNode);
return list;
});
setCleansedTree([...list]);
setTreeDuplicate(true);
} else {
setTreeDuplicate(false);
}
}
});
}
}, [props.duplicateData.responseHierarchy]);
This is a decently complex bit of code to noodle through, but you did say that **setCurrent(current + 1);** is quite important. This pattern isn't effectively handling state the way you think it is...
setCurrent(prevCurrent => prevCurrent + 1)
if you did this
(count === 3)
setCount(count + 1) 4
setCount(count + 1) 4
setCount(count + 1) 4
You'd think you'd be manipulating count 3 times, but you wouldn't.
Not saying this is your answer, but this is a quick test to see if anything changes.
The issue with this problem was that the state was getting set before the promise was resolved. to solve this issue I added a promise.all function inside of my map and then proceeded to set the state.
What was confusing me was that in the console it was displaying the data as it should. but in fact, as I learned, the console isn't as reliable as you think. if someone runs into a similar issue make sure to console the object by getting the keys. this will return the true state of the object, and solve a lot of headache

Change value of variable and check whether the value have changed

I want to check whether the text element changes on x seconds and apply the for loop and conditional structure to verify if the change is applied. If the text is still not changed it will refresh the page and check again
Cypress.Commands.add('checkApprovedStatus', (targetData) =>{
cy.get('div[class^=ui-table-scrollable-body]').contains('tr', targetData).first().parent().within(function(){
cy.get('td').eq(10).children('span[class^=customer-badge]').then(($status) =>
{
//let currStatus = $status.text()
//cy.log(currStatus)
for(let count = 0; count <= 5; count++)
{
let currStatus = $status.text()
cy.log(currStatus)
if (currStatus === 'approved')
{
//if (currStatus.contains('Approved', {matchCase:false}))
//{
cy.log("End to end testing completed. All checks have passed!!")
break
//}
}
else
{
cy.reload()
cy.wait(5000)
$status.trigger('change')
}
}
})
})
})
For loops generally crash and burn in Cypress, but you can use a recursive function to simulate the loop.
When the loop (reload/trigger change) fails to find the status, throw an error to fail the test, or just return.
const checkApprovedStatus = (targetData, attempt = 0) => {
if (attempt === 5) {
// used up all attempts, can either fail the test
throw 'Was never approved'
// or just return without failing
return
}
cy.get('div[class^=ui-table-scrollable-body]')
.contains('tr', targetData).first().parent()
.within(() => {
cy.get('td').eq(10).children('span[class^=customer-badge]')
.then($status => {
if ($status.text() === 'approved') {
cy.log("All checks have passed!!")
} else {
cy.reload()
cy.wait(5000)
$status.trigger('change')
checkApprovedStatus(targetData, ++attempt)
}
})
})
})

Dealing with multiple asynchronous function calls in a for loop

I am trying to do multiple asynchronous actions: Axios requests inside of a for loop. I want to do something after everything is resolved but there is so much going on I don't know how to do it.
I thought of making my sourcer function async and awaiting it on each iteration (and wrapping the for loop in an async function), but one problem is that sourcer doesn't actually return anything. I don't know how to return from sourcer from inside an Axios "finally" clause. Another problem is that I don't want to await each sourcer call because it would be a hit on performance.
Promise.all sounds like the right direction to take but I don't know how to implement it with this for loop.
Here is the relevant part of my code (ts is a large array of objects):
.then(ts => {
// Create an association object that determines each media item's source
const sourcer = media => { // Input is either [image filename, image url] or [image filename, image url, video filename, video url]
// Test to see if the original URL works
let validURL = true
axios.get(media[1])
.then(resp => {
if (resp.status.toString()[0] !== '2') validURL = false
})
.catch(resp => {
if (resp.status.toString()[0] !== '2') validURL = false
})
.finally(() => {
let newSources = JSON.parse(JSON.stringify(this.state.sources))
let newModals = JSON.parse(JSON.stringify(this.state.modals))
if (validURL) newSources[media[0]] = media[1]
// If the original URL does not work, pull media item from server
else newSources[media[0]] = `http://serveripaddress/get_media?filename=${media[0]}`
newModals[media[0]] = false
this.setState({ sources: newSources, modals: newModals })
})
if (media.length > 2) { // If the media item is a video, do the same checks
let validVURL = true
axios.get(media[3])
.then(resp => {
if (resp.status.toString()[0] !== '2') validVURL = false
})
.catch(resp => {
if (resp.status.toString()[0] !== '2') validVURL = false
})
.finally(() => {
let newSources2 = JSON.parse(JSON.stringify(this.state.sources))
let newThumbnails = JSON.parse(JSON.stringify(this.state.thumbnails))
if (validVURL) newSources2[media[2]] = media[3]
else newSources2[media[2]] = `http://serveripaddress/get_media?filename=${media[2]}`
newThumbnails[media[0]] = media[2] // Add an association for the video and its thumbnail
this.setState({ sources: newSources2, thumbnails: newThumbnails })
})
}
}
for (let t of ts) {
if (t.media) for (let m of t.media) sourcer(m)
if (t.preview_media) sourcer(t.preview_media)
if (t.video) sourcer(t.video)
}
})
I want to do something after ts has been iterated through and all sourcer calls are completed.
I'm not fishing for someone to write my code for me but a nudge in the right direction would be greatly appreciated.
axios.get will return a Promise, so simply build up your array of Promises and use Promise.all
So, in your case, instead of executing the http call and waiting on the response, just add it to your array.
Something like this will work. I removed your code that was handling the response of each individual get request. You can merge that code (or just copy/paste) into where I put the placeholder below:
.then(ts => {
// Create an association object that determines each media item's source
const sourcer = media => { // Input is either [image filename, image url] or [image filename, image url, video filename, video url]
// Test to see if the original URL works
let validURL = true;
const promises = [];
promises.push(axios.get(media[1]));
if (media.length > 2) { // If the media item is a video, do the same checks
let validVURL = true;
promises.push(axios.get(media[3]));
}
}
for (let t of ts) {
if (t.media)
for (let m of t.media) sourcer(m)
if (t.preview_media) sourcer(t.preview_media)
if (t.video) sourcer(t.video)
}
// Execute the Promises
Promise.all(promises).then( results => {
const media1 = results[0];
const media3 = results[1];
// TODO: Run your code for media1/media3 results
})
})

how to compare objects values in 2 identical lists in javascript

i have two collections in mongo db that hold reports, in report there is list matches, so what i want is to run on production reports and for ech one check in staging reports and check that if the matches are the same length if the personId and addressId are also the same...
is there a a good way to do this?
i came up with something like this:
db.production_reports.find({}).forEach((prodRep)=> {
db.reports.find({_id: prodRep._id}).forEach((stagingRep)=> {
if (prodRep.matches.length == stagingRep.matches.length) {
prodRep.matches.forEach((match)=> {
var res = stagingRep.matches.filter(element => element.personId == match.personId && element.addressId == match.addressId);
if (res) {
print("yay")
} else {
print("nay")
}
});
}
});
});
i want for each report the script to tell me "yes, all matches equal", or print the reportId that have non equal matches
thanks
I would draft something like this :
return new Promise((resolve) => {
const data = {
// contains an array of _id of missing production_reports
missing: [],
different: [],
};
// Look at each entry in production_reports
db.production_reports.find({})
.cursor()
.eachAsync(async (x) => {
// get the similar data on reports
const copy = await db.reports.find({
_id: x._id,
});
// If the data doesn't exists into reports
if (!copy || !copy.length) {
data.missing.push(x._id);
return;
}
// If it exists, compare the inner values
// if the size isn't the same, it's obviously different
if (x.matches.length !== copy.length) {
data.different.push(x._id);
return;
}
// Check every element of match one by one
if (x.matches.some(y => !copy.matches.some(z => z.personId === y.personId))) {
data.different.push(x._id);
}
}, {
// How many items do we look at same time
parallel: 250,
}, () => {
// When we are done processing all items
resolve(data);
});
});
NOTE : It won't give you missing documents that exists in reports but not in production_reports

Else statement still running when if statement is true

I have search functionality that allows you to search for cryptocurrencies and I'm trying to have it where if the param/coin that is searched doesn't match with the API's title of the coin or symbol, an alert box would pop up telling the user to try again.
The problem I'm having is that if the if statement is true and there's a match, the else statement/alert box pops up regardless. Here's my code within my axios request:
cryPrice(param){
axios.get(`https://api.coinmarketcap.com/v1/ticker/?limit=0`)
.then(res => {
const cryptos = res.data;
const price = []
for(let title in cryptos){
const cryptoTitle = cryptos[title].name.toUpperCase();
const cryptoSymbol = cryptos[title].symbol.toUpperCase();
if(cryptoTitle === param || cryptoSymbol === param){
price.push(cryptos[title].price_usd);
}else{
alert("Please try again");
break;
}
}
this.setState({
priceResults: price
})
})
}
Your code loops through every single item in the array, as soon as a non-matching item is encountered it alerts and breaks the loop
What you probably want is more like
cryPrice(param){
axios.get(`https://api.coinmarketcap.com/v1/ticker/?limit=0`)
.then(res => {
const priceResults = res.data
.filter(item => [item.name.toUpperCase(), item.symbol.toUpperCase()].includes(param))
.map(item => item.price_usd);
if (priceResults.length) {
this.setState({priceResults});
} else {
alert("Please try again");
}
})
}
You find a match on some of the elements but alert about every other, all of those that do not match param. You should probably only alert after the loop execution has stopped and iff there were no currencies matched.

Categories