I hate using "sleepers" (Thread.sleep(millis)) in tests, but without sleepers some tests fail.
I have a ListView in my Android application and I want to tap on the first item in the list (SAUDI ARABIA in our case).
public AndroidDriver androidDriver;
...
androidDriver = new AndroidDriver(serverAddress, capabilities);
androidDriver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driverWait = new WebDriverWait(androidDriver, 30);
// at this moment everything is initialized and working properly,
// Appium server is up and running
driverWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("com.###.debug:id/countries_list_view")));
WebElement countriesList = driver.findElement(By.id("com.###.debug:id/countries_list_view"));
List<WebElement> countries = countriesList.findElements(By.id("com.###.debug:id/list_item_container"));
WebElement country = countries.get(0);
// country isn't null, and it corresponds to a real ListView row
driverWait.until(ExpectedConditions.elementToBeClickable(country));
Thread.sleep(1000); // <---- country isn't clicked without this
country.click();
The same problem exists in Calabash/Cucumber tests (explicit waits required).
I've tried different ways of waiting for the element which should be clicked
driverWait.until(ExpectedConditions.visibilityOfElementLocated(By));
driverWait.until(ExpectedConditions.visibilityOf(WebElement));
driverWait.until(ExpectedConditions.elementToBeClickable(By));
driverWait.until(ExpectedConditions.presenceOfElementLocated(By));
and none is working. At the moment when I try to tap on the ListView 1st item, ListView exists and is all the list elements are on screen.
I've tried to find the ListView 1st row by getting the list row XPath using Appium Inspector. The result is the same - view isn't clicked without Thread.sleep.
Using Thread.sleep in tests is really bad practice and makes my tests unstable. I can't rely on tests results in this case, as they may fail even if the application is working properly. There's an article about "wait" and "sleep" usage in Selenium tests (Selenium WebDriver wait).
How to fix such issues in tests?
How often Thread.sleep calls used in automation world? (I'm mostly Android developer, and not that experienced in mobile automation).
UPDATE:
I've tried to not to mix up implicit and explicit waits, as JeffC mentioned, and it didn't help.
Here's my test:
#Test
public void selectCountryLanguageAndStartApplication() throws Exception {
countryLanguagePage.loaded();
countryLanguagePage.selectFirstCountry();
countryLanguagePage.pleaseSelectCountryTextIsHidden();
countryLanguagePage.startClick();
}
...
/**
* Verify the page has loaded
*/
public static void loaded() {
driver.findElement(By.id("com.###.debug:id/countries_list_view"));
}
I'm verifying if the page is loaded in every test. If I use only implicit waits - the test fails from time to time; if I use only explicit waits - it's the same, the test fails from time to time.
I've found in Appium tutorial that they use implicit in conjunction with explicit ones 1, 2. It looks weird according to the docs.
The working solution: I've modified a bit loaded method
public static void loaded() {
driver.findElement(By.id("com.###.debug:id/countries_list_view"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Having that sleep brings the "stability" to test and I can find the elements and press on them with explicit waits or without them.
Does it mean, that I should add "sleep" when the new Activity launched (the only working solution to me)? Or I'm waiting for the Activity initialization in the wrong way?
You could try this:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.elementToBeClickable(By));
or
while(!driver.findElement(By).isDisplayed())
{
//Thread.sleep(10);
}
I think Thread.sleep calls are fine to use (and almost necessary if your testing involves timing) but for the most part there a better ways to handle most things they would be used for.
Hope this helps,
Liam
I have Tried to write a method , to wait for an element. hope it will work for your case.
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Utility {
public static AndroidElement element;
public static boolean isElementPresent;
public static boolean waitForPresence(AndroidDriver driver, int timeLimitInSeconds, String targetResourceId){
try{
element = (AndroidElement) driver.findElementByAndroidUIAutomator("new UiSelector().resourceId(\""+targetResourceId+"\")");
WebDriverWait wait = new WebDriverWait(driver, timeLimitInSeconds);
wait.until(ExpectedConditions.visibilityOf(element));
isElementPresent = element.isDisplayed();
return isElementPresent;
}catch(Exception e){
isElementPresent = false;
System.out.println(e.getMessage());
return isElementPresent;
}
}
}
Related
Using the Rewarded ad script found on the Unity Ads SDK, I'm running into an issue where the ShowAd() IUnityAdsShowListener => OnUnityAdsShowComplete is firing the debug log incrementally. The first Ad I watch returns one line stating the ad is completed, the second Ad I watch, fires off 2 logs, the third 3, then 4, etc...As if each ShowAd() subscribes a new listener to the callback. is this normal?
Im not using a button to call the ShowAd method, rather I'm just calling a function with a delegate from an AdsManager class.
public delegate void OnSuccessfulAd();
private OnSuccessfulAd _myCallback = null;
public void ShowAd(OnSuccessfulAd myMethod)
{
_myCallback = myMethod;
Advertisement.Show(_adUnitId, this);
}
public void OnUnityAdsShowComplete(string adUnitId, UnityAdsShowCompletionState showCompletionState)
{
if (adUnitId.Equals(_adUnitId) && showCompletionState.Equals(UnityAdsShowCompletionState.COMPLETED))
{
Debug.Log("Unity Ads Rewarded Ad Completed"); //Gets called more times each ad
// Grant a reward.
_myCallback?.Invoke();
}
}
Experiencing the same issue. As a temporary solution I nullify _myCallback after invoking it
I am working on the Ads 4.0.0 version in Unity.
What I observed even for Button Click is that its giving multiple Logs in Unity Editor.
However if I run the Code in my mobile Build its working as expected only 1 Log gets generated and Reward also remains same on multiple ad watches.
The issues seems to be in the CallBack in unity, My suggestion would be Try the Build in your App Once Hopefully that fixes the issue.
Unity Rewarded Ads Code from Official Page
As Unity has Deprecated most of the Previous Listeners in the New Ads 4.0.0 I think its better to cross check in the Build.
I was facing the exact same issue.
My OnUnityAdsShowComplete event callback is invoking one of my delegate.
Every references in my delegate was not accessible.
Look like the OnUnityAdsShowComplete is done on a different thread than the main one.
If in your delegate callback you have a simple Time.timeScale=1f, this should cause a crash since Time is no reachable.
Also this has observable only with reward Ads type.
My solution was to call the show() method inside a coroutine.
By having a flag set i.e. isAdRunning
You can poll that flag and when the flag is false isAdRunnin = false then you can call your delegate.
Very annoying.
Here an example. To make the code the simpliest as possible. All the IUnityAds interfaces are in the same class. This is why you will see this as listener arguments.
using UnityEngine.Advertisements;
private bool isAdsRunning = false;
// Ads start callback
public void OnUnityAdsShowStart(string placementId)
{
isAdsRunning = true;
}
// Ads complete callback
public void OnUnityAdsShowComplete(string placementId, UnityAdsShowCompletionState showCompletionState)
{
isAdsRunning = false;
}
// Entry point to show reward ads
public void ShowRewardedAd()
{
StartCoroutine(RewardRoutine());
}
IEnumerator RewardRoutine()
{
while (Advertisement.isShowing)
{
yield return null;
}
// In 4.0 Ads need to be loaded first, after initialization
// just another flag to make sure everything is initialized :)
while (!isAdLoaded)
{
yield return null;
}
// Show Ads
Advertisement.Show(adsUnitIdReward, this);
yield return new WaitForSeconds(0.25f);
while(isAdsRunning)
{
yield return null;
}
// My custom delegate
AdAction.Invoke();
}
Peace and Love.
I'm working in an app using Parse.com and I've been experiencing some random behavior, I made a simpler version of my code to show you and while it keeps being random (the results I expect happen about 4 in 5 times) it got better (in my code it's correct about 2/5 of the runs).
So the method is this, a very simple creation and filling of a new object:
public void test(){
final List<ParseObject> list = new ArrayList<>();
for(j=0;j<4;j++){
list.add(new ParseObject("Object"));
list.get(j).put("Column1", "sup");
list.get(j).put("Column2", "bro");
if(j==3){
ParseObject.saveAllInBackground(list, new SaveCallback() {
#Override
public void done(ParseException e) {
Toast.makeText(MainActivity.this, "NANANANANANANANA BATMAN!",Toast.LENGTH_LONG).show();
}
});
}
}
}
}
Problem is it creates 4 ParseObjects (as it should) only 4/5 of the tries, then 1/4 it's only 3. Why does this happen?
Why don't you create and store your ParseObject in a variable and then, use put("Column1", "sup"); and put("Column2", "bro"); on it before adding this variable directly to your list? because you are accessing your list two times for nothing where it can be avoided.
It would be cleaner and it would allow you to debug better.
Where is the documentation/sample for all overloads of invokeApi function for Azure Mobile Service client SDK for Android?
I found this article and tried following code, which does not work. There are no compile time or run time errors, invokeApi gets called, but it does not come back to onSuccess or onFailure. If I call invokeApi without order object, everything works as expected
PizzaOrder order = new PizzaOrder();
order.Size = "Large";
order.Flavor = "Four cheeses";
order.UserPhone = "555-555-1234";
ListenableFuture<PizzaOrderResponse> testresult = mClient.invokeApi("bookservice", order, PizzaOrderResponse.class);
Futures.addCallback(testresult, new FutureCallback<PizzaOrderResponse>() {
#Override
public void onFailure(Throwable exc) {
// failure handling code here
}
#Override
public void onSuccess(PizzaOrderResponse testresult) {
// success handling code here
}
});
One of the properties in the data object being returned by the custom API had incorrect data type. I am still not sure where the good documentation is and why custom API call did not fail but at least it is working now.
Friends!
I'm getting occasional and unexpected HTTP 400 responses from nanohttpd in my Android app. The error is following a specific pattern. I've been looking at this for some time now but I've come to the point where I need a different angle or some other help pointing me in the right direction.
Could you please have a look and share your thoughts or even direct points and suggestions?
Why am I getting this HTTP 400 status code?
And why only under the given circumstances? (I don't want it at all!)
Some Background
I'm running nanohttpd in my Android project as a temporary isolation layer (due to server side not being mature enough yet). I have isolated the nanohttpd server in an Android Service, which I start from my custom Application object once it's created. This way nanohttpd is not bound to the lifecycle of any particular Activity but can live rather independent of the overall application logic and component life cycles.
The Problem
Now, (almost) everything is working nice and dandy: I can start nanohttpd and perform some initial login requests, my expected mock response is even delivered. When I perform my first "GET" request, though, nanohttpd throws a 400 Bad request status at me, but only the first time. If I back out of the Activity being responsible for the particular "GET" request, and launch it again (from the home screen), it delivers the expected payload with a 200 status, flawlessly.
What Have I Done So Far
I have had a closer look at the nanohttpd source code, trying to track down where and why this 400 status is set. It's not that many places this status code is used. Roughly speaking only here, here and here. Since I'm not dealing with multipart content, I'm left with the first and third "here". But - of course - I can not for my life find neither the root cause of the 400 status, nor which exact block is causing the state for me. When I debug the code, everything works just peachy.
Some Code
This is roughly what my nanohttpd Service (MyNanoHttpdService) looks like:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_START.equals(intent.getAction())) {
String errorMessage = null;
if (myNanoHttpd == null) {
String hostUrl = intent.getStringExtra(EXTRA_HOST);
Uri uri = Utils.notEmpty(hostUrl) ? Uri.parse(hostUrl) : Uri.EMPTY;
myNanoHttpd = new MyNanoHttpd(this, uri.getHost(), uri.getPort(), null);
}
if (!myNanoHttpd.isAlive()) {
try {
myNanoHttpd.start();
} catch (IOException e) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
errorMessage = stringWriter.toString();
stopSelf();
}
}
final ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_RESULT_LISTENER);
if (resultReceiver != null) {
int status = myNanoHttpd.isAlive() ? CODE_SUCCESS : CODE_FAILURE;
Bundle bundle = new Bundle();
bundle.putString(EXTRA_MESSAGE, errorMessage);
resultReceiver.send(status, bundle);
}
}
return Service.START_STICKY;
}
And this is how I start the service from my custom Application object, initialize my client side state and fetch some content:
#Override
public void onCreate() {
super.onCreate();
// Yes, that is a Java 8 Lambda you see there!
MyNanoHttpdService
.start(this, "http://localhost:8080")
.withStartupListener((status, message) -> {
if (status == 0) {
// POST REQUEST: Works like a charm
myNetworkHelper.login();
// GET REQUEST: Always fails on first launch
myNetworkHelper.getContent();
} else {
Log.e("LOG_TAG", "Couldn't start MyNanoHttpd: " + message);
}
});
}
It's safe to assume that the wrapping convenience code (the .withStartupListener(...) - which essentially wraps a ResultReceiver used by the above Service - and the myNetworkHelper object) works as expected. Also, in production, the getContent() call would be made from an Activity or Fragment, but for the sake ease I have moved it to the Application for now.
I may have found the root cause for my issue, and possibly even a workaround for the moment.
If I'm correct in my investigation, the issue was caused by unconsumed data from a previous (POST) request, contaminating the current (POST) request.
This line in the NanoHTTPD code base (the header parsing block in the NanoHTTPD.HTTPSession.execute() method, just before calling through to any custom serve(...) method - the third "here" in my question above) was the very line where the HTTP 400 status code was thrown, and just as the code suggests, there was no proper value for the "method" header.
The value - which I expected to be "POST" in clear text - was contaminated with parts of the JSON content body from the previous request. As soon as I realized this, I tried to consume the entire request body in my custom MyNanoHttpd.serve(IHTTPSession session) method, like so:
#Override
public Response serve(IHTTPSesion session) {
InputStream inputStream = session.getInputStream();
inputStream.skip(inputStream.available());
// or
// inputStream.skip(Long.MAX_VALUE);
// or even
// inputStream.close();
...
}
This didn't work, though, as I kept getting various exceptions. I ended up gently modifying the NanoHTTPD code, safely closing the input stream in the finally block of the very NanoHTTPD.HTTPSession.execute() method instead.
I'm, nonetheless, considering reaching out to the NanoHTTPD community to discuss a suitable and sustainable solution.
I'm pretty new to Android development, in the later states of my first serious project. Briefly, the program will ssh into a Linux host and perform commands. But I find myself really getting tied into knots trying to finish this.
I'm using ganymed-ssh2 to do the ssh grunt-work.
When an Activity button is hit, I want the program to start a SSH session, verify the host fingerprint - prompting for acceptance if necessary, and then issue remote commands as programed. But this seemingly simple few steps, are getting very complicated by the following:
The ssh cannot be performed in the UI thread, so I have to start an AsyncTask, so all of what I describe in the next hassles are not in the foreground UI thread.
To activate the ssh fingerprinting code, I need to make a call like this inside my AsyncTask class:
#Override
protected String doInBackground(String... command) {
String result;
result = "";
try {
/* Create a connection instance */
Connection conn = new Connection(connect.getHost(), connect.getPort());
/* Now connect */
ConnectionInfo info = conn.connect(new AdvancedVerifier());
boolean isAuthenticated = false;
// first try public key if defined
if (connect.getPrivateKey() != null)
isAuthenticated = conn.authenticateWithPublicKey
(connect.getUserid(), connect.getPrivateKey(), null);
// if failed, or not defined, try password if provide
if (!isAuthenticated && connect.getPassword() != null)
isAuthenticated = conn.authenticateWithPassword(connect.getUserid(),
new String (connect.getPassword()));
// all else, get out
if (!isAuthenticated)
throw new IOException("Authentication failed.");
/* Create a session */
Session sess = conn.openSession();
sess.execCommand(command[0]);
}
However, the conn.connect(new AdvancedVerifier()) line causes a callback interface class of AdvancedVerifier to be called, interrupting the execution path at the connect call to call this class:
class AdvancedVerifier implements ServerHostKeyVerifier
{
public boolean verifyServerHostKey(String hostname, int port,
String serverHostKeyAlgorithm,
byte[] serverHostKey) throws Exception
{
final String host = hostname;
final String algo = serverHostKeyAlgorithm;
/* Check database - code removed*/
/* assuming fingerprint needs verification */
String hexFingerprint =
KnownHosts.createHexFingerprint(serverHostKeyAlgorithm,
serverHostKey);
String msg = "Hex Fingerprint: " + hexFingerprint;
/* right here, I need to display dialog of fingerprint,
and ask user for to continue;
If user accepts, return true, else return false.
If return true, the above class continues after connect(), if false
it is aborted.
*/
return UserAccepts? true : false;
}
}
Well this, in my limited experience, seems to raise lots of truely messy code.
First, I need to reattach back to the UI thread, display a dialog, then if user selects
OK, to then return "true" from verifyServerHostKey(), detach UI thread, and allow the ssh connection code to resume. All without the ability to use modal dialogs.
Frankly, I don't really know where to begin and am looking for ideas, guidance, etc.
I finally worked out at least one way to solve the problem. Using a wait/notify combination between my AdvancedVerifier class and using a AlertDialog in onProgressUpdate, I was able to pause the verifier class while the user accepts/rejects the host fingerprint.
Don't know if there is a better way, but I think I can work with this.