Appium Ruby - Can't Scroll To Accessibility_ID - android

http://appium.io/docs/en/commands/interactions/touch/scroll/
I want to scroll to an element. I keep getting an error. Fix may be simple but I'm totally lost.
Error: "undefined method `scroll' for #<Appium::TouchAction:0x000055d15d31c980> (NoMethodError)"
I am on:
Linux Mint
Ruby version 2.5.1p57
touch_action gem (1.3.3)
appium_lib gem (10.6.0)
appium_lib_core gem (3.7.0)
Below is my code.
require 'appium_lib'
require 'touch_action'
#require 'selenium-webdriver'
server_url = "http://127.0.0.1:4723/wd/hub"
opts = {
caps: {
platformName: :Android,
platformVersion: 9,
deviceName: :'Android Emulator',
app: 'TheApp-v1.9.0.apk',
newCommandTimeout: 600,
automationName: :Appium,
javascript_enabled: true
}
}
driver = Appium::Driver.new(opts, true)
driver.start_driver
ta = Appium::TouchAction.new.driver
sleep 5
scroll1 = ta.scroll_to(:accessibility_id, "Verify Phone Number")
scroll1.perform
sleep 2
print "Completed Successfully!"
driver.driver_quit

scroll_to has historically been flaky in Ruby Appium. I'd suggest writing your own logic similar to the following:
ta = Appium::TouchAction.new.driver
swipeUp = ta.swipe(startX, startY, endX, endY, duration)
clicked = false
(0...times).each do
swipeUp.perform
unless verifyPhoneNumber.isDisplayed
verifyPhoneNumber.click
clicked = true
end
break if clicked == true
end
My Ruby and Appium are a bit rusty; apologies if there are any errors above, but you should get the gist.
For reusability, I'd probably create a function with this logic that returns the element you were attempting to scroll to.

Following Worked for me (solution is for Ruby+Appium+Android)
require 'rubygems'
require 'appium_lib'
desired_caps = {
"appium:deviceName": "055542505S003131",
"platformName": "android",
"appium:appPackage": "app.endometriose.android",
"appium:noReset": true,
"automationName": "UiAutomator2",
"appium:appActivity": "host.exp.exponent.MainActivity",
"app": "/users/user/myApp.apk"
}
appium_driver = Appium::Driver.new({'caps' => desired_caps, }, true)
# Scroll
appium_driver.scroll_to("Button")
**Note:** scroll_to methods takes visible text of the element and scroll to it.

Related

Flutter: How to detect that the app is running on LD Player

