Protractor: verification of pop up elements randomly fails - angularjs

I'm verifying and also clicking on elements of pop up window on Angular page with Protractor. The problem is that verification fails randomly.
My spec file:
describe('...
it('...
// initialize page object
var home = new homePage();
// hover over the shopping cart icon
browser.actions().mouseMove(home.shoppingCartLink).perform();
// pause browser for 4 sec
browser.sleep(4000);
// initialize page object
var shoppingCartPreview = new shoppingCartPage();
// hover over the shopping cart preview window
browser.actions().mouseMove(shoppingCartPreview.window).perform();
// verify elements are displayed
expect(shoppingCartPreview.shopName.isDisplayed()).toBeTruthy();
expect(shoppingCartPreview.price.isDisplayed()).toBeTruthy();
expect(shoppingCartPreview.delete.isDisplayed()).toBeTruthy();
// click on "Checkout" button
shoppingCartPreview.checkoutButton.click();
});
});
As wtritten, the problem is that for all the verifications I get falsy instead of truthy. What I'm doing wrong?
I even tried with the following without a success:
// waiting for elements to be visible
browser.wait(EC.presenceOf(shoppingCartPreview.popUpWindow),10000);
browser.wait(EC.presenceOf(shoppingCartPreview.shopName),10000);
browser.wait(EC.presenceOf(shoppingCartPreview.price),10000);
browser.wait(EC.presenceOf(shoppingCartPreview.delete),10000);

The problem is - you are waiting on - presenceOf() which only checks the presence of the element in DOM and hence it will always return true whether your pop-up is visible or not.
You need to wait like this leveraging visibilityOf() - browser.wait(EC.visibilityOf(shoppingCartPreview.popUpWindow), 5000)

Related

event components on page become unresponsive after page refresh

After I refresh my page(the refresh simply sets the events array to [], then refetches the data to be displayed on screen again), the event components still show, but become unresponsive to touch e.g. no buttons on the event card work and you can not swipe left and right on them. When the app first launches tho, you can interact with the buttons just fine.
The problem occurs after refresh EVERY time, but it also occurs after I go through my other tabs on the screen and come back to the events tab.
this only happens sometimes but I thought it would be important to note.
I have tried to reload the component by adding a *ngIf statement in a parent div of the event card that checks for the event array being empty. I thought this would force the component to reload, but no luck.
I also made sure that the event's array first gets equal to [] before fetching for more data.
I also made sure that the data the event's array gets filled with is the same before and after the refresh happens.
HTML Code where the event cards are present :
<div class="cards" *ngFor="let event of events; index as i" class="final">
<ion-item-sliding class="item-sliding">
<ion-item-options class="item-options" side="start">
<ion-item-option color="success" (click)="saveEvent(event.id)">Mark As Going</ion-item-option>
</ion-item-options>
<app-card *ngIf="event.eventDeleted != true" [id]="event.id"></app-card>
</ion-item-sliding>
</div>
Some relevant global variables inside my TS file :
limit: number = 5;
lastVisible: any;
This method gets run first :
ngOnInit() {
this.fetchEvents();
}
My method for pulling events :
fetchEvents() {
this.fStore.collection('events').ref.limit(this.limit).get().then((events) => {
this.lastVisible = events.docs[events.docs.length-1];
this.events = events.docs
console.log(this.events, "events")
});
}
Problem occurs after this refresh button
doRefresh(event) {
this.fetchEvents()
setTimeout(() => {
event.target.complete();
}, 2000);
}
Expected: After refresh, buttons should be interactive.
Actual: After refresh, buttons are not interactive.
This sounds like ionic/issues/15486 which is basically:
dynamically generated ion-item-sliding becoming unresponsive after removing elements from base array
The issues claims that this was fixed in ionic#4.1.0... Which version are you using?

AngularJS testing with Protractor - chaining promises- How to wait for animation to complete?

