If login button is present, login - Protractor - angularjs

This is login button. So if it is present, it should login. If not, should go on code.
<button class="md-button ng-scope
md-ink-ripple layout-align-xs-start-start"
type="button" ng-transclude="" data-menu-item="login" ng-click="vm.login()"
ng-if="!vm.isAuthenticated()" layout-align-xs="start start"
aria-label="person_outline global.menu.account.login">
<md-icon class="ng-scope material-icons">person_outline</md-icon>
<label translate="" class="ng-scope">Giriş</label>
<div class="md-ripple-container"></div>
</button>
I tried
describe('Product dashboard module', function () {
console.log('Product Dashboard Test starting');
var dashboardPageObject = new DashboardPageObject();
beforeEach(function () {
var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(element(by.css('ng-click="vm.login()"')).then(function () {
console.log('-Loging in');
//here will be login jobs
})
})
but
Failed: element(...).then is not a function
I change to this
var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(element.all(by.cssContainingText('ng-click="vm.login()"'))
.then(function () {
error is:
Failed: Cannot read property 'bind' of undefined
I tried lots of things.

The error Failed: Cannot read property 'bind' of undefined is because in your EC.visibilityOf() method you are trying to pass element.all() which is an array. Buy EC will accept only ElementFinder and not ElementArrayFinder.
So if you want to perform certain operation only if the element available have a look at below example.
beforEach(function(){
element(by.css('button.layout-align-xs-start-start')).isPresent().then(function(isElementDisplayed){
if(isElementDisplayed){
//perform login operation;
}
})
})

I couldn't understand your If not, should go on code. in your question. I have tried the below code, edit the else part as per your wish
var loginBtn = elemeent(by.buttonText('Login'));
loginBtn.isDisplayed().then(function (bool) {
if (bool) {
loginBtn.click();
} else {
// your logic goes here
}
});

You have a typo, you are missing 2 closing parenthesis on your browser.wait() call... Also your locator is incorrect, when accessing an attribute other than class, you need to use square brackets.
browser.wait(EC.visibilityOf(element(by.css('[ng-click="vm.login()"]'))))
And since Protractor is asynchronous you don't need a .then() after browser.wait()

Related

Protractor - if element is displayed, click on it doesn't work with by.buttonText

I have switched from finding an element by id to by.buttonText due to the fact I now use a single button with variable text. My test have started to fail.
This is my button
<button type="button" class="btn btn-primary" ng-click="vm.watchUnwatchDriver()">{{vm.model.isWatched ? 'Un-' : ''}}Watch Driver</button>
This evaluates to either 'Watch Driver' or 'Un-Watch Driver' based on vm.model.isWatched.
Initially I set my button to be Watch Driver so that I test if the Un-Watch button isDisplayed and potentially click on it if it is.
I have started to see this message
Failed: No element found using locator: by.buttonText("Un-Watch Driver")✗
My test looks like so
describe('Watch/Un-Watch Driver Test', function() {
var watchBtn = element(by.buttonText('Watch Driver'));
var unwatchBtn = element(by.buttonText('Un-Watch Driver'));
it('should set Driver watch status to default: un-watched', function() {
unwatchBtn.isDisplayed().then(function(visible) {
if (visible) {
unwatchBtn.click();
}
});
expect(unwatchBtn.isDisplayed()).toBe(false);
});
it('should watch a driver', function() {
watchBtn.click();
expect(unwatchBtn.isDisplayed()).toBe(true);
});
it('should un-watch a driver', function() {
unwatchBtn.click();
expect(unwatchBtn.isDisplayed()).toBe(false);
});
});
Try to print your button text and observe for example:
var unwatchBtn = element(by.css('.btn.btn-primary'));
unwatchBtn.getText().then(function(text){
console.log(text);
})
then use that text in by.buttonText
You can try element(by.partialButtonText('Watch Driver')) and it will work in both cases.
isPresent() seems to work okay for me. It successfully detects if button with such name is present.
it('should set Driver watch status to default: un-watched', function() {
unwatchBtn.isPresent().then(function(visible) {
if (visible) {
unwatchBtn.click();
expect(unwatchBtn.isPresent()).toBe(false);
} else {
expect(unwatchBtn.isPresent()).toBe(false);
}
});
});

Angular-chart not updating chart real-time when using timer [duplicate]

Based on changing the value of a variable I wish to display an error message in my html. I call an api from my angular code, and if it returns an error, I have set up a setInterval function that should update bookingData.tracking_id to false and then show an error message in the html. This should be very easy but combining this with setInterval is proving slightly difficult.
Here is the angular/javascript
this.confirmTrackingTest = function () {
TestService.finalPackageCheck({tracking_id: controller.bookingData.tracking_id}).$promise.then(function (data) {
return data;
}).catch(function (err) {
var i = 0;
var interval = setInterval(function () {
i += 1;
if (i === 3) {
if (err.statusText === "Not Found") {
controller.bookingData.showErrorMessage = true;
}
clearInterval(interval)
}
}, 2000);
console.log(controller.bookingData.showErrorMessage)
});
}
this.bookingData = {
showErrorMessage: false,
tracking_id: 1
};
Here is the html:
{{Packs.bookingData.showErrorMessage}}
<div class="alert alert-danger" role="alert" ng-if="Test.bookingData.showErrorMessage">
<p>Please show this message</p>
</div>
The {{Packs.bookingData.showErrorMessage}} shows false so that is recongised in the html.
Please let me know if any further information is required.
This is exactly the reason why the Angular gods invented $interval in order to remove the need to manually use $apply.
So either you call $scope.$apply inside the callback or you use $interval (don't forget to include it in the parameter list for depedency injection)

How can I duplicate the functionality of a Javascript confirm with an AngularJS service?

I created this alert service:
class AlertService {
msg = null;
constructor() { }
confirm = (msg) => {
var self = this
this.msg = msg;
}
cancel = () => {
this.msg = null;
return false;
}
okay = () => {
this.msg = null;
return true;
}
}
What I would like to do it to have in my controller something like this:
alertService.Confirm("Confirm or cancel")
.then(function () {
ts.doDelete(es.exam.examId)
}
Here's my html. Note that al is already wired to the AlertService.
<div id="alert"
ng-show="al.msg">
<div>{{ al.msg }}</div>
<button ng-click="al.okay()">
Okay
</button>
<button ng-click="al.cancel()">
Cancel
</button>
</div>
My problem with this is I know how to call the confirm() and pass it the message but how can I make the alert service sit waiting until the user presses the Cancel or Okay buttons in a similar way to when I use the javascript confirm to make a confirmation box appear on my screen?
You have to return promise from Confirm method. And resolve it or reject on yes/no handlers.
http://andyshora.com/promises-angularjs-explained-as-cartoon.html
Here you can find similar solutions:
http://www.bennadel.com/blog/2632-creating-asynchronous-alerts-prompts-and-confirms-in-angularjs.htm
https://github.com/likeastore/ngDialog

How to handle modal-dialog box in Protractor?

I am trying to use sendKeys() on a modal-dialog box on this website. This dialog box appears after clicking Sign In button. I cannot seem to find any way to switch focus on the box. See the gist
I tried using browser.driver.switchTo().activeElement(); in
InvalidLogInUnSuccess: {
get: function () {
this.loginButton.click();
browser.driver.switchTo().activeElement();
this.email.sendKeys("Test");
}
}
with no luck and throws ElementNotVisibleError
Message:
ElementNotVisibleError: element not visible
(Session info: chrome=41.0.2272.101)
(Driver info: chromedriver=2.14.313457 (3d645c400edf2e2c500566c9aa096063e707c9cf),platform=Windows NT 6.3 x86_64)
Stacktrace:
ElementNotVisibleError: element not visible
I've experienced a similar issue while testing an internal application when a popup was being opened with an animation effect (I think it is a culprit here) which had me think about waiting for an element inside the popup to become visible.
visibilityOf expected condition works for me in this case:
var email = element(by.css('.container.login.ng-scope #email'));
browser.wait(EC.visibilityOf(email), 5000);
email.sendKeys('test');
where EC is something I usually define globally in the onPrepare():
onPrepare: function () {
...
global.EC = protractor.ExpectedConditions;
},
Just a side note, I think the locator could be improved here:
ng-scope is not something I would rely on
there is a model defined on the email field, how about:
element(by.model('email'));
FYI, the complete spec I've executed:
"use strict";
describe("gifteng test", function () {
var scope = {};
beforeEach(function () {
browser.get("http://www.gifteng.com/?login");
browser.waitForAngular();
});
describe("Logging in", function () {
it("should send keys to email", function () {
var email = element(by.css('.container.login.ng-scope #email'));
browser.wait(EC.visibilityOf(email), 5000);
email.sendKeys('test');
});
});
});
Protractor works with promises you should write :
InvalidLogInUnSuccess: {
get: async() => {
await this.loginButton.click();
await browser.driver.switchTo().activeElement();
await this.email.sendKeys("Test");
just apply Promises before protractor code. I removed function and write async. so i applied async/await.
reference: Link

AngularJS- Prompting the user before routing to other controller to save changes

I have a form in a controller.
If there are unsaved change I want to warn the user about loosing them when leaving.
First I tried:
$scope.$on('$locationChangeStart', function (event, next, current) {
if ($scope.settingsForm.$dirty) {
event.preventDefault();
$scope.theUserWantsToLeave(function (result) {
if (result === "LEAVE") {
$location.path($location.url(next).hash());
$scope.$apply();
}
});
}
The code above throws an error in the line $scope.$apply();:
Error: $digest already in progress
removing this line just don't execute the redirect.
What would be the right way to do it?
===
Edit:
Other option I tried is handling it by reacting only when I need to cancel the redirection:
$scope.$on('$locationChangeStart', function (event, next, current) {
if ($scope.settingsForm.$dirty) {
$scope.theUserWantsToLeave(function (result) {
if (result === "STAY_HERE") {
event.preventDefault();
}
});
}
});
when doing things this way, the UI is breaking (I see the dialog and then it gone).
Seems like I can't call another async method while handling event.
I've managed to interrupt by the route change by listening for $locationChangeSuccess and then assigning $route.current to the last route.
Also, if $scope.theUserWantsToLeave is async, then the callback passed to it may fire too late to stop the route change. You could get around an async call by using a blocking flag, such as okToDiscardChanges in my examples.
JS:
$scope.okToDiscardChanges = false;
var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function () {
if ($scope.settingsForm.$dirty && !$scope.okToDiscardChanges) {
$route.current = lastRoute;
$scope.errorMessage = 'You have unsaved changes. Are you sure you want to leave?';
}
});
HTML:
<form name="settingsForm">
<!-- form stuff -->
</form>
<div ng-show="errorMessage">
{{ errorMessage }}
<label>
<input type="checkbox" ng-model="okToDiscardChanges"> Discard Changes
</label>
</div>
Hope this works!

Resources