Playwright - not working with zoomed out site - playwright

our team decided to zoom out the whole site. So they did this:
This is breaking my PW tests while clicking on the button.
I get this in the inspector:
selector resolved to visible <button id="add-to-cart-btn" data-partid="04-0001" data-…>ADD TO CART</button>
attempting click action
waiting for element to be visible, enabled and stable
element is visible, enabled and stable
scrolling into view if needed
done scrolling
element is outside of the viewport
I found this is an issue in PW https://github.com/microsoft/playwright/issues/2768
My question is: how can I bypass this in the most efficient way?
Is there a way to override a playwright function that sets the initial loading of the page and set my zoom there?
Since if I do it via JavaScript, then I have to do it every time my page reloads, and that can be really tedious and error-prone in the tests.
This is what I have now, but it is really a hack a like solution:
async removeZoomOutClassFromBodyElement() {
await this.#page.evaluate(() => {
const body = document.querySelector('body');
if (body) {
// Removes the class only if it exists on the body tag
body.classList.remove('zoom-out');
} else {
throw Error(ErrorMessage.BODY_NOT_FOUND);
}
});
}
Can you please advise what would be the best approach here?
Thanks!

Related

Intercept dialog from <webview> and read the contents

I use this code to intercept a dialog from a webview but I can not see the content or interact with it:
Element webview= querySelector("#webview");
Map<String,String> map=new Map();
map["src"]=urlWebView+user;
webview.attributes.addAll(map);
querySelector("#webview_cont").style.visibility="visible";
window.addEventListener("dialog",(Event e){ //Use window or webview returns the same result
e.preventDefault();
... //What should I do here ??
} );
Any solution?
Thanks
Edit
Debug:
Open issue: https://code.google.com/p/dart/issues/detail?id=23556
The problem definitely lies with your usage of Dart's Event class.
It simply does not support the extra properties that Chrome is adding to the event: e.dialog, e.messageText, e.messageType.
It does not seem like there is a ready solution for that, at least not in chrome.dart.
Sadly, I don't know Dart well enough to give you a solution. You need to somehow extend that event class, possibly dropping to JS level.
This library, even if abandoned, should give you ideas on how to do that (by catching the JS-level event and stuffing the extra properties in CustomEvent's detail property), though implementing DialogController (which is not JSON-serializable) would be a bit trickier, I guess.

Google Places Autocomplete with Jquery Mobile not working on mobile/touch device

As title suggests I am building a mobile website with JQuery Mobile (1.3.0) and am trying to implement Google Places Autocomplete (API v3) to aid user input of location data.
The autocomplete functions correctly on desktop device, but not when used on a mobile device (I have only tested on iOS 6).
When used on mobile device the dropdown list of relevant locations do appear, but simply disappear when you press one without loading the selection on the map.
I have looked around and seen some solutions that sight the z-index of
.pac-container
as the culprit (see: http://osdir.com/ml/google-maps-js-api-v3/2012-01/msg00823.html).
I have implemented these fixes but to no avail, and I am not convinced that z-index is the problem because I can see that the selected item does change to it's :hover state/colour when pressed on mobile.
Please if anyone has suggestions I am all ears, need any more details let me know.
Saravanan's answer is a bit overkill. To fix the conflict with FastClick and PAC, 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');
Thanks Daniel. But the solution I have given has some performance impact.
I have modifed the FastClick library little bit to accomplish that.
First I have added a param to FastClick constructor, where defaultElCls will be the elements which should not implement fastclick.
function FastClick(layer, defaultElCls) {
'use strict';
var oldOnClick, self = this;
this.defaultElCls = defaultElCls;
Then modify needsClick method:
FastClick.prototype.needsClick = function(target) {
'use strict';
var nodeName = target.nodeName.toLowerCase();
if (nodeName === 'button' || nodeName === 'input') {
// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
// Don't send a synthetic click to disabled inputs (issue #62)
if ((this.deviceIsIOS && target.type === 'file') || target.disabled) {
return true;
}
} else if (nodeName === 'label' || nodeName === 'video') {
return true;
}
return ((/\bneedsclick\b/).test(target.className) || (new RegExp(this.defaultElCls).test(target.className)));
};
Then pass pac-item to the FastClick constructor
new FastClick(document.body, "pac-item");
Hope this will be taken care by FastClick library as well :)
I've also encountered this bug, and determined fastclick to be the culprit. I was originally going to go with Devin Smith's answer, but epegzz's warning about MutationEvents being deprecated led me to MutationObservers, and since I haven't seen a fix involving them I thought I'd share my solution.
var observer_config = { attributes: false, childList: true, subTree: false, characterData: false }
var observer = new MutationObserver( function(mutations) {
var self = this;
mutations.forEach(function(mutation){
// look for the container being added to the DOM
var pac_container_added = $(mutation.addedNodes).hasClass('pac-container');
// if it is, begin observing it
if (pac_container_added){
var pac_container = mutation.addedNodes[0];
self.observe(pac_container, observer_config);
}
// look for pac-items being added (as children of pac_container)
// This will not resolve if the observer on pac-container has not been created
var pac_item_added = $(mutation.addedNodes).hasClass('pac-item');
// when pac items are added, add the needsclick class
if (pac_item_added) {
$('.pac-item, .pac-item span').addClass('needsclick')
}
});
});
observer.observe(document.body, observer_config);
It is more complex than I'd like it to be because we can't just add observer.observe('pac_container') in the top level, since its added asynchronously. Luckily, the solution for that problem is also MutationObservers.
We add another observer to pac_container when it is created. That way, it detects the pac-items being added, and when they are, we add the needsclick class.
This is my first time using MutationObservers, so feedback/improvements would be appreciated. As you can see, I used both jquery, but it should be pretty easy to pull it out.
There is a patch for fastclick that makes it work well with google places autocomplete. See This answer :)
After much hair pulling I have found the problem to be the "FastClick" library I added to my project.
As #Saravanan Shanmugam points out in this comment https://stackoverflow.com/a/16932543/1177832
FastClick seems to interfere with autocomplete. Also see above link for the workaround he has added to get the two to play nice.

