Android Mobile testing with Appium Selenium C# - android

I have tried a lot of different stuff from the google and you-tube and this is where i land and i cannot get it to work, my connection to the Appium and emulator is fine also i have checked the adb devices everything is fine.
I am getting error for the Line driver = new AndroidDriver<IWebElement>(new Uri("http://127.0.0.1:4723/wd/hub"), cap, TimeSpan.FromSeconds(180));
These are the two errors which i get:
"cannot convert from 'System.Uri' to 'OpenQA.Selenium.Appium.Service.AppiumServiceBuilder'"
and
"cannot convert from 'OpenQA.Selenium.Remote.DesiredCapabilities' to 'OpenQA.Selenium.DriverOptions".
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Appium.Enums;
using OpenQA.Selenium.Appium.Android;
namespace UnitTestProject4
{
[TestClass]
public class UnitTest1
{
AppiumDriver<IWebElement> driver;
[TestMethod]
public void TestMethod1()
{
DesiredCapabilities cap = new DesiredCapabilities();
cap.SetCapability("deviceName", "Pixel 3a Pie 9.0 - API 28");
cap.SetCapability("platformVersion", "9.0");
cap.SetCapability("udid", "emulator-5554");
cap.SetCapability("appPackage", "org.mozilla.firefox");
cap.SetCapability("appActivity", "org.mozilla.gecko.BrowserApp");
cap.SetCapability("platformName", "Android");
driver = new AndroidDriver<IWebElement>(new Uri("http://127.0.0.1:4723/wd/hub"), cap, TimeSpan.FromSeconds(180));
driver.Navigate().GoToUrl("https://www.google.com");
}
}
}

You are very close, but I would make a few small tweaks. Your error messages are complaining about two things -- the use of DesiredCapabilities instead of AppiumOptions, and the use of new Uri("http://127.0.0.1:4723/wd/hub") as a parameter for AndroidDriver<IWebElement>.
To solve these issues -- instead of DesiredCapabilities, I initialize my AndroidDriver with AppiumOptions. Additionally, you should try starting Appium through AppiumServiceBuilder() and use that service to start your driver session. You should also specify a parameter for automationName.
Here's what I always use to start a new mobile session on Android with C#:
// start appium service
var builder = new AppiumServiceBuilder();
var appiumLocalService = builder.UsingAnyFreePort().Build();
appiumLocalService.Start();
// create appium driver capabilities
var options = new AppiumOptions { PlatformName = "Android" };
options.AddAdditionalCapability("deviceName", "Pixel 3a Pie 9.0 - API 28");
// add app or appPackage / appActivity depending on preference
options.AddAdditionalCapability("appPackage", "org.mozilla.firefox");
options.AddAdditionalCapability("appActivity", "org.mozilla.gecko.BrowserApp");
options.AddAdditionalCapability("udid", "emulator-5554");
options.AddAdditionalCapability("automationName", "UiAutomator2"); // this one is important
// these are optional, but I find them to be helpful -- see DesiredCapabilities Appium docs to learn more
options.AddAdditionalCapability("autoGrantPermissions", true);
options.AddAdditionalCapability("allowSessionOverride", true);
// start the driver
var driver = new AndroidDriver<IWebElement>(appiumLocalService.ServiceUrl, options);

Related

Streaming mp3 in Xamarin Android MediaManager not working

