protractor browser.actions().mouseMove() not showing hover effects - protractor

I am new to protractor and trying to add tests for a slider panel which is closed by default and hovering mouse over will open it and then there are a list of items on the slider panel to pick.
<div class="slider" [ngClass]="{ closed: state === 1, open: state === 2}" (click)="onClick($event)" (mouseover)="onMouseOver($event)" (mouseleave)="onMouseLeave($event)">
I tried multiple ways, none of them work.
First attempt:(no hover effect, ie, do nothing)
browser.actions().mouseMove(element(by.css('.slider.closed'))).perform();
Second attempt:( got an error: An invalid or illegal selector was specified)
browser.actions().mouseMove(element(by.css('[(mouseover)="onMouseOver($event)"]'))).perform();
Third attempt: (got an error: No element found using locator)
browser.actions().mouseMove(element(by.css('[mouseover="onMouseOver($event)"]'))).perform();

This should work, unless you have multiple elements with class .slider. At which point, you might try including a parent object, or another locator strategy.
browser.actions().mouseMove($('.slider')).perform();

I used webdriver and made it work. browser.executeScript('arguments[0].click()',browser.driver.findElement(By.css('.slider')));

I just have the same problem, after 2 hours, I found this work for me:
src: java mouse over using javascript
let loginElement = await driver.findElement(By.id('header-user'));
let strJavaScript = "var element = arguments[0];"
+ "var mouseEventObj = document.createEvent('MouseEvents');"
+ "mouseEventObj.initEvent( 'mouseover', true, true );"
+ "element.dispatchEvent(mouseEventObj);";
await driver.executeScript(strJavaScript, loginElement);

I got the same issue when run tests with firefox
and find out a solution as below
if (browser.isFirefox) {
var script = `if(document.createEvent) {
var evObj = document.createEvent('MouseEvents');
evObj.initEvent('mouseover', true, false);
arguments[0].dispatchEvent(evObj);
} else if (document.createEventObject) {
arguments[0].fireEvent('onmouseover');
}`;
browser.executeScript(script, elm.getWebElement());
return elm.click();
} else {
return browser.actions()
.mouseMove(elm.getWebElement())
.click()
.perform();
}
Test with:
Protractor: 5.1.1
Selenium: 3.4.0

Related

Protractor page object definition not working as expected

I apologize for the slightly vague title, I'm not sure how exactly to word this.
I have my Page Object which, with one exception, works perfectly. Here's the excerpt:
module.exports = function(){
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = element(by.name('facility')).all(by.tagName('option')).count().then(function(numberOfItems) {
var rnum = parseInt(Math.random() * numberOfItems);
return rnum;
}).then(function(randomNumber) {
element(by.name('facility')).all(by.tagName('option')).get(randomNumber)
});
}
I can access and use facilityList just fine. But then I realized that I'm almost always doing the same thing to facilityList so why don't I just create another line to make it choose a random one. So I create randomFacility using the code from the main conf.js.
It didn't work. The error I see displayed is:
Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"
I'm confused. Is this saying I can't do all that processing in the page object to get the random one or do I simply have to manipulate facilityList in the conf.js and be done with it?
You nee to know the mechanism about how protractor to find element. Protractor only to start find element from page when protractor's action API be called, like getText(), click(), count() etc.
So when you define variable to represent certain element on page, when Nodejs execute this line, protractor won't to start find element from page:
// page object login.page.js
module.exports = function LoginPage(){
this.sumbitButton = element(by.css('#submit'));
this.countName = element.all(by.css('.username')).count();
}
// use page object in conf.js
var LoginPage = require('./login.page.js');
var loginPage = new Loginpage();
When Nodejs execute line var loginPage = new Loginpage();, all lines in function LoginPage will be executed.
When execute the first line, protractor not to find element from current open page,
When execute the second line, protractor will find element from current open page, But at this time point, protractor is possible to launching browser with a blank page, the target page have not been opened or navigated to.
To fix your problem, you need to define randomFacility as class's Method, rather than Property:
module.exports = function() {
this.facilityList = element(by.name('facility')).all(by.tagName('option'));
this.randomFacility = function() {
return element(by.name('facility'))
.all(by.tagName('option')).count()
.then(function(numberOfItems) {
console.log('count: '+numberOfItems);
var rnum = parseInt(Math.random() * numberOfItems);
console.log('random index: '+rnum);
return rnum;
})
.then(function(randomNumber) {
console.log('argument randomNumber: '+randomNumber);
return element(by.name('facility'))
.all(by.tagName('option')).get(randomNumber)
});
}
};
// how to use
pageObject.randomFacility().then(function(ele){
return ele.click();
});

How to detect Google places AutoComplete load issues?