I am currently developing an automated test suite for an AngularJS application developed by my company. I have already designed & developed a number of test cases, which are running & passing/ failing as expected.
However, with the test that I am currently developing, I seem to have run into an issue when chaining promises, and am unable to solve it... The test script as it stands is:
it('should navigate to the browser page', function() {
console.log("Start browser page test");
browser.waitForAngularEnabled(false);
browser.wait(EC.visibilityOf(pagesMenuBtn), 10000).then(
browser.actions().mouseMove(pagesMenuBtn).perform().then(
//expect(pageBrowserBtn.isDisplayed()).toBeTruthy();
browser.wait(EC.visibilityOf(pageBrowserBtn), 12000).then(
pageBrowserBtn.click().then(
function() {
console.log("Browser menu button clicked");
//browser.pause();
}).then(
browser.wait(EC.visibilityOf(browserPageTagsLink), 20000).then(
function(){
console.log("End browser page test (then call)");
expect(browser.getCurrentUrl()).toBe(VM + '/#/pages/browser');
}
)
)
)
)
);
});
When I run my test script (I have a number of other tests that run before this one), the first few run & pass successfully, then when this test starts to execute, the console shows:
Started
....Start browser page test
Browser menu button clicked
F
Failures:
1) App should navigate to the browser page
Message:
Failed: Wait timed out after 20010ms
Stack:
TimeoutError: Wait timed out after 20010ms
at WebDriverError (C:\Users\path\selenium-webdriver\lib\error.js:27:5)
So from the output displayed in the console, it's clear that the test executes correctly as far as the console.log("Browser menu button clicked); statement, which indicates that a click has been performed on the menu button as I intend (i.e. the menu button clicked is displayed on a popup menu that is only shown when the cursor is hovering over the pagesMenuBtn element, so that indicates that the line
browser.wait(EC.visibilityOf(pageBrowserBtn), 12000).then(
is executed correctly).
Since the console.log("Browser menu button clicked"); statement is also displayed in the console, that indicates that the
pageBrowserBtn.click().then(
is also executed correctly.
But for some reason, the test is then timing out after the 20 seconds it waits for the browserPageTagsLink element to be displayed.
This browserPageTagsLink element is just a hyperlink element displayed on the 'Browser' page that my test is trying to navigate to- I am waiting for it to be visible so that I know that the page has loaded before I check that the URL is correct...
But as I watch what's happening in the browser window where these tests are run, and what's displayed in the console while my tests are running, the script seems to 'get stuck'/ pause/ 'hang' for a while after the Browser menu button clicked message is displayed in the console, and I can see from watching the browser window that this button was never actually clicked- the popup menu where this button is displayed is shown very briefly: the line browser.actions().mouseMove(pagesMenuBtn).perform() is causing the cursor to hover over the button required to show the sub-menu, but it seems that the click is performed before the sub-menu element has fully finished loading (there is some animation on the element- it appears to 'fade into view'), but I think that the click is happening before the element has fully finished loading, and so it's possibly not registering correctly?
How can I cause my test to wait for the animation to complete before trying to click the sub-menu menu item, so that the click registers with the element correctly?
I tried doing this with the line:
browser.wait(EC.visibilityOf(pageBrowserBtn), 12000).then(
It seems that the EC.visibilityOf(...) condition is met as soon as the element starts to become visible, rather than waiting until it is fully opaque, but that the
pageTagBrowserBtn.click().then(
line, which is called as soon as the condition is true can't actually be performed at this point- presumably because the element is not 'fully' visible at the point at which it's clicked?
How can I make my test wait for the animation (which has been implemented using CSS) to complete before it tries to click on the element?
I had a look on the Protractor API for anything about animations, but it only seems to provide the function allowAnimations()...
Edit
The animation for this element is set in the CSS with:
/* Animation for moving lists in configuration */
.list-fade.ng-enter,
.list-fade-leave.ng-leave {
-webkit-transition: all linear 0.5s;
transition: all linear 0.5s;
}
i.e. it should take 0.5 seconds for the element to be displayed when the cursor hovers over its parent element.
I tried adding a call to browser.wait(), so that my test would wait for the element to be fully displayed before trying to click on it- I updated the part of my test that is sending the click to:
browser.actions().mouseMove(pagesMenuBtn).perform().then(
//expect(pageTagBrowserBtn.isDisplayed()).toBeTruthy();
browser.wait(EC.visibilityOf(pageTagBrowserBtn), 12000).then(
browser.wait(10000).then(
pageTagBrowserBtn.click().then(
function() {
console.log("Tag Browser menu button clicked");
I told it to wait for 10 seconds at this point to ensure that it definitely gave the element enough time to load (according to the CSS, it should only take 0.5 seconds to be displayed), but for some reason, my test is still failing due to the same timeout issue.
Anyone have any suggestions?
Looking at your tests I'm wondering why you have to chain your promises like that. On a fully angular page Protractor is supposed to automatically chain promises, ie when I write a test like this
driver.get(“http://www.google.com”);
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
console.log(title);
});
it actually is executed in a synchronous manner like this:
driver.get(“http://www.google.com”).
then(function() {
return driver.findElement(webdriver.By.name('q'));
}).
then(function(q) {
return q.sendKeys('webdriver');
}).
then(function() {
return driver.findElement(webdriver.By.name('btnG'));
}).
then(function(btnG) {
return btnG.click();
}).
then(function() {
return driver.getTitle();
}).
then(function(title) {
console.log(title);
});
If your page is fully Angular most of what you've written shouldn't need the promises, and that my be causing timing issues with your test. Have you tried writing the test without chaining promises?
That said, you might also try EC.elementToBeClickable(yourElement) instead of waiting for EC.visibilityOf() if you haven't already.

Execution order of protractor tests

Which is the best way to control the execution order of Protractor tests?
Problem case 1: protractor swipes angular pages so quickly that it cannot manipulate (fill in) input data. (The swipe logic is to transfer from being invisible to visible and by translating them into the window visible area). thus protractor cannot see those beyond the window and with opacity 0. To test i can only fill in the first page. the others are swiped too fast (or async).
Problem case 2: After i filled in the first page and submitted the form, the data is saved and alert shows confirmation message. Then protractor has to click a drop-down list and browser should navigate to the page where saved data is displayed. The problem is that protractor clicks the drop-down list before the data is saved due to alert fired later (have to wait for alert).
Question is: Is there a way to control tests to be executed in the given order in protractor? And is there a way to hold down swiping to fill in the date (otherwise protractor does not see it)? Here is the simplified code:
it('should fill in form and send data', function() {
// fill in textarea field
element.all(by.css('textarea')).first().clear().sendKeys('test');
// goes to page 2
browser.executeScript("angular.element(document.documentElement)
.injector().get('$rootScope').$broadcast('nextPage', {direction: 'next'});");
// Here is Problem 1. Though i can see this page when testing,
// the input is not visible for protractor.
// fill in input-field
element.all(by.css('input')).first().clear().sendKeys('test');
// goes to page 1
browser.executeScript("angular.element(document.documentElement)
.injector().get('$rootScope').$broadcast('prevPage', {direction: 'prev'});");
// submit form
element(by.css('button[type=submit]')).click();
// Here is problem 2. The following test is executed earlier
// than the following alert.
//browser.wait(protractor.ExpectedConditions.alertIsPresent(), 3000);
var alertDialog = browser.switchTo().alert();
expect(alertDialog.getText()).toEqual('Saved');
alertDialog.accept();
});
it('should click drop-down-list', function() {
// click drop-down list
element(by.css('.drop-down-list')).click();
});
I personally believe browser.sleep(5000) should resolve the second issue.
if not can you try with promisies
element(by.css('button[type=submit]')).click().then(function(){
var alertDialog = browser.switchTo().alert();
expect(alertDialog.getText()).toEqual('Saved');
alertDialog.accept();
});
This should wait for the promise to get resolved (i.e to click submit button) and then execute the code snippet inside

what does isPresent() in protractor testing actually do?

whether the isPresent() provides true
only when the element is present in the page
or
only when the element is visible in the page (while scroll down)
If it checks only the element is present in the page, whether there is any other method to provide true only when the element is visible.Kindly provide some input.
Edit:1
I had a scrolling problem while loading a page.ie(while loading the page it will scroll down to the middle of my page)
So I am using a scroll service which will load the page correctly from the top.
The point is while using scroll service the protractor test should pass and fail when not using it.
Now when using the scroll service all the elements will be visible,I using the isPresent() which is returning true
And when not using the scroll service some elements will not be visible due to scroll down,but still I am using the same element which is not visible with the isPresent() which is also returning true.
isPresent() returns a Promise not true or false.
If you want to check if an element is present, you actually have to look at the value that the promise resolves to:
element(anyFinder).isPresent().then(function(isPresent) {
if ( isPresent) {
// The element is present
} else {
// The element is not present
}
});

ionic + android back button + sidemenu isOpen detection - not working reliably

I have an odd situation. I am writing an angular + ionic app with a left slide menu and here is what I am trying to do:
1) Trap the Android back button
2) When you tap the back button, if the menu is not open, take you to the menu (open it)
3) If the menu is open and you hit the back button, exit the app
To trap the back button, I have this code in app.run (also tried relocating to a base controller and injecting it with $controller into other controllers, did not make a difference)
What I am noticing is that if I actually tap the 'menu icon' of the menu, the "isOpen" reliably prints true/false alternately as a I open and close the menu
But, when I tap the Android back button, it works the first time (prints true or false), but every subsequent tap does not change the isOpen state, while the menu actually toggles.
This therefore makes it impossible for me to programmatically detect if the menu is open or close within the android back button handler.
It's confusing me why this is only a problem within the android back handler, and not a problem when I tap the menu item. It's the same code that is called in both cases, which is
$ionicSideMenuDelegate.toggleLeft();
My Android handler code:
$ionicPlatform.registerBackButtonAction(function (event) {
$ionicSideMenuDelegate.toggleLeft();
$ionicSideMenuDelegate.$getByHandle('sideMenu').toggleLeft();
$timeout ( function() {
console.log ("Status of SIDE MENU IS : " + $ionicSideMenuDelegate.$getByHandle('sideMenu').isOpen());
},1000);
}, 100);
I've also set up a codepen, though not sure how one can test it on and android device, because every time I try and hit the backbutton on a codepen or jsfiddle, it makes the browser go back a page.
Any insight into what is going on? I've asked in the ionic forum, but haven't been able to find out why (yet) --> hence the post to the SO community in the hopes it reaches a wider audience.
registerBackButtonAction needs a priority to override the other actions:
The priorities for the existing back button hooks are as follows:
Return to previous view = 100 Close side menu = 150 Dismiss modal =
200 Close action sheet = 300 Dismiss popup = 400 Dismiss loading
overlay = 500
Your back button action will override each of the above actions whose
priority is less than the priority you provide. For example, an action
assigned a priority of 101 will override the 'return to previous view'
action, but not any of the other actions.
I've tested this code and it works as expected:
.run(function($ionicPlatform, $ionicSideMenuDelegate, $ionicPopup) {
$ionicPlatform.registerBackButtonAction(function(e) {
e.preventDefault();
if (!$ionicSideMenuDelegate.isOpenLeft()) {
$ionicSideMenuDelegate.toggleLeft();
} else {
navigator.app.exitApp();
}
}, 1000);
});
As you can see I've used priority 1000 to make sure that I override all the default actions.
I've also used preventDefault(). I don't think you need this but, just in case.
This bit of code only works for the left-side menu as I only check:
$ionicSideMenuDelegate.isOpenLeft()
and only open the left one:
$ionicSideMenuDelegate.toggleLeft()
but you can change it to work with the right menu as well.
UPDATE:
If someone is interested to find out more about Android and Back Button this is the best article I've read so far.

Resources