Mastering QA Articles Android Studio Appium Cucumber (Gherkin) Cypress Eclipse Flutter GitLab JMeter JUnit LambdaTest Patrol Playwright Postman Selenium TestNG VSCode WebDriverIO XCode Android Studio Official Docs Explore the latest tools and features for Android development on the Official Android Studio website. Stay updated with the most powerful integrated development environment (IDE) designed specifically for building & testing high-quality Android apps! Become a Pro Member - Unlock Advanced Tools & ResourcesGain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member!FrameworksAccelerate your testing with our premium Android UI Test Framework. Gain the tools you need to automate, optimize, and perfect your app’s user experience with ease. Android UI Test Framework Purchase Access to the Android UI Test Framework Introduction to Android Studio Introduction to Android StudioWelcome to Mastering QA! In this guide, we’ll start by introducing you to Android Studio, the official Integrated Development Environment (IDE) for Android app development. Whether you’re a beginner or an advanced user, understanding Android Studio is crucial for building and testing Android applications.What is Android Studio?Android Studio is the official IDE for Android app development, based on IntelliJ IDEA. It provides a comprehensive set of tools for developing and debugging Android applications, including a robust code editor, emulator, and more.Key FeaturesHere are some features of Android Studio: Intelligent Code Editor: Offers code completion, refactoring, and analysis. Visual Layout Editor: Design your app visually with drag-and-drop functionality. Flexible Build System: Powered by Gradle, it allows for custom build configurations. Real-time Profiler: Monitor your app's CPU, memory, and network activity in real-time.How To Install Android StudioTo begin the installation process for Android Studio, first, proceed to the official website by selecting this link: Download Android Studio. As of the creation of this document, the most current version of Android Studio is Hedgehog To download this version, click on the Download Android Studio Hedgehog button. Doing so will direct you to the Terms and Conditions page. Android Studio - Hedgehog Version Carefully examine the details outlined in the Terms and Conditions and ensure to mark the checkbox indicating your acknowledgment and agreement with the stated terms. Depending on the specific chip architecture of your Mac, select the appropriate download option to initiate the download of the Integrated Development Environment (IDE). For instance, as I am utilizing a Mac equipped with an Apple chip, I will proceed by selecting the corresponding option designated for Apple silicon Choose A Download Version Compatible For Your MachineSelect a destination for the file to be saved, and upon completion, the file will be located in your designated folder. To initiate the installation process of Android Studio, double-click the file. This action will launch the Android Studio Installer. Proceed by dragging the application into the Applications folder, ensuring it is accessible from the Launchpad for your convenience. Find The DMG File & Add It to Your Applications FolderAfter transferring the Android Studio application to the Applications folder, proceed to double-click the Android Studio icon. You will then be prompted by Apple to verify trust for the application. Upon confirmation, Android Studio will initiate, first presenting tips for optimal usage, followed by the Welcome screen to begin your development journey. Android Studio Welcome ScreenConfiguring The SDKTo configure the SDK on a Mac, ensure that the Android Studio application is active and in the foreground. Next, navigate to the top left corner of your screen, click on Android Studio, and from the dropdown menu, select Settings… Navigating to the Settings Screen in Android StudioUpon accessing the Settings screen, please proceed to the Languages and Frameworks section. Languages & Frameworks via the SettingsPlease proceed to expand the dropdown menu in order to access the Android SDK Settings. Should you encounter a notification indicating “The Android SDK location cannot be at the file system root” kindly select the Edit option to proceed to SDK Components Setup screen. Android SDK & Add The SDK Path Installing The Android SDK PlatformIn this scenario, the screen indicates the presence of an existing Android SDK, which is beneficial. Please proceed by clicking Next Following this, we will be directed to the Verify Settings screen for further confirmation. Verify Settings ScreenGiven that Android Studio has already identified the SDK’s location, we may proceed by selecting Next to advance further in the process. Click Finish To Complete The SDK SetupSince that the SDK is already up to date, we may proceed by selecting Finish This action will redirect us back to the SDK Tools and Platforms screen. View The Different Android Platform Versions Available to DownloadNext, we will select and download various Android platforms, which will be essential for building an Android emulator later on. Below, you will find a comprehensive list of Android versions, allowing you to precisely choose the version you wish to utilize for your application’s development. A Comprehensive List of Android VersionsI have opted to select Android Studio version 13.0, corresponding to API version 34. Adjacent to this option, a download icon is displayed, signifying that this specific version will be downloaded. Select Android Studio Version 13.0Subsequently, proceed to select the SDK Tools tab, then carefully choose all the components listed in Step 2 below. Once completed, click on Apply to proceed with the installation. Click Apply To Download The VersionA confirmation screen will be displayed, enumerating all selected Android platforms and SDK Tools. Please click OK to initiate the download process. Confirm Changes & Click OkUpon completing all necessary steps, please click on Finish to conclude the process. Android SDK Component Setup Is Complete After completing this step, you will be redirected to the Android SDK screen. Please proceed by simply clicking OK To verify that all processes have executed as expected, it is recommended that you close and then reopen Android Studio. This measure ensures the smooth integration of any changes.ConclusionAndroid Studio is a powerful tool that lays the foundation for Android development. In the next guide, we’ll walk you through setting up your first Android emulator, a crucial step for testing your applications. Continue to Setting Up Your First Android Emulator to learn more. Setting Up Your First Android Emulator In the previous guide, we introduced you to Android Studio. Now, let’s move forward by setting up your first Android emulator. Emulators are essential for testing your applications without needing a physical device.What is an Android Emulator?An Android emulator is a virtual device that mimics the hardware and software of a real Android device. It allows you to test your applications on various configurations and Android versions.Open Android StudioFirst things first, let’s make sure Android Studio is up and running on your Mac. Android Studio Hedgehog LaunchedLaunch the Virtual Device ManagerNow that Android Studio is up and running, there are a couple ways you can create or launch a virtual device. Pick a method that best fits your current setup.Welcome ScreenOn the welcome screen click More Actions Virtual Device Manager Android Studio Welcome Screen > Create Virtual DeviceProject ViewIn project view, navigate to the menu bar and click on Tools Device Manager . Android Studio - Device ManagerCreating a New Virtual DeviceNow that the AVD Manager is launched, you may see a list of existing virtual devices, if others were previously created. To create a new one, click on the + button to create a virtual device. Android Studio - Creating A New Virtual DeviceChoose a Device DefinitionNext on the Select Hardware screen, you can choose the type device you want to emulate. If you’re not sure about which one to build, you can’t go wrong with a Pixel. In this example I’m going to choose the Pixel 7 and then click Next . Creating A New Virtual DeviceSelect a System ImageNext, you’ll need to choose a system image. This is essentially the version of Android you want to run on your virtual device. Pick the latest version available, or select an older version if your app requires it. If the version you want to use is grayed out, click the download icon to download that version. Choosing A Device TypeConfigure Your Virtual DeviceNow it’s time to configure your virtual device. For your AVD Name, you can choose to keep the default name but better command line readability, use this style pixel-7-api-34. Ensure the startup orientation is in Portrait and check the box to Enable device frame. Selecting A System ImageFinish and LaunchOnce you’ve configured your virtual device to your liking, click on the Finish button. Android Studio will then create your virtual device. Once it’s done, click on the play button to launch your emulator. New Virtual Device CreatedEmulator RunningDepending on your Mac’s performance, it might take a little while for the emulator to start up. Pixel 7 Emulator LaunchedConclusionWith your emulator set up, you can now test your applications in a virtual environment. The next step involves installing APK apps on your emulator for testing purposes. Proceed to Installing an APK app on an Android Emulator to continue your journey. Installing an APK app on an Android Emulator After setting up your Android emulator, the next step is to install and test APK applications on it. This guide will walk you through the process of installing an APK on your emulator.Installing App via Project ViewWith your emulator up and running, it’s time to fire up your app! Go back to Android Studio and click on the green play button in the toolbar or from the menu bar, select Run . Android Studio will build your app and install it on the emulator. Installing App On EmulatorOnce the installation process is complete, your app will automatically launch on the emulator. App Installed SuccessfullyInstalling Your App via APKAnother method to installing an app on your emulator would be through an apk file. To add an apk to your device simply navigate to location of your apk or download an apk file from a trusted source online. For this example I will be using the same apk generated after building the app from the project. Since I’m using Flutter project to build this app, the location of the apk is here App Project build app outputsflutter-apkapp-debug.apk Build Location of the APK FileOnce you locate your apk, simply drag and drop the apk onto the emulator for it to install. Installing APK By Dragging & Dropping On EmulatorConclusionVoila! Your app is now running on the emulator. Take some time to explore its features and functionalities. Click around, interact with different elements, and get a feel for how it behaves. Next, we’ll explore how to use ADB with Android emulators to perform various debugging tasks. Head over to Using ADB with Android Emulators for more insights. Using ADB with Android Emulators Previously, we covered installing APK apps on your emulator. Now, let’s delve into using ADB (Android Debug Bridge) with Android emulators. ADB is a powerful command-line tool that enables communication with your emulator or device. Want Access to the Test App & Framework?Unlock access to our test app crafted to provide a hands-on approach to Android UI testing. PRO MEMBER Tip: Please ensure you have an emulator created and running before hand. Device Info: Pixel 8 | API 33Connecting ADB to an EmulatorOnce your emulator is running, you need to connect ADB to it.Open Terminal: Launch the Terminal App on your on your Mac. Launch TerminalNavigate to ADB Directory: Navigate to the directory where ADB is installed. This is typically in the platform-tools directory of your Android SDK.bashcd /Users/{UserName}/Library/Android/sdk/platform-tools Changing Directory To Platform ToolsCheck Connected Devices: Run the following command to list connected devices and emulators.bashadb devices List of Running Devices Displayed You should see your emulator listed. If not, restart the ADB server. In Terminal paste the command below:bashadb kill-server adb start-serverCommon ADB CommandsHere are some essential ADB commands for quality testing:Installing an APK: To Install an application on the emulator. Use this command.bashadb install /Users/{UserName}/Desktop/test-apps/app-debug.apk Installing An APK Using ADB CommandGet Android Package Name: Get the name of the Android app’s package name in order to use the uninstall command later. With the test app lauched on the emulator, open a new terminal and enter this command below:bashadb shell dumpsys window | grep 'mCurrentFocus' Name of App Package & Main ActivityUninstall an APK: Remove an application from the emulator.bashadb uninstall com.example.yourapp Uninstalling APK Using ADB CommandConclusionThe ADB is an essential tool for Android development and debugging. Mastering its commands will enhance your ability to manage and debug your applications effectively. Up next, we’ll cover automating UI tests on Android emulators, a crucial step for ensuring your app’s usability. Continue to Automating UI Tests on Android Emulators for detailed instructions. Automating UI Tests on Android Emulators Building on our knowledge of ADB, this guide focuses on automating UI tests on Android emulators. Automated UI tests ensure that your application’s user interface behaves as expected across different scenarios and devices.Why Automate UI Tests?Automated UI tests save time and resources by running tests that simulate user interactions. They help identify bugs and inconsistencies in the UI, providing a reliable way to maintain high-quality applications.Setting Up Espresso for UI TestingAdd DependenciesYou need to add Espresso and other related dependencies in your build.gradle file of your Android app module (app/build.gradle).android/app/build.gradle defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" }Create a Test Class In src/androidTest/java and call it MainActivityTest.This test will ensure that the app is launched and ready for interaction. The test method will simulate a user clicking the plus button and verifies the resulting UI state.MainActivityTest.class@RunWith(AndroidJUnit4.class) @LargeTest public class MainActivityTest {@RunWith(AndroidJUnit4.class): This annotation tells JUnit to run the test class using the AndroidJUnit4 test runner. This runner provides compatibility with Android components and manages the test lifecycle.@LargeTest: This annotation classifies the test as a “large” test. Large tests typically involve integration testing, where multiple components of the application are tested together.MainActivity.class@Rule public ActivityScenarioRule<MainActivity> activityRule = new ActivityScenarioRule<>(MainActivity.class); @Rule public DisableAnimationsRule disableAnimationsRule = new DisableAnimationsRule();@Rule: Rules in JUnit are used to add or extend the behavior of each test method in a test class. They provide additional functionality before and after each test is run.ActivityScenarioRule<MainActivity> activityRule: This rule launches the specified activity (MainActivity in this case) before each test and closes it after each test. It provides a simplified way to test activities. The ActivityScenarioRule starts and stops the activity and also ensures that the activity is running before the test begins.DisableAnimationsRule disableAnimationsRule: This custom rule is used to disable system animations during the test run. Animations can interfere with Espresso tests by causing unexpected delays or timing issues, so disabling them ensures more consistent test results.MainActivity.class@Test public void testClickPlusButton() throws InterruptedException { // Click the plus button to open the AddEditTaskActivity onView(withId(R.id.fab)).perform(click()); // Verify that the AddEditTaskActivity is displayed by checking for the presence of the title EditText onView(withId(R.id.titleEditText)).check(matches(withText(""))); }@Test: This annotation indicates that the following method is a test method. JUnit will execute this method as a test case.public void testClickPlusButton(): This is the test method. The method name typically describes what is being tested. In this case, it tests the behavior of clicking the plus button.onView(withId(R.id.fab)).perform(click());: This line uses Espresso to interact with the UI. It finds a view with the ID fab which is the floating action button in this app and performs a click action on it. Espresso’s onView method is used to find views in the current activity’s layout, and perform is used to execute actions on those views.onView(withId(R.id.titleEditText)).check(matches(withText("")));: This line verifies that a view with the ID titleEditText is displayed and that its text is empty. This check is used to confirm that the AddEditTaskActivity is displayed by looking for the presence of an empty title EditText. The check method is used to perform assertions on views, and matches verifies that the view’s state matches the specified condition. Since this is a ToDo app, let’s enhance the test suite by adding two more critical scenarios: one for adding a task and another for deleting a task. These scenarios will ensure that the core functionalities of creating and removing tasks are working as expected.MainActivity.class@Test public void testAddTask() throws InterruptedException { // Click the plus button to open the AddEditTaskActivity onView(withId(R.id.fab)).perform(click()); // Enter text into the title and description fields and close the keyboard onView(withId(R.id.titleEditText)) .perform(typeText("New Task Title"), closeSoftKeyboard()); onView(withId(R.id.descriptionEditText)) .perform(typeText("New Task Description"), closeSoftKeyboard()); // Click the save button onView(withId(R.id.saveButton)).perform(click()); // Verify that the new task is displayed onView(withText(endsWith("New Task Title"))) .check(matches(isDisplayed())); } @Test public void testDeleteTask() throws InterruptedException { // Delete the task onView(withId(R.id.doneButton)).perform(click()); Thread.sleep(2000); // Verify that the task is deleted by checking that the item is not in the list onView(withText(endsWith("Task to Delete"))).check(doesNotExist()); Thread.sleep(2000); }Running UI TestsClick on the green play icon next to the class definition to run all tests in the class. Alternatively, click on the green play icon next to individual test methods to run specific tests. Running Android UI TestViewing Test Results Once the tests start running, the Run window will display the progress and results. The Run window shows which tests passed or failed, along with detailed logs and stack traces for any failures.Analyze Test Results Green checkmarks indicate passed tests. Red X marks indicate failed tests, with details about the failure. Yellow warning signs indicate ignored or skipped tests. Reviewing Expresso Test ResultsConclusionAutomating UI tests with Espresso provides a robust way to ensure your app’s user interface functions correctly. Next, we’ll explore performance testing on Android emulators, which is vital for optimizing your app’s performance. Proceed to Performance Testing on Android Emulators for more information. Performance Testing on Android Emulators Having covered UI testing, we now turn to performance testing on Android emulators. Performance testing helps identify bottlenecks and ensures your application runs smoothly under various conditions.Performance TestingPerformance testing is crucial for delivering a responsive and efficient app. It helps detect issues related to memory usage, CPU load, and network performance, ensuring a seamless user experience.Using Android Profiler Open Android Profiler - In Android Studio, navigate to: View > Tool Windows > Profiler or you can click the Profiler icon in the bottom toolbar. Android Studio Profiler Select an Emulator: Choose the emulator or device to profile. If your device is already running, it will automatically use that device. Android Studio Profiler > Select Active Emulator CPU Profiler: Monitor your app's CPU usage, threads, and methods. Android Studio Profiler > CPU Profiler Memory Profiler: Track memory allocation and garbage collection. Android Studio Profiler > Memory ProfilerRunning Performance Tests Profile Your App: Use the profiler tools to identify performance issues during test execution.Memory Profiler Record Android Studio > Memory Profiler Record Android Studio > Memory Profiler ResultsCPU Profiler Record Android Studio > CPU Profiler Record Android Studio > CPU Profiler ResultsConclusionPerformance testing on Android emulators is essential for optimizing your app and ensuring it performs well under various conditions. This completes our series of guides on mastering Android Studio and emulators. Keep exploring and honing your skills to become a proficient Android developer and QA tester. Appium Official DocsDiscover more about Appium, the powerful tool for automating mobile app testing, by visiting the Official Appium Website. Explore its full range of features, documentation, and community resources to enhance your testing efficiency. Become a Pro Member - Unlock Advanced Tools & ResourcesGain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member! Intro to Appium Welcome to the first part of our Mastering QA series, where we delve into the world of Appium, a powerful open-source tool for mobile app automation. Appium allows you to write tests for iOS and Android applications using the same API, which makes it a versatile and indispensable tool for QA engineers. Appium Desktop AppWhat is Appium?Appium is an open-source tool for automating mobile applications. It allows you to write tests for mobile apps on Android and iOS platforms using a variety of programming languages, such as Java, Python, Ruby, and more. Appium is built on the philosophy that testing native or hybrid apps shouldn’t require including an SDK or recompiling your app. Appium Server RunningKey Features of Appium Cross-Platform: Supports testing on both Android and iOS. Multiple Languages: Write tests in any language that has a Selenium client library. Open Source: Free to use and has a large, active community. No App Modification: No need to modify or recompile your app for testing. Understanding Android Desired Capabilities When setting up your testing environment for Android applications, it's crucial to configure the desired capabilities properly. For our setup, we define the following properties:PLATFORM_NAME: AndroidPLATFORM_VERSION: 13.0DEVICE_NAME: emulator-5554APP: [Your app path here]AUTOMATION_NAME: Flutter (for Flutter applications), for typical Android frameworks use UIAutomator2 Android Desired Capabilities Setup Understanding IOS Desired Capabilities To set up your iOS testing environment, configure the following Desired Capabilities:PLATFORM_NAME: iOSPLATFORM_VERSION: 17.0.1DEVICE_NAME: iPhone 15 ProUDID: [Add your device ID here]APP: [Your app path here]AUTOMATION_NAME: Use Flutter for Flutter applications, or opt for XCUITest for native iOS testing.Additionally, ensure to include:xcodeOrgID: [Your Xcode organization ID]xcodeSigningID: [Your Xcode signing ID]This configuration ensures a seamless testing experience across iOS platforms, leveraging the latest capabilities and features. IOS Desired Capabilities SetupWhy Use AppiumAppium stands out for several reasons, here are a few to consider. Versatility: It supports a wide range of mobile applications, including native, hybrid, and mobile web applications. Flexibility: You can use your preferred development tools, practices, and frameworks. Integration: Easily integrates with popular CI/CD tools, enhancing your development workflow. Community: Strong community support ensures continuous improvement and a wealth of shared knowledge and resources.ConclusionNow that you have a basic understanding of what Appium is and why it’s beneficial, it’s time to get hands-on. In the next guide, we’ll walk you through Setting up Appium on Your Local Machine. Setting Up Appium on Local Machine In the previous guide, we introduced you to Appium and its benefits. Now, let’s get started with setting up Appium on your local machine so you can begin writing and executing your tests.PrerequisitesBefore you start, ensure you have the following installed. Java Development Kit (JDK): Appium requires Java, so download and install the JDK. Node.js: Appium is built on Node.js, so you'll need to install it. Android SDK: Necessary for Android app testing. [conditional_data dependency="Windows"]Xcode: N/A[/conditional_data][conditional_data dependency="Mac"]Xcode: Required for iOS app testing.[/conditional_data]Getting StartedInstall Java and Configure the Environment Variables. Download and install the JDK from the Oracle website. Next we are going to setup the JAVA_HOME and update the PATH environment variable to ensure Java is configured correctly on your system. How to Set JAVA HOME Environment Variable on Mac and Windows Install Node.js Installing Node.js is essential for setting up Appium, as Appium relies on Node.js. With Node.js, you can run the Appium server and use npm to install Appium and its dependencies efficiently. This setup is crucial for automating mobile application tests on both Android and iOS platforms. Download and install Node.js from the official website. How To Install Node.js On Mac & Windows Guide Install Appium CLI & Appium Doctor CommandsInstall Appium: Appium is an open-source tool for automating mobile applications on Android and iOS. To get started, you need to install Appium and its dependencies: Open your [conditional_data dependency="windows"]Command Prompt[/conditional_data][conditional_data dependency="mac"]Terminal[/conditional_data] and run the following command.bashnpm install -g appiumInstall Appium Doctor: Appium Doctor is a tool that helps you verify that all the dependencies required for running Appium are properly installed on your system. It checks for Node.js, Java, Android SDK, Xcode and more.Install Appium Desktop GUI Appium Desktop is a graphical user interface (GUI) for Appium, providing an easy way to interact with the Appium server and inspect mobile application elements. It simplifies the process of setting up and managing Appium sessions, making it an essential tool for mobile test automation. Appium Desktop App Download and install Appium Desktop from the Appium website.Install Android SDK To use Appium for automating tests on Android devices, you need to install the Android Software Development Kit (SDK). The Android SDK provides the necessary tools and libraries for developing and testing Android applications. It includes the Android platform tools, such as adb, which Appium uses to interact with Android devices and emulators. Download and install the Android SDK from the Android Developer website or you can follow our guide below. Introduction to Android Studio Configure Android Environment VariablesSet ANDROID_HOME and update the PATH environment variable..bash_profile/.zshrcexport ANDROID_HOME=/path/to/android/sdk export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH Install XcodeTo use Appium for testing iOS applications, you’ll need to install Xcode on your Mac. Xcode is Apple’s integrated development environment (IDE) for macOS, used for developing software for iOS, macOS, watchOS, and tvOS. It includes a suite of software development tools, including the iOS Simulator, which is essential for testing iOS apps with Appium.Searching For XCode In Mac App StoreFollow this guide below to Setuo Xcode on your machine. Protected: Setting Up Xcode for New Users ConclusionCongratulations! You have successfully set up Appium on your local machine. Now you’re ready to write your first test case with Appium. In the next guide, we’ll walk you through Writing Your First Appium Test Case with Appium. Writing Your First Test Case with Appium Now that you have Appium set up on your local machine, it’s time to dive into writing your first test case. This guide will walk you through the process of creating a simple test case in Java.Create a New Maven ProjectUse your favorite IDE to create a new Maven project. We’re going to be using Eclipse in this setup. Eclipse IDE LaunchingCreating A New ProjectStart a new project by navigating to the top menu and selecting File then New and finally Other... File > New > OtherIn the wizard window that appears, scroll down to find the Maven folder. Expand the Maven folder by clicking on the small triangle next to it, and then select Maven Project. Click Next to proceed with the project setup. Choosing Maven ProjectIn the next step of the wizard, you will see an option to create a simple project. To proceed, click the checkbox labeled Create a simple project (skip archetype selection). Once you have checked this option, click the Next > button to move forward with the project setup. Check The Create A Simple Project BoxOn the next step of the wizard, you will need to create a group ID and an artifact ID for your project. For this guide, use com.test.app.todo as both the group ID and artifact ID. Enter these values in the respective fields provided. After filling in the details, click the Finish button to continue. Create a Group Id & Artifact Id nameCreate a New Test ClassWith our Maven project created, the next step is to create a new test class. Navigate to the directory src/test/java/. Inside this directory, create a new package by following this path: com.test. Create A New Package To Store Your Test Files Setting 'com.test' As A Package NameOnce the package is created, add a new class within it and name the class FirstAppiumTest. Creating A New Class Set The Class Name As FirstAppiumTest The FirstAppiumTest Class Is CreatedAdd Dependencies to pom.xmlNow, navigate to the pom.xml file in your project. This file is essential for managing your project’s dependencies and configurations. Open the pom.xml file, as we will be adding the necessary dependencies to run an Appium test script. Once the file is open, so we can add the xml dependencies below.pom.xml<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test-todo-app</groupId> <artifactId>test-todo-app</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>io.appium</groupId> <artifactId>java-client</artifactId> <version>8.3.0</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.7.0</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-remote-driver</artifactId> <version>4.7.0</version> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> <version>2.2</version> <scope>test</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M5</version> </plugin> </plugins> </build> </project>Add Your APK To The ProjectTo add your test APK to your project, begin by creating a new directory within your project’s structure. Navigate to the src/test/resources/ directory. Within this directory, create a new folder named app. This is where you will store your APK file for testing purposes. Create A New Folder To Store The Test App Setting The Directory As 'App' Added The Test App In The 'App' FolderWrite Your First Test ScriptLet’s take a look at our test application and discuss the test scenario that we’ll be automating. The test application we’ll be using is a TODO app. If you need access to the APK file, please join our Patreon. Members get access to all the existing frameworks we’ve created and more. You can follow along with this guide or use your own test application and tweak the elements as needed. In this test, our goal is to simply click on the Add Task button to display the Add Task screen. Add A Task Button Viewing Add Task ScreenFirstAppiumTest.javapackage com.test; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.net.MalformedURLException; import java.net.URL; public class FirstAppiumTest { public static void main(String[] args) throws MalformedURLException, InterruptedException { File app = new File("src/test/resources/app/app-debug.apk"); // Set the desired capabilities for your test DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("deviceName", "emulator-5554"); caps.setCapability("platformName", "android"); caps.setCapability("app",app.getAbsolutePath()); // Initialize the Appium driver AndroidDriver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps); // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("ADD_YOUR_ID_HERE")); addTaskButton.click(); // quick debug wait for 1 seconds Thread.sleep(1000); // Close the driver session driver.quit(); } }Launch Appium Desktop & Appium InspectorNow, we need to find the id associated with the element that we want to click. To locate the id element or other useful selectors, ensure that the emulator or device is booted up. First, launch the Appium Server and Inspector. Open the Appium Desktop Server and click the startServer button. Next, launch the Appium Inspector, making sure that the server port matches the Appium server’s port. Appium Desktop with Emulator Appium Server Is Running Appium Inspector + Setting Up Desired Capabilities Ensure the Remote Port is set to 4273 Set the Remote Path to /wd/hub Click the pencil & Copy the Desired Capabilities from below and paste in the JSON Representation box Click the Save button Click the Start Session button Desired Capabilities JSON DesiredCapabilities.json{ "appium:platformName": "Android", "appium:platformVersion": "13.0", "appium:deviceName": "emulator-5554", "appium:automationName": "UiAutomator2", "appium:app": "/Users/{userName}/eclipse-workspace/test-todo-app/src/test/resources/app/app-debug.apk", "appium:appWaitForLaunch": true }Inspecting The App ElementsWith the Appium Inspector now launched, you should see a preview of your application. In the preview window, locate and click on the element for which you want to retrieve attributes. For the purposes of this guide, we will click on the Add Task button. By doing so, the attributes related to this specific element will be displayed, allowing you to inspect and utilize them as needed. Appium Inspector Viewing The Element's Properties The accessibility id: value is to Add Task The id: value is to com.example.todoapp:id/fab The xpath: value is to //android.widget.ImageButton[@content-desc="Add Task"]You have the flexibility to use any available selector, but for this guide, we will select the second option, which represents the id attribute with the value com.example.todapp:id/fab. This value will be used in our code. Close the Appium Inspector Session to free up the Appium Server 4273 port.Copy this id value and navigate to the FirstAppiumTest class in your project. Find the element designated for adding a task and paste the copied id value into the addTaskButton element. This ensures that our test script can correctly interact with the element. Finding Add Task Button Element By IDJavaWebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 1 seconds Thread.sleep(1000); System.out.println("TEST PASSED!"); // Close the driver session driver.quit();Run Your TestFinally, it’s time to run the script. Yay! In the FirstAppiumTest class, right-click to open the context menu. Navigate to Run As and select Java Application. Now, sit back and watch as your script takes off for the first time! If everything goes well, you will see TEST PASSED in the console. Appium Run As Java ApplicationAnalyze the Test ResultsAfter the test execution is complete, review the results to ensure your test case ran successfully. Later in this series, we will learn how to implement TestNG to organize tests based on industry standards. Test Results - Passed Running Appium Test ScriptConclusionYou have now learned how to perform basic UI testing with Appium. This includes finding elements and performing actions. In the next guide, we’ll take a closer look at Organizing Multiple Test Scenarios In Appium with TestNG. Organizing Multiple Test Scenarios in Appium Using TestNG In the dynamic world of mobile application testing, managing and organizing multiple test scenarios efficiently is crucial for ensuring robust and reliable testing. Appium, combined with TestNG, provides a powerful framework to achieve this. This guide will walk you through the process of organizing multiple test scenarios in Appium using TestNG, leveraging the power of Java. Whether you’re a beginner or an advanced user, this comprehensive guide will help you streamline your test automation process and enhance your testing capabilities. We will be using the project we setup previously. Setting Up Maven ProjectLet’s navigate to the pom.xml file so we can add the TestNG dependency. We’ll be using TestNG version 7.1.0 for our project. Adding TestNG Dependency To pom.xmlTestNG Dependency (pom.xml)<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.1.0</version> <scope>compile</scope> </dependency>By adding the TestNG dependency to your Maven project, you now have the necessary annotations to write and execute TestNG tests within the Appium project.Creating TestNG Class Let’s head back to our directory /src/test/java/com/test/ where we’ll create a copy of the existing FirstAppiumTest class. We’ll then rename this copy to FirstAppiumTestNG to begin restructuring the test to support TestNG. This new class will serve as our foundation for integrating TestNG functionalities. Copying FirstAppiumTest Class Pasting FirstAppiumTest Class Rename Copied File to FirstAppiumTestNGImporting TestNG AnnotationsIn the newly created FirstAppiumTestNG class, begin by importing the necessary TestNG annotations. These will include @BeforeClass, @AfterClass, and @Test.FirstAppiumTestNG.classimport org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; The @BeforeClass annotation will be used to set up the Appium driver before any tests are run, ensuring that the environment is correctly initialized. Similarly, the @AfterClass annotation will handle the teardown process, cleaning up resources once all tests have been executed. The @Test annotation will be applied to individual test methods, marking them as TestNG test cases.Modifying Class To Support TestNGSo what we’re going to do is remove the main() function call and close the curly bracket from our initial setup. Next, we will create a new public static AndroidDriver variable called driver. BeforeClassIn the @BeforeClass method, we will move the Desired Capabilities setup into the setup() function. This approach ensures that our Appium driver is properly configured before any tests are execute. Moving Desired Capabilities To BeforeClass MethodTest MethodIn the @Test method, we will add our simple test case from the previous guide, which is to click the Add Task button. This test will validate that our application responds correctly when adding a new task. By organizing our tests this way, we maintain a clear separation of concerns, making our test cases easier to manage and understand. Moving Scenario To Test MethodAfterClass MethodFinally, we’ll move the driver.quit() function into the @AfterClass teardown method. This adjustment ensures that the Appium driver is properly closed after all tests have been executed, cleaning up any resources used during the test run. Moving The Closing of the Driver in AfterClass MethodFirstAppiumTestNG.class (w/ Before & After Methods)package com.test; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FirstAppiumTestNG { public static AndroidDriver driver; @BeforeClass public void setUp() throws MalformedURLException { File app = new File("src/test/resources/app/app-debug.apk"); // Set the desired capabilities for your test DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("deviceName", "emulator-5554"); caps.setCapability("platformName", "android"); caps.setCapability("app",app.getAbsolutePath()); // Initialize the Appium driver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps); } @Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 1 seconds Thread.sleep(1000); System.out.println("TEST PASSED!"); } @AfterClass public void tearDown() { if (driver != null) { // Close the driver session driver.quit(); } } }Adding More Test & AssertionsWhy stop here? Next, we’ll add some assertions and create two more test scenarios to highlight the beauty of TestNG running multiple scenarios and validating our expectations. We will create new tests called addingTaskToDoTheList() and deletingTaskFromTheList(), similar to the test we created using Espresso in our Android guides. We will add these methods to our file, and then we should be ready to run our tests.In our first new test scenario, we focus on adding a task to our to-do list. This test begins by clicking the “Add Task” button to navigate to the task addition screen. We verify that the user is on the correct screen by checking the presence of the title input field. Here’s how the implementation looks:Test: clickingAddTaskButton()@Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen"); driver.navigate().back(); Thread.sleep(1000); }addingTaskToDoTheList() TestNext, we have the addingTaskToDoTheList() method, which adds a task to the to-do list. This method clicks the “Add Task” button, enters a title and description for the new task, and then saves it. After saving, it verifies that the new task appears in the task list.Test: addingTaskToDoTheList()@Test public void addingTaskToDoTheList() throws InterruptedException { WebElement addTaskButton, saveButton; WebElement addTaskTitleField, addTaskDescField; // click the Add Task button addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); // add title to the task addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); addTaskTitleField.click(); addTaskTitleField.sendKeys("Buy Milk"); // add description to the task addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText")); addTaskDescField.click(); addTaskDescField.sendKeys("Grab 2 Gallons of Milk"); // click the Save button saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton")); saveButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView")); Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found"); }deletingTaskFromTheList() TestFinally, we have the deletingTaskFromTheList() method, which tests the deletion of a task from the list. This method locates the delete button and clicks it, then verifies that the task is removed from the task list.Test: deletingTaskFromTheList()@Test public void deletingTaskFromTheList() throws InterruptedException { WebElement deleteButton; // click the Delete button deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton")); deleteButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen"); }Full ImplementationHere’s the full implementation of the FirstAppiumTestNG file. FirstAppiumTestNG - Full ImplementationFirstAppiumTestNG.classpackage com.test; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FirstAppiumTestNG { public static AndroidDriver driver; @BeforeClass public void setUp() throws MalformedURLException { File app = new File("src/test/resources/app/app-debug.apk"); // Set the desired capabilities for your test DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("deviceName", "emulator-5554"); caps.setCapability("platformName", "android"); caps.setCapability("app",app.getAbsolutePath()); // Initialize the Appium driver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps); } @Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen"); driver.navigate().back(); Thread.sleep(1000); } @Test public void addingTaskToDoTheList() throws InterruptedException { WebElement addTaskButton,saveButton; WebElement addTaskTitleField,addTaskDescField; // click the Add Task button addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); // add title to the task addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); addTaskTitleField.click(); addTaskTitleField.sendKeys("Buy Milk"); // add description to the task addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText")); addTaskDescField.click(); addTaskDescField.sendKeys("Grab 2 Gallons of Milk"); // click the Save button saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton")); saveButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView")); Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found"); } @Test public void deletingTaskFromTheList() throws InterruptedException { WebElement deleteButton; // click the Delete button deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton")); deleteButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen"); } @AfterClass public void tearDown() { if (driver != null) { // Close the driver session driver.quit(); } } }Running Test: TestNG XML File SetupNow that we’re ready to run our test, let’s create a new testng.xml file in the root of our project. In this new file, we’ll add the XML code below to enable running our FirstAppiumTestNG class.TestNG Suite Config (testng.xml)<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="My First Appium TestNG Test"> <test name="TODO App Automation Testing"> <classes> <class name="com.test.FirstAppiumTestNG"/> </classes> </test> <!-- Test --> </suite> <!-- Suite --> Create A New TestNG File Naming The File testng.xml Pasting The XML Script In The New Testng.xml FileTo properly run our TestNG XML file, we need to configure the pom.xml file accordingly. Start by opening your pom.xml file and locating the Maven Surefire Plugin section. Within this section, you’ll need to add the TestNG configuration. Specifically, scroll down to where you see the <version> tag within the Maven Surefire Plugin and insert the following configuration just below it:TestNG Suite Setup (pom.xml)<configuration> <suiteXmlFiles> <suiteXmlFile>testng.xml</suiteXmlFile> </suiteXmlFiles> <testFailureIgnore>false</testFailureIgnore> </configuration> Pasting TestNG XML ConfigurationThis snippet tells Maven to use the testng.xml file to determine which tests to run. The <testFailureIgnore> tag is set to false, ensuring that the build will fail if any test fails, which is often the desired behavior in a continuous integration environment.Once you’ve added this configuration, make sure to save your pom.xml file. With these changes in place, your project is now ready to run with the specified TestNG configuration. Let's open the Terminal in Eclipse so we can execute the Maven command. Type or copy the command mvn test -DsuiteXmlFile=testng.xml into the Terminal. Press Enter to execute. The script should begin running the three scenarios we created earlier. As the tests execute, you should see passing logs appear in the console, indicating successful execution. Pasting Maven Command To Run TestNG Successful Test Results After Running CommandRunning Test: TestNG PluginAlternatively, if you have the TestNG plugin installed on your IDE, you can simply right-click on the test file and choose Run As TestNG. This method provides a quick and easy way to execute your tests without the need to manually configure the XML file. class. Running Test File Using 'Run As TestNG'Running FirstAppiumTestNG ScriptAlright, let’s sit back and enjoy watching the results. In the video below, you’ll see the script in action as it runs via the mvn command. The test executes all three scenarios and they pass successfully! It’s always a great feeling when everything works perfectly, isn’t it? Yay! GIF: Script Is Running TestNG Results Pane TestNG HTML Web ResultsConclusionOrganizing multiple test scenarios in Appium using TestNG is a critical step in building a robust test automation strategy. With TestNG, we can group our test cases logically, execute them in a specific order, and generate detailed reports. This structured approach not only saves time but also minimizes errors, making our testing process more reliable and efficient. Stay tuned for our next topic, where we will delve into Understanding Appium UI Locators. Understanding Appium UI Locator Strategies In this guide, we will delve into Appium UI Locator Strategies. Understanding how to efficiently locate elements is crucial for creating robust and maintainable automated tests. This guide is designed to be comprehensive and accessible for both beginners and advanced users. By the end of this guide, you’ll be proficient in various locator strategies in Appium, using Java as our code language.Introduction to LocatorsLocators are used to find UI elements on the mobile application. Appium supports various locator strategies: ID - is a unique identifier for elements. It is one of the most reliable and fastest ways to locate elements. Name - is another attribute that can be used, although it's less common and sometimes deprecated. Class Name - locates elements by their class attribute. It can return multiple elements, so it's often used with other strategies. XPath - is a powerful and flexible locator strategy but can be slower and more brittle. It's often used when other locators are not available. iOS Predicate String (iOS) - iOS Predicate String is used for complex queries on iOS. iOS Class Chain (iOS) - iOS Class Chain is another iOS-specific strategy that allows chaining class names and attributes.Using ID Using an id is one of the most efficient ways to identify and capture elements in Appium, provided that this option is available in our inspector. The id attribute serves as a unique identifier for elements within the DOM, allowing for precise and reliable element selection. This method is particularly advantageous because IDs are designed to be unique within a given page, thereby reducing the risk of selecting the wrong element.By.idWebElement taskButton = driver.findElement(By.id("add-task-button"));Using Name By using the name attribute, you ensure your code remains clear and intuitive. This method not only enhances readability but also reduces the risk of errors that can occur with more complex locators. It’s a straightforward way to improve your Appium testing strategy, making it easier to manage and scale your automated tests. Adopting this practice can lead to more robust and reliable test scripts, ultimately contributing to a more efficient development cycle.By.nameWebElement taskButton = driver.findElement(By.name("add-task-button"));Using XPath When using xpath to identify an element in Appium, you can target specific attributes or hierarchical relationships within the UI structure. For example, you might want to locate a button based on its ID, class, or even its position relative to other elements. This flexibility is one of the key advantages of using xpath over other locating strategies.By.xpathWebElement taskButton = driver.findElement(By.xpath("//android.widget.Button[@content-desc='SIGN IN']"));Using Class Name You can capture and interact with an element by specifying its className. This method is particularly useful when elements share common characteristics or belong to the same class.By.classNameWebElement taskButton = driver.findElement(By.className("android.widget.Button"));[IOS] iOS Predicate StringThis technique offers a precise way to locate elements based on specific attributes. The iOS Predicate String is a powerful tool that leverages the NSPredicate class from Apple’s iOS development environment, allowing developers to create complex queries for UI elements.[IOS] iOS Class Chain This approach leverages the class chain strategy, providing a powerful alternative to traditional locator strategies. By utilizing iOSClassChain, developers can efficiently target elements based on their hierarchical structure, enhancing the precision of their UI automation tests.By.iOSClassChainWebElement taskButton = driver.findElement(By.iOSClassChain("**/XCUIElementTypeButton[`label == 'Task'`]"));ConclusionIn this guide, we explored various Appium UI locator strategies using Java. By mastering these locators, you can write efficient and reliable automated tests for your mobile applications. Remember to prioritize IDs and Accessibility IDs for their reliability and speed, and use XPath judiciously. Stay tuned for our next topic, where we will dive into Advanced Automating Gestures in Appium. Automating Gesture Actions in Appium In the previous guide, we learned about Appium UI Locator Strategies. Now, let’s take it a step further by automating gesture actions. Gestures such as swipes, scrolls, and taps are essential for comprehensive mobile app testing.Common Gesture ActionsAlright, let’s dive into Gesture Actions in Appium. These actions are essential for simulating complex interactions with your mobile app, mimicking how a real user would engage with it. Whether you need to swipe, pinch, zoom, or perform a drag-and-drop action, Appium’s gesture commands have you covered. These gestures are critical for testing user interfaces that rely heavily on touch interactions, ensuring your app behaves as expected in the hands of actual users.Create Gestures Util ClassLet’s dive right in and enhance our Appium project by adding a new class to handle gesture methods efficiently. To begin, we’ll create a new class called GesturesUtil which will serve as a repository for various gesture methods. This step is essential to keep our code organized and maintainable. First, navigate to your project directory and create a new package namedcom.helpers. This package will be the home for our GesturesUtilclass. Organizing your code into packages not only improves readability but also aligns with best practices in software development, making your project more modular and easier to manage.Import DependenciesIn the com.helpers package, create the GesturesUtil class. This class will encapsulate all the gesture methods you need for your Appium tests, such as swipe, tap, and scroll. To get started, the first step is importing the necessary dependencies. In your project, add the following imports:GesturesUtil.classimport io.appium.java_client.AppiumDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.PointerInput; import org.openqa.selenium.interactions.Sequence; import java.time.Duration; import java.util.Arrays; import java.util.Collections;With these imports in place, you can now proceed to define your gesture methods without encountering any compilation issues. This setup ensures that your code is well-structured and ready to handle a variety of automated testing scenarios, making your Appium testing framework robust and efficient.Simulating Tap or Long Press A tap is simply a quick touch on the screen, often used for selecting items, while a long press involves holding down on an element for a longer duration. This is typically used for actions like bringing up a context menu or initiating a special function. Appium’s capabilities allow you to simulate both, ensuring that these interactions are tested thoroughly.Gesture: tapElementpublic void tapElement(WebElement element) { PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger"); Sequence tap = new Sequence(finger, 1) .addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), element.getLocation().x + element.getSize().width / 2, element.getLocation().y + element.getSize().height / 2)) .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Collections.singletonList(tap)); }TapThe tapElement method simulates a tap on a web element by: Creating a touch input named finger. Creating a sequence of actions that: - Moves the touch pointer to the center of the specified element. - Presses down on the element. - Releases the press. Perform the sequence of actions using the driver.Gesture: Long Presspublic void longPressElement(WebElement element, Duration duration) { PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger"); Sequence longPress = new Sequence(finger, 1) .addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), element.getLocation().x + element.getSize().width / 2, element.getLocation().y + element.getSize().height / 2)) .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger.createPointerMove(duration, PointerInput.Origin.viewport(), element.getLocation().x,element.getLocation().y)) .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Collections.singletonList(longPress)); }Long PressThe longPressElement method simulates a long press on a mobile or web element by: Moving the virtual finger to the center of the element. Pressing down on the element. Holding the press for a specified duration. Releasing the press.Simulating Swipe GesturesIn Appium, swiping is straightforward but powerful, allowing you to simulate the user’s finger moving across the screen.To implement a swipe, you define the start and end coordinates, which tells Appium where the swipe should begin and end. By fine-tuning these coordinates, you can create swipes that mimic natural user behavior, ensuring your test cases are as realistic as possible.Gesture: Swipepublic void swipe(int startX, int startY, int endX, int endY, Duration duration) { PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger"); Sequence swipe = new Sequence(finger, 1) .addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX, startY)) .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger.createPointerMove(duration, PointerInput.Origin.viewport(), endX, endY)) .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Collections.singletonList(swipe)); }SwipeThe swipe function simulates a swipe gesture on a touch screen. First, it moves the touch pointer from a starting point (startX, startY) Next it moves to the ending point (endX, endY) over a given duration. The process involves moving the pointer to the start position, touching down, moving to the end position, and then lifting up All of these actions are coordinated through a sequence of actions performed by the driver.Simulating a Zoom InNext we have pinch and zoom gestures, which are indispensable for applications that involve maps, images, or any form of visual content that users might need to zoom in and out of.Gesture: Zoom Inpublic void zoomIn(WebElement element) { int centerX = element.getLocation().getX() + element.getSize().getWidth() / 2; int centerY = element.getLocation().getY() + element.getSize().getHeight() / 2; int endX1 = centerX - 100; int endY1 = centerY - 100; int endX2 = centerX + 100; int endY2 = centerY + 100; PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1"); Sequence pinch1 = new Sequence(finger1, 1) .addAction(finger1.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY)) .addAction(finger1.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger1.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), endX1, endY1)) .addAction(finger1.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2"); Sequence pinch2 = new Sequence(finger2, 1) .addAction(finger2.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY)) .addAction(finger2.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger2.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), endX2, endY2)) .addAction(finger2.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Arrays.asList(pinch1, pinch2)); }PinchingPinching involves bringing two fingers together on the screen, while zooming involves spreading them apart. Appium handles these multi-touch gestures by specifying the touch points and their movements, giving you precise control over the interactions. Calculate the center coordinates (centerX, centerY)of the element. Define end coordinates for the pinch gesture (endX1, endY1, endX2, endY2). Create the first finger input sequence pinch1to: - Move to the center of the element. - Press down. - Move to the end coordinates over 600 ms. - Lift up the finger. Create the seond finger input sequence pinch2 to: - Move to the center of the element. - Press down. - Move to the end coordinates over 600 ms. - Lift up the finger. Execute both sequences simultaneously to perform the pinch gesture.Simulating a Zoom OutPerform a zoom out gesture by reversing the pinch gesture:Gesture: Zoom Outpublic void zoomOut(WebElement element) { int centerX = element.getLocation().getX() + element.getSize().getWidth() / 2; int centerY = element.getLocation().getY() + element.getSize().getHeight() / 2; int startX1 = centerX - 100; int startY1 = centerY - 100; int startX2 = centerX + 100; int startY2 = centerY + 100; PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1"); Sequence pinchIn1 = new Sequence(finger1, 1) .addAction(finger1.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX1, startY1)) .addAction(finger1.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger1.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), centerX, centerY)) .addAction(finger1.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2"); Sequence pinchIn2 = new Sequence(finger2, 1) .addAction(finger2.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX2, startY2)) .addAction(finger2.createPointerDown(PointerInput.MouseButton.LEFT.asArg())) .addAction(finger2.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), centerX, centerY)) .addAction(finger2.createPointerUp(PointerInput.MouseButton.LEFT.asArg())); driver.perform(Arrays.asList(pinchIn1, pinchIn2)); }ZoomingPinching involves bringing two fingers together on the screen, while zooming involves spreading them apart. Appium handles these multi-touch gestures by specifying the touch points and their movements, giving you precise control over the interactions. Calculate the center coordinates of the element. Define starting points for two touch actions, positioned diagonally around the center. Create a touch action sequence for the first finger, moving from the starting point to the center. Create a touch action sequence for the second finger, moving from the starting point to the center. Execute both sequences simultaneously to perform the pinch-in gesture.ConclusionIncorporating gesture actions into your Appium tests enhances functionality and verifies a seamless user experience. By simulating real user gestures, you can uncover issues that traditional testing may miss, leading to a more robust and user-friendly app.Whether you’re testing a simple or complex app, mastering these gestures will improve your testing outcomes. In the next guide, you’ll learn about Capturing Screenshots and Logs in Appium. Capturing Screenshots and Logs In Appium Capturing screenshots and logs during your tests is crucial for diagnosing issues, verifying UI elements, and ensuring your app behaves as expected. Screenshots provide visual evidence, while logs offer detailed information about the app’s behavior, network requests, errors, and more.Create New Utils ClassLet’s begin by creating a new Utils class, which will be instrumental in managing your screenshot captures and logging methods. To start, navigate to your project and create a new class within the com.helpers package, or alternatively, any directory that suits your organizational preferences. Creating A New Utils ClassUtils.classpackage com.helpers; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.logging.LogEntry; import org.openqa.selenium.io.FileHandler; import org.openqa.selenium.logging.LogEntries; import org.openqa.selenium.logging.LogType;Capturing ScreenshotsTo capture screenshots in Appium using Java, you can use the getScreenshotAs method. Utils.classpublic class Utils { public static void captureScreenshot(WebDriver driver, String fileName) { File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); try { FileHandler.copy(srcFile, new File("./target/screenshots/" + fileName + ".png")); } catch (IOException e) { e.printStackTrace(); } } It’s important to organize your project structure effectively. To achieve this, we’ll create a dedicated /screenshots directory within the target folder of your project. This organization ensures that all screenshots are stored in a centralized location, making them easy to locate and manage. Creating A New Screenshots Directory For instance, when you capture a screenshot during the automation process, you can save it in this newly created directory. To maintain clarity and avoid confusion, it's essential to give each screenshot file a descriptive name. In this particular example, we will name the screenshot file add_new_task_screen.In this particular example, we will name the screenshot file add_new_task_screen. This naming convention not only helps in identifying the context of the screenshot quickly but also enhances the overall readability and maintainability of your test reports.Call this method in your test script where you want to capture the screenshot: Test: clickingAddTaskButton()@Test public void clickingAddTaskButton() throws InterruptedException { // Add test case scenario here WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab")); addTaskButton.click(); // quick debug wait for 2 seconds Thread.sleep(2000); WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText")); Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen"); Utils.captureScreenshot(driver, "add_new_task_screen"); driver.navigate().back(); Thread.sleep(1000); }When executing your script in Appium, the captured screenshot is stored in the /target/screenshot/ directory. To view the newly captured screenshot, you will need to refresh your project. Once refreshed, the file named add_new_task_screen will appear in the screenshots directory. This step is crucial for verifying that your automation scripts are correctly capturing the visual output you expect. GIF: Reviewing Screenshot Image After Executing TestCapturing LogsTo capture logs in Appium using Java, you can use the getLog method. Here’s how:Test: captureLogs()public static void captureLogs(WebDriver driver) { LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER); for (LogEntry entry : logEntries) { System.out.println(entry.getMessage()); } }Call this method in your test script to capture and print the logs: JavaUtils.captureLogs(driver);Troubleshooting Permission Issues: Ensure your script has write permissions to the directory where screenshots and logs are saved. Driver Compatibility: Make sure the Appium driver versions are compatible with your testing framework and mobile OS. Error Handling: Implement error handling in your scripts to manage exceptions during screenshot or log capture.Best Practices Organize Screenshots: Save screenshots with meaningful names and organize them in folders based on test cases or test runs. Log Levels: Use different log levels (e.g. INFO, DEBUG, ERROR) to filter logs effectively. Automate Log Analysis: Consider automating log analysis to highlight errors or warnings. Periodic Captures: Capture screenshots and logs periodically during long test runs to monitor app behavior over time.ConclusionBy now, you should know how to capture screenshots and logs during your Appium test executions. This knowledge will significantly enhance your ability to debug and report on your tests. Continue honing your skills and exploring more advanced topics in Appium and QA testing. Happy testing! Cucumber (Gherkin) Official Docs Discover more about Cucumber, the powerful tool for Behavior-Driven Development (BDD). To learn more, visit the official Cucumber Website, where you can explore its features, documentation, and resources. Become a Pro Member - Unlock Advanced Tools & ResourcesGain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member! Introduction to Cucumber and Gherkin Welcome to Mastering QA! In this guide, we’ll introduce you to Cucumber and Gherkin, two powerful tools that revolutionize Behavior-Driven Development (BDD). Understanding these tools will provide a strong foundation for writing and automating your tests effectively.What is Cucumber?Cucumber is an open-source BDD framework that simplifies the process of defining and executing tests. It encourages collaboration between technical and non-technical team members, fostering better communication and understanding of software requirements.What is Gherkin?Gherkin is a human-readable language used to write Cucumber scenarios. It’s designed to be simple, easy to understand, and accessible to non-developers. Gherkin acts as the bridge between plain text descriptions of software behaviors and the automation code that validates those behaviors.Feature FilesFeature files are where Gherkin shines. These text files have a .feature extension and contain high-level descriptions of software features or functionalities. They serve as documentation and test scripts simultaneously.ScenariosScenarios are individual test cases written in Gherkin. They describe a specific behavior or test case, typically following a Given-When-Then structure. For example:Scenario: home-screen.featureFeature: Home Screen - Verify Web App Navigation Menu Links Scenario: Click the Login Icon Given the user is on the home screen When the user clicks the "login" icon Then the "Login" screen is displayed 1 Given 2 When 3 Then This keyword sets the stage for the scenario by describing the initial context or preconditions. It establishes the state of the system before the action occurs.This keyword defines the action or event that triggers the scenario. It represents the user's interaction with the system or the event that takes place.This keyword outlines the expected outcome or result after the action is performed. It specifies what should happen as a result of the interaction, allowing for validation of the scenario. Step DefinitionsStep definitions are the automation code that executes the steps in Gherkin scenarios.Step Defintionspublic class HomeStepDefs { public WebDriver driver = Hooks.driver; @Given("the user is on the home screen") public void the_user_is_on_the_home_screen() throws InterruptedException { // logic goes here } @When("the user clicks the {string} icon") public void the_user_clicks_the_icon(String iconName) { // logic goes here } @Then("the {string} screen is displayed") public void the_screen_is_displayed(String screenName) { // logic goes here } @When("the user clicks the {string} link") public void the_user_clicks_the_link(String linkName) { // logic goes here } }Benefits of Cucumber and Gherkin Improved Collaboration: Cucumber and Gherkin facilitate effective communication between technical and non-technical team members, leading to better software understanding. Reusable Steps: Gherkin steps can be reused across multiple scenarios, reducing redundancy and maintenance efforts. Living Documentation: Feature files serve as living documentation that stays up-to-date with your application's behavior. Automation: Cucumber allows you to automate tests based on Gherkin scenarios, making it easier to validate software functionality.ConclusionNow that you have a basic understanding of Cucumber and Gherkin, it’s time to Set Up Cucumber in Your Project. Setting Up Cucumber in Your Project In this guide, we’ll walk you through the essential steps to set up Cucumber in a Java project. Proper setup is crucial for ensuring a smooth workflow for your Behavior-Driven Development (BDD) testing. By following this guide, you’ll be well on your way!Prerequisites Java Development Kit (JDK) installed. Integrated Development Environment (IDE) Eclipse. Maven for dependency management.Create a New Maven ProjectTo embark on your journey with a Cucumber Gherkin project, the first step is to create a new Maven project. If you’re unfamiliar with setting up a Maven project, don’t worry. Our guide here on How To Create A New Maven Project in Eclipse, will walk you through the process step by step.Once your Maven project is successfully set up, the next crucial task is to add the core Maven dependencies required for your Cucumber Gherkin project. Head over to your pom.xml file and these between your dependencies tag. Adding Dependencies To pom.xmlpom.xml<!-- Selenium Java --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.20.0</version> </dependency> <!-- Cucumber Java --> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-java</artifactId> <version>7.11.0</version> </dependency> <!-- Cucumber JUnit --> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-junit</artifactId> <version>7.11.0</version> </dependency> <!-- JUnit 4 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- Extent Reports Cucumber Adapter --> <dependency> <groupId>tech.grasshopper</groupId> <artifactId>extentreports-cucumber7-adapter</artifactId> <version>1.14.0</version> </dependency> <!-- Extent Reports --> <dependency> <groupId>com.aventstack</groupId> <artifactId>extentreports</artifactId> <version>5.1.1</version> </dependency> <!-- Commons IO --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>Organizing Your Project Structure Now that we have our project created, let’s set up our base folders and directories. To get started, we’ll need to create a few specific folders. In this guide we’ll be incorporating the com.kicksapp package in our project to keep our files organize. Organizing Cucumber Project com/kicksapp/runners - This folder is where our test runner files will be stored. These files are essential for executing our test suites. com/kicksapp/stepdefs - Here, we'll keep our test step definitions. This organization helps in managing the steps involved in our tests, making them easy to locate and modify. src/test/resources/driver - This is the designated folder for our driver files. For this project, we'll be using Chromedriver. Ensuring the driver is in the right place helps in seamless test execution. src/test/resources/features - Most importantly, this folder will store our feature files. Feature files are the cornerstone of our behavior-driven development (BDD) approach, outlining the scenarios and behaviors our application should exhibit. Tip: Naming Your Package DirectoryYou can choose to keep you package as simple as src/test/java/runners or src/test/java/stepdefs. However in this guide We’ll be using the com/kicksapp/… package.Downloading the Cucumber Plugin for EclipseOnce we have these packages and folders set up, the next step is to download the Cucumber plugin for Eclipse. This plugin is essential for integrating Cucumber with Eclipse, providing a robust environment for running and managing our BDD tests.Navigate to the top menu and click on Help . From the dropdown menu, select Eclipse Marketplace… Installing Cucumber Plugin From The Eclipse Marketplace Search for Cucumber: In the Eclipse Marketplace window, use the search bar to type in [direction]"Cucumber"[/direction]. Press Enter to view the search results. Install the Cucumber Plugin: Locate the Cucumber plugin from the list of results. Click the [direction]Install[/direction] button next to the Cucumber plugin entry. Follow the prompts to complete the installation process. Restart Eclipse: Once the installation is finished, you will be prompted to restart Eclipse. Click [direction]Restart Now[/direction] to apply the changes.ConclusionOrganizing your project with these folders ensures a streamlined process where each component of your testing framework is easily accessible. This setup not only enhances productivity but also aligns with best practices in test automation, making it easier to scale and maintain your tests.Now you’re ready to Write Your First Gherkin Feature File. Continue to the next guide to dive into writing Gherkin scenarios. Writing Your First Gherkin Feature File Now that you have Cucumber set up in your project, it’s time to write your first Gherkin feature file. This guide will help you create a feature file and define scenarios using Gherkin syntax.Gherkin feature files are written with the .feature extension and contain a structured language with keywords like Feature, Scenario, Given, When, Then, And, and But. Let’s write a simple feature file for a checking the navigation on the Kicks Web App functionality. Kicks App | Flutter WebCreating a Feature FileFirst, navigate to your project’sfeaturesdirectory. This is where all your feature files will reside. To get started with our scenarios, we need to create a new file. Create a file named home-screen.feature inside the features directory. Creating The Home Screen Feature FilePath: home-screen.featuresrc/test/resources/features/home-screen.featureBy creating the home-screen.feature file, we establish a dedicated space for our home screen scenarios. This approach not only helps in organizing our tests but also makes it easier to locate and update them as needed.Write a Feature Scenario Ensuring a seamless user experience starts with verifying that all navigation links on the home screen function as expected. Below we are going test a few test cases related to the navigation menu.home-screen.feature# Author: J Richard | Mastering QA Feature: Home Screen - Verify Web App Navigation Menu Links Scenario: Click the Login Icon Given the user is on the home screen When the user clicks the "login" icon Then the "Login" screen is displayed Scenario: Click the Products link Given the user is on the home screen When the user clicks the "Products" link Then the "Products" screen is displayed Home Screen Feature File ScenariosUnderstanding Gherkin Syntax Feature: Provides a detailed overview of the feature being tested, outlining its purpose and functionality. Scenario: Specifies a particular test case for the feature, illustrating a unique situation to validate its performance. Given: Establishes the initial conditions and context necessary for the test to proceed, ensuring a proper setup. When: Captures the specific actions taken by the user during the test, detailing the interactions that trigger the functionality. Then: Articulates the expected results of the test, defining the criteria for success and the desired behavior of the feature. Given the user is on the home screenThis step sets the initial context. It assumes the user has already landed on the home screen of the web application. When the user clicks the "login" icon This action step simulates the user clicking on the login icon, which is expected to take them to the login screen. Then the "Login" screen is displayedThe final step verifies the outcome, ensuring that clicking the login icon indeed navigates the user to the login screen. Click the Products Link TestThe second scenario is pretty much similar but in this case we will be clicking the products link and verifying that we landed there successfully.ConclusionYou’ve written your first Gherkin feature file. Next, you’ll learn how about Scenario Outlines and Examples. Continue to the next guide to explore step definitions. Scenario Outlines and Examples In this guide, you’ll learn how to use scenario outlines and examples to write more dynamic and data-driven tests. This allows you to test multiple cases with different inputs and expected outcomes efficiently.What is a Scenario Outline? A Scenario Outline is a template for a scenario that can be run multiple times with different sets of data. It is useful when you want to test the same scenario with different inputs and expected outcomes. This helps in reducing redundancy and improving the readability and maintainability of your test suite.Syntax of Scenario OutlineThe syntax of a Scenario Outline in Gherkin is as follows:GherkinScenario Outline: Title of the scenario Given some precondition When some action is performed Then some expected outcome should happen Examples: | parameter1 | parameter2 | | value1 | value2 | | value3 | value4 | Scenario Outline: This keyword establishes a scenario template that allows for the reuse of the same test steps with varying data inputs, streamlining the testing process. Examples: This section specifies the various sets of data that will be used to fill in the placeholders defined in the Scenario Outline, enabling comprehensive testing of multiple scenarios efficiently.Using Examples in Scenario Outline The Examples section contains a table where each row represents a different set of values to be used in the scenario. The values from the table are substituted into the scenario outline, and the scenario is run once for each row. Cucumber Scenario Outline ExampleConsider a scenario where we want to test the products filter functionality of the Kicks website with different filters and verifying the item counts. This involves simulating user actions on the website to ensure that the filters for products work as expected.GherkinFeature: Products Page Filters & Stock Count Scenario Outline: User clicks product filter, choose a gender option and verify item count Given the user is on the products screen When the user clicks "<filter>" filter option And the user clicks the "<gender>" gender option And the user clicks a "<size>" shoe Then the first sneaker option is "<first_sneaker>" And the result is now "<item_count>" Examples: | filter | gender | size | first_sneaker | item_count | | Most popular | Male | 10.5 | Adidas Converse | 7 items | | Lowest price | Female | 6 | New Balance Streetwear | 13 items | | Highest price | Male | 9.5 | Jordan Orginal | 9 items | | Newest | Female | 7 | Nike Air Max 360 | 14 items |This feature focuses on verifying that the product filters on the Kicks website are working correctly. It includes tests for various filters such as Most popular, Lowest price, Highest price, and Newest to ensure they return the correct item count. Given the user is on the products screenThis step sets the initial condition that the user is on the products page of the website. When the user clicks "<filter>" filter optionThis action simulates the user clicking on a specific filter option, such as Most popular or Lowest price. And the user clicks the "<gender>" gender optionThis action simulates the user selecting a gender filter, such as Male or Female. And the user clicks a "<size>" shoeThis action simulates the user selecting a shoe size, such as 10.5 or 6. Then the first sneaker option is "<first_sneaker>"This step verifies that the first sneaker displayed matches the expected sneaker for the given filter. And the result is now "<item_count>"This step verifies that the total number of items displayed matches the expected item count.ConclusionGherkin Scenario Outlines are essential for enhancing clarity and efficiency in your behavior-driven development (BDD) process. They allow for reusable scenarios with varying inputs, simplifying test case creation and promoting collaboration among team members. In the next guide, you’ll learn about Implementing Step Definitions, where we’ll connect your Gherkin scenarios to executable code. Implementing Step Definitions Now is the time to create and implement our Step Definition Class in Cucumber. This critical step will ensure our test automation framework is robust and efficient. In this guide, we will walk you through the process of setting up your Step Definition Class, specifically focusing on creating a file to store your HomeStepDefs file within your project.Setting Up Your Step Definition ClassTo begin, navigate to the appropriate location in your project directory where you want to store your Step Definition files. It’s essential to keep your project well-organized, making it easier to maintain and scale as needed. In this case we’ll be storing our files in this location – src/test/java/com/kicksapp/stepDefs Cucumber Step Definitions Directory IDE: Launch Eclipse and open your project to get started on your Gherkin test definitions. Directory: Navigate to the src/test/java/com/kicksapp/stepDefs/ directory, where your step definitions will be organized. Create a New File: In the stepDefs directory, right-click and choose [direction]New File[/direction] to create a new file named HomeStepDefs.java, which will house your Gherkin step definitions for the Home feature.HomeStepDefssrc/test/java/kicksapp/stepDefs/HomeStepDefs.javaConvert Project to A Cucumber ProjectRight-click on your project and select Configure Convert to Cucumber Project . This set is necessary so we can generate our gherkin snippets. Converting Project To A Cucumber ProjectGenerate Gherkin Method SnippetsTo generate the necessary Gherkin method snippets, run the home-screen.feature file: Run Feature File: Right-click on the home-screen.feature file and select [direction] Run As > Cucumber Feature[/direction]. Review Snippets: Eclipse will execute the feature file, and if any step definitions are missing, it will generate method snippets for you. Copy these snippets into your HomeStepDefs.java class. Gherkin Generated Sample SnippetsGherkin Method Snippets@Given("the user is on the home screen") public void the_user_is_on_the_home_screen() { // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); } @When("the user clicks the {string} icon") public void the_user_clicks_the_icon(String string) { // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); } @Then("the {string} screen is displayed") public void the_screen_is_displayed(String string) { // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); } @When("the user clicks the {string} link") public void the_user_clicks_the_link(String string) { // Write code here that turns the phrase above into concrete actions throw new io.cucumber.java.PendingException(); }Now that we have our snippets, it’s time to add the necessary logic to each method to complete our HomeStepDefs class. This step is crucial as it bridges the gap between our feature files written in Gherkin and the actual automation code that interacts with our web application.In the HomeStepDefs class, we initialize a WebDriver instance through the Hooks class, ensuring a consistent browser session. The testUrl variable holds the URL of our web application, setting the stage for user interaction scenarios.HomeStepDefs – WebDriverpublic class HomeStepDefs { public WebDriver driver = Hooks.driver; private final String testUrl = "https://jahmalrichard.github.io/kicks-flutter-web-app/";Navigating to the Home ScreenThe first step is to navigate the user to the home screen. Using the @Given annotation, we define the method the_user_is_on_the_home_screen. This method directs the browser to the specified URL and pauses for 2 seconds to ensure the page is fully loaded. Kicks App | Home Screen@Given@Given("the user is on the home screen") public void the_user_is_on_the_home_screen() throws InterruptedException { driver.get(testUrl); Utils.wait(2); }Interacting with IconsNext, we manage user interactions with icons on the home screen. The @When annotation is used to define the method the_user_clicks_the_icon. This method receives an icon name as a parameter, locates the corresponding icon using a CSS selector, and performs a click action. Find & Click The Login Icon@When@When("the user clicks the {string} icon") public void the_user_clicks_the_icon(String iconName) { try { switch(iconName.toLowerCase()) { case "login": { WebElement loginIcon = driver.findElement( By.cssSelector("flt-semantics[aria-label=\"login-icon\"]")); loginIcon.click(); Utils.wait(2); break; } default: System.err.println("The icon called '" + iconName + "' was not found. Try again."); } } catch (Exception e) { e.printStackTrace(); } }Verifying Screen DisplaysAfter interacting with icons, it’s essential to verify that the correct screen is displayed. The @Then annotation defines the method the_screen_is_displayed, which checks for the presence of the Sign In button on the login screen to confirm successful navigation. Verify That The Sign In Button Exist Verifying That The Product Page Is Displayed@Then@Then("the {string} screen is displayed") public void the_screen_is_displayed(String screenName) { try { switch(screenName.toLowerCase()) { case "login": { WebElement loginSignInButton = driver.findElement(By.cssSelector("flt-semantics[aria-label=\"Sign In\"]")); assert loginSignInButton.isDisplayed(); Utils.wait(2); break; } case "products": { WebElement filterMostPopular = driver.findElement(By.cssSelector("flt-semantics[aria-label=\"Most popular\"]")); assert filterMostPopular.isDisplayed(); Utils.wait(2); break; } default: System.err.println("The screen named '" + screenName + "' was not found. Try again."); } } catch (Exception e) { e.printStackTrace(); } }Navigating via LinksLastly, we enable users to click on various links within the application. The @When annotation is used again to define the method the_user_clicks_the_link, which handles click actions for specified links. Tip: Navigating LinksThis method is related to the second scenario, where we click on the Products link and verify that we’re on he Products screen. User Clicks The Products Link@When@When("the user clicks the {string} link") public void the_user_clicks_the_link(String linkName) { try { switch(linkName.toLowerCase()) { case "products": { WebElement productsNavLink = driver.findElement( By.cssSelector("flt-semantics[aria-label=\"Products\"]")); productsNavLink.click(); Utils.wait(2); break; } default: System.err.println("The link named '" + linkName + "' was not found. Try again."); } } catch (Exception e) { e.printStackTrace(); } } } Tip: HomeStepDefsBy integrating these methods into our HomeStepDefs class, each method is crafted to handle specific interactions and verifications, making our tests both comprehensive and easy to understand.ConclusionNow that we have a solid grasp of creating and managing step definitions, it’s time to elevate our Cucumber skills further. In next guide, we’ll delve into Understanding Cucumber Tags, a powerful feature that can enhance the flexibility and efficiency of your testing framework. Understanding Cucumber Tags In this guide, you’ll learn how to use Cucumber tags and hooks to organize and manage your tests efficiently. Tags allow you to categorize your scenarios, and hooks provide a way to run code before or after scenarios.Tags in CucumberTags are a way to organize and control the execution of your tests. They allow you to group scenarios, features, or even specific steps, making it easier to manage large test suites. Tags are prefixed with @ and placed above the relevant Gherkin keyword. Single TagA single tag, such as @smoketest or @ignore, is used to label a specific test scenario. For instance, @smoketest indicates a basic test run to check the essential functionality, while @ignore is used to exclude certain tests from execution.Single Tag: @smoketest | @ignore@smoketest Scenario: Click the Login Icon Given the user is on the home screen When the user clicks the "login" icon Then the "Login" screen is displayed @ignore Scenario: Click the Products link Given the user is on the home screen When the user clicks the "Products" link Then the "Products" screen is displayedMultiple TagsMultiple tags, like @smoketest @critical, combine multiple categories, providing a more granular control over which tests to run. This combination might be used to run tests that are both part of the smoke test suite and critical for the application, ensuring that key functionalities are validated promptly.Multiple Tags: @smoketest @critical@smoketest @critical Scenario: Click the Login Icon Given the user is on the home screen When the user clicks the "login" icon Then the "Login" screen is displayedCreating a Test RunnerCreate a test runner class in the src/test/java/com/kicksapp/runners directory. We’re going to name this class HomeScreenRunner. Creating Home Screen Runner FileRunning Tests with TagsTo run tests with specific tags, use the @RunWithand @CucumberOptions annotations in your test runner class.The @CucumberOptions annotation is where you configure various aspects of your Cucumber tests. Here’s a breakdown of the options used in the snippet: Cucumber Runner File With OptionsHomeScreenRunner.classimport org.junit.runner.RunWith; import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; @RunWith(Cucumber.class) @CucumberOptions( features = "src/test/resources/features/home-screen.feature", glue = "com.kicksapp.stepdefs", tags = "@smoketest", plugin = {"pretty", "html:target/cucumber-reports.html"}, monochrome = true ) public class HomeScreenRunner { }features = "src/test/resources/features/home-screen.feature": This specifies the path to the feature files. Feature files contain scenarios written in Gherkin language, which Cucumber executes.glue = "com.kicksapp.stepdefs": This option specifies the package where step definition methods are located. Step definitions are the actual code implementations of the steps described in the feature files.tags = "@smoketest": Tags are used to filter which tests to run. In this case, only the scenarios tagged with @smoketest will be executed.plugin = {"pretty", "html:target/cucumber-reports.html"}: This specifies the reporting plugins to use. The html plugin generates a simple html test report.monochrome = true: This option makes the console output more readable by removing unnecessary characters and colors.Tag ExpressionsCucumber supports tag expressions to combine multiple tags using logical operators: AND The AND operator in Cucumber tag expressions is used to run scenarios that are tagged with multiple tags simultaneously. For instance, consider the tags @login and @critical. By using the expression @login and @critical, Cucumber will execute only those scenarios that are tagged with both @login and @critical. This is particularly useful when you need to focus on tests that are both essential and pertain to specific functionalities.Tags: AND@CucumberOptions( features = "src/test/resources/features/home-screen.feature", glue = "com.kicksapp.stepdefs", tags = "@login and @critical", plugin = {"pretty", "html:target/cucumber-reports.html"}, monochrome = true ) OR The OR operator broadens the scope by running scenarios that match any of the specified tags. For example, using @moketest or @critical will run all scenarios tagged with either @smoketest or @critical. This approach is beneficial when you want to cover a broader range of tests without being too restrictive, ensuring that all relevant functionalities are tested.Tags: OR@CucumberOptions( features = "src/test/resources/features/home-screen.feature", glue = "com.kicksapp.stepdefs", tags = "@smoketest or @critcal", plugin = {"pretty", "html:target/cucumber-reports.html"}, monochrome = true ) NOT The NOT operator is employed to exclude specific tags from the test run. For example, the expression not @ignore will execute all scenarios except those tagged with @ignore. This is especially useful for excluding tests that are either known to fail, are under development, or are not currently relevant to the test cycle.Tags: NOT@CucumberOptions( features = "src/test/resources/features/home-screen.feature", glue = "com.kicksapp.stepdefs", tags = "@smoketest and not @ignore", plugin = {"pretty", "html:target/cucumber-reports.html"}, monochrome = true )ConclusionYou’ve mastered the art of using tags. Tags allow you to categorize your scenarios, making it easier to run specific tests based on your needs. Whether you’re focusing on a particular feature or running regression tests, tags streamline the process, saving you valuable time.Now that you are comfortable with tags, it’s time to start Understanding Cucumber Hooks. Understanding Cucumber Hooks In this guide, you’ll learn how to use Cucumber hooks to streamline your testing process and make your scenarios more efficient. Cucumber hooks are blocks of code that run at various points in the Cucumber test cycle, allowing you to set up and tear down the test environment, manipulate data, and configure test settings dynamically. By mastering hooks, you can enhance your test suite’s maintainability and readability, ensuring that your tests run smoothly and reliably.Hooks in CucumberHooks are special blocks of code that run at specific points in the test execution lifecycle. They allow you to set up preconditions and postconditions for your tests. In Cucumber, hooks are defined using the @Before and @After annotations.Types of HooksBefore HookThe @Before hook, as the name suggests, runs before each scenario. This means that any code you include in a @Before hook will execute before your test case starts. This is essential for preparing the test environment, ensuring that each test runs in a clean and consistent state. For instance, you might want to launch a browser, navigate to a specific URL, or initialize test data.@Before Hookpublic class Hooks { public static WebDriver driver; @Before public void setup() { System.setProperty("webdriver.chrome.driver", "src/test/resources/driver/chromedriver"); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); driver.manage().window().maximize(); }After HookAmong the different types of hooks, the @After hook plays a crucial role in ensuring your test scenarios are executed smoothly and efficiently. Specifically, the @After hook runs after each scenario, providing a perfect opportunity to perform cleanup tasks, release resources, or log information that helps in debugging and analysis.@After Hook@After public void tearDown() { if (driver != null) { driver.quit(); driver = null; }BeforeStepThe @BeforeStep hook, as its name suggests, runs before each individual step in your test scenarios. This hook can be particularly useful for setting up preconditions or performing repetitive tasks that need to be executed before every step.@BeforeStep Hook@BeforeStep public void beforeStep(Scenario scenario) { System.out.println("About to execute step: " + scenario.getName()); }AfterStepThe @AfterStep hook in Cucumber is designed to run a block of code after every single step of your test scenario. This capability is essential for tasks such as taking screenshots after each step to help with debugging or logging detailed information about the execution of each step. Implementing the @AfterStep hook can significantly enhance the visibility and traceability of your tests, making it easier to identify where an issue occurred if a test fails.@AfterStep Hook@AfterStep public void afterStep(Scenario scenario) { Utils.wait(3); final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES); scenario.attach(screenshot, "image/png", "image"); }Conditional Hooks To further refine and control the execution of hooks, Cucumber provides the feature of conditional hooks with tags. Tags in Cucumber are metadata assigned to scenarios or feature files, and they can be used to conditionally apply hooks. For instance, if you have specific setup or teardown procedures that should only run for certain tests, you can tag those tests accordingly and define hooks that only trigger for those tags.Conditional Tagsimport io.cucumber.java.Before; import io.cucumber.java.After; public class Hooks { @Before("@login") public void beforeLogin() { // Code to run before scenarios tagged with @login } @After("@logout") public void afterLogout() { // Code to run after scenarios tagged with @logout } }ConclusionIncorporating hooks into your Cucumber tests is a powerful way to maintain a stable test environment, enhancing the overall reliability of your test suite. With hooks, you gain precise control over your test execution process, ensuring each scenario begins and ends in a consistent state. This mastery can lead to more trustworthy and efficient testing, ultimately contributing to higher quality software. Now that you are comfortable with tags and hooks, it’s time to start Running Your Cucumber Tests & Generating Reports. Running Cucumber Tests & Generating Reports Setting up Hooks and Tags in Cucumber is just the beginning of efficient test automation. Once your environment is configured, the next step is to explore the various methods available for executing your Cucumber scripts.Each method has its unique advantages and use cases. In this guide, we will delve into three primary ways to run your Cucumber tests: The Feature File - This method is ideal for quickly running specific features during development. JUnit Test - This method is suitable for developers looking to perform rapid testing of their scripts with minimal setup. Maven using Terminal - This method is perfect for integrating into continuous integration/continuous deployment.Running as a Cucumber FeatureThe first method to execute your Cucumber script is directly from the feature file. This method is straightforward and does not consider tags. Running As A Cucumber FeatureHow to Execute: Right-click on the feature file and select Run As > Cucumber Feature.Best Use Case: This method is ideal for quickly running specific features during development, allowing you to verify functionality without the need for additional configurations. Running as a Cucumber FeatureThis method does not allow for the use of tags, which can be limiting if you need to run specific subsets of tests.Running as a JUnit TestThe second method involves running your Cucumber scripts using JUnit, which is great for quick testing. Running As A JUnit TestHow to Execute: Open the Runner File and select Run As > JUnit Test.Best Use Case: This method is suitable for testers looking to perform rapid testing of their scripts with minimal setup. Running as a JUnit TestPrimarily used within a local development setup and may not be suitable for larger, continuous integration environments.Configuring Cucumber OptionsOne of the standout features of Cucumber is its ability to integrate with various plugins, which allows users to generate a variety of reports.Common Plugin Options html: This plugin generates a comprehensive HTML report, providing a clear and visually appealing overview of your test results. json: The JSON plugin creates a structured JSON report, offering detailed insights that can be easily integrated into other tools or systems for further analysis. junit: The JUnit plugin produces a standard JUnit XML report, ensuring compatibility with various testing frameworks and continuous integration tools. extents adapter: This plugin generates a visually stunning HTML report with rich formatting and detailed analytics, making it easy to share and present your test outcomes.CucumberOptions@CucumberOptions( features = "src/test/resources/features", glue = "com.masteringqa.stepdefinitions", tags = "@smoketest", plugin = {}, monochrome = true, )Generating ReportsCucumber can generate various types of reports. The most commonly used are HTML and JSON reports.HTML ReportHTML reports are user-friendly and provide a detailed overview of test scenarios, steps, and their outcomes.HTML Report@CucumberOptions( features = "src/test/resources/features", glue = "com.masteringqa.stepdefinitions", tags = "@smoketest", plugin = {"pretty","html:target/cucumber-reports.html"}, monochrome = true, ) Example: HTML ReportJSON ReportJSON reports are useful for integrating Cucumber test results with other tools, such as CI/CD pipelines or dashboards. These reports provide a structured format that can be easily parsed and processed.JSON Reports@CucumberOptions( features = "src/test/resources/features", glue = "com.masteringqa.stepdefinitions", tags = "@smoketest", plugin = {"pretty","json:target/cucumber-reports.json"} monochrome = true, ) Example: JSON ReportExtent HTML ReportThe ExtentCucumberAdapter plugin is a highly versatile and essential tool for modern test reporting, seamlessly integrating with your testing pipeline to deliver a cutting-edge HTML reporting design. Its interactive, visually appealing format transforms test results into clear and actionable insights, making it indispensable for enhancing the efficiency and transparency of your testing processes.Extent HTML Report@CucumberOptions( features = "src/test/resources/features", glue = "com.masteringqa.stepdefinitions", tags = "@smoketest", plugin = {"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"}, monochrome = true, ) Example: Extent HTML Report Ensure you add the plugin to your runner before proceeding!Once the plugin is added, execute the mvn test command to run your tests. After the tests complete, you can view the detailed report generated by the ExtentsCucumberAdapter. This will also work for Running as a JUnit Test method.Running from Terminal using MavenThe third method is running your scripts from the terminal using the mvn test command with the Surefire plugin, ideal for pipeline integration. In this scenario we’ll use the extents report. Running The Test Using Maven Command in TerminalTerminal: mvn test<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M5</