I am working in a Flutter app with some security requirements, one of them is to prevent the app from working in Emulators, just real devices, in order to prevent the screenshots and screen recordings from the Emulators.
I have used safe_device and device_info_plus packages to detect whether the app is running on Emulator or Physical device and every thing is working fine but when I tried LD Player Emulator the packages failed to detect that it is emulator because it is very good at mocking the real device.
So any ideas to detect that the device is running on LD Player?
Here is the output from device_info_plus which might be helpful:
{
"id": "N2G48B",
"host": "ubuntu",
"tags": "release-keys",
"type": "user",
"model": "ASUS_Z01QD",
"board": "SM-G975N",
"brand": "asus",
"device": "aosp",
"product": "SM-G975N",
"display": "N2G48B",
"hardware": "android_x86",
"androidId": null,
"bootloader": "unknown",
"version": {
"baseOS": "",
"sdkInt": 25,
"release": "7.1.2",
"codename": "REL",
"incremental": "V9.5.8.0.OCACNFA",
"previewSdkInt": 0,
"securityPatch": "2017-10-05"
},
"fingerprint": "google/android_x86/x86:7.1.2/N2G48B/V9.5.8.0.OCACNFA:user/release-keys",
"manufacturer": "asus",
"supportedAbis": [
"x86",
"armeabi-v7a",
"armeabi"
],
"systemFeatures": [
"android.hardware.sensor.proximity",
"android.hardware.sensor.accelerometer",
"android.software.controls",
"android.hardware.faketouch",
"android.hardware.usb.accessory",
"android.software.backup",
"android.hardware.touchscreen",
"android.hardware.touchscreen.multitouch",
"android.software.print",
"android.hardware.ethernet",
"android.software.activities_on_secondary_displays",
"android.hardware.wifi.rtt",
"com.google.android.feature.PIXEL_2017_EXPERIENCE",
"android.software.voice_recognizers",
"com.google.lens.feature.CAMERA_INTEGRATION",
"android.software.picture_in_picture",
"android.hardware.fingerprint",
"android.hardware.sensor.gyroscope",
"android.hardware.audio.low_latency",
"android.software.vulkan.deqp.level",
"com.google.android.feature.PIXEL_2018_EXPERIENCE",
"android.hardware.opengles.aep",
"android.hardware.bluetooth",
"android.hardware.camera.autofocus",
"com.google.android.feature.GOOGLE_BUILD",
"android.hardware.telephony.gsm",
"android.hardware.telephony.ims",
"android.software.sip.voip",
"android.hardware.vr.high_performance",
"android.hardware.usb.host",
"android.hardware.audio.output",
"android.software.verified_boot",
"android.hardware.camera.flash",
"android.hardware.camera.front",
"android.hardware.sensor.hifi_sensors",
"android.hardware.se.omapi.uicc",
"android.hardware.screen.portrait",
"android.hardware.nfc",
"com.google.android.feature.TURBO_PRELOAD",
"android.hardware.sensor.ambient_temperature",
"com.nxp.mifare",
"android.hardware.sensor.stepdetector",
"android.software.home_screen",
"android.hardware.microphone",
"android.software.autofill",
"android.software.securely_removes_users",
"android.software.vr.mode",
"com.google.android.feature.PIXEL_EXPERIENCE",
"android.hardware.bluetooth_le",
"android.hardware.sensor.compass",
"android.hardware.touchscreen.multitouch.jazzhand",
"android.hardware.sensor.barometer",
"android.software.app_widgets",
"android.software.input_methods",
"android.hardware.sensor.light",
"android.hardware.vulkan.version",
"android.software.companion_device_setup",
"android.software.device_admin",
"com.google.android.feature.WELLBEING",
"android.hardware.wifi.passpoint",
"android.hardware.camera",
"com.google.android.feature.ZERO_TOUCH",
"android.hardware.screen.landscape",
"android.software.device_id_attestation",
"android.hardware.ram.normal",
"android.software.managed_users",
"android.software.webview",
"android.hardware.sensor.stepcounter",
"android.hardware.camera.capability.manual_post_processing",
"com.google.ar.core.depth",
"android.hardware.camera.any",
"android.hardware.camera.capability.raw",
"android.software.connectionservice",
"android.hardware.touchscreen.multitouch.distinct",
"android.hardware.location.network",
"android.software.cts",
"android.software.sip",
"android.hardware.camera.capability.manual_sensor",
"android.software.app_enumeration",
"com.google.android.apps.dialer.SUPPORTED",
"android.hardware.camera.level.full",
"android.hardware.wifi.direct",
"android.software.live_wallpaper",
"com.google.android.feature.GOOGLE_EXPERIENCE",
"android.software.ipsec_tunnels",
"com.google.android.feature.EXCHANGE_6_2",
"android.software.freeform_window_management",
"android.hardware.audio.pro",
"android.hardware.nfc.hcef",
"android.hardware.location.gps",
"android.software.midi",
"android.hardware.nfc.any",
"android.hardware.nfc.hce",
"android.hardware.wifi",
"android.hardware.location",
"android.hardware.vulkan.level",
"android.hardware.wifi.aware",
"android.software.secure_lock_screen",
"android.hardware.telephony",
"android.software.file_based_encryption",
null
],
"isPhysicalDevice": true,
"supported32BitAbis": [
"x86",
"armeabi-v7a",
"armeabi"
],
"supported64BitAbis": []
}
The solution is to check for the existence of these folders, if any of them exists, then it is an LD Player.
'/storage/emulated/0/storage/secure',
'/storage/emulated/0/Android/data/com.android.ld.appstore'
I have implemented a method to take a list of folders paths and return true if any of them exists, which is the following:
bool anyFolderExists(List<String> foldersPaths) {
for (String folderPath in foldersPaths) {
if (Directory(folderPath).existsSync()) {
return true;
}
}
return false;
}
and I'm using it like this:
List<String> harmfulFoldersPaths = [
'/storage/emulated/0/storage/secure',
'/storage/emulated/0/Android/data/com.android.ld.appstore',
];
if(anyFolderExists(harmfulFoldersPaths))
{
print('LD Player Detected!');
}
Also I am using these two values from the output of device_info_plus package to decide that the app is working on an Emulator because they seems very generic:
"host": "ubuntu",
"device": "aosp",
I am using them like the following:
final androidInfo = await deviceInfoPlugin.androidInfo;
if (androidInfo.host == 'ubuntu' && androidInfo.device == 'aosp') {
print('LD Player Detected!');
}
But to be honest, I am afraid of this approach because I do not want to block any user by mistake, so I am using them with Firebase Remote Config to enable/disable it at any time but until now I am enabling them without any problem recorded.
Check this Package
https://pub.dev/packages/safe_device
bool isRealDevice = await SafeDevice.isRealDevice;
this method returns false if running device is an emulator

