Cypress : XPATH - Do something if the element exists - xpath

I need to click on a button if the button exists. I am using the cypress xpath. Currently i am using below code but not working
cy.xpath('//button[text()="New"]')
.then(($button) => {
if ($button.is(':visible')) {
cy.log('visible')
cy.xpath('//button[text()="New"]').click();
} else {
//do something
}
})

In case if you want to click a button based on it existence, you can do like this:
cy.get('body').then(($body) => {
if ($body.find('button:contains("New")').length > 0) {
cy.log('visible')
cy.xpath('//button[text()="New"]').click()
} else {
//do something
}
})
In case if you want to check if the element is visible and then click on it.
cy.xpath('//button[text()="New"]').then(($button) => {
if ($button.is(':visible')) {
cy.log('visible')
cy.wrap($button).click()
} else {
//do something
}
})

XPath has a count() function that tells you if the element exists.
cy.xpath('count(//button[text()="New"])').then(count => { // check existence first
if (count) {
cy.xpath('//button[text()="New"]').then($button =>
if ($button.is(':visible')) {
cy.log('visible')
cy.wrap($button).click()
} else {
//do something
}
}
})
Splitting exists and visible checks like that will work if the DOM is stable.

Related

Angular 11 how to pass row item from template to observable

html:
<tr
*ngFor="let workflow of auditWorkflows"
class="border-bottom"
[rowClick]="workflow | auditWorkflowRouteNavigate"
[rowClickGate]="startAuditIfNotStarted$"
>
.ts
startAuditIfNotStarted$ = new Observable((subscriber) => {
if (this.auditInProgress) {
subscriber.next(true);
subscriber.complete();
} else {
***//Here i need to get the current row item i.e workflow.id to do some additional logic***
this.confirmDialog.confirm({
header: 'Begin audit',
message: 'Are you sure you would like to start the audit?',
acceptLabel: 'Yes',
rejectLabel: 'No',
accept: () => {
this.auditInstanceService.start(this.auditId).subscribe(() => {
this.auditInProgress = true;
subscriber.next(true);
subscriber.complete();
});
},
reject: () => {
subscriber.next(false);
subscriber.complete();
}
});
}
});
directive code block:
#Input('rowClick')
options: RouterNavigateParams;
#Input('rowClickGate')
gate$?: Observable<boolean>;
private applyGateThen(callback: () => void) {
if (this.gate$) {
this.gate$.pipe(take(1)).subscribe((allow) => {
if (allow) {
callback();
}
});
} else {
callback();
}
}
Now, in the existing code , i want to pass the 'workflow' item from *ngFor into the observable, so i can do some additional logic. If i used a method as below, the method is called so many times. Is there a better way to get hold of the row item?
[rowClickGate]="provideSub(workflow)"

returning stuff from custom commands cypress

I created the below function but im having great difficulties in getting stuff returned from the last if block (elArr[3]).
It works fine if i remove all the return statements and say put: cy.get(el).click() in the if blocks but i dont want to have that command in this function but performed in the test instead like this:
cy.traverseIFrame(['1', '2', '3'], 'myelement').click()
can someone help me out it is driving me crazy trying to get this working.
Cypress.Commands.add('traverseIFrame', (elArr, searchEl) => {
return cy.iframe(elArr[0]).within((res) => {
if (res.find(searchEl).length > 0) {
console.log('true1');
cy.get(searchEl).click(150, 220, {
force: true
});
}
return cy.iframe(elArr[1]).within((res) => {
if (res.find(searchEl).length > 0) {
console.log('true2');
cy.get(searchEl).click(150, 220, {
force: true
});
}
return cy.iframe(elArr[2]).within((res) => {
if (res.find(searchEl).length > 0) {
console.log('true3');
cy.get(searchEl).click(150, 220, {
force: true
});
}
return cy.iframe(elArr[3]).within((res) => {
if (res.find(searchEl).length > 0) {
console.log('true4');
return cy.get(searchEl);
}
});
});
});
});
});
It's because the .within() commands pays no attention to inner return, but gives back the previous subject
within#Yields
.within() yields the same subject it was given from the previous command.
Trying to return a different element the .within callback have no effect
Instead, an equivalent should be .then() & cy.wrap(...).find(...) combo,
Cypress.Commands.add('traverseIFrame', (elArr, searchEl) => {
return cy.iframe(elArr[0]).then(res => {
// this find sb ok since it's jquery
if (res.find(searchEl).length > 0) {
console.log('true1');
// cy.wrap().find() here equates to .within(() => cy.get()
cy.wrap(res).find(searchEl).click(150, 220, { force: true });
}
// this nested cy.iframe may be ok - depends on internals of this command
return cy.iframe(elArr[1]).then((res) => {
...
// inner-most return
return cy.wrap(res).find(searchEl)

If table contains something then do something

How can I code: If table contains some text then do something.
I tried it with contains but that throws me error if table does not contains.
if(cy.get(tableCode).contains('td', value)){
cy.get(tableCode).contains('td', value).click()
}else{
cy.reload()
}
Thanks for your time.
The proper way to us jQuery :contains() would be
cy.get(tableCode).then($table => {
const $cell = $table.find('td:contains(value)')
if ($cell.length) {
$cell.click()
} else {
cy.reload()
}
})
You can use the Jquery length method to check if the element is present in the table or not -
cy.get('tableCode').then(($ele) => {
if ($ele.find('td').contains('value').length > 0) {
//Element found
cy.wrap($ele).find('td').contains('value').click()
}
else {
//Element not found
cy.reload()
}
})

route.params not visible inside useFocusEffect()

With React Navigation 5.x, params are passing back to parent function. Here is the code in parent receiving 2 params index and type:
import { useFocusEffect } from "#react-navigation/native"
export default MyWork = ({navigation, route}) => {
console.log("route.params :", route.params); //<<==route.params : {"index": 0, "type": "forsale"}}
....
useFocusEffect(
useCallback(() => {
console.log("in navigation", route.params); //<<== route.params undefined
try {
if (route.params?.index && route.params?.type) {
updateCnt(route.params.type, route.params.index);
}
} catch(err) {
}
}, []));
However inside the useFocusEffect, route.params becomes undefined. What is wrong here?
It looks like you need to add the route dependency to useCallback, otherwise it uses the old value (in this case undefined) rather than the updated one.
useFocusEffect(
useCallback(() => {
console.log('in navigation', route.params);
try {
if (route.params?.index && route.params?.type) {
updateCnt(route.params.type, route.params.index);
}
} catch (err) {
}
}, [route]),
);
A similar question was answered here where you can find more details https://stackoverflow.com/a/64190936/13912074

Cypress - if - else condition doesn't work

I need to automate an if/else condition with Cypress, but it doesn't work in my script. If an if element is present (or visible) then click Yes otherwise proceed. But in my case, if the first condition is not present the test try to click Yes anyway.
it('Logout', () => {
const out = new logout();
const lged = new logged();
lged.logged().then($button => {
if ($button.is(':visible')){
lged.logged().click()
out.bar().click()
out.clickout()
}
else {
out.bar().click()
out.clickout()
}
})
})
in my pageObjects I have the class "logged":
class logged {
logged(){
return cy.contains('Yes', { timeout: 10000 })
}
}
export default logged

Resources