Flutter自动化元素定位方法调用报错问题排查
Flutter App元素定位复刻逻辑的问题排查
问题背景
原本为Android App实现了一套元素定位逻辑,现在复刻到Flutter App后调用findMobileLocatorElement报错,需排查方法实现或调用过程中的问题。
Android原定位代码
public static AppiumLocator findMobileLocatorElement( final String pageName, final String elementName, AppiumDriver driver, Object... dynamicLocatorValue) { return findMobileLocatorElement( pageName, elementName, driver, AppiumLocator::getElement, dynamicLocatorValue); } /** * Finds the page element. * * @param pageName page name tag in web locator file. * @param elementName name of element. * @return instance of weblocator class. */ private static AppiumLocator findMobileLocatorElement( final String pageName, final String elementName, AppiumDriver webdriver, BiFunction<String, String, AppiumLocator> appiumLocatorProvider, Object... dynamicLocatorValue) { AppiumLocator appiumLocator; Map<String, String> locatorMap = new HashMap<>(); try { locatorMap = WebLocatorFileTypeFactory.getInstance().getLocatorValue(pageName, elementName); } catch (JAXBException exception) { log.warn("Failed to read OR file for pagename {}", pageName, exception); } if (!locatorMap.isEmpty()) { for (final Map.Entry<String, String> entry : locatorMap.entrySet()) { if (0 == dynamicLocatorValue.length) { appiumLocator = appiumLocatorProvider.apply(entry.getValue(), entry.getKey()); } else { appiumLocator = appiumLocatorProvider.apply( String.format(entry.getValue(), dynamicLocatorValue), entry.getKey()); } try { webdriver.findElement(appiumLocator.getBy()); return appiumLocator; } catch (NoSuchElementException e) { log.info("Not able to find element: {} with locator : {}.", elementName, appiumLocator); } } } else { log.error( "NameOfElement or SectionName is given wrong in object repository file or PageName in Page Object" + " Class is wrong"); } webdriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); throw new NoSuchElementException( String.format( "no valid WebLocator found in object repository for page: %s and element: %s", pageName, elementName)); }
Flutter复刻的定位代码
public static FlutterLocator findMobileLocatorElement( final String pageName, final String elementName, AppiumDriver driver, Object... dynamicLocatorValue) { return findMobileLocatorElement( pageName, elementName, driver, FlutterLocator::getElement, dynamicLocatorValue); } private static FlutterLocator findMobileLocatorElement( final String pageName, final String elementName, AppiumDriver webdriver, BiFunction<String, String, FlutterLocator> appiumLocatorProvider, Object... dynamicLocatorValue) { FlutterLocator flutterLocator = null; Map<String, String> locatorMap = new HashMap<>(); try { locatorMap = WebLocatorFileTypeFactory.getInstance().getLocatorValue(pageName, elementName); } catch (JAXBException exception) { log.warn("Failed to read OR file for pagename {}", pageName, exception); } if (!locatorMap.isEmpty()) { for (final Map.Entry<String, String> entry : locatorMap.entrySet()) { if (0 == dynamicLocatorValue.length) { flutterLocator = appiumLocatorProvider.apply(entry.getValue(), entry.getKey()); } else { flutterLocator = appiumLocatorProvider.apply( String.format(entry.getValue(), dynamicLocatorValue), entry.getKey()); } try { webdriver.findElement(flutterLocator.getBy()); return flutterLocator; } catch (NoSuchElementException e) { log.info("Not able to find element: {} with locator : {}.", elementName, flutterLocator); } } } else { log.error( "NameOfElement or SectionName is given wrong in object repository file or PageName in Page Object" + " Class is wrong"); } webdriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(20)); throw new NoSuchElementException( String.format( "no valid WebLocator found in object repository for page: %s and element: %s", pageName, elementName)); }
排查出的问题点
FlutterLocator.getElement方法未适配Flutter专属定位策略:Android的定位策略(如id、xpath)不适用于Flutter App,Flutter需要使用flutterByText、flutterBySemanticsLabel等专属定位方式,如果FlutterLocator的getElement方法未实现这些策略的解析,会直接导致定位失败。- 定位对象库(OR)内容不匹配:若复用了Android的对象库,其中存储的是原生Android定位键值对,无法被Flutter解析;即使新建了Flutter定位项,若格式不符合
FlutterLocator的要求,locatorMap中的内容也无法生成有效定位器。 getBy()返回类型错误:Appium定位Flutter元素需要使用FlutterBy相关实现类,而非原生Android的By类。如果FlutterLocator.getBy()返回原生By实例,调用webdriver.findElement()时会因类型不兼容抛出异常。- 空指针风险:
flutterLocator初始化为null,若locatorMap为空或所有定位尝试失败,在catch块打印日志时会触发空指针异常,而Android版本中AppiumLocator在循环内必然被赋值,不存在此问题。 - 隐式等待设置时机无效:在所有定位尝试失败后才设置隐式等待,此时已经要抛出异常,完全起不到辅助定位的作用,正确的做法是在driver初始化时或查找元素前设置。
- 异常信息误导:抛出的异常文本写的是
no valid WebLocator found,但实际针对的是FlutterLocator,会干扰问题排查,需修改提示文本。
内容的提问来源于stack exchange,提问作者Bhagyashree meena
相关产品推荐
相关产品推荐