I'm using this nu-get package to stream mp3 url in a Xamarin Android project:
https://github.com/martijn00/XamarinMediaManager
I followed the instructions in the link up there... and it shows the music playing in the notification bar but it is not working (no sound and it's not even starting the song).
Code snippet:
clickButton.Click += (sender, args) =>
{
ClickButtonEvent();
};
private static async void ClickButtonEvent()
{
await CrossMediaManager.Current.Play("http://www.montemagno.com/sample.mp3");
}
I built the sample included in the link, and I got the same result from their sample. Also deployed on real device too, same result!
Image:
Am I missing something ?
Or is the library broken ?
I ran into this using Android Emulator on Hyper-v. It turns out that the network is set to internal. So the http://www.montemagno.com/sample.mp3 could not be found. My workaround:
Hyper-v -> Virtual Switch Manager, add an external network.
Hyper-v -> Virtual Machines->Settings, add new hardware->Network adapter and set to external network.
"Visual Studio Emulator for Android" desktop app, launch phone vm,
in Visual Studio, deploy and run app.
Sound should work from external source now.
Permissions maybe? In the project site it states that for Android:
You must request AccessWifiState, Internet, MediaContentControl and
WakeLock permissions
By default example use ExoPlayerAudioService.
There are issue with url escape in ExoPlayerAudioService.GetSource method
private IMediaSource GetSource(string url)
{
string escapedUrl = Uri.EscapeDataString(url);
var uri = Android.Net.Uri.Parse(escapedUrl);
var factory = URLUtil.IsHttpUrl(escapedUrl) || URLUtil.IsHttpsUrl(escapedUrl) ? GetHttpFactory() : new FileDataSourceFactory();
var extractorFactory = new DefaultExtractorsFactory();
return new ExtractorMediaSource(uri
, factory
, extractorFactory, null, this);
}
string escapedUrl = Uri.EscapeDataString(url);
I.E. http://example.com/path_to_audio.mp3 will be escaped to "http%3A%2F%2Fexample.com%2Fpath_to_audio.mp3" as result HTTP error.
To fix just skip url escape.

Api calls in the app is not able to be debugged in Charles/Fiddler (Bypassing proxy)

My App is developed using Xamarin.Android. When I try to do API debugging using Charles, I am not able to see the APIs in Charles. But I can see APIs of the other Apps installed in my device.
I have set the proxy in the android device taking IP from my system.
Here is the code which I have used in the PCL code, which is used for both IOS and Android.
return new HttpClient(new AuthenticatedHttpClientHandler(new NativeMessageHandler()))
{
BaseAddress = new Uri(baseUrl),
Timeout = new TimeSpan(0, 0, timeout)
};
public class AuthenticatedHttpClientHandler : DelegatingHandler
{
public AuthenticatedHttpClientHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//------
}
}
This is common code written in PCL.
In IOS APIs are not getting bypassed from the proxy and able to track it in Charles.
The Mono HttpClient isn't using the proxy settings. Configure your app to use the native ClientHandler.
https://developer.xamarin.com/releases/android/xamarin.android_6/xamarin.android_6.1/#Native_HttpClientHandler
add a file to your project
insert XA_HTTP_CLIENT_HANDLER_TYPE=Xamarin.Android.Net.AndroidClientHandler
set Build Action to AndroidEnvironment
or create your HttpClient like:
var client = new HttpClient (new Xamarin.Android.Net.AndroidClientHandler ());

sendkeys not working properly in Appium RemotewebDriver

I am using Appium 1.4.16 to automate apk file stored in my system in real android device. I am using java-client 3.4.1
Here is the code:
public static void main(String[] args) {
File app = new File("C:\\Users\\dell\\Downloads\\App.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("device", " Android");
//mandatory capabilities
capabilities.setCapability("deviceName","Android");
capabilities.setCapability("platformName","Android");
capabilities.setCapability("udid", "849e82c6");
capabilities.setCapability("app",app.getAbsolutePath());
capabilities.setCapability("appPackage", "xxxxxxxxxxx");
capabilities.setCapability("appActivity", "xxxxxxxxxx.MainActivity");
try{
RemoteWebDriver driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);
System.out.println("Device Started");
driver.manage().timeouts().implicitlyWait(25, TimeUnit.SECONDS);
RemoteWebElement number = (RemoteWebElement)driver.findElement(By.xpath("//android.widget.EditText[#resource-id='xxxx' and #content-desc = 'Mobile Number']"));
number.sendKeys("90002");
RemoteWebElement passwordKey = (RemoteWebElement)driver.findElement(By.xpath("//android.widget.EditText[#resource-id='yyyyy']"));
passwordKey.sendKeys("ezr123");
RemoteWebElement loginButton = (RemoteWebElement)driver.findElement(By.xpath("//android.view.View[#resource-id='ezm_submit_login_form']"));
loginButton.click();
}catch(Exception e){
e.printStackTrace();
}
}
}
I am not getting any error in Appium server but facing strange actions in UI.
While entering value in username field, it automatically clicks on Login Button then again enters value in password field. Here, it always starts with entering '2' in the field and ends with 8-digit password.But my supplied password is 6-digit long.Then nothing happens.
I have also tried giving Thread.sleep() between each action.But no change is observed.
Best solution is to tap on the element first using the xpath or Id, then type on the element , this is fail proof and will work
U can also give timeout after tap and also hide keyboard by pressing key value for back (4)
Or hide keyboard command

Could not start a website in android emulator with capybara, appium, ruby

I try to open a website in chrome and native android browser (emulated Android 5.0 and 6) to check several items.
every time i run the test, the choosen browser get started and in the url field stays 'data:,' btw the actual tab is also loaded two times.
I know there is a way to do this with selenium webdriver, but this is not the right way for me because i used the followed code for several emulated devices to test this website and on iOS/Mac osx its working.
So why not on android. My way to test this website is with capybara, appium and ruby.
on iOS there exists a
:safariInitialUrl =>'http://www.mypage.com'
cap.
but not for android.
So, my question is: how is it possible to start my website on an emulated android devices without using selenium webdriver.
code:
Capybara.register_driver :androidphone do |app|
capabilities = {
:deviceName => 'nex5_5',
:avd => 'nex5_5',
:browserName => 'Chrome',
:platformVersion => '5.0',
:platformName => 'Android',
:automationName => 'Appium',
}
url = "http://localhost:4723/wd/hub"
appium_lib_options = {
server_url: url
}
all_options = {
appium_lib: appium_lib_options,
caps: capabilities,
}
Appium::Capybara::Driver.new app, all_options
You have to add this line in your config file :
exports.config = {
directConnect:false,
}
I think you have also to add the Timeout in your configuration file, if you are using jasmine framework for example add this code :
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}