In Geb, what is the difference between displayed and present?

I am writing functional tests and dealing with a modal window that fades in and out.
What is the difference between displayed and present?
For example I have:
settingsModule.container.displayed and settingsModule.container.present
where settingsModule represents my modal window.
When testing my modal window (the modal from Twitter's bootstrap), I usually do this:
def "should do ... "() {
setup:
topMenu.openSettingsModal()
expect:
settingsModule.timeZone.value() == "Asia/Hong_Kong"
cleanup:
settingsModule.closeSettingsModal()
}
def "should save the time zone"() {
setup:
topMenu.openSettingsModal()
settingsModule.timeZone = "Japan"
when:
settingsModule.saveSettings()
then:
settingsModule.alertSuccess.size() == 1
settingsModule.alertSuccess.text() == "Settings updated"
when:
settingsModule.saveSettings()
then:
settingsModule.alertSuccess.size() == 1
cleanup:
settingsModule.closeSettingsModal()
}
and on and on. In my modules, I have:
void openSettingsModal() {
username.click()
settingsLink.click()
}
void closeSettingsModal() {
form.cancel().click()
}
I always get a complain: "Element must be displayed to click".
In my openSettingsModal and closeSettingsModal, i tried many combination of waitFor with time interval and using present or not ... Can't figure it out.
Any pointers would be highly appreciated. Thanks!
I think the main difference is that present would check that there is an element in your DOM, whereas displayed checks on the visibility of this element.
Remember that webdriver simulates the actual experience of an user using and clicking the website using a mouse, so if the element is not visible to them, they will not be able to click on it.
I wonder if your issue has to do with settingsLink not being in the DOM when the page is first loaded. If you are waiting for a dialog to popup and a link to live in this dialog, then you probably want to set something like
content{
settingsLink( required: false ) { $( '...' }
settingsModal( required: false ) { $( '#modalDialog' ) }
}
your waitfor should look something like
username.click()
waitFor{ settingsModal.displayed }
settingsLink.click()
I would stick with the book of geb conventions and just use displayed all the time.
Geb Manual - Determining visibility
Thanks for your reply. I was actually able to resolve my issue.
The problem was that the modal window had an animation of 500ms. Opening and closing the window several times in my tests made them succeed/fail inconsistently.
What I ended up doing is hooking the the "shown" event provided by the plugin. I ended up adding a "shown" class to the modal and check for it every 100ms during 1s.
void openSettingsModal() {
username.click()
settingsLink.click()
waitFor (1, 0.1) { $("#settingsModal", class: "shown").size() == 1 }
}
void closeSettingsModal() {
form.cancel().click()
waitFor (1, 0.1) { $("#settingsModal", class: "shown").size() == 0 }
}
As a side note, the tests were failing in Chrome and Firefox BUT were passing in IE!! I am guessing that because IE 8 doesn't support animations that my tests were passing.
It is all good now.
I hope it will help someone someday!
Where we can use displayed?
If a particular element you are removing or deleting, if it is still there in DOM and not displayed in page, you can use assert thatelement.displayed == false which will make sure that element is not displayed in the page (but still it is present in DOM)
Where we can use present?
In the same example as above, after removing,if the element is not found at the DOM ,you should use present for verification
assert thatelement.present == false
Hope you understand....
Adding to the above, present takes more time in script execution

Is there any way to control the layout of the close button on a jQuery Mobile custom select menu?

I have a custom select menu (multiple) defined as follows:
<select name="DanceStyles" id="DanceStyles" multiple="multiple" data-native-menu="false">
Everything works fine except that I want to move the header's button icon over to the right AND display the Close text. (I have found some mobile users have a problem either realising what the X icon is for or they have trouble clicking it, so I want it on the right with the word 'Close' making too big to miss.) There don't seem to be any options for doing that on the select since its options apply to the select bar itself.
I have tried intercepting the create event and in there, finding the button anchor and adding a create handler for that, doing something like this (I have tried several variations, as you can see by the commenting out):
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn').button({
create: function (event, ui) {
var $btn = $(this);
$btn.attr('class', $btn.attr('class').replace('ui-btn-left', 'ui-btn-right'));
$btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// $(this).button({ iconpos: 'right' });
// $btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// // $btn.attr('data-iconpos', 'left');
$(this).button('refresh');
}
});
}
});
});
So I have tried resetting the button options and calling refresh (didn't work), and changing the CSS. Neither worked and I got weird formatting issues with the close icon having a line break.
Anyone know the right way to do this?
I got this to work cleanly after looking at the source code for the selectmenu plugin. It is not in fact using a button; the anchor tag is the source for the buttonMarkup plugin, which has already been created (natch) before the Create event fires.
This means that the markup has already been created. My first attempt (see my question) where I try to mangle the existing markup is too messy. It is cleaner and more reliable to remove the buttonMarkup and recreate it with my desired options. Note that the '#search' selector is the id of the JQ page-div, and '#DanceStyles' is the id of my native select element. I could see the latter being used for the id of the menu, which is why I select it first and navigate back up and down to the anchor; I couldn't see any other reliable way to get to the anchor.
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn')
.empty()
.text('Done')
.attr('class', 'ui-btn-right')
.attr("data-" + $.mobile.ns + "iconpos", '')
.attr("data-" + $.mobile.ns + "icon", '')
.attr("title", 'Done')
.buttonMarkup({ iconpos: 'left', icon: 'arrow-l' });
}
});
});
The buttonMarkup plugin uses the A element's text and class values when creating itself but the other data- attributes result from the previous buttonMarkup and have to be removed, as does the inner html that the buttonMarkup creates (child span, etc). The title attribute was not recreated, for some reason, so I set it myself.
PS If anyone knows of a better way to achieve this (buttonMarkup('remove')? for example), please let us know.
the way i achieved it was changing a bit of the jquery mobile code so that the close button always came to the right, without an icon and with the text, "Close"
not the best way i agree. but works..
I got a similar case, and I did some dirty hack about this :P
$("#DanceStyles-button").click(function() {
setTimeout(function(){
$("#DanceStyles-dialog a[role=button]").removeClass("ui-icon-delete").addClass("ui-icon-check");
$("#DanceStyles-dialog .ui-title").html("<span style='float:left;margin-left:25px' id='done'>Done</span>Dance Styles");
$("#DanceStyles-dialog .ui-title #done").click(function() {
$("#DanceStyles").selectmenu("close")
});
},1);
} );

