How to Use the Emulator Virtual Keyboard in Flutter App with Appium

Testing mobile applications can be a complex task, especially when it comes to handling text input via the virtual keyboard. In this blog post, we will walk you through the steps to use the emulator virtual keyboard in a Flutter app for Appium testing. We’ll cover the necessary changes in your Flutter code and provide examples of how to handle text input in your Java-based Appium tests.

Modify Your Flutter Code

To ensure that the Flutter app is correctly set up for Appium testing, you need to disable text entry emulation. This allows the virtual keyboard to interact naturally with the app. Add the following line in your main.dart file:

main.dart
import 'package:flutter_driver/driver_extension.dart';
import 'package:flutter/material.dart';
import 'my_app.dart'; // Replace with your actual import

void main() {
 // setting enableTextEntryEmulation: false allows keyboard interations
  enableFlutterDriverExtension(enableTextEntryEmulation: false);
  runApp(MyApp());
}

Modify Your AppiumCapabilities Code

When configuring your Appium capabilities for automated testing, it’s essential to understand the role of unicodeKeyboard and resetKeyboard capabilities. These settings play a crucial role in managing the virtual keyboard’s behavior during your test execution. Below is a brief explanation of what these capabilities do and why you might want to set them to false and true respectively:

unicodeKeyboard

  • Purpose: This capability is used to enable a Unicode keyboard on Android devices. It allows the Appium driver to input text using Unicode characters, which can be particularly useful for testing applications with internationalization and special character requirements.
  • Setting to false: By setting unicodeKeyboard to false, you disable the Unicode keyboard. This might be necessary if your application does not require special characters or if you want to use the default keyboard provided by the device. It ensures that the keyboard behavior remains as close to the typical user experience as possible.
  • resetKeyboard

    • Purpose: This capability resets the keyboard to its original state after the test is finished. It is helpful in ensuring that any custom keyboard settings applied during the test do not persist beyond the test session.
    • Setting to true: By setting resetKeyboard to true, you ensure that any modifications made to the keyboard (such as enabling the Unicode keyboard) are reverted after the test. This is particularly useful for maintaining a clean state between test runs and ensuring that subsequent tests are not affected by previous keyboard configurations.
Dart
DesiredCapabilities caps = new DesiredCapabilities();
// ...
// Keyboard capabilities
caps.setCapability("unicodeKeyboard", false);
caps.setCapability("resetKeyboard", true);
// ...

Creating the Utils Class

The Utils class is a helper utility designed to facilitate context switching and keyboard state detection in an Appium-based test automation setup. The class primarily focuses on managing contexts (switching between native and Flutter contexts) and checking the visibility of the virtual keyboard in an Android environment.

Utils.class
public class Utils {
    private AppiumDriver driver;
// ...

 

Declared a private instance variable driver of type AppiumDriver, which will be used to interact with the mobile application.

Method: switchToNativeContext
switchToNativeContext.class
public void switchToNativeContext(AppiumDriver driver) {
    this.driver = driver;
    try {
        // Ensure the driver supports context switching
        if (!(driver instanceof SupportsContextSwitching)) {
            throw new IllegalStateException("The driver does not support context switching.");
        }

        // List all available contexts
        Set<String> contextNames = ((SupportsContextSwitching) driver).getContextHandles();
        for (String contextName : contextNames) {
            System.out.println(contextName); // Print available contexts for debugging
        }

        // Switch to native context if available
        if (contextNames.contains("NATIVE_APP")) {
            ((SupportsContextSwitching) driver).context("NATIVE_APP");
        } else {
            System.out.println("NATIVE_APP context not found!");
        }
    } catch (Exception e) {
        System.err.println("An error occurred while switching context: " + e.getMessage());
        e.printStackTrace();
    }
}
  • Method Purpose: This method switches the Appium driver context to the native context of the mobile application.
  • Parameter: Accepts an AppiumDriver object named driver.
  • Context Switching Check: Checks if the provided driver supports context switching using instanceof SupportsContextSwitching. Throws an exception if it doesn’t.
  • Listing Contexts: Retrieves all available contexts and prints them for debugging purposes.
  • Switching Context: Attempts to switch to the native context (NATIVE_APP). If not found, it logs a message indicating that the native context was not found.
  • Exception Handling: Catches any exceptions that occur during context switching and logs the error message and stack trace.
Method: switchToFlutterContext
switchToFlutterContext.class
public void switchToFlutterContext(AppiumDriver driver) {
    this.driver = driver;
    try {
        // Ensure the driver supports context switching
        if (!(driver instanceof SupportsContextSwitching)) {
            throw new IllegalStateException("The driver does not support context switching.");
        }

        // List all available contexts
        Set<String> contextNames = ((SupportsContextSwitching) driver).getContextHandles();
        for (String contextName : contextNames) {
            System.out.println(contextName); // Print available contexts for debugging
        }

        // Switch to flutter context if available
        if (contextNames.contains("FLUTTER")) {
            ((SupportsContextSwitching) driver).context("FLUTTER");
        } else {
            System.out.println("FLUTTER context not found!");
        }
    } catch (Exception e) {
        System.err.println("An error occurred while switching context: " + e.getMessage());
        e.printStackTrace();
    }
}
  • Switching Context: Attempts to switch to the Flutter context (FLUTTER). If not found, it logs a message indicating that the Flutter context was not found.
  • Exception Handling: Same as the previous method.
Method: isKeyboardShown
isKeyboardShown()
public boolean isKeyboardShown() {
    return ((AndroidDriver) driver).isKeyboardShown();
}

Checks if the virtual keyboard is currently shown on the Android device.