Protractor's waitForAngular() fails on angular-webapp (appium/chrome on real device)

I'm (newly) using protractor to run e2e cucumber tests.
I got a web-app which is angularJS based. I'm using appium to remotely run the test on a real android device. Here are the versions i'm using :
windows8.1
protractor#1.3.1 (with submodule selenium-webdriver#2.43.5)
appium#1.3.0beta1
android device with 4.4.4
my protractor configuration (extracts), corresponding to https://github.com/angular/protractor/blob/master/docs/browser-setup.md:
currentDeviceUDID = (...);
var appToTestURL = 'http://my.website.com:9000/app/index.html';
exports.config = {
seleniumAddress: 'http://localhost:4723/wd/hub';
chromeOnly: false,
specs: ['features/sample.feature'],
capabilities: {
browserName: 'chrome',
'appium-version': '1.0',
platformName: 'Android',
platformVersion: '4.4.4',
udid: currentDeviceUDID
},
baseUrl: appToTestURL
framework: 'cucumber',
cucumberOpts: {
require: 'features/stepDefinitionsSample.js',
tags: '#dev',
format: 'progress'
},
// configuring wd in onPrepare
onPrepare: function () {
var wd = require('wd'),
protractor = require('protractor'),
wdBridge = require('wd-bridge')(protractor, wd);
wdBridge.initFromProtractor(exports.config);
},
allScriptsTimeout: 30000,
getPageTimeout: 30000
};
As you can see, i have replaced the protractor's webdriver url with the appium webdriver. i start the appium from commandline with "appium &", then i run the test with "protactor cucumbertest.conf"
The phone opens chrome browser and navigates to the url i give it with "browser.get(url)"
the problem is the following:
the call waitForAngular(), which is asynchronously waiting for the website to load and on all open http request (as far as i understand), is not executed sucessfully on the phone. the phone does not react to the call, and the webdriver proxy returns a 500.
Corresponding to https://github.com/angular/protractor/issues/1358, i understood that the waitForAngular() function is mixed in protractor into the calls
['getCurrentUrl', 'getPageSource', 'getTitle'];
Behind waitForAngular() in the file protractor.js is the function below, which is proxied to the phone:
functions.waitForAngular = function(selector, callback) {
var el = document.querySelector(selector);
try {
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (e) {
callback(e);
}
};
Additional information: when i stimulate an error on the webdriver (browser) object, the error message points to the chromedriver.exe inside the protractor directory. i dont understand why the error is not from appium's chromedriver
so tldr;
without the successful call waitForAngular, i cannot (stable or at all) access elements on the page on the phone, so not testing. maybe im misunderstanding some fundamental configuration detail here, all hints are welcome.
edit: added appium server logs here: http://pastebin.com/vqBGUdXH
I assume i have identified the problem. Appium and Protractor work fine.
My angularJS app causes the issue. It uses $timeout for polling (im forced on angular 1.07 which has no $interval). This causes protractor to expect the page to be still in the loading stage and not finished. Therefore the function call waitForAngular() never returns and the test timeouts after the specified timeout-timespan.
This behaviour is expected and known, also documented (better read doc first ;) ) at http://angular.github.io/protractor/#/timeouts
The doc suggests the following for continuous polling: replace $timeout with $interval:
If your application continuously polls $timeout or $http, it will never be registered as completely loaded. You should use the $interval service (interval.js) for anything that polls continuously (introduced in Angular 1.2rc3).
For now, i fixed the issue another way: disable the built-in angular sync and manually sync
this.Before(function(next){
ptor = protractor.getInstance();
ptor.ignoreSynchronization = true; //disables waitForangular()
next();
});
Sync method 1:
//at a testcase, wait for an element to be visible with a promise/then
browser.wait(function () {
element.all(by.css('.myCssClass')).then(function (items) {
items[0].getText().then(function (text) {
console.log(text);
});
});
return true;
}
Sync method 2 :
// "eventually" (chai-as-promised) internally uses "promise" (and therefore acts like "then")
browser.get(url);
expect(browser.getTitle()).to.eventually.equal("connect me").and.notify(next);

Categories

Resources