AngularJS chained promises and finally callback - angularjs

So I have 2 promise functions. When there is an error for the first function I want it to display an error message. When either complete or fail I would like them to execute a finally catch all function but for some reason it isn't working.
my code looks like this:
// If our garment has a logo
shared.logoExists(garment, model).then(function () {
// Save our panel
return shared.save(model);
// If there was an error
}, function () {
// Display an error message
toastr.warning(localization.resource.logoPlacementError.message);
// Always close the library
}).finally(function () {
// Reset our attachments
self.resetAttachment();
// Hide our library
self.closeLibrary();
});
So basically what I am trying to achieve is if the first function fails, it will display and error.
When the second function fails, it won't do anything.
But if either succeed or fail, it will always close the library.
Does anyone know how I can achieve this?

You have to use .catch after closing the then function:
// If our garment has a logo
shared.logoExists(garment, model).then(function () {
// Save our panel
return shared.save(model);
// If there was an error
}).catch(function () {
// Display an error message
toastr.warning(localization.resource.logoPlacementError.message);
// Always close the library
}).finally(function () {
// Reset our attachments
self.resetAttachment();
// Hide our library
self.closeLibrary();
});

Depending on which version of Angular you're using, you may have to use "always" instead of "finally". Try "always" and see if it works.
How to always run some code when a promise is fulfilled in Angular.js

It turns out that my way works fine. The logoExists function was not resolving / rejecting a promise in all places that it should be. When I fixed that, my code above worked.

Related

Issue with the $mdDialog.show(confirm), not able to execute the code below this dialog directives in AngularJS

I'm finding this issue with $mdDialog.show(confirm), the code below the dialog function executes even before the popup arise.
I can handle by setting a flag to restrict the execution of below code. but after the completion of the dialog activity it goes to Error(ie, resolvePromise()) without executing the below code:
//This is the code I have used.
var confirm = $mdDialog.confirm()
.title('Early Dispatch Date Available.')
.textContent('Do you want to reschedule and Change Quantity.')
.ariaLabel('day')
.ok('Yes')
.cancel('Plan on Date');
$mdDialog.show(confirm).then(function (obj)
{
$scope.targetDates[lastItem].Qty = 0;
return;
}, function () {
condition = 'QtyLessThanCap';
});
//for example,this is the code which gets executed even before the comfirmation dialog pops up..
angular.forEach($scope.targetDates, function (Datess)
{
totalCalQty = totalCalQty + parseInt(Datess['Qty']);
});
I want the codes to be executed in the order I have coded them,I mean the below code need to be executed only after the confirmation dialog activity.
Thank you in advance.
The only way I've been able to deal with the same type of functionality is by splitting the function, so for example you have an action function that determines whether you need a modal or can just calculate the total:
function something() { // if modal show modal.then(doSomething) }
then the actual calculation function which can be called directly, or from any level of mdModal.then():
function doSomething() { // calculate total }
It's probably not as pretty as you're looking for but it works.

$timeout function not working inside if statement

I am setting up a web form using angular whereby users will complete the form, get a response from the server, and then get redirected to another page.
angular.module('discountController', ['discServices'])
.controller('discCtrl', function(Discount, $timeout, $location){
var app = this;
app.reqDiscount = function(discountData) {
Discount.reqDiscount(app.discountData).then(function(data) {
if (data.data.success) {
app.successMsg = data.data.message ; // Create Success Message
$timeout(function(){
console.log('timeout fired');
$location.path('/discountoutcome');
} , 3000);
} else {
app.errorMsg = data.data.message; // Create an error message
}
});
};
});
In the above code I call the app.reqDiscount function and I successfully get a response from the server which populates the app.successMsg variable. But the $timeout function does not then work. However, if I place the $timeout function outside of the if-else statement it does work. This is not what I want, because if there is an error I want to stay on the page.
In other areas of my code I have placed a $timeout function in a nested position like this and it works, so I don't understand why it would not work here.
Any help you can give me would be great. Even if you can not answer this question if you can give me some tips on debugging that would be helpful as console.log() is my only method of debugging currently. I am using Visual Studio Code.
Chrome console:
Chrome console screen shot
Visual Studio Console:
VSC console
I got it. I had coded the API incorrectly. data.data.success was returning false instead of true. Thanks for your help.

browser.get returning before the given URL completely loads using Protractor

I'm using Protractor with Cucumber to write some tests but I'm stuck at some point. In step after login, I'm rerouting to another page using browser.get(url) function provided by protractor. But it always returns before the page is completely loaded. I have tried many solutions so far but no luck. I have tried with browser.wait, browser.get(url).then(function(){ // code when it loads}) but Im getting 0 positive results.
Here's my code:
// Steps will be implemented here
this.Given(/^I am logged in as user \'([^\']*)\'$/, function (user, callback) {
console.log('USER: ' + user);
browser.driver.get('https://cit-was70-l06/ipa')
browser.driver.findElement(by.xpath('my_xpath')).sendKeys(user);
browser.driver.findElement(by.xpath('my_xpath')).sendKeys(user);
browser.driver.findElement(by.xpath('my_xpath')).click().then(callback);
});
this.Then(/^The screen is shown, with title \'([^\']*)\'$/, function (title, callback) {
console.log('Title from feature file: ' + title);
var url = 'some/url/in/application/';
browser.get(url).then(function(){
// This portion executes before page is completely loaded.
// So if I try to get any element, it throws me an error.
// [15:32:13] E/launcher - "process.on('uncaughtException'" error, see
// launcher
// [15:32:13] E/launcher - Process exited with error code 199
// It works if I add static delay to wait for page load completely
// but that will not be a good solution if I have too much pages to test
callback();
});
console.log('After page laoad');
});
Any suggested work around will be much appreciated.
[15:32:13] E/launcher - "process.on('uncaughtException'" error, see launcher
[15:32:13] E/launcher - Process exited with error code 199
The above error can be caused due to various reasons mostly related to promises. But it should throw the correct message. There is already a work around provided here https://github.com/angular/protractor/issues/3384 to catch the exact error message.
You could change the launcher.ts file in your protractor dependency as mentioned in above forum to catch the error inorder to debug your issue.
And I would suggest you to return your promises instead of callbacks when writing step definitions in protractor-cucumber, in this way cucumber would know when to complete its async actions.
Try the below code.check whether it helps.
browser.get(url);
browser.waitForAngular();
then try to call your function.
Use protractor.ExpectedConditions to check visibility of any elements on page which will be displayed after successful login. Write a customized method as shown below.
If element displayed, then navigate other page using browser.get();
Code Snippet
EC = protractor.ExpectedConditions;
//targetElement=element(locator);
this.isElementVisible = function (targetElement, timeOut) {
'use strict';
timeOut = timeOut !== undefined ? timeOut : 8000;
browser.wait(EC.visibilityOf(targetElement),
timeOut).thenCatch(function()
{
assert.fail(' element is not visible');
});
};

