Change value of variable and check whether the value have changed - javascript

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)
}
})
})
})

Related

Exit from while loop with if/else in Cypress

I am writing a test case which requires me to reload the page N number of times, and compare its title for a value, if that value does not exists then break the while loop without rising error.
Below is a demo program, similar to the one that I am looking to implement.
/// <reference types='cypress' />
it("Visiting Google",function(){
var webUrl = 'https://html5test.com/'
cy.visit(webUrl)
var loop_iter = 0
while(loop_iter < 5)
{
cy.get('body:nth-child(2) div:nth-child(2) div.header h1:nth-child(1) > em:nth-child(2)').then(($text_data) =>{
if($text_data.text().contains('HTML123'))
{
cy.log(" --> ITERATION = ",loop_iter)
cy.reload()
}
else
{
cy.log("Unknown website")
loop_iter = 10
}
})
loop_iter += 1
}
})
I need a way to break from the while loop when the else part is executed, without rising any error.
The if condition when false returns AssertionError, in such case it should execute else part.
cy.title() is asynchronous (proof is, you need to use .then()), so, the entire while loop ends even before the first .then() triggers. That's how asynchronism works.
You need another approach :
it("Visiting Google", async function () {
var webUrl = 'https://html5test.com/'
cy.visit(webUrl)
for (let i = 0; i < 5; i++) { // You can't await in a 'while' loop
const $text_data = await cy.title();
if ($text_data.includes('HTML')) {
cy.log(" --> ITERATION = ", i)
cy.reload()
}
else {
cy.log("Unknown website")
break;
}
}
})
Please take a look at the sample recipe Page reloads. It uses recursion as suggested in comments.
This is your code adapted to the pattern,
it('reload until "HTML" disappears', () => {
// our utility function
const checkAndReload = (recurse_level = 0) => {
cy.title().then(title => {
if (title.includes('HTML') && recurse_level < 5) {
cy.log(" --> ITERATION = ", recurse_level)
cy.wait(500, { log: false }) // just breathe here
cy.reload() // reload
checkAndReload(recurse_level + 1) // check again
} else {
cy.log("Unknown website")
}
})
}
cy.visit('https://html5test.com/') // start the test by visiting the page
checkAndReload() // and kicking off the first check
})

botpress - increment vlaue

I am trying to get a custom action running to simply incrementing a value on passing a specific node on the flow.
My custom actions looks like this:
function action(bp: typeof sdk, event: sdk.IO.IncomingEvent, args: any, { user, temp, session } = event.state) {
/** Your code starts below */
let i = undefined
const p = new Promise((resolve, reject) => {
if (i === undefined) {
resolve((i = 0))
} else if (i >= 0) {
resolve(i + 1)
} else {
reject('i cannot be < 0')
}
})
const runCount = async () => {
try {
const counter = await p
i = counter
return (session.count = counter)
} catch (err) {
console.log(err)
}
}
return runCount()
/** Your code ends here */
}
When I runCount() variable i will be set to 0. But then, after in rerun runCount() it does not increment further.
What do I need to do to save the variable so it increments on every runCount() call.
Greetings
Lorenz
I just managed to solve the problem.
I had to declare i = session.count at the beginning.
Now it gets the value out of the session state and increments the state on every call.
Maybe someone gets some help out of this.
Lorenz

How can I run recursive function in cypress or find length with async await

