[Automating hybrid Android apps] driver.findElements() result: [] on Ionic 4 hybrid application


#1

With the purpose to make test-automation for my Ionic App, I am trying to do the following but the main problem is that I cannot find any element in the webview.

I am trying to follow the steps listed here in the official Appium documentation.

Here’s the basic Ionic setup I am using for this test:

  • Ionic 4
  • A sample test project available on GitHub
  • Python 2.7.15
  • robotframework-3.1.1 installed via pip
  • appium 1.11.1 installed via npm (I also have Appium Client for Windows 1.11.0)

These are the steps to reproduce the issue.

git clone https://github.com/fbcyborg/simple-app.git
cd simple-app
npm install

One important thing we must notice, is the cordova-plugin-debuggable-webview plugin available here. This does exactly what is mentioned below from the Appium guide:

There is an additional step necessary within your app build, unfortunately. As described in the Android remote debugging docs it is necessary to set to true the setWebContentsDebuggingEnabled property on the android.webkit.WebView element.

As you can see, the plugin is enabled and the result is a fully debuggable ionic application via Chrome Inspector.
immagine

To test the application, just perform the following commands:

ionic cordova build android
adb install app-debug.apk

Once the application is installed on the device, we start the application and the uiautomtorviewer as well.

Here’s the screenshoot:

After that, I start Appium:

[Appium] Welcome to Appium v1.11.1
[Appium] Appium REST http interface listener started on 0.0.0.0:4723

Here’s the RobotFramework .robot file I prepared for a simple test: clicking a button:

*** Settings ***
Library           C:/Python27/Lib/site-packages/AppiumLibrary/

*** Test Cases ***
Simple Test
    Open Application    http://localhost:4723/wd/hub    platformName=Android    platformVersion=8.0.0    deviceName=emulator-5554    appPackage=io.ionic.starter    appActivity=io.ionic.starter.MainActivity    appWaitActivity=io.ionic.starter.MainActivity    udid=emulator-5554
    Wait Activity   .MainActivity    15
    Click Element   class=android.widget.Button[@text='RUN TEST']
    Close All Applications

If I try to launch this robot file, I cannot find any element in the WebView:

[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type ACTION
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command action: find
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Finding 'android.widget.Button[@text='RUN TEST']' using 'CLASS_NAME' with the contextId: '' multiple: true
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Using: UiSelector[CLASS=android.widget.Button[@text='RUN TEST']]
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] getElements selector:UiSelector[CLASS=android.widget.Button[@text='RUN TEST']]
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Element[] is null: (0)
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] getElements tmp selector:UiSelector[CLASS=android.widget.Button[@text='RUN TEST'], INSTANCE=0]
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Failed to locate element. Clearing Accessibility cache and retrying.
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Finding 'android.widget.Button[@text='RUN TEST']' using 'CLASS_NAME' with the contextId: '' multiple: true

I tried the same thing in Java, but there is no way to find any element.

What am I doing wrong?


#2

The button is in the Native Context.
So you should switch to the native context before clicking on the RUN TEST Button.
Please share the apk file so that I will share the working code.


#3

Hi!

Thank you very much for your reply.

Regarding what you’re saying, I’ve even tried to switch to native context but without any success in Java:

public static void main( String[] args ){
	//Set the Desired Capabilities
	DesiredCapabilities caps = new DesiredCapabilities();
	caps.setCapability("deviceName", "AndroidTest");
	caps.setCapability("udid", "emulator-5554"); //Give Device ID of your mobile phone
	caps.setCapability("platformName", "Android");
	caps.setCapability("platformVersion", "8.0.0");
	caps.setCapability("appPackage", "io.ionic.starter");
	caps.setCapability("appActivity", "io.ionic.starter.MainActivity");
	caps.setCapability("noReset", "true");

	//Instantiate Appium Driver
	try {
		AppiumDriver<MobileElement> driver = new AndroidDriver<MobileElement>(new URL("http://localhost:4723/wd/hub"), caps);		
		driver.context("NATIVE_APP");
		driver.findElement(By.className("android.widget.Button[@text='RUN TEST']")).click();
		driver.quit();
	} catch (MalformedURLException e) {
		System.out.println(e.getMessage());
	} catch (Exception e) {
		e.printStackTrace();
	}
}

Anyway, here’s the apk link!
Doing this with RobotFramework is my first target!


#4

Hello! Sorry for bothering you, but it’s very important to me.
Can you still help me on this please?


#5
	driver.findElement(By.className("android.widget.Button[@text='RUN TEST']")).click();

As per the code, this is invalid, you gave the XPATH but clicking again by className.
Change to below line:
driver.findElement(By.xpath(“android.widget.Button[@text=‘RUN TEST’]”)).click();


#6

Thanks a lot for your support.
I made the changes you suggested. So I finally have this code:

try {
			AppiumDriver<MobileElement> driver = new AndroidDriver<MobileElement>(new URL("http://localhost:4723/wd/hub"), caps);
			
			Thread.sleep(10000);
		
			driver.context("NATIVE_APP");
			driver.findElement(By.xpath("android.widget.Button[@text='RUN TEST']")).click();

			driver.quit();
		} catch (MalformedURLException e) {
			System.out.println(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
		}

For what I can see, there’s no way to execute a click() on such button. Here’s the appium logs:

[debug] [AndroidDriver] Parsed pid: '4756' pkg: 'io.ionic.starter' from
[debug] [AndroidDriver]     USER           PID  PPID     VSZ    RSS WCHAN            ADDR S NAME
[debug] [AndroidDriver]     u0_a86        4756  1461 1551596 155204 SyS_epoll_wait      0 S io.ionic.starter
[debug] [AndroidDriver] Returning process name: 'io.ionic.starter'
[debug] [AndroidDriver] Found webviews: ["WEBVIEW_io.ionic.starter"]
[debug] [AndroidDriver] Available contexts: ["NATIVE_APP","WEBVIEW_io.ionic.starter"]
[debug] [W3C (1b4a767c)] Responding to client with driver.setContext() result: null
[HTTP] <-- POST /wd/hub/session/1b4a767c-3145-4177-8275-e190ca84363a/context 200 443 ms - 14
[HTTP]
[HTTP] --> POST /wd/hub/session/1b4a767c-3145-4177-8275-e190ca84363a/element
[HTTP] {"using":"xpath","value":"android.widget.Button[@text='RUN TEST']"}
[debug] [W3C (1b4a767c)] Calling AppiumDriver.findElement() with args: ["xpath","android.widget.Button[@text='RUN TEST']","1b4a767c-3145-4177-8275-e190ca84363a"]
[debug] [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
[debug] [BaseDriver] Waiting up to 0 ms for condition
[debug] [AndroidBootstrap] Sending command to android: {"cmd":"action","action":"find","params":{"strategy":"xpath","selector":"android.widget.Button[@text='RUN TEST']","context":"","multiple":false}}
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"action","action":"find","params":{"strategy":"xpath","selector":"android.widget.Button[@text='RUN TEST']","context":"","multiple":false}}
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type ACTION
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command action: find
[debug] [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Finding 'android.widget.Button[@text='RUN TEST']' using 'XPATH' with the contextId: '' multiple: false

I think the following instruction is completely ignored:

driver.context("NATIVE_APP");