Closed ws-cdavis closed 2 years ago
@ws-aweaver
Which info will you use for find_element_by_id
?
(e.g. accessibility id from below image)
Could you check your app with Appium Desktop?
@ws-aweaver
You can see appium log on terminal by adding stdout=None
as below.
Could you take and attach appium log?
service = AppiumService()
service.start(stdout=None)
@ki4070ma Thank you so much for this! I've attached the full logs below, but I saw a few possible candidates for the issue:
[ADB] Using 'apkanalyzer' from '/Users/andrewweaver/Library/Android/sdk/tools/bin/apkanalyzer'
[debug] [ADB] Starting '/Users/andrewweaver/Library/Android/sdk/tools/bin/apkanalyzer' with args ["manifest","print","/Users/andrewweaver/.nvm/versions/node/v10.15.0/lib/node_modules/appium/node_modules/io.appium.settings/apks/settings_apk-debug.apk"]
[ADB] Cannot extract apk info using apkanalyzer. Falling back to aapt. Original error: Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
[ADB] at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
[ADB] at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
[ADB] at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
[ADB] at com.android.tools.apk.analyzer.ApkAnalyzerCli.getAaptInvokerFromSdk(ApkAnalyzerCli.java:277)
[ADB] at com.android.tools.apk.analyzer.ApkAnalyzerCli.main(ApkAnalyzerCli.java:129)
[ADB] Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
[ADB] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
[ADB] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
[ADB] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
[ADB] ... 5 more
[ADB]
[ADB] Using 'aapt' from '/Users/andrewweaver/Library/Android/sdk/build-tools/29.0.2/aapt'
Maybe it is unable to analyze the apk to get all of the ids?
ADB] The application at 'PATH/TO/APP/android-app.apk' is already cached to '/data/local/tmp/appium_cache/06e635178a30e612dd2256a4d5401acf1b4eee8f.apk'
[debug] [ADB] Running '/Users/andrewweaver/Library/Android/sdk/platform-tools/adb -P 5037 -s 5200615242e31623 shell pm install /data/local/tmp/appium_cache/06e635178a30e612dd2256a4d5401acf1b4eee8f.apk'
It may be taking cached data from an old version of the application that did not have the IDs (doubtful, as I've verified the ID exists in Appium Studio)
Full logs:
Moved to https://gist.github.com/ki4070ma/7740f16c776c8b2e5540911c385c7559
@ws-aweaver Which info will you use for
find_element_by_id
? (e.g. accessibility id from below image) Could you check your app with Appium Desktop?
I am using the ID value, not the accessibility id. I've verified the ID is correct using Appium Studio, which has similar functionality to the Appium Desktop you showed.
@KazuCocoa @mykola-mokhnach
Is below result expected(as design)?
It seems that android:id/text1
works, but io.appium.android.apis:id/text1
doesn't work.
Native element identifier. resource-id for android; name for iOS.
android:id/text1
as resource id.
id/text1
as properties > mID
. print(len(driver.find_elements_by_android_uiautomator('new UiSelector().resourceId("text1")')))
print(len(driver.find_elements_by_android_uiautomator('new UiSelector().resourceId("id/text1")')))
print(len(driver.find_elements_by_android_uiautomator('new UiSelector().packageName("android").resourceId("id/text1")')))
print(len(driver.find_elements_by_android_uiautomator('new UiSelector().packageName("android").resourceId("text1")')))
print(len(driver.find_elements_by_android_uiautomator('new UiSelector().packageName("io.appium.android.apis").resourceId("id/text1")')))
print(len(driver.find_elements_by_android_uiautomator('new UiSelector().packageName("io.appium.android.apis").resourceId("text1")')))
$python SampleAndroidTest_apidemo.py
0
12
0
#!/usr/bin/python
# -*- coding: utf-8 -*-
from appium import webdriver
caps = {
'platformName': "Android",
'deviceName': "Android Emulator",
'appPackage': "io.appium.android.apis",
'appActivity': ".ApiDemos",
'automationName': "uiautomator2",
}
if __name__ == '__main__':
driver = webdriver.Remote('http://localhost:4723/wd/hub', caps)
# Found elements: 0
els = driver.find_elements_by_id("id/text1")
print(len(els))
# Found elements: 12
els = driver.find_elements_by_id("android:id/text1")
print(len(els))
# Found elements: 0
els = driver.find_elements_by_id("io.appium.android.apis:id/text1")
print(len(els))
driver.quit()
Yes.
It depends on the app under test. You can find elements by io.appium.android.apis:id/text1
if the app under test had their customised resource id. Android's general component could have android:
prefixed resource id if nothing developers specified.
The behaviour is not Appium specific.
@ws-aweaver At first, you will use resource-id, right? If so, check if the id which you will use is same to the resource-id in appium desktop.
As https://github.com/appium/python-client/issues/509#issuecomment-596169368, it might be necessary to update used id.
I am trying to replicate this behavior in my code. I am using this function to wait for the element to appear:
def wait_for_element_by_id(self, id, time):
try:
WebDriverWait(self.driver, time).until(EC.visibility_of_element_located((MobileBy.ID, id)))
except NoSuchElementException:
print("Element not found: " + id)
return False
except TimeoutException:
print("Timeout occurred: " + id)
return False
return True
My understanding is MobileBy.ID
will not work. I do not see MobileBy.Resource_ID
. I've also tried experimenting with just getting the element without a wait using this:
def is_element_present_by_id(self, id):
try:
element = self.driver.find_element_by_id("android:id/"+id)
if element is None:
return False
except NoSuchElementException:
return False
except TimeoutException:
return False
return True
I also tried element = self.driver.find_element_by_id("io.appium.android.apis:id/"+id)
but this is not working either. The original code used self.driver.find_element(MobileBy.ID, id)
. I checked in Appium Studio. The ID and Resource ID are the same value.
I also tried downloading Appium Desktop just to be sure. It looks like the application I already have and was previously using to manually set up the Appium service. However, Mac is being difficult and says the app can't be opened with no explanation why. The version of Appium Desktop I already have doesn't have any element inspection services that I know of.
Update: I tried yesterday to demonstrate to somebody that XPATH works. It is no longer working. I also confirmed that I am in the correct context ("NATIVE_APP"). I am unsure what this means, as I have not changed the code in the application or the automation suite.
EDIT: XPATH is working correctly with UIAutomator2. It breaks on UIAutomator1. ID does not work with either. I also tried a cheap workaround by using XPATH to find an element with the ID //*[@resource-id='pairing-go-to-pair-by-login-button']
and this worked.
It looks like I need to find a method that looks by resource ID. I tried all of the methods below and they do not find the element:
io.appium.android.apis:id/pairing-go-to-pair-by-login-button
android:id/pairing-go-to-pair-by-login-button
package_name:id/pairing-go-to-pair-by-login-button
I have the app set the ID programatically, but not the resource ID. The resource ID is the same as the regular ID, so for now I am able to progress with the ugly workaround. I would like to do this properly, though.
@ki4070ma How do I get resource ID properly in Appium Python Client? I didn't find a method for it. I used the ugly workaround in my above comment for now, and it looks like there is a serious performance issue. My test is taking around 15 minutes to execute. The old suite of 12 tests took around 20 minutes. I'd really like to get the execution time much lower.
@ws-cdavis just wondering if you ever found a resolution for this? I'm afraid I'm not proficient in python like you clearly are so I'm utilising the appiumlibrary that's part of robot framework, however, I too have a problem that if I express as id=X it fails to find the element. If I express that same element as //*[@resource-id="X"] it works flawlessly.
I am trying to replicate this behavior in my code. I am using this function to wait for the element to appear:
def wait_for_element_by_id(self, id, time): try: WebDriverWait(self.driver, time).until(EC.visibility_of_element_located((MobileBy.ID, id))) except NoSuchElementException: print("Element not found: " + id) return False except TimeoutException: print("Timeout occurred: " + id) return False return True
My understanding is
MobileBy.ID
will not work. I do not seeMobileBy.Resource_ID
. I've also tried experimenting with just getting the element without a wait using this:def is_element_present_by_id(self, id): try: element = self.driver.find_element_by_id("android:id/"+id) if element is None: return False except NoSuchElementException: return False except TimeoutException: return False return True
I also tried
element = self.driver.find_element_by_id("io.appium.android.apis:id/"+id)
but this is not working either. The original code usedself.driver.find_element(MobileBy.ID, id)
. I checked in Appium Studio. The ID and Resource ID are the same value.I also tried downloading Appium Desktop just to be sure. It looks like the application I already have and was previously using to manually set up the Appium service. However, Mac is being difficult and says the app can't be opened with no explanation why. The version of Appium Desktop I already have doesn't have any element inspection services that I know of.
Hey Did you find the way to find elements by id?
Basically id
locator is for resource-id
. https://github.com/appium/appium-uiautomator2-driver/blob/93be98ec9583ca498a2abad08e38f3220c0a5323/README.md#element-location (uia1 as well)
UiAutomator's By.res is used as the backend.
Try specifying "chromeOptions": {"w3c": False} in your dc.
I am facing a similar issue too. This does not work:by.ID("text") This works: By.XPATH("//*[@resource-id='text']")
Does anyone know why? potential fix ID directly?
It is via findObject by Android directly https://github.com/appium/appium-uiautomator2-server/blob/cef81e2a9755e103ff5a6fb488938a14ff8a7016/app/src/main/java/io/appium/uiautomator2/handler/FindElement.java#L82 or XPath info cached by Appium/UIA2 server from AccessibilityNodeInfo by Android (since Android does not support XPath natively).
The difference might cause it.
^ This could also be an issue with accessibility identifiers naming (app identifier prefix is missing). Then https://github.com/appium/appium/issues/15138#issuecomment-1127709588 could be used as a workaround.
I'm having the same issue maybe:
I've attached two screenshots, the second one is to show that selecting with id: "org.plantnet:id/action_bar_root" does work. but the first one with id: "org.plantnet:id/bottomtabexplorer" or simply "bottomtabexplorer" does not work.
Here is my capabilities:
{
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:appPackage": "org.plantnet",
"appium:appActivity": "org.plantnet.MainActivity",
"appium:disableIdLocatorAutocompletion": true
}
it's crazy but the only thing that worked for me was to use
`xpath://*[@resource-id='${selector}']`
I had updated Appium globally, tried to change the capabilities to be more accurate and everything but this solve the issue right away. Before I even had strange behavior where I needed to click somewhere else for the next click to work.
Yes I cannot get the accessibility ID's to work either and like @HugoGresse I can only get it to find the elements by the xpath in appium with webdriver i/o latest versions. This is a react native app that I'm working with:
DC's are
capabilities: { platformName: "android", automationName: "Appium", platformVersion: "12", deviceName: "emulator-5554", app: "path-to-my-app", automationName: "UiAutomator2", autoGrantPermissions: 'true', }
I'm using an android nexus 6p with android 12
I have tried everything suggested.
This is blocking for me as one of the elements is off the screen and the scrolltoView is not implemented yet and I can't find elements that are not visible with xpaths. Any suggestions?
@mtaylor-evidation if you're dealing with android you have a different problem--elements that are not on screen do not exist (android doesn't have any concept of an element being available/existing if it's not actually on screen). so you'll never be able to find it. the best practice for the uiautomator2 driver is to do what a user would do--perform a scroll and then check if the element is on screen, and repeat.
Totally agree,
Unfortunately, ScrollIntoView in webdriverio does appear to work. However, I know there may be other ways to scroll with appium, just trying to find the best way to do it. :)
I don't know what "scroll into view" is. sounds like maybe it's a webdriverio thing. it's not an appium command. it's unclear to me how webdriverio implements it under the hood. it'd be better to do the correct appium thing, which is to use the actions api to construct a finger movement that will perform a scroll.
I've made something like this to scroll the view down. It's not perfect but it works ~ok
/**
* Scroll down by simulating a swipe down gesture.
*
* @param driver
* @param scrollAmount does not work currently...
* @param scrollDuration a lower scroll duration add more fling speed.
*/
export const scrollDown = async (driver, scrollAmount =1, scrollDuration = 300) => {
const startPercentage = 90
const endPercentage = 10
const anchorPercentage = 50
const { width, height } = await driver.getWindowSize()
const density = (await driver.getDisplayDensity()) / 100
const anchor = (width * anchorPercentage) / 100
const startPoint = (height * startPercentage) / 100
const endPoint = (height * endPercentage) / 100
for (let i = 0; i < scrollAmount; i++) {
await driver.performActions([
{
type: 'pointer',
id: 'finger1',
parameters: { pointerType: 'touch' },
actions: [
{ type: 'pointerMove', duration: 0, x: anchor, y: startPoint },
{ type: 'pointerDown', button: 0 },
{ type: 'pause', duration: 100 },
{ type: 'pointerMove', duration: scrollDuration, origin: 'pointer', x: 0, y: -endPoint * density },
{ type: 'pointerUp', button: 0 },
{ type: 'pause', duration: scrollDuration },
],
},
])
}
}
@HugoGresse Check https://github.com/appium/appium/issues/15138
So amazed by this community. Although the solution proposed won't work for me (JavaScript is what I'm using) but I've really gleaning off of all of your knowledge. I appreciate your responses today I'll be heads down trying to figure it out for JavaScript maybe even consider branching out and using native webdriver
I am also facing issue to find the locator, I have mentioned the code below
package Mobile_Testing;
import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By; import org.openqa.selenium.remote.DesiredCapabilities;
import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.remote.MobileCapabilityType;
public class First_TestCase {
public static void main(String[] args) throws MalformedURLException, InterruptedException {
File app = new File("D:\\Technogiq Work", "standard-bank.apk");
DesiredCapabilities C=new DesiredCapabilities();
C.setCapability(MobileCapabilityType.AUTOMATION_NAME , "uiautomator2");
C.setCapability(MobileCapabilityType.PLATFORM_NAME,"Android");
C.setCapability(MobileCapabilityType.DEVICE_NAME,"Android");
C.setCapability(MobileCapabilityType.PLATFORM_VERSION,"7.0");
C.setCapability("appPackage", "com.bank.standard");
C.setCapability("appActivity", "com.bank.standard.MainActivity");
URL url=new URL("http://0.0.0.0:4723/wd/hub");
AndroidDriver driver=new AndroidDriver(url,C);
Thread.sleep(2000);
driver.findElement(By.xpath("//*[@resource-id, '${com.bank.standard:id/urs_nm}']")).sendKeys("1234");
driver.quit();
}}
I have also tried By.xpath("//[@resource-id, 'com.bank.standard:id/urs_nm']" By.xpath("//android.widget.EditText[@resource-id, 'com.bank.standard:id/urs_nm']") By.xpath("//*[contains(@resource-id, 'com.bank.standard:id/urs_nm')]") By.xpath("//com.bank.standard[@id='com.bank.standard:id/urs_nm']") By.id("com.bank.standard:id/urs_nm")
Please help me
Error on Selenium
try replacing your Xpath to look like this: "//*[@resource-id='com.bank.standard:id/urs_nm']"
Hi thanks for the reply
I have tried but not working.
The problem
I've been working on dual Appium/Selenium test suite for a web page and mobile app. When using Appium, it is unable to find the element by ID. If I change it to use XPATH, it works as expected, then fails to find the next element by ID. This may not sound like a problem, but other elements in the app are not easily distinguished by XPATH values.
This test suite worked previously with manual app install and the Appium Service running on Mac. I've since tried to automate the process to install the application and run Appium Service programmatically. I am wondering if the way I've set this up is causing it not to detect elements by ID.
I know for certain the ID is correct. It works for the Selenium + web page combination, and I've tried digging into the app with Appium Studio. It displays the ID correctly in the app, and copy pasting the ID into my code doesn't change anything.
Environment
Link to Appium logs
Unfortunately, it doesn't look like the AppiumService in Python creates logs. If it does, I'll attach them when I find them or somebody tells me where they are
Code To Reproduce Issue [ Good To Have ]
Code below (redesign_tags and redesign_locators contain some sensitive info, but they work as intended in the Selenium flow):