Scrolling in android using Appium + Ruby - android

I am trying to scroll through the android app to find a specific element. Below is the code for scrolling:
def self.swipe_to (programme)
begin
scroll_to(programme)
rescue
puts 'unable to find ' + programme
return false
end
return true
end
The scrolling works fine however, the issue is the app scrolls to the programme but as soon the programme is found, the app scrolls back to the top of the list.
And then an error is thrown saying element could not be found.
Has anybody seen similar kind of issue before? Is there any way to stop scrolling as soon as programme is found? I just want to stop the scrolling back to the top as soon as programme is found. Please help.

I created a method to scroll to an element that is not on screen yet, because scroll_to was not working for me. This methos scrolls to any element on screen even if its not visible yet
def scroll_to_element(class_name, element_name)
ele_by_json(typeArray: [class_name], onlyVisible: false, name: {target: element_name, substring: false, insensitive: false})
end

Below code worked for me :
def scrollTo el_start, el_end
#get element coordinates start
el_start = $driver.find_element(:id, el_start)
screen_x_start = el_start.location.x
screen_y_start = el_start.location.y
#get element coordinates end
el_end = $driver.find_element(:id, el_end)
screen_x_end = el_end.location.x
screen_y_end = el_end.location.y
Appium::TouchAction.new.swipe(start_x: screen_x_start, start_y: screen_y_start, delta_x: screen_x_end, delta_y: screen_y_end).perform
end

Related

Focus html page or element from a webview with talckback

I have an hybrid app developed with ionic 1.x. When the app loads I am forcing the webview to take the focus from native side with the hope that after some initialization request a survey dialog appear and take the focus it self(When dialog appear I am forcing it to take focus). I am trying to make it work with talkback
The problem is that when you load the app from scratch the dialog is not focused so it is not read, after navigate through the app and come back to the original page then in works as expected, looks like as the user is in fact inside the page things works ok.
Is there any workaround or strategy to solve this particular situation?
Thanks in advance
I don't know if it helps you,
but we use it to focus on specific elements in the web view.
it works in android and ios,
but in android, before every element it read webview.
(if you found a solution for it please let me know)
function putFocus(elementForFocus) {
var $element = $(elementForFocus);
var focusInterval = 10; // ms, time between function calls
var focusTotalRepetitions = 10; // number of repetitions
$element.attr('tabindex', '0');
$element.blur();
var focusRepetitions = 0;
var interval = window.setTimeout(function () {
$element.focus();
}, focusInterval);
};

On Android in Cucumber/Calabash, how do I test with a webview iframe?