I'm using the API successfully but encountered an error this morning with "OOPS! Something went wrong" sitting in the textbox and the user cannot type into it. I found the issue to be key related and fixed, however, this brought to light that some issue may arise and the user cannot complete because of this blocking. I'd like to be able to detect in javascript if there is some issue with the google.maps.places.Autocomplete object and not bind it to the textbox.
For anyone else wanting to do this.
Thanks to the folks for the idea over at:
Capturing javascript console.log?
// error filter to capture the google error
(function () {
var oldError = console.error;
console.error = function (message) {
if (message.toLowerCase().includes("google maps api error")) {
document.getElementById('<%=hdnGoogleSelected.ClientID %>').value = "DISABLE";
triggerUpdatePanel();
//alert(message);
}
oldError.apply(console, arguments);
};
})();
Mine is in an update panel so I triggered the update which sets the onfocus back to this.select(); for the textbox which effectively disables the autocomplete attempts.
tbAddress1.Attributes["onfocus"] = "javascript:this.select();";
Another option:
Google will return an error after about 5 seconds from loading.
"gm-err-autocomplete" class indicates any error with the autocomplete component.
You can periodically check for the error class google returns. I do it for 10 seconds after loading:
function checkForGoogleApiErrors() {
var secCounter = 0;
var googleErrorCheckinterval = setInterval(function () {
if (document.getElementById("AddressAutocomplete").classList.contains("gm-err-autocomplete")) {
console.log("error detected");
clearInterval(googleErrorCheckinterval);
}
secCounter++;
if (secCounter === 10){
clearInterval(googleErrorCheckinterval);
}
}, 1000);
}

Ionic scrollTop "Cannot read property 'scrollTo' of null" (still exists in 1.0.0-rc.1)

This bug was referred to here: in ionic changing route causes "TypeError: Cannot read property 'scrollTo' of null"
The answer says that this bug was fixed in beta-13, but I'm using 1.0.0-rc.1 and the bug still appears.
In my case, it the error is showing when navigating back to a page that uses $ionicScrollDelegate.scrollTop()
Is anyone else getting this error after updating to rc.1?
EDIT:
I find that if I do not call $ionicScrollDelegate.scrollTop() automatically when my view loads, the error does not come up. Should I be calling scrollTop() within a specific Ionic event that waits for the right time?
Had the same problem, even with v1.0.0 "uranium-unicorn".
Wrapping the scroll call into a $timeout helped - this is what it looks like in my code:
$timeout(function() {
$ionicScrollDelegate.scrollTo(scrollPosition.left, scrollPosition.top);
}, 0);
You can just put it in
$ionicPlatform.ready(function () {
$ionicScrollDelegate.scrollTop();
})
Im late to this but was getting the same error but by calling the scroll top element with:
$ionicScrollDelegate.scrollTop();
but rather:
var scrollTop = e.detail.scrollTop;
and fixed my by using the following:
var scrollTop = $ionicScrollDelegate.getScrollPosition().top;
Im also using js scrolling as it seems to work better with the scrolla-sista plugin so I have the following in my config block at the start of my app
$ionicConfigProvider.scrolling.jsScrolling(true);
where their docs state:
Whether to use JS or Native scrolling. Defaults to native scrolling. Setting this to true has the same effect as setting each ion-content to have overflow-scroll='false'.
I hope this helps someone
For what it's worth, I saw this solution on this thread here and it worked for me with version 1.0.0-beta.14
If upgrading to version 1.0.0-beta.14 is not an option, you can change the ionic-bundle.js file with the following:
Approximately Line 39910:
this.scrollTop = function(shouldAnimate) {
this.resize().then(function() {
if(typeof scrollView !== 'undefined' && scrollView !== null){
scrollView.scrollTo(0, 0, !!shouldAnimate);
}
});
};
And Approximately line 39813:
if (!angular.isDefined(scrollViewOptions.bouncing)) {
ionic.Platform.ready(function() {
if(!scrollView){
return;
}
scrollView.options.bouncing = true;
if(ionic.Platform.isAndroid()) {
// No bouncing by default on Android
scrollView.options.bouncing = false;
// Faster scroll decel
scrollView.options.deceleration = 0.95;
}
});
}
Please change
e.detail.scrollTop
to
e.target.scrollTop
then this will Work

Google's autocomplete not activated by pasting with mouse

