├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── packageTest.sh ├── pom.xml ├── readme_images └── appium-tests.gif ├── src ├── main │ └── assembly │ │ └── zip.xml └── test │ ├── java │ ├── Pages │ │ ├── BasePage.java │ │ ├── LoginPage.java │ │ ├── NavigationPage.java │ │ └── WaitConfig.java │ └── Tests │ │ ├── AbstractBaseTests │ │ └── TestBase.java │ │ └── LoginTest.java │ └── resources │ └── LoginTest │ └── LoginTest.feature └── start-appium-android.sh /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/issues), or [recently closed](https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | AWS Device Farm Appium Cucumber Tests For Sample App 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS Device Farm Appium Cucumber Tests For Sample App 2 | 3 | Sample Appium Cucumber tests for Android sample app that can be used on AWS Device Farm. 4 | 5 | Instructions to package and run this test can be found [here.](https://aws.amazon.com/blogs/mobile/testing-mobile-apps-with-cucumber-and-appium-through-testng-on-aws-device-farm/) 6 | 7 | ## License 8 | 9 | This library is licensed under the Apache 2.0 License. 10 | -------------------------------------------------------------------------------- /packageTest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mvn clean package -DskipTests=true -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.amazon.aws.adf.referenceapp.appium.test 8 | Referenceapp-Appium-Test 9 | 1.0-SNAPSHOT 10 | jar 11 | ReferenceAppAppiumTests 12 | http://maven.apache.org 13 | 14 | 15 | 16 | org.testng 17 | testng 18 | 6.8.8 19 | test 20 | 21 | 22 | io.appium 23 | java-client 24 | 3.1.0 25 | 26 | 27 | info.cukes 28 | cucumber-java 29 | 1.2.5 30 | test 31 | 32 | 33 | info.cukes 34 | cucumber-testng 35 | 1.2.4 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-jar-plugin 44 | 2.6 45 | 46 | 47 | 48 | test-jar 49 | 50 | 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-dependency-plugin 56 | 2.10 57 | 58 | 59 | copy-dependencies 60 | package 61 | 62 | copy-dependencies 63 | 64 | 65 | ${project.build.directory}/dependency-jars/ 66 | 67 | 68 | 69 | 70 | 71 | maven-assembly-plugin 72 | 2.5.4 73 | 74 | 75 | package 76 | 77 | single 78 | 79 | 80 | zip-with-dependencies 81 | false 82 | 83 | src/main/assembly/zip.xml 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /readme_images/appium-tests.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-device-farm-appium-cucumber-tests-for-sample-app/ce71432fbfc53eedf13ebf27699aa5c8565066a0/readme_images/appium-tests.gif -------------------------------------------------------------------------------- /src/main/assembly/zip.xml: -------------------------------------------------------------------------------- 1 | 15 | 20 | zip 21 | 22 | zip 23 | 24 | false 25 | 26 | 27 | ${project.build.directory} 28 | ./ 29 | 30 | *.jar 31 | 32 | 33 | 34 | ${project.build.directory} 35 | ./ 36 | 37 | /dependency-jars/ 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/test/java/Pages/BasePage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Pages; 17 | 18 | 19 | import io.appium.java_client.AppiumDriver; 20 | import io.appium.java_client.pagefactory.AppiumFieldDecorator; 21 | import org.openqa.selenium.WebElement; 22 | import org.openqa.selenium.support.PageFactory; 23 | 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * A base for all the pages within the suite 28 | */ 29 | public abstract class BasePage { 30 | private static final int KEYBOARD_ANIMATION_DELAY = 1000; 31 | private static final int XML_REFRESH_DELAY = 1000; 32 | 33 | /** 34 | * The driver 35 | */ 36 | protected final AppiumDriver driver; 37 | 38 | /** 39 | * A base constructor that sets the page's driver 40 | * 41 | * The page structure is being used within this test in order to separate the 42 | * page actions from the tests. 43 | * 44 | * Please use the AppiumFieldDecorator class within the page factory. This way annotations 45 | * like @AndroidFindBy within the page objects. 46 | * 47 | * @param driver the appium driver created in the beforesuite method. 48 | */ 49 | protected BasePage(AppiumDriver driver){ 50 | this.driver = driver; 51 | PageFactory.initElements(new AppiumFieldDecorator(driver, 5, TimeUnit.SECONDS), this); 52 | } 53 | 54 | /** 55 | * Tries three times to send text to element properly. 56 | * 57 | * Note: This method was needed because Appium sometimes sends text to textboxes incorrectly. 58 | * 59 | * @param input String to be sent 60 | * @param element WebElement to receive text, cannot be a secure text field. 61 | * @param appendNewLine true to append a new line character to incoming string when sending to element, else false 62 | * 63 | * @return true if keys were successfully sent, otherwise false. 64 | */ 65 | protected boolean sendKeysToElement(String input, WebElement element, boolean appendNewLine) throws InterruptedException { 66 | final int MAX_ATTEMPTS = 3; 67 | int attempts = 0; 68 | 69 | do { 70 | element.clear(); 71 | Thread.sleep(KEYBOARD_ANIMATION_DELAY); 72 | 73 | if (appendNewLine) { 74 | element.sendKeys(input + "\n"); 75 | } else { 76 | element.sendKeys(input); 77 | } 78 | 79 | Thread.sleep(XML_REFRESH_DELAY); 80 | } while (!element.getText().contains(input) && ++attempts < MAX_ATTEMPTS); 81 | 82 | return element.getText().contains(input); 83 | } 84 | } -------------------------------------------------------------------------------- /src/test/java/Pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Pages; 17 | 18 | import io.appium.java_client.AppiumDriver; 19 | import io.appium.java_client.MobileElement; 20 | import io.appium.java_client.pagefactory.AndroidFindBy; 21 | 22 | /** 23 | * A login page 24 | */ 25 | public class LoginPage extends BasePage { 26 | private static final int KEYBOARD_ANIMATION_DELAY = 1000; 27 | 28 | /** 29 | * The login button 30 | */ 31 | @AndroidFindBy(id = "com.amazonaws.devicefarm.android.referenceapp:id/login_button") 32 | private MobileElement loginButton; 33 | 34 | /** 35 | * The user name input 36 | */ 37 | @AndroidFindBy(id = "com.amazonaws.devicefarm.android.referenceapp:id/username_text_input") 38 | private MobileElement usernameField; 39 | 40 | /** 41 | * The password input 42 | */ 43 | @AndroidFindBy(id = "com.amazonaws.devicefarm.android.referenceapp:id/password_text_input") 44 | private MobileElement passwordField; 45 | 46 | public LoginPage(AppiumDriver driver) { 47 | super(driver); 48 | } 49 | 50 | /** 51 | * Tries to login with a set of credentials 52 | * 53 | * @param username the username 54 | * @param password the password 55 | * 56 | * @return true if username was entered in correctly, else false. 57 | */ 58 | public boolean login(String username, String password) throws InterruptedException { 59 | boolean usernameStatus = sendKeysToElement(username, usernameField, false); 60 | 61 | passwordField.click(); 62 | Thread.sleep(KEYBOARD_ANIMATION_DELAY); 63 | passwordField.sendKeys(password); 64 | 65 | loginButton.click(); 66 | 67 | return usernameStatus; 68 | } 69 | 70 | /** 71 | * 72 | * @return the login message 73 | */ 74 | public String getMessage() { 75 | return driver.findElementById("Alt Message").getText(); 76 | } 77 | 78 | /** 79 | * Checks to see if back at login page 80 | * 81 | * @return is back at login 82 | */ 83 | public boolean checkIfBackAtLogin() { 84 | return loginButton.isDisplayed() && usernameField.isDisplayed() && passwordField.isDisplayed(); 85 | } 86 | 87 | /** 88 | * Presses the logout/try again button 89 | */ 90 | public void pressAltButton() { 91 | driver.findElementById("Alt Button").click(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/Pages/NavigationPage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Pages; 17 | 18 | import io.appium.java_client.AppiumDriver; 19 | import io.appium.java_client.pagefactory.AndroidFindBy; 20 | import org.openqa.selenium.NoSuchElementException; 21 | import org.openqa.selenium.WebElement; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * A page for navigation drawer 28 | */ 29 | public class NavigationPage extends BasePage{ 30 | 31 | private final int TRIES = 5; 32 | 33 | /** 34 | * Get the toggle button 35 | */ 36 | @AndroidFindBy(accessibility = "ReferenceApp") 37 | private WebElement toggle; 38 | 39 | public NavigationPage(AppiumDriver driver) { 40 | super(driver); 41 | } 42 | 43 | /** 44 | * Go to a specific category within the navigation drawer 45 | * 46 | * @param categoryName category 47 | */ 48 | public void gotoCategory(String categoryName) { 49 | int counter = 0; 50 | toggle.click(); 51 | try { 52 | Thread.sleep(WaitConfig.DRAWER_ANIMATION_WAIT); 53 | } catch (InterruptedException e) { 54 | e.printStackTrace(); 55 | } 56 | 57 | WebElement categoryElement = null; 58 | List categoryElements; 59 | 60 | while (categoryElement == null) { 61 | counter++; 62 | if (counter == TRIES) 63 | return; 64 | categoryElements = driver.findElementsById("com.amazonaws.devicefarm.android.referenceapp:id/drawer_row_title"); 65 | for (WebElement categoryTitleElement: categoryElements){ 66 | String titleText = categoryTitleElement.getText(); 67 | if (titleText.equalsIgnoreCase(categoryName)) categoryElement = categoryTitleElement; 68 | 69 | } 70 | if (categoryElement == null) { 71 | driver.scrollTo(categoryName); 72 | } 73 | } 74 | 75 | categoryElement.click(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/Pages/WaitConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Pages; 17 | 18 | public class WaitConfig { 19 | public static final int DRAWER_ANIMATION_WAIT = 2000; 20 | public static final int VIEWPAGE_BEFORE_WAIT = 1000; 21 | public static final int VIEWPAGE_BEFORE_AFTER = 4000; 22 | } -------------------------------------------------------------------------------- /src/test/java/Tests/AbstractBaseTests/TestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Tests.AbstractBaseTests; 17 | 18 | import cucumber.api.testng.AbstractTestNGCucumberTests; 19 | 20 | import Pages.NavigationPage; 21 | import io.appium.java_client.MobileElement; 22 | import io.appium.java_client.android.AndroidDriver; 23 | import org.openqa.selenium.remote.DesiredCapabilities; 24 | import org.testng.annotations.*; 25 | 26 | import java.net.MalformedURLException; 27 | import java.net.URL; 28 | import java.util.concurrent.TimeUnit; 29 | 30 | /** 31 | * An abstract base for all of the Android tests within this package 32 | * 33 | * Responsible for setting up the Appium test Driver 34 | */ 35 | public abstract class TestBase extends AbstractTestNGCucumberTests { 36 | /** 37 | * Make the driver static. This allows it to be created only once 38 | * and used across all of the test classes. 39 | */ 40 | public static AndroidDriver driver; 41 | 42 | /** 43 | * This allows the navigation to work within the app. 44 | * The category name is returned so we can navigate to it from the navigation 45 | * drawer. 46 | * 47 | * @return The name of the Android category 48 | */ 49 | public abstract String getName(); 50 | 51 | /** 52 | * A page containing the navigation drawer 53 | */ 54 | private NavigationPage navigationPage; 55 | 56 | /** 57 | * Method to initialize the test's page 58 | */ 59 | @BeforeTest 60 | public abstract void setUpPage(); 61 | 62 | /** 63 | * This method runs before any other method. 64 | * 65 | * Appium follows a client - server model: 66 | * We are setting up our appium client in order to connect to Device Farm's appium server. 67 | * 68 | * We do not need to and SHOULD NOT set our own DesiredCapabilities 69 | * Device Farm creates custom settings at the server level. Setting your own DesiredCapabilities 70 | * will result in unexpected results and failures. 71 | * 72 | * @throws MalformedURLException An exception that occurs when the URL is wrong 73 | */ 74 | @BeforeSuite 75 | public void setUpAppium() throws MalformedURLException { 76 | 77 | final String URL_STRING = "http://127.0.0.1:4723/wd/hub"; 78 | 79 | URL url = new URL(URL_STRING); 80 | 81 | //Use a empty DesiredCapabilities object 82 | DesiredCapabilities capabilities = new DesiredCapabilities(); 83 | 84 | //Set the DesiredCapabilities capabilities only for local development 85 | capabilities.setCapability("platformName", "Android"); 86 | capabilities.setCapability("deviceName", "Android Emulator"); 87 | capabilities.setCapability("appPackage", "com.amazonaws.devicefarm.android.referenceapp"); 88 | capabilities.setCapability("appActivity", "com.amazonaws.devicefarm.android.referenceapp.Activities.MainActivity"); 89 | capabilities.setCapability("udid", "emulator-5554"); 90 | 91 | driver = new AndroidDriver(url, capabilities); 92 | 93 | //Use a higher value if your mobile elements take time to show up 94 | driver.manage().timeouts().implicitlyWait(35, TimeUnit.SECONDS); 95 | } 96 | 97 | /** 98 | * Always remember to quit 99 | */ 100 | @AfterSuite 101 | public void tearDownAppium() { 102 | driver.quit(); 103 | } 104 | 105 | /** 106 | * 107 | * Creates a navigation page and navigates to the Class' category 108 | * within the navigation drawer 109 | * 110 | */ 111 | @BeforeClass 112 | public void navigateTo() throws InterruptedException { 113 | navigationPage = new NavigationPage(driver); 114 | navigationPage.gotoCategory(getName()); 115 | } 116 | 117 | /** 118 | * Restart the app after every test class to go back to the main 119 | * screen and to reset the behavior 120 | */ 121 | @AfterClass 122 | public void restartApp() { 123 | driver.resetApp(); 124 | } 125 | } -------------------------------------------------------------------------------- /src/test/java/Tests/LoginTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package Tests; 17 | 18 | import cucumber.api.CucumberOptions; 19 | import cucumber.api.java.en.Given; 20 | import cucumber.api.java.en.Then; 21 | import cucumber.api.java.en.When; 22 | 23 | 24 | import Pages.LoginPage; 25 | import Tests.AbstractBaseTests.TestBase; 26 | import org.testng.Assert; 27 | import org.testng.annotations.AfterMethod; 28 | import org.testng.annotations.BeforeTest; 29 | import org.testng.annotations.Test; 30 | 31 | /** 32 | * Tests for a login page 33 | */ 34 | 35 | 36 | @CucumberOptions( 37 | strict = true, 38 | monochrome = true, 39 | features = "classpath:LoginTest", 40 | plugin = {"pretty"} 41 | ) 42 | public class LoginTest extends TestBase { 43 | private static final String LOGIN_SUCCESS_MESSAGE = "You are logged on as admin"; 44 | private static final String LOGIN_FAIL_MESSAGE = "You gave me the wrong username and password"; 45 | private static final String CORRECT_USER_NAME = "admin"; 46 | private static final String CORRECT_PASSWORD = "password"; 47 | private static final String FAIL_USER_NAME = "Wrong User"; 48 | private static final String FAIL_PASSWORD = "12345"; 49 | private static final String BAD_TEXT_ENTRY_MSG = "Username sent to text field incorrectly"; 50 | 51 | private LoginPage loginPage; 52 | 53 | @Override 54 | public String getName() { 55 | return "Login Page"; 56 | } 57 | 58 | /** 59 | * Creates a login 60 | */ 61 | @Given("^I navigate to the login page$") 62 | public void setUpPage() { 63 | loginPage = new LoginPage(driver); 64 | } 65 | 66 | /** 67 | * Tests logging in with valid credentials by verifying if the login message is correct 68 | */ 69 | @Given("^username is correct$") 70 | public void loginSuccess() throws InterruptedException { 71 | Assert.assertTrue(loginPage.login(CORRECT_USER_NAME, CORRECT_PASSWORD)); 72 | Assert.assertEquals(loginPage.getMessage(), LOGIN_SUCCESS_MESSAGE); 73 | } 74 | 75 | /** 76 | * Tests logging in with invalid credentials by verifying if the error message is correct 77 | */ 78 | @Given("^username is bad$") 79 | public void loginFail() throws InterruptedException { 80 | Assert.assertTrue(loginPage.login(FAIL_USER_NAME, FAIL_PASSWORD)); 81 | Assert.assertEquals(loginPage.getMessage(), LOGIN_FAIL_MESSAGE); 82 | } 83 | 84 | /** 85 | * After each test method, logout or try again 86 | */ 87 | @Then("^log out$") 88 | public void logOut() { 89 | loginPage.pressAltButton(); 90 | Assert.assertTrue(loginPage.checkIfBackAtLogin()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/resources/LoginTest/LoginTest.feature: -------------------------------------------------------------------------------- 1 | Feature: Does the login page work? 2 | We want the login page to work when the login credentials are valid, and fail otherwise 3 | 4 | Background: A Login Page 5 | Given I navigate to the login page 6 | 7 | Scenario: Login fails 8 | Given username is bad 9 | Then log out 10 | 11 | 12 | Scenario: Login succeeds 13 | Given username is correct 14 | Then log out -------------------------------------------------------------------------------- /start-appium-android.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function die { 4 | echo $1 5 | exit 1 6 | } 7 | 8 | pkg_root_dir=`find $PWD | grep "/Config$" | head -n 1 | xargs dirname` 9 | app_filename="$pkg_root_dir/app/app.apk" 10 | ls -1 $app_filename || die "Did not find app in $pkg_root_dir" 11 | 12 | appium --pre-launch --app-pkg com.amazonaws.devicefarm.android.referenceapp --app-activity .Activities.MainActivity --platform-name Android --app $app_filename 13 | --------------------------------------------------------------------------------