I can locate an iframe in an Android webview, but I need to interact with it. Various pages suggest
query("webView css:'iframe'", :stringByEvaluatingJavaScriptFromString => '...')
but that results in "No such method found: stringByEvaluatingJavaScriptFromString([String])" and it looks like an iOS function, so I'm pretty sure this is an iOS-only solution: I need Android.
I know I can pass javascript queries in by opening them in a URL, but I've only experienced getting stuff out of an Android webview with specially-code Chrome objects linked in to the application.
Any ideas for getting data out?
The iOS responses are correct, you should use javascript to get the contents of an iframe. However, you should use evaluate_javascript(query_string, javascript) to evaluate javascript in Android. e.g
evaluate_javascript("webview", "return document.getElementsByTagName('iframe')[0].contentWindow.document.getElementById('...').getBoundingClientRect();")
Use the coordinates to tap the view.
If the rect is not parsed correctly, you could do something like this:
var boundingBox = document.getElementsByTagName('iframe')[0].contentWindow.document.getElementById('main').getBoundingClientRect();
var rect = {};
rect.width = boundingBox.width;
rect.height = boundingBox.height;
rect.left = boundingBox.left;
rect.top = boundingBox.top;
return rect;
Secondly, query('webView css:#grabby') is not a valid query. query('webView css:"#grabby"') or query("webView css:'#grabby'") is. You are most likely running a (very) old version of Calabash-Android if the test-server is crashing instead of reporting it.
I wrote what amounted to an answer while I was exploring, but I'm posting it here to save someone else time (hopefully).
I can successfully run Javascript in the view:
query("webView index:0", :loadUrl => 'javascript:alert("Hello")')
so I can probably arrange to press buttons plausibly enough for testing:
query("webview index:0", :loadUrl => 'javascript: ifr = document.getElementsByTagName("iframe")[0]; idoc = ifr.contentDocument || ifr.contentWindow.document; idoc.getElementById('myCheck').click(); false')
To get data out again, I can create a DIV and set its title (for example) with some 'return' value:
query("webView index:0", :loadUrl => 'javascript:var idiv = document.createElement("div"); idiv.id="grabby"; document.getElementsByTagName("body")[0].appendChild(idiv); idiv.title="some return value"; false')
(The trailing 'false' in the javascript: command is there to prevent the result of running the javascript: command from replacing the page - that took a while to work out.)
I can look into the iframe too:
query("webView index:0", :loadUrl => 'javascript:var idiv = document.getElementById("grabby"); ifr = document.getElementsByTagName("iframe")[0]; idoc = ifr.contentDocument || ifr.contentWindow.document; idiv.title = idoc.getElementsByTagName("input")[3].id; false')
When I tried to retrieve it with
query('webView css:#grabby')
it hung for a while, then crashed with a timeout:
HTTPClient::ReceiveTimeoutError: execution expired
from /Users/tim./.rvm/gems/ruby-2.1.5/gems/httpclient-2.6.0.1/lib/httpclient/session.rb:876:in `gets'
from /Users/tim./.rvm/gems/ruby-2.1.5/gems/httpclient-2.6.0.1/lib/httpclient/session.rb:876:in `block in parse_header'
from ...
curiously, query('webView css:"*"') mostly seems to work without timeouts, and reports the 'grabby' DIV complete with the title string
query('webView css:"*"').find { |e| e['id'] == 'grabby' }
so that's useful enough. I'll have to write some horrible recursive descent thingy to fish out the iframe's contents - perhaps make the div invisible and just copy the htmlContent there.
I'm really not sure why the direct query crashes.

.focus() after reloading page with jQuery in phoneGap

I'm trying to solve an issue with a phonegap app for Android.
I have a function like this one on a dinamic page
$(objLid).change(
function (e){
//Save data for reload
_prototype.saveFormData();
//reload call
reloadPage();
//first attempt to have the focus on the right obj
$(objLid).focus();
}
);
That's how it work:
The button have type "select-one" after the user select one of the element i save all the previous item on text field, then i call the reload function that add other field on the page.
On iOs without the .focus() call i have no problem but on Android after the reload the application automatically makes a scroll at the top of the page. I've tried:
$mobile.silentscroll(Y) //with Y as a given Y position
But it work as the focus, after the reload Android makes a scroll at the top. The same with setTimout hoping for a delayed effect but unsuccessfully:
setTimeout(function() {
$(objLid).focus();
}, 1000 );
There's an hack to this annoying "scroll"?
Thanks

Prevent body scrolling in Chrome on Android doens't work and generated error message

