I currently have the following code in one of my test specs for Protractor:
.then(function() {
return button.click();
})
.then(function() {
return element(otherButton).isDisplayed();
})
.then(function(otherButtonIsPresent) {
if(otherButtonIsPresent) {
return browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime())
.then(function() {
element(otherButton).click();
return element(continueButton).isPresent();
})
}
})
When I use Chrome to debug using the --debug-brk and --inspect flags, I am able to pass these checks and resume as normal. When I run the same test without the flags, the test fails and stalls during looking for otherButton before trying to click on it.
I'm wondering if this is because during debugging, I set breakpoints and wait for the buttons to show up on the screen before attempting to click on them.
I need to make sure that this element is visible on the page before trying to click it and was wondering if there were another way if accomplishing this?
Thanks
I'm using Answer as I can't comment yet.
You're basically mention it yourself: after you clicked a button you just want to wait until a next button is clickable.
Therefore your .then()-functions should start from the button it depends on. To me it seems, the three lined-up .then()-functions depend on the same condition, so after you .click() the first button, the second .then() gets immediately executed, not waiting the previous .click() to finish.
Therefore putting the .then() directly behind the relevant .click() and inside the preceding .then()-function, this should work:
.then(function() {
element(button).click().then(function(){
element(otherButton).click().then(function(){
return element(continueButton).isPresent();
});
});
});
Or if you go with ExpectedConitions, you shouldn't need .then()-functions. Because Protractor should manage the ControlFlow, allowing you to write it without chained .then()-functions:
.then(function() {
browser.wait(EC.elementToBeClickable(element(button)), getWaitTime());
element(button).click();
browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime());
element(otherButton).click();
browser.wait(EC.elementToBeClickable(element(continueButton)), getWaitTime());
return element(continueButton).isPresent();
});
This nice post elaborates a bit on asynchronous writing, but thanks to Protractor synchronous execution.
As alternative an example combining my both inputs, kind of double-securing the test:
.then(function() {
browser.wait(EC.elementToBeClickable(element(button)), getWaitTime());
element(button).click().then(function(){
browser.wait(EC.elementToBeClickable(element(otherButton)), getWaitTime());
element(otherButton).click().then(function(){
browser.wait(EC.elementToBeClickable(element(continueButton)), getWaitTime());
return element(continueButton).isPresent();
});
});
});
Related
so in ionic 3 there was registerBackButton() but in ionic 4 this option is no longer there and has been sitting on the shelf for quite some time now.
I have read the post here that tries to solve the solution I am looking for, however, the back button still performs as it wants to.
this SO answer shows another way but it is the same idea of intercepting and navigating, however, I am just, for now, trying to dismiss the top modal in the stack.
scenario: users open a search modal(modal1) which then they click on a users profile modal(modal2). The person wants to go back to the search modal(modal1) but instead of clicking the nice button that allows them to do that, they use the hardware back button.
result: all modals(modal1 and modal2) are closed.
desired effect: using the hardware back button will allow for custom navigation based on logic in place.
attempted code:
this.platform.backButton.subscribeWithPriority(0, (): void => {
this.modalCtrl.getTop().then(
async (value: HTMLIonModalElement): Promise<void> => {
if (!!value) {
await this.modalCtrl.dismiss();
} else {
this.navCtrl.navigateRoot('/home');
}
},
);
});
also have tried :
// registering back, if there is a view on top, close it, don't go to home.
this.platform.backButton.subscribeWithPriority(0, async (): Promise<void>=> {
try {
console.log('try');
const element = await this.modalCtrl.getTop();
if (element) {
console.log('in true');
await element.dismiss();
}
} catch (error) {
console.log('error closing modal', error);
}
});
note when pressing the back button I never see ANY of the console logs... maybe things have changed a lot more? since the previous Stack overflow questions.
UPDATE:
If you are having this same issue then know you are not alone!
This, and many others are well known, see here for a list they are tracking the issues. Nothing else to do... but wait... I guess...
I will update this when there is a change
This is one of many (imho rather incomplete) examples in the docs:
var button = document.querySelector('#submit-button');
braintree.dropin.create({
authorization: 'CLIENT_AUTHORIZATION',
container: '#dropin-container'
}, function (createErr, instance) {
button.addEventListener('click', function () {
instance.requestPaymentMethod(function (requestPaymentMethodErr, payload) {
// Submit payload.nonce to your server
});
});
});
It's all nice and easy but I don't see how I can change the state of button according to the state of "is the user done with adding a payment method?".
Is this even possible? It seems that the click on the button actually performs the fetching of the nonce (which comes as payload.nonce). However, how can I disable button until the user has finished his conversation with Braintree/PayPal?
And the answer is look in the docs (no not those docs) - those docs.
I still don't know how I found that link.
The dropin instance has a on() function where you can register a callback for certain events (just do it - look at the docs already):
instance.on('paymentMethodRequestable', function(event) {
thiz._logger.info('Payment method is now requestable');
setTimeout(() => thiz.paymentMethodAvailable = true, 400);
});
I am trying to wait for spinner to disappear and then for my steps to execute but nothing is working for me.
browser.wait(function () {
return this.spinner.isDisplayed().then(function (result) {
return !result;});}, 20000);
and i even tried with
browser.wait(function () {
return !browser.isElementPresent(this.spinner);}, 20000);
even with below method
browser.sleep(1000);
this.spinner.isPresent().then(function (result) {
if (result === true) {
var EC = protractor.ExpectedConditions;
browser.wait(EC.invisibilityOf(this.spinner), 10000);}});
then only thing that works is
browse.sleep(10000);
i don't want to use sleep in my code. can anyone help me with how to wait for complete http request to complete and then process with testing
you should consider using Expected Conditions since they return true/false based on current conditions
http://www.protractortest.org/#/api?view=ProtractorExpectedConditions.prototype.invisibilityOf
so your test case would become:
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
...continue test, spinner gone
});
UPDATE
in order to use done, you would generally pass this cb into your it() function. This means your test could look like
describe("example describe",function(){
it("should be an example only", function(done){
request.get("www.google.com",function(res){
//done with async request, now call done
done();
})
})
});
Since your entire code isn't posted up here, you should have something similar to:
it("should wait for spinner to go bye-bye",function(done){
browser.wait(EC.invisibilityOf(this.spinner),20000).then(function(){
done()
});
});
TL:DR; I have an list. You can: Add, Remove, Edit and Search/Filter items.
I want to run my tests only if the first test it('shall delete a new item', ..) was successful.
Is there a way I can do this?
I am looking for a better way to do this, but this is a hacky way I would do it.
Use afterEach to set a conditional
Return from test if that conditional is false;
var firstPassed = true;
it ('first test', function() {
....
});
it('second test', function(){
if (!firstPassed) return;
....
});
afterEach(function() {
if(this.results_.description === 'first test'){
if(this.results_.failedCount !== 0){
firstPassed = false;
}
}
}
You can tell protractor to "failfast". That is it should stop running subsequent tests as soon as one test fails. Not quite what you're asking for but technically accomplishes what you want in this case.
This is really a (missing) feature of the test runner (Jasmine, Jasmine2, etc), so the specific solution might be different. If you're using the default, Jasmine, see How to stop protractor from running further testcases on failure?
Assume button A in an HTML5 webapp built with jQuery Mobile.
If someone taps button A, we call foo(). Foo() should get called once even if the user double taps button A.
We tried using event.preventDefault(), but that didn't stop the second tap from invoking foo(). event.stopImmediatePropagation() might work, but it also stops other methods further up the stack and may not lead to clean code maintenance.
Other suggestions? Maintaining a tracking variable seems like an awfully ugly solution and is undesirable.
You can set a flag and check if it's OK to run the foo() function or unbind the event for the time you don't want the user to be able to use it and then re-bind the event handler after a delay (just a couple options).
Here's what I would do. I would use a timeout to exclude the subsequent events:
$(document).delegate('#my-page-id', 'pageinit', function () {
//setup a flag to determine if it's OK to run the event handler
var okFlag = true;
//bind event handler to the element in question for the `click` event
$('#my-button-id').bind('click', function () {
//check to see if the flag is set to `true`, do nothing if it's not
if (okFlag) {
//set the flag to `false` so the event handler will be disabled until the timeout resolves
okFlag = false;
//set a timeout to set the flag back to `true` which enables the event handler once again
//you can change the delay for the timeout to whatever you may need, note that units are in milliseconds
setTimeout(function () {
okFlag = true;
}, 300);
//and now, finally, run your original event handler
foo();
}
});
});
I've created a sample here http://jsfiddle.net/kiliman/kH924/
If you're using <a data-role="button"> type buttons, there is no 'disabled' status, but you can add the appropriate class to give it the disabled look.
In your event handler, check to see if the button has the ui-disabled class, and if so, you can return right away. If it doesn't, add the ui-disabled class, then call foo()
If you want to re-enable the button, simply remove the class.
$(function() {
$('#page').bind('pageinit', function(e, data) {
// initialize page
$('#dofoo').click(function() {
var $btn = $(this),
isDisabled = $btn.hasClass('ui-disabled');
if (isDisabled) {
e.preventDefault();
return;
}
$btn.addClass('ui-disabled');
foo();
});
});
function foo() {
alert('I did foo');
}
});