The Google autocomplete API doesn't seem to be activating by pasting content into a text input with the mouse. It works fine if involving the keyboard at all, but not with just mouse.
I did notice, however, that after you paste your content into the text input it will activate from almost any keypress (tested right arrow key, end key, space).
You can repro it here on their autocomplete demo site.
Is this a bug? or as designed? If it's as designed, how to apply workaround?
I've got this as a workaround so far, but no simulated keypress events seem to work.
$('.txtLocation').bind("paste", function (e)
{
$('.txtLocation').focus();
var e = jQuery.Event("keydown");
e.keyCode = 39; //39=Arrow Right
$('.txtLocation').trigger(e);
});
It seems this impacts not only the context-menu Paste, but also that of Edit|Paste from the browser menu bar as well as the iOS paste functionality. I've opened a bug with Google. You may wish to "Star" that bug report to catch updates.
I found a workaround that, while a bit of a hack, seems to fix the problem. If you store the pasted value, switch focus on a different field, set the value in the Autocomplete field, and finally focus back on the Autocomplete field things work more or less as expected. Also, you have to do this in a setTimeout() callback - the delay time doesn't seem to matter at all, but if you just do this inline you won't see the expected results.
Here's a code sample of what I'm describing above:
$("#address_field").on("paste", googleMapsAutocompletePasteBugFix);
googleMapsAutocompletePasteBugFix = function() {
return setTimeout(function() {
var field, val;
field = $("#address_field");
val = field.val();
$("#price").focus();
field.val(val);
return field.focus();
}, 1);
};
The last focus() is optional, but the UI is a little less surprising than if you just skipped automatically to the next field.
Following solution seems to work for me (existence of field ending with "address_2" is assumed). Tested on IE8, IE9, IE10, Chrome, FF and Safari
if document.addEventListener
$(document).on("paste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
$(document).on("onpaste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
else
for element in $("input[name*=address_1]")
document.getElementById($(element).attr('id')).onpaste = #googleMapsAutocompletePasteBugFix
googleMapsAutocompletePasteBugFix: (e) ->
unless e
e = window.event
if e.srcElement
target = e.srcElement
else
target = e.target
field = $(target)
fieldId = field.attr('id')
focusSwitchFieldId = fieldId.replace(/(\d)$/, '2')
setTimeout(->
if window.chrome || /Safari/.test(navigator.userAgent)
val = field.val()
$("##{focusSwitchFieldId}").focus()
field.val(val)
field.focus()
else
field = document.getElementById(fieldId)
val = field.value
document.getElementById(focusSwitchFieldId).focus()
setTimeout(->
field.value = val
field.focus()
field.focus()
, 50)
, 10)

can't tap on item in google autocomplete list on mobile

I'm making a mobile-app using Phonegap and HTML. Now I'm using the google maps/places autocomplete feature. The problem is: if I run it in my browser on my computer everything works fine and I choose a suggestion to use out of the autocomplete list - if I deploy it on my mobile I still get suggestions but I'm not able to tap one. It seems the "suggestion-overlay" is just ignored and I can tap on the page. Is there a possibility to put focus on the list of suggestions or something that way ?
Hope someone can help me. Thanks in advance.
There is indeed a conflict with FastClick and PAC. I found that I needed to add the needsclick class to both the pac-item and all its children.
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');
There is currently a pull request on github, but this hasn't been merged yet.
However, you can simply use this patched version of fastclick.
The patch adds the excludeNode option which let's you exclude DOM nodes handled by fastclick via regex. This is how I used it to make google autocomplete work with fastclick:
FastClick.attach(document.body, {
excludeNode: '^pac-'
});
This reply may be too late. But might be helpful for others.
I had the same issue and after debugging for hours, I found out this issue was because of adding "FastClick" library. After removing this, it worked as usual.
So for having fastClick and google suggestions, I have added this code in geo autocomplete
jQuery.fn.addGeoComplete = function(e){
var input = this;
$(input).attr("autocomplete" , "off");
var id = input.attr("id");
$(input).on("keypress", function(e){
var input = this;
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(37.2555, -121.9245),
new google.maps.LatLng(37.2555, -121.9245));
var options = {
bounds: defaultBounds,
mapkey: "xxx"
};
//Fix for fastclick issue
var g_autocomplete = $("body > .pac-container").filter(":visible");
g_autocomplete.bind('DOMNodeInserted DOMNodeRemoved', function(event) {
$(".pac-item", this).addClass("needsclick");
});
//End of fix
autocomplete = new google.maps.places.Autocomplete(document.getElementById(id), options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
//Handle place selection
});
});
}
if you are using Framework 7, it has a custom implementation of FastClicks. Instead of the needsclick class, F7 has no-fastclick. The function below is how it is implemented in F7:
function targetNeedsFastClick(el) {
var $el = $(el);
if (el.nodeName.toLowerCase() === 'input' && el.type === 'file') return false;
if ($el.hasClass('no-fastclick') || $el.parents('.no-fastclick').length > 0) return false;
return true;
}
So as suggested in other comments, you will only have to add the .no-fastclick class to .pac-item and in all its children
I was having the same problem,
I realized what the problem was that probably the focusout event of pac-container happens before the tap event of the pac-item (only in phonegap built-in browser).
The only way I could solve this, is to add padding-bottom to the input when it is focused and change the top attribute of the pac-container, so that the pac-container resides within the borders of the input.
Therefore when user clicks on item in list the focusout event is not fired.
It's dirty, but it works
worked perfectly for me :
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');
Configuration: Cordova / iOS iphone 5