I'm trying to prevent scrolling of the body content when reaching the end of the scrollable content in a fixed div.
It was working really well in iOS, and still is, and well enough in Chrome on Android.
But when we did some testing a few days ago, suddenly it worked really bad in Chrome. It might be related to the release of Chrome 36 on the 14 of august.
When reaching the bottom of the fixed div, and I'll continue to "scroll" without stopping or lifting my finger, the body starts to scroll, even though it should be prevented by my script, and generated the following error message:
Ignored attempt to cancel a touchmove event with cancelable=false, for
example because scrolling is in progress and cannot be interrupted.
Is there anyway around this? Or some other trick I can use?
The following code is used:
var scrolling = false,
ts = null;
$('body').on('touchstart.scrollable', '.a', function(e) {
// Only execute the below code once at a time
if (!scrolling) {
scrolling = true;
if (e.currentTarget.scrollTop === 0) {
e.currentTarget.scrollTop = 1;
} else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
e.currentTarget.scrollTop -= 1;
}
scrolling = false;
}
ts = e.originalEvent.touches[0].clientY;
});
$('body').on('touchmove.scrollable', '.a', function(e) {
//If there is no scrollabe content we disable default event
var te = e.originalEvent.changedTouches[0].clientY,
direction = ts > te ? 'down' : 'up';
$container = $('.a');
$content = $('.b');
if ($content.height() <= $container.height()) {
e.preventDefault();
console.log('Default prevented');
} else if ($container.scrollTop() <= 1 && direction == 'up') {
e.preventDefault();
console.log('Default prevented');
} else if ($container.scrollTop() > 0 && ($container.scrollTop() + $container.height() >= $content.height() - 1) && direction == 'down') {
e.preventDefault();
console.log('Default prevented');
}
/* Keep from bubbling */
e.stopPropagation();
});
Please see the following example for complete source and to test:
Link to JSBin (They seems to expire after 24 hours) Please press File -> Clone if that has happend, and then view in fullscreen)
Thanks!
I had this issue recently on android. very frustrating, especially as the debug affects what happens.
In the end, I ended up putting a transparent div over the scrollable div and writing my own touch handlers on it that passed down the delta between the touchstart and touchmove event Y position to the scrollTop() function of the scrollable div (using jquery). This allowed me complete control of the scroll.
I thought I had it all worked out, then it stopped working again.
I added a wrapper around the menu with overflow-y: scroll and 10000px height.
Since the scroll bubbles I assumed it was gonna bubble to my wrapper and catch the scrolling there. But no, it goes straight to body and scrolls it. Even though it has static height to reflect the screen height and overflow: hidden!important.
It was however working when I had the wrapper selected in the DOM tree while debugging in Chrome. I no longer receive the error message when it's selected either.
It also works if you first scroll fast, let go, and let the scroll bubble to the body and continue scrolling until it stops by it self. Next time I scroll the prevent-method works and I don't receive the error message
I have no idea what the fudge is going on...
Calling preventDefault on touchmove while you are scrolling is not working in Chrome. To prevent performance issues, you cannot interrupt a scroll.
Try to call preventDefault() from touchstart and everything should be ok.

The click event is made but it isn't showed in the screen

I'm making a mobile application with phonegap and jquery mobile. Everytime I select one of the menu elements I call to a WS that gives me an answer that I show in the screen. It works perfectly up to there.
As I want to have a better view so I use the code trigger ('create'). (http://jquerymobile.com/demos/1.0a4.1/docs/forms/forms-checkboxes.html but insted of refresh I have to make an create)
var listadohtml = '<div data-role="fieldcontain"><fieldset data-role="controlgroup">';
for (var i=0;i<resultado.length;i++){
var item = '';
var id = resultado[i]['id'];
item += '<input type="checkbox" name="checkbox-'+id+'" id="checkbox-'+id+'" class="custom" />';
item += '<label for="checkbox-'+id+'">'+resultado[i]["title"]+'</label>';
listadohtml += item;
}
listadohtml += '</fieldset></div>';
$('#listaPreguntas').html(listadohtml).trigger('create');
Inmediatly after that I associate an event:
$("#listaPreguntas input[type='checkbox']").bind( "click", function(event, ui) {... some code ...});
It shows everything fine, but the problem is that sometimes (not always, that's the problem) when I click a checkbox the green tick is not shown but the event change is made. When it happens I can see, by clicking in other part of the screen, that I have clicked before because it refreshes and shows the tick.
The conclussions I have
It is not the AVD because im making all the tests in my mobile phone with android 4.0.
It appears that its something of the code that includes jquery mobile when I use de trigger.
I think it is not loading time because I can wait for years and it can happens.
As you can see its not a "logic" problem but a usability one.
Thanks in advance!
For checkbox and radio, use change event not click. And keep in mind that attaching events to dynamic elements is different, I have updated my answer accordingly.
Demo
$(document).on('change', '[type=checkbox]', function () {
// code here
});
If the event click fires every time as expected then try to set the check box checked/unchecked classes using addClass and removeClass in your code pragmatically rather than relying on the JQM.

Categories

Resources