  • Return Type: Returns a boolean value indicating whether the keyboard is shown (true) or not (false).
  • Casting: Casts the AppiumDriver instance to an AndroidDriver to use the isKeyboardShown method.

Implement Switching Context In Test

Setup your class to start interacting with the keyboard. In this example I have a class called LoginScreenAndoridTest this is where I’ll use the Utils class to interact with the virtual keyboard. Here’s how to set it up:

loginIntoAppTest()
@Test()
	public void loginIntoAppTest() throws Exception {
	    utils = new Utils();

		FlutterElement signInButton = find.byText("SIGN IN");

		signInButton.click();
		// switch to native context to interact with keyboard
		utils.switchToNativeContext(testDriver);

		WebElement emailTextFeild = driver.findElement(AppiumBy.xpath("//android.view.View[contains(@content-desc, 'Email')]/android.widget.EditText[1]"));
		emailTextFeild.click();
        // enter email
        if (utils.isKeyboardShown()) {
        	utils.typeTextViaKeyboard(testDriver,"JohnDoe@mytest.com");
           ((AndroidDriver) testDriver).pressKey(new KeyEvent(AndroidKey.ENTER));
        }

		WebElement passwordTextFeild = testDriver.findElement(AppiumBy.xpath("//android.view.View[contains(@content-desc, 'Password')]/android.widget.EditText[2]"));
		passwordTextFeild.click();
        // enter password
        if (utils.isKeyboardShown()) {
        	utils.typeTextViaKeyboard(testDriver,"Welcome");
           ((AndroidDriver) testDriver).pressKey(new KeyEvent(AndroidKey.ENTER));
        }
        // switch back to Flutter context
		utils.switchToFlutterContext(testDriver);

	}

Key Points

  1. Flutter Code Configuration: Add enableFlutterDriverExtension(enableTextEntryEmulation: false); in your main.dart file to disable text entry emulation.
  2. Context Switching: Use the Utils class to switch between contexts in your Appium tests.
  3. Typing Text via Virtual Keyboard: Use the typeTextViaKeyboard method to handle text input, including uppercase characters.

Conclusion

By following these steps, you can effectively use the emulator virtual keyboard in your Flutter app for Appium testing. This setup ensures that your automated tests can interact with the app just as a real user would, providing more reliable and comprehensive test coverage. Happy testing!

Facebook
Twitter
LinkedIn
Want Access to The GitHub Repository?

Want Access to The GitHub Repository?

Join our community on Patreon! As a member, you'll get exclusive access to our private code repositories, receive personalized one-on-one debugging and implementation support, and much more. 

Become A Member

Leave a Comment

Review Your Cart
0
Add Coupon Code
Subtotal
Total Installment Payments
Bundle Discount