I am running tests using Cypress.
I have an array of Litecoin addresses. I am trying to set first in the input. Then submit the form.
If the address is duplicate then a notification is displayed and submit button will be not visible. The same I want to set for the second element and so on till end of the array.
I tried recursive function:
function runTillElementFound (totalCount, currentCount, litecoin_addresses)
{
var self = this;
if (currentCount < totalCount) {
return cy.get('body').then(($body) =>
{
if ($body.find(dash_page.save_wallet_circle_btn)) {
//if there is save button then set address and submit form
cy.log('taken address: ' + litecoin_addresses[ currentCount ]);
dashact.fill_wallet(litecoin_addresses[ currentCount ]);
cy.log('address is filled');
dashact.submit_wallet(true, 0);
self.runTillElementFound(totalCount, currentCount++);
}
});
} else {
return false; //if element not present after Max count reached.
}
I try to call it:
it('Set wallet', () =>
{
cy.log('this is array length: ' + litecoin_addresses);
runTillElementFound(20, 0, litecoin_addresses);
/* comact.submit_form(true, 1);
let ltc_address = promisify(dashact.get_wallet_value());
cy.log('this is address: ' + ltc_address);
//close popup and check that it is closed:
popact.submit_payment(); */
});
However I receive undefined:
I have also tried non recursive function:
for (var i = 0; i < litecoin_addresses.length; i++) {
cy.log('taken address: ' + litecoin_addresses[ i ])
if (litecoin_addresses[ i ] == wallet_before_edit || litecoin_addresses[ i ].length == 0 || litecoin_addresses[ i ].startsWith('ltc')) {
continue;
}
else {
cy.log('this is curent i: ' + i);
dashact.fill_wallet(litecoin_addresses[ i ]);
dashact.submit_wallet(true, null);
cy.get('body').then(($body) =>
{
// synchronously query from body
// to find which element was created
if ($body.find(com_page.not_message).length) {
// error was found, do something else here
cy.log('error was found');
}
else {
cy.log('error not found');
// input was not found, do something else here
i = litecoin_addresses.length;
cy.log('current i value: ' + i);
}
})
}
However it for sure, does not work, as i inside promise has one valued but in the loop it still remains the same.
If you use a specific array in your test code, you can easily get the length of the array by using the .lenght and access its elements by using the for loop.

Angular2/Rxjs nested maps with conditions in guard

I'd stuck with Rxjs operators.
This is a part of Angular's guard canActivate
const ifNoPatientCondition$ = this.dataService.getList().map(pl => {
console.log('im here'); // <<< this message not showing
const found = findOnlyAvailablePatients(pl);
if (found[0] === 1) {
this.stateService.patient.setCurrent(found[1]);
this.dataService.getPatientData(pid);
// return Observable.of(true);
return true;
} else {
if (found[0] === 0) {
this.stateService.app.message.send('Wrong patient status');
} else if (found[0] === -1) {
this.stateService.app.message.send('Wrong patient ID');
}
this.subscribes.forEach(subscribe => subscribe.unsubscribe());
this.stateService.navigate('/patients');
// return Observable.of(false);
// return false;
}
});
const warnOkCondition$ = this.stateService.patient.getCurrent().pipe(mergeMap(pat => {
if (!pat || pat.patient_id !== pid) { // <<< i'm interested with this condition
console.log('there is no patient!', pat); // <<< i see this message
return ifNoPatientCondition$; // <<< but cannot reach this line
} else {
if (pat.status === 'TREATMENT_COMPLETE') {
return Observable.of(false);
}
return Observable.of(true);
}
}));
return warningDialog().pipe(concatMap(warningResult => {
if (!warningResult) { // <<< if clicked No
this.stateService.navigate('/patients');
return Observable.of(false);
} else { // <<< 'Yes'
console.log('you are the best');
return warnOkCondition$;
}
}));
warningDialog() shows a dialog and returns observable of result.
If i clicked No, code works right: guard returns false and router navigate to /patients.
else if i clicked Yes, warnOkCondition$ works partially right (i'm interesting with first condition (with console.log)): i see message in console, but cannot reach next line - ifNoPatientCondition$ code.
Thanks!
Please use Types if you are working with Typescript. It is not clear what is an array and what is an Observable. Since warnOkCondition$ returns Observable.of(true/false) on some conditions, I assume this.dataService.getList() returns an Observable as well, and not a list, even though pl has no $-suffix at the end. In this case you need to subscribe to ifNoPatientCondition$ if you want it to be executed.
You might want to use switchMap or mergeMap here. https://netbasal.com/understanding-mergemap-and-switchmap-in-rxjs-13cf9c57c885

How to call async function to use return on global scope

I'm currently struggling with a function call, when I call the function from an if statement it does work but when I call it from outside it doesn't, my if statement only checks which button was pressed but I'm trying to remove the function from the button and just call it as soon as my app starts.
We will look at fetchJokes() inside jokeContainer.addEventListener('click', event => {
This is my current code:
const jokeContainer = document.querySelector('.joke-container');
const jokesArray = JSON.parse(localStorage.getItem("jokesData"));
// Fetch joke count from API endpoint
async function sizeJokesArray() {
let url = 'https://api.icndb.com/jokes/count';
let data = await (await fetch(url)).json();
data = data.value;
return data;
}
// use API endpoint to fetch the jokes and store it in an array
async function fetchJokes() {
let url = `https://api.icndb.com/jokes/random/${length}`;
let jokesData = [];
let data = await (await fetch(url)).json();
data = data.value;
for (jokePosition in data) {
jokesData.push(data[jokePosition].joke);
}
return localStorage.setItem("jokesData", JSON.stringify(jokesData));;
}
const jokeDispenser = (function() {
let counter = 0; //start counter at position 0 of jokes array
function _change(position) {
counter += position;
}
return {
nextJoke: function() {
_change(1);
counter %= jokesArray.length; // start from 0 if we get to the end of the array
return jokesArray[counter];
},
prevJoke: function() {
if (counter === 0) {
counter = jokesArray.length; // place our counter at the end of the array
}
_change(-1);
return jokesArray[counter];
}
};
})();
// pass selected joke to print on html element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Fetch') {
fetchJokes(length);
} else if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
And I'm trying to do something like this:
// pass selected joke to print on HTML element
function printJoke(joke) {
document.querySelector('.joke-text p').textContent = joke;
}
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
jokeContainer.addEventListener('click', event => {
if (event.target.value === 'Next') {
printJoke(jokeDispenser.prevJoke(jokesArray));
} else if (event.target.value === 'Prev') {
printJoke(jokeDispenser.nextJoke(jokesArray));
}
});
By the way, I'm aware that currently, you can't actually iterate through the array elements using prev and next button without refreshing the page but I guess that will be another question.
Couldn't think of a better title.(edits welcomed)
Async functions are, as the name implies, asynchronous. In
sizeJokesArray().then(size => (length = size)); // Size of array in response
fetchJokes(length);
you are calling fetchJokes before length = size is executed because, as you may have guessed, sizeJokesArray is asynchronous.
But since you are already using promises the fix is straightforward:
sizeJokesArray().then(fetchJokes);
If you have not fully understood yet how promises work, maybe https://developers.google.com/web/fundamentals/getting-started/primers/promises helps.

Categories