I just need to pass true for the button variable if the if condition is ok. Then i need to pass the test case if the button variable value is true. Can someone help me to fix this. This is what i have got so far.
cy.get('#checkSkipButton').then(checkSkipButton => {
if (checkSkipButton) {
cy.log("NOT CLICKABLE")
cy.then(button = true)
//cy.log(button)
//return button;
//cy.log(button)
//return button
}else{
cy.log("CLICKABLE")
button = False
//return this
}
} )
cy.log("value is"+button)
button.should(have,value=true)
}
The code is close to working, but false instead of False and return the button to let you chain the .should() test.
cy.get('#checkSkipButton').then(checkSkipButton => {
let button;
if (checkSkipButton) {
cy.log("NOT CLICKABLE")
button = true;
} else {
cy.log("CLICKABLE")
button = false;
}
return button // passes to should
}
.should('eq', true)
If you want to use button globally, you must wait for it's value to be set by using .then()
let button; // undefined now and also later in the test if not wrapped in .then()
cy.get('#checkSkipButton').then((checkSkipButton) => {
if (checkSkipButton) {
cy.log('NOT CLICKABLE')
button = true;
} else {
cy.log('CLICKABLE')
button = false;
}
})
cy.wrap(button).should('equal', true) // Error: expected undefined to equal true
// neither true nor false, but original value (undefined)
// Allow above cy.get() to process
cy.then(() => {
cy.log('Value is: ' + button);
cy.wrap(button).should('equal', true) // passes
})
You were very close, the above will work fine with some minor changes.
let button //Declare it globally so that it can be accessed outside if
cy.get('#checkSkipButton')
.then((checkSkipButton) => {
if (checkSkipButton) {
cy.log('NOT CLICKABLE')
button = true //instead of cy.then directly update the value of button
} else {
cy.log('CLICKABLE')
button = false
}
})
.then(() => {
cy.log('Value is: ' + button) //prints the button value
cy.wrap(button).should('equal', true) //Asserts the button value
})
I think this is the same logic
cy.get('#checkSkipButton')
.then(checkSkipButton => !!checkSkipButton) // convert truthy to true/false
.then(value => cy.log("value is" + value))
.should('eq', true)
Related
Brief logic is the next: after clicking on 'li' element, request is sent, and based on response value of 'contacts', it should select if it's greater than 0, once such element is find, i need to break each loop. But currently, despite I set value, which should break each loop on next iteration (returns false). count[] has been restored with old values, what's an issue?
cy.get('div[id=company_select]').then($el => {
const count = []
cy.wrap($el).click().find('li').each((element, index) => {
cy.intercept('GET', '**/company/view-json**').as('getCompanyProps')
cy.log(count.length)
if (count.length > 0) {
return false
} else {
cy.wrap(element).click().wait('#getCompanyProps').then((interception) => {
if (interception.response.body.contacts.length === 0) {
cy.wrap($el).find('button[vs__clear]').click()
} else {
count.push(1)
cy.log(count.length)
}
})
}
})
})
You can't early-exit with return false in this scenario, but you can use count to prevent inner execution after body.contacts.length > 0.
cy.intercept('GET', '**/company/view-json**').as('getCompanyProps') // this can be here
cy.get('div[id=company_select]').then($el => {
const count = []
cy.wrap(count).as('count') // make an alias value of the count variable
cy.wrap($el).click().find('li')
.each((element, index) => {
cy.get('#count').then(count => { // retrieve count asynchronously
if (count.length === 0) { // no result yet?
cy.wrap(element).click().wait('#getCompanyProps')
.then((interception) => {
if (interception.response.body.contacts.length === 0) {
cy.wrap($el).find('button[vs__clear]').click()
} else {
count.push(1)
console.log(count.length)
}
})
}
})
})
})
The reason for this behaviour is the mixture of asynchronous commands like .wait('#getCompanyProps') and synchronous code for checking the early exit.
If you use console.log() instead of cy.log() to debug the values, you'll see the logs before the early exit all run before the logs after count.push(1).
If I understand your question correctly, you wish to know why on the second pass of your cypress each loop cy.wrap($el).click().find('li').each((element, index) => { the cy.log(count.length) is equal to 0.
Even though further down inside another then loop cy.wrap(element).click().wait('#getCompanyProps').then((interception) => { you increase count by count.push(1) and right after cy.log(count.length) which returns 1.
The short answer is scope. If you change a variable within a cypress loop to return that variable you need to add something like this after .then( () =>{ cy.wrap(count)} My solution is below but I also changed the position of your const count = [] if you want to know why I suggest reading What is the difference between 'let' and 'const' ECMAScript 2015 (ES6)?
const count = []
cy.intercept('GET', '**/company/view-json**').as('getCompanyProps')
cy.get('div[id="company_select"]')
.then( ($el) => {
cy.wrap($el)
.click()
.find('li')
.each( ($el) => {
if (count.length === 0){
cy.wrap($el)
.click()
.wait('#getCompanyProps')
.then((interception) => {
if (interception.response.body.contacts.length === 0) {
cy.wrap($el)
.find('button[vs__clear]')
.click()
} else {
count.push(1)
cy.log(count.length)
}
})
}
})
.then( () =>{
cy.wrap(count).as('count')
})
})
cy.get('#count')
.then( (count) =>{
cy.log(count.length)
})
Below is the code which I am using.
I am working with Cypress + Cucumber + Typescript.
Scenario: I need to get a list of unique values using a for loop. Then I am passing this value to an API to verify some condition and if the condition is met I want to exit the loop.
To exit the loop I somewhere read a solution that if I use "return false" as first-line in if condition then loop will exit which seems to work fine.
The issue here is, when I try to set a flag from inside the for-if loop to the instance variable then the value read by if condition (for exiting the loop) is not picking the updated value of instance variable. And the loop continues to run.
Below is the code snippet:
class test {
static isVinavailable: boolean = false;
static setEligibleVehicleVinTest() {
cy.xpath(eligibleForSaleVehicleVin).then((esv) => {
const listingCount = Cypress.$(esv).length;
for (let i = 0; i < listingCount; i++) {
let text123 = esv.eq(i).text();
genericAction.getAuthenticationKey();
cy.fixture("authResp.json")
.then((authResp) => {
cy.request({
method: "GET",
url: vehicleCheckEligibility + text123,
headers: {
Authorization: authResp.access_token,
},
});
})
.then((response: any) => {
cy.wait(5000);
let responseDataelig = response.body;
if (
(responseDataelig.val1 =
"Y" &&
responseDataelig.val2 === "N" &&
responseDataelig.val3 === "N")
) {
this.isVinavailable = true;
}
});
if (this.isVinavailable) {
return false;
}
}
});
}
}
class test {
static isVinavailable = false;
static setEligibleVehicleVinTest(): Cypress.Chainable<boolean> {
return cy.xpath(eligibleForSaleVehicleVin).each(($el) => {
let text123 = $el.text();
cy.fixture('authResp.json')
.then((authResp) => {
return cy.request({
// your code block
});
})
.then((response: any) => {
// your code block
if (condition) {
this.isVinavailable = true;
return false;
};
});
}).then(() => {
return this.isVinavailable;
});
}
}
I'm working on a username search input that fires after a debounceTime(). I also filter out values. I want to trigger some side effects if values are filtered (such as setting an error message and stopping loaders).
I'm achieving this right now by using tap() and checking the same predicate that I later check in a filter() function. I feel this is bad/there is a more proper way to achieve this.
private setUserSearchObservable() {
this.userSearch = userSearch$.pipe(
tap(() => this.loading = true),
debounceTime(500),
this.filterValuesWithErrorMessages(),
......
);
}
private filterValuesWithErrorMessages() {
return pipe(
tap((val: string) => { if (this.usernamesMatch(val)) { this.errorMessage = 'You will be added to the frame automatically'; this.loading = false; }}),
tap((val: string) => { if (this.usernameInArray(val)) { this.errorMessage = 'User is already added'; this.loading = false; }}),
tap((val: string) => { if (val.length < 2) { this.errorMessage = ''; this.loading = false; }}),
filter((val: string) => (val.length >= 2 && !this.usernamesMatch(val) && !this.usernameInArray(val))),
);
}
As you can see, I explicitly check the exact same conditionals using tap() right before using them on filter(). Is there an operator/different pattern that will allow me to achieve this in a more concise way?
Refactored your code a little bit, there is no specific operator to deal with error checking, you can use switchMap and inner observable e.g of, never to control whether the result should go through.
private setUserSearchObservable() {
this.userSearch = userSearch$.pipe(
tap(() => this.loading = true),
debounceTime(500),
map((value) => this.filterValuesWithErrorMessages(value)),
swtichMap(msg => {
if (msg !== false) {
this.errorMessage = result
this.loading = false
return never()
}
return of(true)
})
);
}
private filterValuesWithErrorMessages(val) {
if (this.usernamesMatch(val)) return 'You will be added to the frame automatically'
if (this.usernameInArray(val)) return 'User is already added'
if (val.length < 2) return ''
return false
}
I tried reactive form valueChanges but valueChanges method doesn't return input field name which has changed.
I thought code like this. but I think this is not smart way. Because I have to compare every each input field. so I need more smart way.
// get init view data from local storage
this.localstorageService.getPlaceDetail().subscribe(data => {
this.initPlaceDetail = data;
// watch changed value
this.editPlaceForm.valueChanges.subscribe(chengedVal => {
if (chengedVal['ja_name'] !== this.initPlaceDetail.languages.ja.name.text) {
this.changedJA = true;
}
if (chengedVal['ja_romaji'] !== this.initPlaceDetail.languages.ja.name.romaji) {
this.changedJA = true;
}
// ...... I have to check all input fields??
});
});
I'm adding form controls from an array and something like this worked for me. Just reference the item you need instead of expecting the valueChanges observable to pass it to you.
myFields.forEach(item => {
const field = new FormControl("");
field.setValue(item.value);
field.valueChanges.subscribe(v => {
console.log(item.name + " is now " + v);
});
});
This is my way to get changed control in form.
I shared for whom concerned.
Method to get list control changed values
private getChangedProperties(form): any[] {
let changedProperties = [];
Object.keys(form.controls).forEach((name) => {
let currentControl = form.controls[name];
if (currentControl.dirty)
changedProperties.push({ name: name, value: currentControl.value });
});
return changedProperties;
}
If you only want to get latest changed control you can use
var changedProps = this.getChangedProperties(this.ngForm.form);
var latestChanged = changedProps.reduce((acc, item) => {
if (this.changedProps.find(c => c.name == item.name && c.value == item.value) == undefined) {
acc.push(item);
}
return acc;
}, []);
Instead of listening to whole form changes you can listen to value changes event for each form control as shown in below code:
this.myForm.get('ja_name').valueChanges.subscribe(val => {
this.formattedMessage = `My name is ${val}.`;
});
I am using the this great angular2-modal but can't figure out how to return a result value from my custom modal.
I instantiate it like this:
let dialog: Promise<ModalDialogInstance>;
let bindings = Injector.resolve([
provide(ICustomModal, { useValue: this.gewaehltesBild })
]);
var self = this;
dialog = this.modal.open(
<any>ImagecropperComponent,
bindings,
new ModalConfig("md", true, 27));
dialog.then((resultPromise) => {
return resultPromise.result.then((result) => {
this.lastModalResult = result;
this.mitarbeiter.avatarImg = this.gewaehltesBild;
$(self.elementRef.nativeElement).find('#bildSelector').val("");
}, () => this.lastModalResult = 'Rejected!');
});
I have tried to send my returnvalue with
this.dialog.close(this.croppedImage);
but result is always null. Is there a convention in angular2 how to return values from components, that is used by angular2-modal?
Thank you!
Works fine for me, I too am using custom dialog and here is how i catch the result
var dialog = this._modal.open(VideoPlayerComponent,
resolvedBindings,
new ModalConfig('lg', true, 27));
dialog
.then((d) => d.result)
.then((r) => { console.log(r); }, (error) => { console.log(r); });
When i call close on the instance
this._dialog.close("Hello");
It does print Hello