Protractor expectation that element is eventually present

Is there a way to have an expectation that an element is eventually on the page? e.g. a way for
browser.wait(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))), 1000, 'Unable to find continue link');
to fail with an expectation error instead of a timeout? Essentially a way to have a isEventuallyPresent() instead of isPresent() in the line below
expect(element(by.partialLinkText('Continue')).isPresent()).toBe(true);
For reference, I'm using browser.ignoreSynchronization = true even though it's an Angular app, and using Jasmine (at least for now).
Using the facts that
browser.wait returns a promise that is resolved once the condition function returns truthy, or rejected if it times out.
If expect is passed a promise, it only runs the expectation when the promise is resolved
You can make a function that wraps a call to browser.wait
function eventual(expectedCondition) {
return browser.wait(expectedCondition, 2000).then(function() {
return true;
}, function() {
return false;
});
}
and then create an expectation
expect(eventual(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))))).toBe(true);
Or, to make it work on any browser instance, you can monkey-patch the Protractor prototype
protractor.Protractor.prototype.eventual = function(expectedCondition) {
return this.wait(expectedCondition, 2000).then(function() {
return true;
}, function() {
return false;
});
}
and can be used as
expect(browser.eventual(protractor.ExpectedConditions.presenceOf(element(by.partialLinkText('Continue'))))).toBe(true);
To avoid timeouts, you must make sure that the timeout passed to browser.wait is less than the the Jasmine async test timeout, which is specified as jasmineNodeOpts: {defaultTimeoutInterval: timeout_in_millis} in the protractor configuration file
The presenceOf expected condition used with a browser.wait() would allow to have a single line in the test:
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(element(by.partialLinkText('Continue'))), 1000, 'Unable to find continue link');
where EC is protractor.ExpectedConditions - I usually make it global in onPrepare() through the global namespace.
Note that in case of a failure, you would have a Timeout Error, but with the Unable to find continue link error description.
As a side note, it is important to provide a meaningful custom error description, as you've already did. If you want to enforce it, there is a eslint-plugin-protractor plugin to ESLint static code analysis tool that would warn you if there is a browser.wait() used without an explicit error description text.

Make Protractor wait for an alert box?

I am writing E2E tests for a log in page. If the log in fails, an alert box pops up informing the user of the invalid user name or password. The log in itself is a call to a web service and the controller is handling the callback. When I use browser.switchTo().alert(); in Protractor, it happens before the callback finishes. Is there a way I can make Protractor wait for that alert box to pop up?
I solved similar task with the following statement in my Protractor test:
browser.wait(function() {
return browser.switchTo().alert().then(
function() { return true; },
function() { return false; }
);
});
In general, this code constantly tries to switch to an alert until success (when the alert is opened at last). Some more details:
"browser.wait" waits until called function returns true.
"browser.switchTo().alert()" tries to switch to an opened alert box and either has success, or fails.
Since "browser.switchTo().alert()" returns a promise, then the promise either resolved and the first function runs (returns true), or rejected and the second function runs (returns false).
You may use the ExpectedConditions library now, which makes the code more readable:
function openAndCloseAlert () {
var alertButton = $('#alertbutton');
alertButton.click();
// wait up to 1000ms for alert to pop up.
browser.wait(protractor.ExpectedConditions.alertIsPresent(), 1000);
var alertDialog = browser.switchTo().alert();
expect(alertDialog.getText()).toEqual('Hello');
alertDialog.accept();
};

Resources