AppiumTestDistribution / appium-flutter-integration-driver

MIT License
33 stars 12 forks source link

Support for Flutter semantic identifier to improve test scalability and maintainability #98

Open ReverseScale opened 2 months ago

ReverseScale commented 2 months ago

Description:

As Flutter apps grow, automated testing becomes increasingly challenging. Common issues include:

Multi-language support: Test scripts need to adapt to the language displayed in the app. Dynamic content: Non-static content, such as A/B tests, may cause inconsistencies in UI tests. Large-scale applications: The growing number of screens increases the complexity and difficulty of test maintenance. To address these challenges, Flutter introduced the semantic identifier feature, which helps uniquely identify UI elements independently of the content they display. This makes automated testing more robust and easier to maintain.

Why semantic identifier is important:

Language independence: Semantic identifiers do not rely on displayed text or labels, making tests more resilient to language changes and localization. Dynamic content readiness: Since semantic identifiers are static, even when UI content changes due to experiments (like A/B tests), the test scripts remain stable. Ease of maintenance: Using semantic identifiers reduces the need to frequently update tests when content or UI changes. Feature availability:

This feature is available starting from Flutter 3.19 (released on February 15th, 2024) in the stable channel. To use it, you need to upgrade to the latest stable Flutter release.

References:

Flutter Semantics Documentation Flutter 3.19 Release Notes

Request: Please add support for semantic identifier in appium-flutter-integration-driver to enable more robust and scalable testing for Flutter applications.

ReverseScale commented 2 months ago

Example: Tap on a widget by semantics identifier

Semantics(
  identifier: 'signin_button',
  child: ElevatedButton(
    onPressed: _signIn,
    child: Text('Sign in'),
  ),
)
saikrishna321 commented 2 months ago

@ReverseScale Have you tried

const loginButton = await browser.flutterBySemanticsLabel$('login_button');
await loginButton.click();
ReverseScale commented 2 months ago

I understand that labels can work well for identifying UI elements in projects. However, with the release of Flutter 3.19, the official Flutter team recommends using identifiers instead of labels for a more robust and scalable approach to automated testing.

While labels have been commonly used for UI element identification, they can be susceptible to issues such as localization changes, dynamic content updates, and maintainability challenges in large-scale applications. The semantic identifier feature introduced in Flutter 3.19 addresses these limitations by allowing unique identification of UI elements independent of their displayed content.

By adopting semantic identifiers, automated tests become more resilient to language changes, dynamic content variations (e.g., A/B tests), and UI updates. This approach aligns with the Flutter team's best practices and recommendations for enhancing the reliability and maintainability of automated testing for Flutter applications.

Although labels can still be functional, the official guidance from the Flutter team is to leverage semantic identifiers for a more future-proof and scalable solution, especially for projects with multi-language support, dynamic content, or large-scale applications.

Semantics(
  label: signin_button',
  identifier: 'signin_button', // Flutter 3.19 later
  child: ElevatedButton(
    onPressed: _signIn,
    child: Text('Sign in'),
  ),
)
ReverseScale commented 2 months ago

Other 🫣

When using the pushNamedAndRemoveUntil method to navigate to a new route, elements from the previous pages may become unidentifiable on the new page. This can lead to test failures or runtime errors.

Steps to Reproduce:

Start on Page A. Navigate to Page B using Navigator.pushNamed. From Page B, use Navigator.pushNamedAndRemoveUntil to navigate to Page C, keeping only the root route (e.g., /). Try to interact with or find elements that were present on Page A or Page B. Expected Behavior: Elements from the previous pages (A and B) should remain identifiable and accessible on the new page (C) after using pushNamedAndRemoveUntil.

Actual Behavior: Elements from the previous pages become unidentifiable and cannot be interacted with or found on the new page.

saikrishna321 commented 2 months ago

@ReverseScale Thanks for providing detail information.

Adding the identifier to Semantics, UIAutomator and XcUi should be able to find it! We don't need to anything on the this flutter integration driver.

saikrishna321 commented 2 months ago

Actual Behavior: Elements from the previous pages become unidentifiable and cannot be interacted with or found on the new page.

This is expected! When you run your automation you want to focus on elements that are in the current screen.

saikrishna321 commented 2 months ago

When using the pushNamedAndRemoveUntil method to navigate to a new route, elements from the previous pages may become unidentifiable on the new page.

The current driver does not modify anything on how the app should render. We completely depend on what flutter returns.