Adding Back Tracks Does Not Work on WebRTC

We create an app with React Native WebRTC and Janus Gateway. It works as wanted. Our app is based on push to talk. So when an users in listen mode need to break microphone for other apps. And take back when anyone press to speak button.
Breaking Mic:
if (!globalTrack) {
globalTracks = config.myStream.getTracks();
}
config.myStream.getTracks().forEach(t => {
config.myStream.removeTrack(t);
});
Get Back the Tracks:
globalTracks.forEach(t => {
config.myStream.addTrack(t);
});
pluginHandle.createOffer({
media: { addVideo: true },
success: function(jsep) {
Janus.debug(jsep);
pluginHandle.send({message: {audio: true, video: false}, "jsep": jsep });
},
error: function(error) {
console.log("WebRTC error... " + JSON.stringify(error));
}
});
// also I have try this:
devices = await mediaDevices.getUserMedia({audio: true, video: false})
// devices output https://pastebin.ubuntu.com/p/KQqBq2QRy3/
devices._tracks.forEach(t => {
config.myStream.addTrack(t);
});
pluginHandle.createOffer({
media: {audio: {deviceId: devices._tracks[0]['id']}, replaceAudio: true},
success: function(jsep) {
pluginHandle.send({message: {audio: true, video: false}, "jsep": jsep});
},
error: function(error) {
console.log(("WebRTC error... " + JSON.stringify(error));
}
});
Problem:
Problem: E.g: when a call came to the phone and answered it. The user's voice does not pass anymore even after restarting the app.
On Janus Gateway every things is normal. I think problem is about renegotiation.
Problem occurred only on Android phones. And works after force stopping the app.
Janus Gateway Log which when I speak at room:
There's a message for JANUS AudioBridge plugin
Setting muted property: true (room 20, user 2301490876606211)
Notifying participant 329012611897879 (kardan)
Sending event to transport...
>> 0 (Success)
We can not find a generic solution.
For now restarting app is works with react-native-restart

(Appium-Jasmine) How to ignore splash screen or wait until finished

I'm trying to test a Cordova hybrid app with Appium. I have setup the environment and I can launch a test. But if I try to find a element, I have an error because the app lauch the splash screen. I'm using cordova-splash-screen plugin and I'm hidding it manually in my index.js.
This is my package.json:
"appium": "appium",
"appium-doctor": "appium-doctor",
"test:android": "wdio ./config/wdio.android.conf.js",
My wdio.shared.conf.js:
exports.config = {
// ====================
// Runner and framework
// Configuration
// ====================
runner: 'local',
framework: 'jasmine',
jasmineNodeOpts: {
// Updated the timeout to 30 seconds due to possible longer appium calls
// When using XPATH
defaultTimeoutInterval: 90000
},
sync: true,
logLevel: 'error',
deprecationWarnings: true,
bail: 0,
waitforTimeout: 10000,
connectionRetryTimeout: 90000,
connectionRetryCount: 3,
reporters: ['spec'],
// ====================
// Appium Configuration
// ====================
services: ['appium'],
appium: {
// For options see
// https://github.com/webdriverio/webdriverio/tree/master/packages/wdio-appium-service
args: {
// For arguments see
// https://github.com/webdriverio/webdriverio/tree/master/packages/wdio-appium-service
},
// Esto sirve para que coja la versiĆ³n local de appium y no la global
command: 'appium'
},
port: 4723,
// ====================
// Some hooks
// ====================
beforeSession: (config, capabilities, specs) => {
require('#babel/register');
}
};
My wdio.android.conf.js:
const {config} = require('./wdio.shared.conf');
// ============
// Specs
// ============
config.specs = [
'./test/specs/*.js'
];
// ============
// Capabilities
// ============
// For all capabilities please check
// http://appium.io/docs/en/writing-running-appium/caps/#general-capabilities
config.capabilities = [
{
// The defaults you need to have in your config
platformName: 'Android',
maxInstances: 1,
// For W3C the appium capabilities need to have an extension prefix
// http://appium.io/docs/en/writing-running-appium/caps/
// This is `appium:` for all Appium Capabilities which can be found here
deviceName: 'any',
platformVersion: '8.0',
orientation: 'PORTRAIT',
// `automationName` will be mandatory, see
// https://github.com/appium/appium/releases/tag/v1.13.0
automationName: 'appium',
appPackage: 'com.nss.ExacctaPrototype',
appActivity: '.MainActivity',
// The path to the app
app: './cordova/platforms/android/app/build/outputs/apk/debug/app-debug.apk',
// Read the reset strategies very well, they differ per platform, see
// http://appium.io/docs/en/writing-running-appium/other/reset-strategies/
noReset: true,
newCommandTimeout: 240
}
];
exports.config = config;
I was trying to setup a wait in the wdio.shared.conf.js but the test script is launched when the splash is showd anyways.
Have someone solved this issue?

Android - PWA does not open in standalone mode with service worker

While developing a Progressive-Web-App the following Problem occurred:
Standalone mode works perfectly without including the service worker - but does NOT work with.
Without Service-Worker a2hs (added to Homescreen) PWA gets correctly started in "standalone"-Mode.
After adding the Service-Worker (a2hs + installed / Web-APK) PWA opens new Tab in new Chrome-Window.
Chrome-PWA-Audit:
login_mobile_tablet.jsf / include service worker:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../serviceWorker.js', {scope: "/application/"})
/* also tried ".", "/", "./" as scope value */
.then(function(registration) {
console.log('Service worker registration successful, scope is: ', registration.scope);
})
.catch(function(error) {
console.log('Service worker registration failed, error: ', error);
});
}
</script>
serviceWorker.js:
var cacheName = 'pwa-cache';
// A list of local resources we always want to be cached.
var filesToCache = [
'QS1.xhtml',
'pdf.xhtml',
'QS1.jsf',
'pdf.jsf',
'login_pages/login_mobile_tablet.jsf',
'login_pages/login_mobile_tablet.xhtml'
];
// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll(filesToCache);
})
);
})
// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
// The fetch handler serves responses for same-origin resources from a cache.
self.addEventListener('fetch', event => {
// Workaround for error:
// TypeError: Failed to execute 'fetch' on 'ServiceWorkerGlobalScope': 'only-if-cached' can be set only with 'same-origin' mode
// see: https://stackoverflow.com/questions/48463483/what-causes-a-failed-to-execute-fetch-on-serviceworkerglobalscope-only-if
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin')
return;
event.respondWith(
caches.match(event.request, {ignoreSearch: true})
.then(response => {
return response || fetch(event.request);
})
);
});
manifest.json:
{
"name":"[Hidden]",
"short_name":"[Hidden]",
"start_url":"/application/login_pages/login_mobile_tablet.jsf",
"scope":".",
"display":"standalone",
"background_color":"#4688B8",
"theme_color":"#4688B8",
"orientation":"landscape",
"icons":[
{
"src":"javax.faces.resource/images/icons/qsc_128.png.jsf",
"sizes":"128x128",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_144.png.jsf",
"sizes":"144x144",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_152.png.jsf",
"sizes":"152x152",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_192.png.jsf",
"sizes":"192x192",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_256.png.jsf",
"sizes":"256x256",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_512.png.jsf",
"sizes":"512x512",
"type":"image/png"
}
]
}
The following questions / answers were considered - but no solution was found:
PWA wont open in standalone mode on android
WebAPK ignores display:standalone flag for PWA running on local network
PWA deployed in node.js running in Standalone mode on Android and iOS
Technical Background
The Moment you add your Service-Worker (along all other PWA-Requirements) your App gets created as an Real PWA - with Web-APK getting installed.
Therefore you also need to use Default-HTTPS-Port 443 - make sure you use a valid HTTPS-Certificate.
Before adding the Service-Worker, this mandatory requirement was missing so your PWA was NOT installed and therefore needed less other requirements to be displayed in "standalone-mode".
It's just a shame that this is nowhere documented... and we had to "find out" for ourselves.
Short-List of Mandatory Requirements for "Installable Web-APK":
(As we could not find a full List, i try to include all Points)
Registered Service-Worker (default-implementation like yours is enough)
manifest.json (yours is valid)
https with valid certificate
https default-port (443, eg. https://yourdomain.com/test/)
... for the rest just check chrome audit tool (HINT: you don't need to pass all requirements - your web-apk should work when switching to https-default-port)

app cache doesn't work in the android device (works well on the chrome browser)

I'm trying to use app cache to approve the performance.
I have been guided in various sites. (ex. http://xguru.net/621 ... )
make cache.man file, set mime-type as text/cache-manifest.
Problem is...
it works well at the Google chrome browser, but does not work in my android phone.
I tested at ICS and Gingerbread.
This is manifest file .
CACHE MANIFEST
# manifest version v0.1
CACHE:
./programs.png
./video.png
NETWORK:
*
and then, I set my webview like this.
getSettings().setAppCacheEnabled(true);
getSettings().setDomStorageEnabled(true);
getSettings().setPluginsEnabled(true);
getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
(I changed the cacheMode to LOAD_NORMAL, NO_CACHE, but it's not different.)
To see the cache state, I use this site.
http://jonathanstark.com/blog/2009/09/27/debugging-html-5-offline-application-cache/
var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';
var cache = window.applicationCache;
cache.addEventListener('cached', logEvent, false);
cache.addEventListener('checking', logEvent, false);
cache.addEventListener('downloading', logEvent, false);
cache.addEventListener('error', logEvent, false);
cache.addEventListener('noupdate', logEvent, false);
cache.addEventListener('obsolete', logEvent, false);
cache.addEventListener('progress', logEvent, false);
cache.addEventListener('updateready', logEvent, false);
function logEvent(e) {
var online, status, type, message;
online = (navigator.onLine) ? 'yes' : 'no';
status = cacheStatusValues[cache.status];
type = e.type;
message = 'online: ' + online;
message+= ', event: ' + type;
message+= ', status: ' + status;
if (type == 'error' && navigator.onLine) {
message+= ' (prolly a syntax error in manifest)';
}
console.log(message);
}
window.applicationCache.addEventListener(
'updateready',
function(){
window.applicationCache.swapCache();
console.log('swap cache has been called');
},
false
);
Lastly, This is the log I see on my android phone.
[cache Resource] app cache support!
[cache Resource] DOWNLOADING
[cache Resource] event online: yes, event: checking, status: uncached
[cache Resource] event online: yes, event: downloading, status: uncached
[cache Resource] event online: yes, event: progress, status: uncached
[cache Resource] event online: yes, event: progress, status: uncached
[cache Resource] event online: yes, event: error, status: uncached (prolly a syntax error in manifest)
Images are downloaded but we get the error at last line.
So it is always in a uncached.
I guess the problem is on the webview setting or android application.
But i cannot handle it.
give me a tip to use app cache.. plz...
Indirectly the answer linked by yugidroid led me to the right line. The blog which is linked in the answer shows what to do:
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webView.getSettings().setAppCachePath(appCachePath);
I removed those lines again for testing: same error - readded: no error!

Categories

Resources