ie9: annoying pops-up while debugging: "Error: '__flash__removeCallback' is undefined"

I am working on a asp.net mvc site that uses facebook social widgets. Whenever I launch the debugger (ie9 is the browser) I get many error popups with: Error: '__flash__removeCallback' is undefined.
To verify that my code was not responsible I just created a brand new asp.net mvc site and hit F5.
If you navigate to this url: http://developers.facebook.com/docs/guides/web/#plugins you will see the pop-ups appearing.
When using other browsers the pop-up does not appear.
I had been using the latest ie9 beta before updating to ie9 RTM yesterday and had not run into this issue.
As you can imagine it is extremely annoying...
How can I stop those popups?
Can someone else reproduce this?
Thank you!
I can't seem to solve this either, but I can at least hide it for my users:
$('#video iframe').attr('src', '').hide();
try {
$('#video').remove();
} catch(ex) {}
The first line prevents the issue from screwing up the page; the second eats the error when jquery removes it from the DOM explicitly. In my case I was replacing the HTML of a container several parents above this tag and exposing this exception to the user until this fix.
I'm answering this as this drove me up the wall today.
It's caused by flash, usually when you haven't put a unique id on your embed object so it selects the wrong element.
The quickest (and best) way to solve this is to just:
add a UNIQUE id to your embed/object
Now this doesn't always seem to solve it, I had one site where it just would not go away no matter what elements I set the id on (I suspect it was the video player I was asked to use by the client).
This javascript code (using jQuery's on document load, replace with your favourite alternative) will get rid of it. Now this obviously won't remove the callback on certain elements. They must want to remove it for a reason, perhaps it will lead to a gradual memory leak on your site in javascript, but it's probably trivial.
this is a secondary (and non-optimal) solution
$(function () {
setTimeout(function () {
if (typeof __flash__removeCallback != "undefined") {
__flash__removeCallback = __flash__removeCallback__replace;
} else {
setTimeout(arguments.callee, 50);
}
}, 50);
});
function __flash__removeCallback__replace(instance, name) {
if(instance != null)
instance[name] = null;
}
I got the solution.
try {
ytplayer.getIframe().src='';
} catch(ex) {
}
It's been over a months since I last needed to debug the project.
Facebook has now fixed this issue. The annoying pop-up no longer shows up.
I have not changed anything.

Resources