├── .env ├── .github ├── pull_request_template.md └── workflows │ └── main.yml ├── .gitignore ├── .travis.yml ├── app.log ├── conftest.py ├── data └── apps │ ├── Android-NativeDemoApp-0.2.1.apk │ ├── iOS-RealDevice-NativeDemoApp-0.2.1.ipa │ └── iOS-Simulator-NativeDemoApp-0.2.1.app │ ├── AppIcon20x20@2x.png │ ├── AppIcon20x20@3x.png │ ├── AppIcon29x29@2x.png │ ├── AppIcon29x29@3x.png │ ├── AppIcon40x40@2x.png │ ├── AppIcon40x40@3x.png │ ├── AppIcon60x60@2x.png │ ├── AppIcon60x60@3x.png │ ├── Assets.car │ ├── Entypo.ttf │ ├── EvilIcons.ttf │ ├── Feather.ttf │ ├── FontAwesome.ttf │ ├── FontAwesome5_Brands.ttf │ ├── FontAwesome5_Regular.ttf │ ├── FontAwesome5_Solid.ttf │ ├── Foundation.ttf │ ├── Frameworks │ ├── XCTest.framework │ │ ├── Info.plist │ │ ├── XCTest │ │ ├── _CodeSignature │ │ │ └── CodeResources │ │ ├── en.lproj │ │ │ └── InfoPlist.strings │ │ └── version.plist │ └── libXCTestBundleInject.dylib │ ├── Info.plist │ ├── Ionicons.ttf │ ├── LaunchImage-1100-Portrait-2436h@3x.png │ ├── LaunchImage-700-568h@2x.png │ ├── LaunchImage-800-667h@2x.png │ ├── LaunchImage-800-Portrait-736h@3x.png │ ├── LaunchImage.png │ ├── MaterialCommunityIcons.ttf │ ├── MaterialIcons.ttf │ ├── Octicons.ttf │ ├── PkgInfo │ ├── PlugIns │ ├── wdioDemoAppTests.xctest.dSYM │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ └── DWARF │ │ │ └── wdioDemoAppTests │ └── wdioDemoAppTests.xctest │ │ ├── Info.plist │ │ ├── _CodeSignature │ │ └── CodeResources │ │ └── wdioDemoAppTests │ ├── SimpleLineIcons.ttf │ ├── Zocial.ttf │ ├── _CodeSignature │ └── CodeResources │ ├── assets │ ├── js │ │ └── assets │ │ │ └── webdriverio.png │ └── node_modules │ │ ├── @tele2 │ │ └── react-native-select-input │ │ │ └── src │ │ │ └── icons │ │ │ ├── arrowDown.png │ │ │ └── arrowUp.png │ │ ├── react-native-elements │ │ └── src │ │ │ └── rating │ │ │ └── images │ │ │ ├── bell.png │ │ │ ├── heart.png │ │ │ ├── rocket.png │ │ │ └── star.png │ │ └── react-navigation-stack │ │ └── dist │ │ └── views │ │ └── assets │ │ ├── back-icon-mask.png │ │ ├── back-icon.png │ │ ├── back-icon@2x.png │ │ └── back-icon@3x.png │ ├── main.jsbundle │ └── wdioDemoApp ├── pytest.ini ├── readme.md ├── report ├── 6d01bfcc-98f1-4278-a4c5-6fc2b55772bb-result.json ├── assets │ └── style.css ├── c5704f6f-6816-476a-83df-b5b8b491dee2-container.json └── report.html ├── requirements.txt ├── runner ├── android │ └── smoke_run.sh └── ios │ ├── smoke_run.sh │ └── smoke_run_bitrise.sh ├── screenshots └── test_home_2019-09-10_13-29-38.png ├── settings.py ├── src ├── helpers │ ├── app.py │ ├── appiumdriver.py │ ├── business.py │ └── constants.py ├── screens │ ├── android │ │ ├── base_screen.py │ │ ├── home_screen.py │ │ └── login_screen.py │ └── ios │ │ ├── base_screen.py │ │ ├── home_screen.py │ │ └── login_screen.py └── spec │ ├── android │ ├── home_test.py │ └── login_test.py │ └── ios │ ├── home_test.py │ └── login_test.py └── tasks.py /.env: -------------------------------------------------------------------------------- 1 | SLACK_TOKEN=XXXXXXX/XXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXX 2 | UDID=XXXXXXXXXXXXXXXXXXXXXXXXXXXX -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Merge checklist 2 | - [ ] TravisCI tests passed 3 | - [ ] Documentation -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Lint Python 3 | jobs: 4 | lint: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: cclauss/Find-Python-syntax-errors-action@master -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app.log 2 | .DS_Store 3 | src/helpers/helpers_old.py 4 | src/helpers/helpers.py 5 | __pycache__/ 6 | *.pyc 7 | .travis.yml 8 | screenshots/ 9 | report/ 10 | .idea/ 11 | dump/ 12 | .pytest_cache/ 13 | venv/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: android 3 | jdk: oraclejdk8 4 | image: thyrlian/android-sdk 5 | 6 | android: 7 | components: 8 | - tools 9 | - platform-tools 10 | # - build-tools-29.0.0 11 | # - build-tools-28.0.2 12 | - build-tools-25.0.2 13 | - android-25 14 | # - android-28 15 | - extra-google-google_play_services 16 | - extra-google-m2repository 17 | - extra-android-support 18 | - extra-android-m2repository 19 | # - addon-google_apis-google-28 20 | # - sys-img-armeabi-v7a-android-28 21 | - add-on 22 | - extra 23 | 24 | before_install: 25 | - sudo apt-get update 26 | - sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev 27 | libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev 28 | - git clone https://github.com/pyenv/pyenv.git ~/.pyenv 29 | - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile 30 | - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile 31 | - echo 'eval "$(pyenv init -)"' >> ~/.bash_profile 32 | - git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv 33 | - echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile 34 | - source ~/.bash_profile 35 | - pyenv versions 36 | - pyenv install 3.6.1 37 | - pyenv virtualenv 3.6.1 undang 38 | - pyenv activate undang 39 | - pip install -r requirements.txt 40 | - curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - 41 | - sudo apt-get install nodejs 42 | - sudo apt-get install build-essential 43 | - PATH=$PATH:$JAVA_HOME/bin 44 | - npm install appium 45 | - npm install appium-doctor 46 | - "./node_modules/.bin/appium-doctor" 47 | - "./node_modules/.bin/appium --log-level info > appium_log.txt &" 48 | - sdkmanager tools 49 | # - echo yes | sdkmanager "build-tools;25.0.2" 50 | # - echo yes | sdkmanager "platforms;android-25" 51 | 52 | before_script: 53 | - echo y | sdkmanager "system-images;android-25;google_apis;armeabi-v7a" 54 | - echo "no" | avdmanager --verbose create avd -n PF -k "system-images;android-25;google_apis;armeabi-v7a" -b google_apis/armeabi-v7a -f 55 | # -k "system-images;android-25;google_apis;armeabi-v7a" --abi "google_apis;armeabi-v7a" --tag google_apis --device "pixel" --name PF --force 56 | # - echo no | android create avd --force -n PF -t android-28 --abi armeabi-v7a 57 | - $ANDROID_HOME/emulator/emulator -avd PF -no-skin -no-audio -no-window & 58 | - android-wait-for-emulator 59 | - adb shell input keyevent 82 & 60 | 61 | script: 62 | - avd devices 63 | - "./gradlew assemble" # Build 64 | # - ./gradlew clean connectedCheck 65 | # - chmod +x ./gradlew 66 | # - ./gradlew connectedAndroidTest mergeAndroidReports --continue -PdisablePreDex --stacktrace 67 | - python3 -m pytest src/spec/* # Test 68 | 69 | after_script: 70 | - cat ./appium_log.txt # Check appium log 71 | -------------------------------------------------------------------------------- /app.log: -------------------------------------------------------------------------------- 1 | 07/16/2020 12:09:02 PM - INFO: Configuring desired capabilities 2 | 07/16/2020 12:09:02 PM - INFO: Initiating Appium driver 3 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | 4 | 5 | @pytest.hookimpl 6 | def pytest_addoption(parser): 7 | parser.addoption('--app', action='store', default="ios", help="Choose App: ios or android") 8 | parser.addoption('--device', action='store', default="emulator", help="Choose Device: simulator / emulator / real " 9 | "device") 10 | 11 | 12 | @pytest.fixture(scope="session") 13 | def app(request): 14 | return request.config.getoption("--app") 15 | 16 | 17 | @pytest.fixture(scope="session") 18 | def device(request): 19 | return request.config.getoption("--device") 20 | 21 | 22 | @pytest.fixture(scope='session') 23 | def get_logger(): 24 | logger = logging.getLogger(__name__) 25 | logger.setLevel(logging.DEBUG) 26 | ch = logging.FileHandler(r'app.log', mode='w') 27 | ch.setLevel(logging.DEBUG) 28 | formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s', '%m/%d/%Y %I:%M:%S %p') 29 | ch.setFormatter(formatter) 30 | logger.addHandler(ch) 31 | return logger 32 | 33 | # @pytest.fixture(scope='session', autouse=True) 34 | # def session_setup_teardown(): 35 | # yield 36 | # notify_slack() 37 | -------------------------------------------------------------------------------- /data/apps/Android-NativeDemoApp-0.2.1.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/Android-NativeDemoApp-0.2.1.apk -------------------------------------------------------------------------------- /data/apps/iOS-RealDevice-NativeDemoApp-0.2.1.ipa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-RealDevice-NativeDemoApp-0.2.1.ipa -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon20x20@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon20x20@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon29x29@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon40x40@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/AppIcon60x60@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Assets.car: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Assets.car -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Entypo.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/EvilIcons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Feather.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Brands.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Brands.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Regular.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Solid.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/FontAwesome5_Solid.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Foundation.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/Info.plist -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/XCTest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/XCTest -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Headers/XCAbstractTest.h 8 | 9 | 4jnRu9kM4nMP+Xh3ikwmHuBDxsI= 10 | 11 | Headers/XCTActivity.h 12 | 13 | BVKd+CuVL/fMWVnojVTY7BZiXkc= 14 | 15 | Headers/XCTAttachment.h 16 | 17 | D+igalTdqMWvG/cB1056ns8u3B8= 18 | 19 | Headers/XCTAttachmentLifetime.h 20 | 21 | uBkx/rPKjZiieZXjaYSrZHfYrQc= 22 | 23 | Headers/XCTContext.h 24 | 25 | S2c/fkq5xnjLgsMY3mNIE7jPMFE= 26 | 27 | Headers/XCTDarwinNotificationExpectation.h 28 | 29 | T1bfewH+fYADesmaBVQWzTdVRjk= 30 | 31 | Headers/XCTKVOExpectation.h 32 | 33 | s28+hglUCU24y2eMlji4++ZVC+0= 34 | 35 | Headers/XCTNSNotificationExpectation.h 36 | 37 | ZC9t23DBiU7y/pJ116Zgt8q1/J4= 38 | 39 | Headers/XCTNSPredicateExpectation.h 40 | 41 | ZeWBK1Un0h29h5DRuqDXCiqCOnk= 42 | 43 | Headers/XCTWaiter.h 44 | 45 | 3xRcrUqW54PHl7VXGv1RNSfgZAg= 46 | 47 | Headers/XCTest.apinotes 48 | 49 | WqUywzmEAqoV6c0qeOnMA2dcIQc= 50 | 51 | Headers/XCTest.h 52 | 53 | vyHRJ5iIHDimvUMhPRtMJzhrlW4= 54 | 55 | Headers/XCTestAssertions.h 56 | 57 | TFhruscn++ANKgidq0O8+oRGZg0= 58 | 59 | Headers/XCTestAssertionsImpl.h 60 | 61 | FMlfpxJpHMUMoOhkV78DHSY1H74= 62 | 63 | Headers/XCTestCase+AsynchronousTesting.h 64 | 65 | dIWmXJMmBG4KZlskftye7w5BFSI= 66 | 67 | Headers/XCTestCase.h 68 | 69 | wj3AeIl6hv7IjEECC8+IYM1Mm2Q= 70 | 71 | Headers/XCTestCaseRun.h 72 | 73 | /XUqDHA/BFdQDUxQU8Ft5LXo/Ps= 74 | 75 | Headers/XCTestDefines.h 76 | 77 | po6ETUvux87Rma0YA5sp9vfGHSs= 78 | 79 | Headers/XCTestErrors.h 80 | 81 | +vO07iqBB7ZsrpEHPOAtvqTwUVc= 82 | 83 | Headers/XCTestExpectation.h 84 | 85 | Y/ssvPOSAIHfa/G1pVREFYwgDq8= 86 | 87 | Headers/XCTestLog.h 88 | 89 | 9BU/gwbaKcfn2L9dfo2dHRFN6Bc= 90 | 91 | Headers/XCTestObservation.h 92 | 93 | eYPPds+/sIm1g8tzzWEi74ngT8s= 94 | 95 | Headers/XCTestObservationCenter.h 96 | 97 | 5ySsNYFGF0ZFvLZnL7UTg1HNRR4= 98 | 99 | Headers/XCTestObserver.h 100 | 101 | DV3Cjdd1CAe6nYFEzmUrCtnzxQg= 102 | 103 | Headers/XCTestProbe.h 104 | 105 | fIVR0xRsxMAabrJmeGX3hPDwL0Y= 106 | 107 | Headers/XCTestRun.h 108 | 109 | 7GVNxTeghh0aBxY/Gvb+j2VTkqQ= 110 | 111 | Headers/XCTestSuite.h 112 | 113 | eRc+OVrMoZSKfP/hWkP9044Xkwo= 114 | 115 | Headers/XCTestSuiteRun.h 116 | 117 | OX+g52bOAnhjLVDKkweTKM8jTHQ= 118 | 119 | Headers/XCUIApplication.h 120 | 121 | 3xPGyAQELvSZZ4RHMwhQEnlzFhg= 122 | 123 | Headers/XCUICoordinate.h 124 | 125 | ISpzcCIN+bNtcvHSlqKq3H0dHAA= 126 | 127 | Headers/XCUIDevice.h 128 | 129 | 6pJZzs6nb9PxIhPZMSzM3Pnoyyk= 130 | 131 | Headers/XCUIElement.h 132 | 133 | 25uxff90oirJoEGqmcoId+OQAJU= 134 | 135 | Headers/XCUIElementAttributes.h 136 | 137 | 8ihGn99tX4C4PPRNW4qUqlS9tBo= 138 | 139 | Headers/XCUIElementQuery.h 140 | 141 | C3ZXTnkZIFu38bImb5YnKX8ME3s= 142 | 143 | Headers/XCUIElementTypeQueryProvider.h 144 | 145 | RByqnqCJz+rOh+n5b6A0LWE4ipY= 146 | 147 | Headers/XCUIElementTypes.h 148 | 149 | rS+FtIJ/fnc0UIdAg5Fupx0KuVc= 150 | 151 | Headers/XCUIKeyboardKeys.h 152 | 153 | iM5NitaH7AFOmYTcSm86X0OTpSw= 154 | 155 | Headers/XCUIRemote.h 156 | 157 | +rbCM60bDizOcqH+NaoTiCwtEH4= 158 | 159 | Headers/XCUIScreen.h 160 | 161 | DBqshlCvI4VeOu1t7slE1L12Akw= 162 | 163 | Headers/XCUIScreenshot.h 164 | 165 | WRAFpS5fsJOjpa68uJDYY7QcwzQ= 166 | 167 | Headers/XCUIScreenshotProviding.h 168 | 169 | qghz8l697gauRG1WZGkXCsisS40= 170 | 171 | Headers/XCUISiriService.h 172 | 173 | NtIeUU61kDhd8LGgBr1FjKXe6JQ= 174 | 175 | Info.plist 176 | 177 | DQ4GPJ7FuM6H+FaCC/2wxhPSGCQ= 178 | 179 | Modules/module.modulemap 180 | 181 | ha0qqLvU0UdkLu07qH5tE4agQV4= 182 | 183 | en.lproj/InfoPlist.strings 184 | 185 | hash 186 | 187 | TuBj57ZP6zBqcL9HttO2Rucaw9E= 188 | 189 | optional 190 | 191 | 192 | version.plist 193 | 194 | P6P66kW7+LvLIo4WHjXGltpT8CA= 195 | 196 | 197 | files2 198 | 199 | Headers/XCAbstractTest.h 200 | 201 | hash 202 | 203 | 4jnRu9kM4nMP+Xh3ikwmHuBDxsI= 204 | 205 | hash2 206 | 207 | IFgW59C1Ktqp4LtLT30sw91amGbNOGweE+JfCOD3+Zg= 208 | 209 | 210 | Headers/XCTActivity.h 211 | 212 | hash 213 | 214 | BVKd+CuVL/fMWVnojVTY7BZiXkc= 215 | 216 | hash2 217 | 218 | rRcgcNhfkv8++PLGoc2+V7RKA+20od2gktcAZnNphso= 219 | 220 | 221 | Headers/XCTAttachment.h 222 | 223 | hash 224 | 225 | D+igalTdqMWvG/cB1056ns8u3B8= 226 | 227 | hash2 228 | 229 | 5aviQX7pgXyeS3UISWFOjiiUf8kPCzFtPNnk08B2rrQ= 230 | 231 | 232 | Headers/XCTAttachmentLifetime.h 233 | 234 | hash 235 | 236 | uBkx/rPKjZiieZXjaYSrZHfYrQc= 237 | 238 | hash2 239 | 240 | yrLG05PHjYkx013jrhQuHeuuP2sz3+LqbAIRN/0Mqc4= 241 | 242 | 243 | Headers/XCTContext.h 244 | 245 | hash 246 | 247 | S2c/fkq5xnjLgsMY3mNIE7jPMFE= 248 | 249 | hash2 250 | 251 | aKMqn4OBmb2Fg3/8sTMLXW2eHWiyWP3bQkSzTnvrwmQ= 252 | 253 | 254 | Headers/XCTDarwinNotificationExpectation.h 255 | 256 | hash 257 | 258 | T1bfewH+fYADesmaBVQWzTdVRjk= 259 | 260 | hash2 261 | 262 | yghcN+Vtx2KfRi9uMiorSiMSUWkgipo2aBxjXGpindM= 263 | 264 | 265 | Headers/XCTKVOExpectation.h 266 | 267 | hash 268 | 269 | s28+hglUCU24y2eMlji4++ZVC+0= 270 | 271 | hash2 272 | 273 | s24Kr8S1fbS62TmPjWUVYBWo7l0mxOge/yAw3RVvRCQ= 274 | 275 | 276 | Headers/XCTNSNotificationExpectation.h 277 | 278 | hash 279 | 280 | ZC9t23DBiU7y/pJ116Zgt8q1/J4= 281 | 282 | hash2 283 | 284 | vHwq0rw8c1B93uSPcxyrdcpNF6gp5UqVvnMHKFPMSMg= 285 | 286 | 287 | Headers/XCTNSPredicateExpectation.h 288 | 289 | hash 290 | 291 | ZeWBK1Un0h29h5DRuqDXCiqCOnk= 292 | 293 | hash2 294 | 295 | S1UvUDqqEddmWd/HrxA/x6Hc5VP0fYA6PWhhbAX9PzY= 296 | 297 | 298 | Headers/XCTWaiter.h 299 | 300 | hash 301 | 302 | 3xRcrUqW54PHl7VXGv1RNSfgZAg= 303 | 304 | hash2 305 | 306 | mA5vx6/QQ25gHCNLjo9Y0eX1khy7s52IB7yacIGlrNk= 307 | 308 | 309 | Headers/XCTest.apinotes 310 | 311 | hash 312 | 313 | WqUywzmEAqoV6c0qeOnMA2dcIQc= 314 | 315 | hash2 316 | 317 | k+5JrEIKeIUahHN4rMRX6ihL13259MqcP597ms2vgMs= 318 | 319 | 320 | Headers/XCTest.h 321 | 322 | hash 323 | 324 | vyHRJ5iIHDimvUMhPRtMJzhrlW4= 325 | 326 | hash2 327 | 328 | vq64eNbcQBW4F9zCLXsPBM4vawf51Eq6PcVMcSyxLYI= 329 | 330 | 331 | Headers/XCTestAssertions.h 332 | 333 | hash 334 | 335 | TFhruscn++ANKgidq0O8+oRGZg0= 336 | 337 | hash2 338 | 339 | HNwN4r4tVDYAyxvEdGWpbCOzE9tjFMwivSpf/OMiSA0= 340 | 341 | 342 | Headers/XCTestAssertionsImpl.h 343 | 344 | hash 345 | 346 | FMlfpxJpHMUMoOhkV78DHSY1H74= 347 | 348 | hash2 349 | 350 | HR9g/DQVSYIlmIjN9aQo9QONQPkTY+7GRuFBie/i2so= 351 | 352 | 353 | Headers/XCTestCase+AsynchronousTesting.h 354 | 355 | hash 356 | 357 | dIWmXJMmBG4KZlskftye7w5BFSI= 358 | 359 | hash2 360 | 361 | zLn+sqbu8TwZu3fllS4K4kPFcGnfr8jhG5UWuQteqyI= 362 | 363 | 364 | Headers/XCTestCase.h 365 | 366 | hash 367 | 368 | wj3AeIl6hv7IjEECC8+IYM1Mm2Q= 369 | 370 | hash2 371 | 372 | grTesKyxgSO20bny3hiyO0ISXvlgcdenyXkWGIGjQFQ= 373 | 374 | 375 | Headers/XCTestCaseRun.h 376 | 377 | hash 378 | 379 | /XUqDHA/BFdQDUxQU8Ft5LXo/Ps= 380 | 381 | hash2 382 | 383 | jEzXeXeFAbT7xbfbqjlf4yF+lZvOKKw9u0dhT8Lzpe4= 384 | 385 | 386 | Headers/XCTestDefines.h 387 | 388 | hash 389 | 390 | po6ETUvux87Rma0YA5sp9vfGHSs= 391 | 392 | hash2 393 | 394 | XEUB26q3NNiOejd2zU8pAaf6LXWLdjEN4SgBi/oEHfU= 395 | 396 | 397 | Headers/XCTestErrors.h 398 | 399 | hash 400 | 401 | +vO07iqBB7ZsrpEHPOAtvqTwUVc= 402 | 403 | hash2 404 | 405 | hRldg6Kd690zh5Kxqa/je1cM/QAdhCdHnhSex8B/qQQ= 406 | 407 | 408 | Headers/XCTestExpectation.h 409 | 410 | hash 411 | 412 | Y/ssvPOSAIHfa/G1pVREFYwgDq8= 413 | 414 | hash2 415 | 416 | bzHkvrq2f+1FFP3qie5fF78p6scQOnD/r7WYoDW764A= 417 | 418 | 419 | Headers/XCTestLog.h 420 | 421 | hash 422 | 423 | 9BU/gwbaKcfn2L9dfo2dHRFN6Bc= 424 | 425 | hash2 426 | 427 | Tu+6JYZZzftcXmUWH11IO9/jXCXi6QPeWDrL6izup6s= 428 | 429 | 430 | Headers/XCTestObservation.h 431 | 432 | hash 433 | 434 | eYPPds+/sIm1g8tzzWEi74ngT8s= 435 | 436 | hash2 437 | 438 | DlaZPljnXduHBIxVFsQHWivHsQV6+QqtkPm3wqcNC9c= 439 | 440 | 441 | Headers/XCTestObservationCenter.h 442 | 443 | hash 444 | 445 | 5ySsNYFGF0ZFvLZnL7UTg1HNRR4= 446 | 447 | hash2 448 | 449 | d+hY4S23zmWO8E2YIrh4biGe9oQWCfD497a+oVk2+yY= 450 | 451 | 452 | Headers/XCTestObserver.h 453 | 454 | hash 455 | 456 | DV3Cjdd1CAe6nYFEzmUrCtnzxQg= 457 | 458 | hash2 459 | 460 | 7CTdhCJbuEzQNSyp3exgcCn6JnIRjBwpUcOKmiddBtU= 461 | 462 | 463 | Headers/XCTestProbe.h 464 | 465 | hash 466 | 467 | fIVR0xRsxMAabrJmeGX3hPDwL0Y= 468 | 469 | hash2 470 | 471 | FKXb32Ennc+6f3SkuVdo8bBNcIIWwryV5u5FmQYN8Fc= 472 | 473 | 474 | Headers/XCTestRun.h 475 | 476 | hash 477 | 478 | 7GVNxTeghh0aBxY/Gvb+j2VTkqQ= 479 | 480 | hash2 481 | 482 | bSeEEos9toHX4ZeMGeRYdv1KXdCziExa2r95Y6Qcem8= 483 | 484 | 485 | Headers/XCTestSuite.h 486 | 487 | hash 488 | 489 | eRc+OVrMoZSKfP/hWkP9044Xkwo= 490 | 491 | hash2 492 | 493 | L7lrx0/vT/6C441YiHqyBo8c41P7nh8AVfj2Ju9MWF0= 494 | 495 | 496 | Headers/XCTestSuiteRun.h 497 | 498 | hash 499 | 500 | OX+g52bOAnhjLVDKkweTKM8jTHQ= 501 | 502 | hash2 503 | 504 | QDxhlFfxAJEcudV29W9M96FJW5LQiR0yqdUHzkjMuA0= 505 | 506 | 507 | Headers/XCUIApplication.h 508 | 509 | hash 510 | 511 | 3xPGyAQELvSZZ4RHMwhQEnlzFhg= 512 | 513 | hash2 514 | 515 | c5JhLgu1HF3BRKMZa+lW3Uv/rhC85w7hROiHmgBDw8k= 516 | 517 | 518 | Headers/XCUICoordinate.h 519 | 520 | hash 521 | 522 | ISpzcCIN+bNtcvHSlqKq3H0dHAA= 523 | 524 | hash2 525 | 526 | WqIHIIX29PruSt0Ux3ajf2d2Ya6W7ES85APt7RfZEUQ= 527 | 528 | 529 | Headers/XCUIDevice.h 530 | 531 | hash 532 | 533 | 6pJZzs6nb9PxIhPZMSzM3Pnoyyk= 534 | 535 | hash2 536 | 537 | a332EuTW+1XyYOs10oV/xXmV18ua86gJqI6rQ/QIzJE= 538 | 539 | 540 | Headers/XCUIElement.h 541 | 542 | hash 543 | 544 | 25uxff90oirJoEGqmcoId+OQAJU= 545 | 546 | hash2 547 | 548 | tcQVVPrLnGHtpuOYH54AchAIAxphDf4BcsEKEIh9CVU= 549 | 550 | 551 | Headers/XCUIElementAttributes.h 552 | 553 | hash 554 | 555 | 8ihGn99tX4C4PPRNW4qUqlS9tBo= 556 | 557 | hash2 558 | 559 | /RERxiLo8BzHBf5biK7xsVJnDB73TOHeOH72FBuhMTo= 560 | 561 | 562 | Headers/XCUIElementQuery.h 563 | 564 | hash 565 | 566 | C3ZXTnkZIFu38bImb5YnKX8ME3s= 567 | 568 | hash2 569 | 570 | LF3E68WtedEEM/IFD3q/tOZ3q0JtUQQhOK4XkamNjNM= 571 | 572 | 573 | Headers/XCUIElementTypeQueryProvider.h 574 | 575 | hash 576 | 577 | RByqnqCJz+rOh+n5b6A0LWE4ipY= 578 | 579 | hash2 580 | 581 | KPNzI8l6orkq7Lw9Lptey1l4nsXuyg/c9kYgH2/O5x0= 582 | 583 | 584 | Headers/XCUIElementTypes.h 585 | 586 | hash 587 | 588 | rS+FtIJ/fnc0UIdAg5Fupx0KuVc= 589 | 590 | hash2 591 | 592 | PUsaHf1pPvtkPng1Gk8jnyBg64It8wcfcNQK5lbNMs4= 593 | 594 | 595 | Headers/XCUIKeyboardKeys.h 596 | 597 | hash 598 | 599 | iM5NitaH7AFOmYTcSm86X0OTpSw= 600 | 601 | hash2 602 | 603 | MbFj4xHxsP2eF3L+IKG6cETqjvOpZFLq0ztIDCdeyt8= 604 | 605 | 606 | Headers/XCUIRemote.h 607 | 608 | hash 609 | 610 | +rbCM60bDizOcqH+NaoTiCwtEH4= 611 | 612 | hash2 613 | 614 | w7DXRAekwdX2XMbVLAxEj/q2faSvgp1LMbKGZDcUznE= 615 | 616 | 617 | Headers/XCUIScreen.h 618 | 619 | hash 620 | 621 | DBqshlCvI4VeOu1t7slE1L12Akw= 622 | 623 | hash2 624 | 625 | 45JwTQ4UtWVT2wvzdq2QOl8rBZ9Wxq9ubBB2vGvgBKc= 626 | 627 | 628 | Headers/XCUIScreenshot.h 629 | 630 | hash 631 | 632 | WRAFpS5fsJOjpa68uJDYY7QcwzQ= 633 | 634 | hash2 635 | 636 | F2tCZijPx0hU+7CIdW0fMZK4cwKbgFYiI9LKYINt5sU= 637 | 638 | 639 | Headers/XCUIScreenshotProviding.h 640 | 641 | hash 642 | 643 | qghz8l697gauRG1WZGkXCsisS40= 644 | 645 | hash2 646 | 647 | s35VI6Lzy6LUDsIoANQTenLSsJeaPXvonWElqk8cJbM= 648 | 649 | 650 | Headers/XCUISiriService.h 651 | 652 | hash 653 | 654 | NtIeUU61kDhd8LGgBr1FjKXe6JQ= 655 | 656 | hash2 657 | 658 | 6JTR/e2zA54rVmT1cblklOkL8LFXaYg81YGhVhoagsw= 659 | 660 | 661 | Modules/module.modulemap 662 | 663 | hash 664 | 665 | ha0qqLvU0UdkLu07qH5tE4agQV4= 666 | 667 | hash2 668 | 669 | w5Zd8voFpYyDVfx4t9/bCAZAs1kTrhmGSzTXQMiBd/c= 670 | 671 | 672 | en.lproj/InfoPlist.strings 673 | 674 | hash 675 | 676 | TuBj57ZP6zBqcL9HttO2Rucaw9E= 677 | 678 | hash2 679 | 680 | 89RGkjZaKuewYnjpzwhIswhqfrU8+pcEXqM/DHVrUmo= 681 | 682 | optional 683 | 684 | 685 | version.plist 686 | 687 | hash 688 | 689 | P6P66kW7+LvLIo4WHjXGltpT8CA= 690 | 691 | hash2 692 | 693 | 2BV684CZjHtMZHxSiwC5qc/DGXv9WIOWUc9dEU/Q1pw= 694 | 695 | 696 | 697 | rules 698 | 699 | ^ 700 | 701 | ^.*\.lproj/ 702 | 703 | optional 704 | 705 | weight 706 | 1000 707 | 708 | ^.*\.lproj/locversion.plist$ 709 | 710 | omit 711 | 712 | weight 713 | 1100 714 | 715 | ^Base\.lproj/ 716 | 717 | weight 718 | 1010 719 | 720 | ^version.plist$ 721 | 722 | 723 | rules2 724 | 725 | .*\.dSYM($|/) 726 | 727 | weight 728 | 11 729 | 730 | ^ 731 | 732 | weight 733 | 20 734 | 735 | ^(.*/)?\.DS_Store$ 736 | 737 | omit 738 | 739 | weight 740 | 2000 741 | 742 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ 743 | 744 | nested 745 | 746 | weight 747 | 10 748 | 749 | ^.* 750 | 751 | ^.*\.lproj/ 752 | 753 | optional 754 | 755 | weight 756 | 1000 757 | 758 | ^.*\.lproj/locversion.plist$ 759 | 760 | omit 761 | 762 | weight 763 | 1100 764 | 765 | ^Base\.lproj/ 766 | 767 | weight 768 | 1010 769 | 770 | ^Info\.plist$ 771 | 772 | omit 773 | 774 | weight 775 | 20 776 | 777 | ^PkgInfo$ 778 | 779 | omit 780 | 781 | weight 782 | 20 783 | 784 | ^[^/]+$ 785 | 786 | nested 787 | 788 | weight 789 | 10 790 | 791 | ^embedded\.provisionprofile$ 792 | 793 | weight 794 | 20 795 | 796 | ^version\.plist$ 797 | 798 | weight 799 | 20 800 | 801 | 802 | 803 | 804 | -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/en.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/XCTest.framework/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildAliasOf 6 | XCTest 7 | BuildVersion 8 | 1 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 14460.20 13 | ProjectName 14 | XCTest_Sim 15 | SourceVersion 16 | 14460020000000000 17 | 18 | 19 | -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/libXCTestBundleInject.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Frameworks/libXCTestBundleInject.dylib -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Info.plist -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Ionicons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-1100-Portrait-2436h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-1100-Portrait-2436h@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-700-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-700-568h@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-800-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-800-667h@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-800-Portrait-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage-800-Portrait-736h@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/LaunchImage.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/MaterialIcons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Octicons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.org.reactjs.native.example.wdioDemoAppTests 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 0.2.1 17 | CFBundleVersion 18 | 2 19 | 20 | 21 | -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest.dSYM/Contents/Resources/DWARF/wdioDemoAppTests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest.dSYM/Contents/Resources/DWARF/wdioDemoAppTests -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest/Info.plist -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Info.plist 8 | 9 | +hxJp3KTJhYFaxpSb0nRb6xol60= 10 | 11 | 12 | files2 13 | 14 | rules 15 | 16 | ^.* 17 | 18 | ^.*\.lproj/ 19 | 20 | optional 21 | 22 | weight 23 | 1000 24 | 25 | ^.*\.lproj/locversion.plist$ 26 | 27 | omit 28 | 29 | weight 30 | 1100 31 | 32 | ^Base\.lproj/ 33 | 34 | weight 35 | 1010 36 | 37 | ^version.plist$ 38 | 39 | 40 | rules2 41 | 42 | .*\.dSYM($|/) 43 | 44 | weight 45 | 11 46 | 47 | ^(.*/)?\.DS_Store$ 48 | 49 | omit 50 | 51 | weight 52 | 2000 53 | 54 | ^.* 55 | 56 | ^.*\.lproj/ 57 | 58 | optional 59 | 60 | weight 61 | 1000 62 | 63 | ^.*\.lproj/locversion.plist$ 64 | 65 | omit 66 | 67 | weight 68 | 1100 69 | 70 | ^Base\.lproj/ 71 | 72 | weight 73 | 1010 74 | 75 | ^Info\.plist$ 76 | 77 | omit 78 | 79 | weight 80 | 20 81 | 82 | ^PkgInfo$ 83 | 84 | omit 85 | 86 | weight 87 | 20 88 | 89 | ^embedded\.provisionprofile$ 90 | 91 | weight 92 | 20 93 | 94 | ^version\.plist$ 95 | 96 | weight 97 | 20 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest/wdioDemoAppTests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/PlugIns/wdioDemoAppTests.xctest/wdioDemoAppTests -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/Zocial.ttf -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | AppIcon20x20@2x.png 8 | 9 | cQA2D7311Y5BS+yRjqXaoMTLGsE= 10 | 11 | AppIcon20x20@3x.png 12 | 13 | x0oQEZHvnDK31K5WuHtIqORHB8M= 14 | 15 | AppIcon29x29@2x.png 16 | 17 | 7I1dHNemalKrg/gMTiFwgwcXdsM= 18 | 19 | AppIcon29x29@3x.png 20 | 21 | w5oSziIFTapWAd2hVLfLHW7AjS4= 22 | 23 | AppIcon40x40@2x.png 24 | 25 | yd8J3m2ix7thyDKAybUzHVeebkY= 26 | 27 | AppIcon40x40@3x.png 28 | 29 | A8iXBEunjDTpgCglx+B0lu/ZW0Q= 30 | 31 | AppIcon60x60@2x.png 32 | 33 | A8iXBEunjDTpgCglx+B0lu/ZW0Q= 34 | 35 | AppIcon60x60@3x.png 36 | 37 | +uzoK4t4OJvCZfnnvi1OSqbGbDQ= 38 | 39 | Assets.car 40 | 41 | fFo5EUmn9fwj5tzxyT6C8FZq3vQ= 42 | 43 | Entypo.ttf 44 | 45 | R4cKZ91Qhxdl95nKqX2ochnuR8U= 46 | 47 | EvilIcons.ttf 48 | 49 | kdN36jz0dJCyVsLtCBcEp9q9rgw= 50 | 51 | Feather.ttf 52 | 53 | N8tVG0ETiQxSP0aeapsrKcTEm+Q= 54 | 55 | FontAwesome.ttf 56 | 57 | E7HqtlqYPHpzvHmXxHnWaUP3xss= 58 | 59 | FontAwesome5_Brands.ttf 60 | 61 | GeMCdg454lpfjZDWzQFk72zXT4w= 62 | 63 | FontAwesome5_Regular.ttf 64 | 65 | wUAIWDOjir7Gt9+Z1Mysk+smYDE= 66 | 67 | FontAwesome5_Solid.ttf 68 | 69 | xEWGSpZGlI4Nf/RJMK1zLuYUJ9g= 70 | 71 | Foundation.ttf 72 | 73 | SyvObHkkk6SlcWtv7C2+/olJLD8= 74 | 75 | Info.plist 76 | 77 | 9+Cdw1moi4MQsz29li0fMthH0VI= 78 | 79 | Ionicons.ttf 80 | 81 | mRu3+slwnNWNo3kBdw79RwPFQu0= 82 | 83 | LaunchImage-1100-Portrait-2436h@3x.png 84 | 85 | WVMhrESCCLI1t9yIOtrcuL+3Xxw= 86 | 87 | LaunchImage-700-568h@2x.png 88 | 89 | EWkGx/uPO2x11IQOfOPBNRFujc8= 90 | 91 | LaunchImage-800-667h@2x.png 92 | 93 | GohLdllr7BPHrWsF1KypmMzdKUw= 94 | 95 | LaunchImage-800-Portrait-736h@3x.png 96 | 97 | wIAJDjWk3HIwS+XL2l8819swQPE= 98 | 99 | LaunchImage.png 100 | 101 | 8w6cSczMaWkzN7+6DFpjZ1WZTWQ= 102 | 103 | MaterialCommunityIcons.ttf 104 | 105 | S1x3dOYog1mECtkRU/Ko2+92DD8= 106 | 107 | MaterialIcons.ttf 108 | 109 | /AXeMSNOAJD33cKM4bI69AJssdo= 110 | 111 | Octicons.ttf 112 | 113 | o/QP7s8JqAqYbxLVfGRtK0Wa+so= 114 | 115 | PkgInfo 116 | 117 | n57qDP4tZfLD1rCS43W0B4LQjzE= 118 | 119 | SimpleLineIcons.ttf 120 | 121 | n/uBpaEREuKS8swyPphIa61ZdZk= 122 | 123 | Zocial.ttf 124 | 125 | C9pZx7zT05J94EfgkYdaRCi/0as= 126 | 127 | assets/js/assets/webdriverio.png 128 | 129 | bzB5QCc/0qI/v7xgSfSg+bZBY6E= 130 | 131 | assets/node_modules/@tele2/react-native-select-input/src/icons/arrowDown.png 132 | 133 | EYQ62FQkMWvWIjm4HdYHdmoVNSU= 134 | 135 | assets/node_modules/@tele2/react-native-select-input/src/icons/arrowUp.png 136 | 137 | 10I7Y4F+kHEkxHvKSNQwjAlHeTM= 138 | 139 | assets/node_modules/react-native-elements/src/rating/images/bell.png 140 | 141 | mRk2D6wOdyusOvkEInbyL3K/E6k= 142 | 143 | assets/node_modules/react-native-elements/src/rating/images/heart.png 144 | 145 | rhZVvqRdTKoU0IrsdqQezFd0zb8= 146 | 147 | assets/node_modules/react-native-elements/src/rating/images/rocket.png 148 | 149 | mqOYKD+48iI8i2r6/LHKVlm0RGw= 150 | 151 | assets/node_modules/react-native-elements/src/rating/images/star.png 152 | 153 | XPFaCu1j/HeeE7zoK38ulP635qc= 154 | 155 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon-mask.png 156 | 157 | twCElRF9b860vkYvLPGRVtwtBcA= 158 | 159 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon.png 160 | 161 | keLOi1inJdXs0IRSKnXqyhW57Aw= 162 | 163 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@2x.png 164 | 165 | rSvG8m4uPMSItIcsIF+N2tDJD8U= 166 | 167 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@3x.png 168 | 169 | 8kFG8Vv7Hfrw4yVcFrhUhbHieBA= 170 | 171 | main.jsbundle 172 | 173 | ncuRxpKp81bWfMSflTw2td5B/e4= 174 | 175 | 176 | files2 177 | 178 | AppIcon20x20@2x.png 179 | 180 | hash 181 | 182 | cQA2D7311Y5BS+yRjqXaoMTLGsE= 183 | 184 | hash2 185 | 186 | /lvx5ZsVaMR7aAuIrA3pMnJq8Y9rU1q6+v3Dry9OaPk= 187 | 188 | 189 | AppIcon20x20@3x.png 190 | 191 | hash 192 | 193 | x0oQEZHvnDK31K5WuHtIqORHB8M= 194 | 195 | hash2 196 | 197 | UBHAjlJI2yNrwDEsZ3qqd584S15qDyEmH7O2l26oJAQ= 198 | 199 | 200 | AppIcon29x29@2x.png 201 | 202 | hash 203 | 204 | 7I1dHNemalKrg/gMTiFwgwcXdsM= 205 | 206 | hash2 207 | 208 | R0yvn717jCZEwSxk6Kagq1ASFSSlqG7SH3/JYENubOA= 209 | 210 | 211 | AppIcon29x29@3x.png 212 | 213 | hash 214 | 215 | w5oSziIFTapWAd2hVLfLHW7AjS4= 216 | 217 | hash2 218 | 219 | fJs46g2Tw89C8LZwLjbjrhzYyddUS0eT3bKF5YT2Axc= 220 | 221 | 222 | AppIcon40x40@2x.png 223 | 224 | hash 225 | 226 | yd8J3m2ix7thyDKAybUzHVeebkY= 227 | 228 | hash2 229 | 230 | Ek4f8vkBdaHborzTv9ukRYOkImXK6ZsJXTUYkcftJF8= 231 | 232 | 233 | AppIcon40x40@3x.png 234 | 235 | hash 236 | 237 | A8iXBEunjDTpgCglx+B0lu/ZW0Q= 238 | 239 | hash2 240 | 241 | VyrYS6kA+FxrzEEx6tukwEcQvqGU8LtK9opqKcqfvr8= 242 | 243 | 244 | AppIcon60x60@2x.png 245 | 246 | hash 247 | 248 | A8iXBEunjDTpgCglx+B0lu/ZW0Q= 249 | 250 | hash2 251 | 252 | VyrYS6kA+FxrzEEx6tukwEcQvqGU8LtK9opqKcqfvr8= 253 | 254 | 255 | AppIcon60x60@3x.png 256 | 257 | hash 258 | 259 | +uzoK4t4OJvCZfnnvi1OSqbGbDQ= 260 | 261 | hash2 262 | 263 | ngUJoIEyMqZLYRyuaS4AM6z2r+OqYpOGCfAHqGdk1m8= 264 | 265 | 266 | Assets.car 267 | 268 | hash 269 | 270 | fFo5EUmn9fwj5tzxyT6C8FZq3vQ= 271 | 272 | hash2 273 | 274 | ksZVqEQTf3hHcEBWd28GAeOkQdrrFfm1pfi2NYMGDGY= 275 | 276 | 277 | Entypo.ttf 278 | 279 | hash 280 | 281 | R4cKZ91Qhxdl95nKqX2ochnuR8U= 282 | 283 | hash2 284 | 285 | 3QhJoVkfiNp5N7I/kiQYpc7FTgdeCePMyo/rYgFvqoI= 286 | 287 | 288 | EvilIcons.ttf 289 | 290 | hash 291 | 292 | kdN36jz0dJCyVsLtCBcEp9q9rgw= 293 | 294 | hash2 295 | 296 | pcrrTTlcXjLx1aMKyzgq68Zk8brf0UkxmQfyIV5OPiY= 297 | 298 | 299 | Feather.ttf 300 | 301 | hash 302 | 303 | N8tVG0ETiQxSP0aeapsrKcTEm+Q= 304 | 305 | hash2 306 | 307 | vJZj1K7YcJfMyjc62U/QjeJKxKNRAOPfO30oFCyQCUo= 308 | 309 | 310 | FontAwesome.ttf 311 | 312 | hash 313 | 314 | E7HqtlqYPHpzvHmXxHnWaUP3xss= 315 | 316 | hash2 317 | 318 | qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg= 319 | 320 | 321 | FontAwesome5_Brands.ttf 322 | 323 | hash 324 | 325 | GeMCdg454lpfjZDWzQFk72zXT4w= 326 | 327 | hash2 328 | 329 | NlFjtwbIzvX8bGmgoN38QLXHJtWpVfwqLOxQ3qzXeSg= 330 | 331 | 332 | FontAwesome5_Regular.ttf 333 | 334 | hash 335 | 336 | wUAIWDOjir7Gt9+Z1Mysk+smYDE= 337 | 338 | hash2 339 | 340 | rlr07d3JsGDC71CcsJ6+GkaD5oljOBFDRoDfMZ/qUQc= 341 | 342 | 343 | FontAwesome5_Solid.ttf 344 | 345 | hash 346 | 347 | xEWGSpZGlI4Nf/RJMK1zLuYUJ9g= 348 | 349 | hash2 350 | 351 | UvbXegBXJ/S5IFERnnbplWt+5xvywiOFgZr7GobSiqQ= 352 | 353 | 354 | Foundation.ttf 355 | 356 | hash 357 | 358 | SyvObHkkk6SlcWtv7C2+/olJLD8= 359 | 360 | hash2 361 | 362 | fh3QPdTOkLZYBSVUzXRZ3xZxZxc4mlUvpMbVal+JM+Y= 363 | 364 | 365 | Ionicons.ttf 366 | 367 | hash 368 | 369 | mRu3+slwnNWNo3kBdw79RwPFQu0= 370 | 371 | hash2 372 | 373 | INFzvLYFHQlzvgymqi+08npbKQ2AEGyyxWfI/cdyxxE= 374 | 375 | 376 | LaunchImage-1100-Portrait-2436h@3x.png 377 | 378 | hash 379 | 380 | WVMhrESCCLI1t9yIOtrcuL+3Xxw= 381 | 382 | hash2 383 | 384 | rzLjosQCKBURKlt1GGImS6VTomcyAVZVmbDY7L4MEJ8= 385 | 386 | 387 | LaunchImage-700-568h@2x.png 388 | 389 | hash 390 | 391 | EWkGx/uPO2x11IQOfOPBNRFujc8= 392 | 393 | hash2 394 | 395 | /GoELurqPQ8mDNB6QgjM9Lit+475eFt0aJJXw9C+6Tw= 396 | 397 | 398 | LaunchImage-800-667h@2x.png 399 | 400 | hash 401 | 402 | GohLdllr7BPHrWsF1KypmMzdKUw= 403 | 404 | hash2 405 | 406 | ezgQ+luY/nAcGF/84iMXFkuberXfpu2u1E1sZrj/XcU= 407 | 408 | 409 | LaunchImage-800-Portrait-736h@3x.png 410 | 411 | hash 412 | 413 | wIAJDjWk3HIwS+XL2l8819swQPE= 414 | 415 | hash2 416 | 417 | lQqv8QAGSpt0kprQhNJlfZH/9QDlIEmDRsllBrTXv/o= 418 | 419 | 420 | LaunchImage.png 421 | 422 | hash 423 | 424 | 8w6cSczMaWkzN7+6DFpjZ1WZTWQ= 425 | 426 | hash2 427 | 428 | Sf7YgE74cPk62E5A73W+4ObteNPPuYGLGu4EqLE2+/s= 429 | 430 | 431 | MaterialCommunityIcons.ttf 432 | 433 | hash 434 | 435 | S1x3dOYog1mECtkRU/Ko2+92DD8= 436 | 437 | hash2 438 | 439 | 9TfAzAnJLqAXEVh/QzQ9l4FAl3HGtS4KVqVdOpLoZvE= 440 | 441 | 442 | MaterialIcons.ttf 443 | 444 | hash 445 | 446 | /AXeMSNOAJD33cKM4bI69AJssdo= 447 | 448 | hash2 449 | 450 | t/Sjq1YgSPKN0fppFgG8QzY6YdD4dtFtgxbFLk8y1pY= 451 | 452 | 453 | Octicons.ttf 454 | 455 | hash 456 | 457 | o/QP7s8JqAqYbxLVfGRtK0Wa+so= 458 | 459 | hash2 460 | 461 | 8KI41G1nSeYBwS8g+PwDIB8Ze5/jR75MLJRP/FxLYDU= 462 | 463 | 464 | SimpleLineIcons.ttf 465 | 466 | hash 467 | 468 | n/uBpaEREuKS8swyPphIa61ZdZk= 469 | 470 | hash2 471 | 472 | P1Ad2wXHCCm7tRz+nKn/9X854GBFfCV7PM8l33Z/CHA= 473 | 474 | 475 | Zocial.ttf 476 | 477 | hash 478 | 479 | C9pZx7zT05J94EfgkYdaRCi/0as= 480 | 481 | hash2 482 | 483 | 17EKHr4YMOWi8I9JA7moDiwZEsDdL3O5P88r+DIhZgI= 484 | 485 | 486 | assets/js/assets/webdriverio.png 487 | 488 | hash 489 | 490 | bzB5QCc/0qI/v7xgSfSg+bZBY6E= 491 | 492 | hash2 493 | 494 | A7c7hbBu6SKCh7qV4duxg2WBs6CgwH2pcDikcJQRAu8= 495 | 496 | 497 | assets/node_modules/@tele2/react-native-select-input/src/icons/arrowDown.png 498 | 499 | hash 500 | 501 | EYQ62FQkMWvWIjm4HdYHdmoVNSU= 502 | 503 | hash2 504 | 505 | uwri/agrTNpF25UBmIPQzOn/ceX0rSzsHUvVb432Cjg= 506 | 507 | 508 | assets/node_modules/@tele2/react-native-select-input/src/icons/arrowUp.png 509 | 510 | hash 511 | 512 | 10I7Y4F+kHEkxHvKSNQwjAlHeTM= 513 | 514 | hash2 515 | 516 | tPZsy9GmTJOwa50Z1OnS4f9XalgNHAwMRoif4ELuexM= 517 | 518 | 519 | assets/node_modules/react-native-elements/src/rating/images/bell.png 520 | 521 | hash 522 | 523 | mRk2D6wOdyusOvkEInbyL3K/E6k= 524 | 525 | hash2 526 | 527 | MVdJITYj1tDwle06K+p8IFp8haF5kBT3gxuzDfc9AYg= 528 | 529 | 530 | assets/node_modules/react-native-elements/src/rating/images/heart.png 531 | 532 | hash 533 | 534 | rhZVvqRdTKoU0IrsdqQezFd0zb8= 535 | 536 | hash2 537 | 538 | v2rfzDt3/cDiJKjdhP8ejuEJZF2q6bsySGtwzOb8AxY= 539 | 540 | 541 | assets/node_modules/react-native-elements/src/rating/images/rocket.png 542 | 543 | hash 544 | 545 | mqOYKD+48iI8i2r6/LHKVlm0RGw= 546 | 547 | hash2 548 | 549 | ICOGuBMxnevPKkpTB/Aa5C5FHGGdwlrVPfiIpgRfeqk= 550 | 551 | 552 | assets/node_modules/react-native-elements/src/rating/images/star.png 553 | 554 | hash 555 | 556 | XPFaCu1j/HeeE7zoK38ulP635qc= 557 | 558 | hash2 559 | 560 | QomdN3rBYNJR6hzK8VcKZmuxkf8KClRArNMi+Fxau5U= 561 | 562 | 563 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon-mask.png 564 | 565 | hash 566 | 567 | twCElRF9b860vkYvLPGRVtwtBcA= 568 | 569 | hash2 570 | 571 | qPaOshDnK+iP+MqrK2VwfgeqJN7zzzEIZ75i1AijBds= 572 | 573 | 574 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon.png 575 | 576 | hash 577 | 578 | keLOi1inJdXs0IRSKnXqyhW57Aw= 579 | 580 | hash2 581 | 582 | LN/rjlzN55dvcBL7jM5zryIpAp7iHU8VCf7RFIccbNg= 583 | 584 | 585 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@2x.png 586 | 587 | hash 588 | 589 | rSvG8m4uPMSItIcsIF+N2tDJD8U= 590 | 591 | hash2 592 | 593 | K3RDqaWOksoRpXW9wRWYYVpX3eMFzYznDWAmBrMCzZg= 594 | 595 | 596 | assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@3x.png 597 | 598 | hash 599 | 600 | 8kFG8Vv7Hfrw4yVcFrhUhbHieBA= 601 | 602 | hash2 603 | 604 | Pd0Hc+0n4j0leJ8wFzGzrEVa2L5aonoKG4OPicbSciU= 605 | 606 | 607 | main.jsbundle 608 | 609 | hash 610 | 611 | ncuRxpKp81bWfMSflTw2td5B/e4= 612 | 613 | hash2 614 | 615 | MXWV1yyyW6sNGt+EiY5hESTD62Vp3tJ8CCR4eVEQ91s= 616 | 617 | 618 | 619 | rules 620 | 621 | ^.* 622 | 623 | ^.*\.lproj/ 624 | 625 | optional 626 | 627 | weight 628 | 1000 629 | 630 | ^.*\.lproj/locversion.plist$ 631 | 632 | omit 633 | 634 | weight 635 | 1100 636 | 637 | ^Base\.lproj/ 638 | 639 | weight 640 | 1010 641 | 642 | ^version.plist$ 643 | 644 | 645 | rules2 646 | 647 | .*\.dSYM($|/) 648 | 649 | weight 650 | 11 651 | 652 | ^(.*/)?\.DS_Store$ 653 | 654 | omit 655 | 656 | weight 657 | 2000 658 | 659 | ^.* 660 | 661 | ^.*\.lproj/ 662 | 663 | optional 664 | 665 | weight 666 | 1000 667 | 668 | ^.*\.lproj/locversion.plist$ 669 | 670 | omit 671 | 672 | weight 673 | 1100 674 | 675 | ^Base\.lproj/ 676 | 677 | weight 678 | 1010 679 | 680 | ^Info\.plist$ 681 | 682 | omit 683 | 684 | weight 685 | 20 686 | 687 | ^PkgInfo$ 688 | 689 | omit 690 | 691 | weight 692 | 20 693 | 694 | ^embedded\.provisionprofile$ 695 | 696 | weight 697 | 20 698 | 699 | ^version\.plist$ 700 | 701 | weight 702 | 20 703 | 704 | 705 | 706 | 707 | -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/js/assets/webdriverio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/js/assets/webdriverio.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/@tele2/react-native-select-input/src/icons/arrowDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/@tele2/react-native-select-input/src/icons/arrowDown.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/@tele2/react-native-select-input/src/icons/arrowUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/@tele2/react-native-select-input/src/icons/arrowUp.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/bell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/bell.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/heart.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/rocket.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-native-elements/src/rating/images/star.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon-mask.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@2x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/assets/node_modules/react-navigation-stack/dist/views/assets/back-icon@3x.png -------------------------------------------------------------------------------- /data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/wdioDemoApp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app/wdioDemoApp -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | json_report = report/json/report.json 3 | markers = 4 | login: mark as login tests 5 | home: mark as home tests 6 | addopts = -vs -rf --html-report=./report -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Python Appium Framework 2 | > Complete Python Appium framework in 360 degree 3 | 4 | ## Features 5 | - [x] Locator strategy 6 | - [x] Hooks (unittest) 7 | - [x] Helper methods 8 | - [x] Database connectivity + SSH Tunneling 9 | - [x] Screenshot on failure 10 | - [x] Docker support for Android 11 | - [x] Handle local storage 12 | - [x] Bash Runner 13 | - [x] Slack notify 14 | - [x] Define environment variable 15 | - [x] HTML report 16 | - [x] JSON report 17 | - [x] Allure report 18 | - [x] CLI arguments as a fixture (Pytest) 19 | - [x] In-house data storage 20 | - [x] Logger 21 | - [x] Runner (Pytest) 22 | - [x] Runner percentage with style (Pytest) 23 | - [x] Parallel Tests (Pytest) x2 24 | - [x] Re-run failures (Pytest) 25 | - [x] Test script validation 26 | 27 | ## Installation 28 | Install python libraries 29 | 30 | pip3 install -r requirements.txt 31 | 32 | ## Test Runner 33 | 34 | | Action | Command | 35 | | -------------- | --------- | 36 | | Bash runner | `bash runner/android/smoke_run.sh` | 37 | | Default | `python3 -m pytest src/spec/* --app=android` | 38 | | Rerun failures | `python3 -m pytest src/spec/home_test.py --app=android --reruns 1` | 39 | | Parallel Test | `python3 -m pytest src/spec/home_test.py --app=android -v -n2` | 40 | 41 | #### Docker Run 42 | > Android test - x1 run 43 | ```shell script 44 | docker run --privileged -d -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 \ 45 | -v $(pwd)/data/apps/Android-NativeDemoApp-0.2.1.apk:/root/tmp/Android-NativeDemoApp-0.2.1.apk \ 46 | -e DEVICE="Samsung Galaxy S9" -e APPIUM=true --name android-container \ 47 | budtmo/docker-android-x86-11.0 48 | ``` 49 | **noVnc interface:** http://localhost:6080 50 | 51 | ## Test Report 52 | | Type | Command | 53 | | -------------- | --------- | 54 | | HTML Report | `python3 -m pytest src/spec/android/*.py --html-report=report/report.html --app=android` | 55 | | JSON Report | `python3 -m pytest src/spec/android/*.py --json=report/json/report.json --app=android` | 56 | | Allure Report | `python3 -m pytest src/spec/android/* --alluredir=report --app=android` | 57 | 58 | - Download allure commandline 59 | https://github.com/allure-framework/allure2/releases 60 | 61 | > generate allure report 62 | ``` 63 | allure serve report/ 64 | ``` 65 | 66 | ## Wrapper Methods 67 | | Methods | Usage | 68 | | -------------- | --------- | 69 | | element | `App.element(self, locator)` | 70 | | elements | `App.elements(self, locactor)` | 71 | | is_displayed | `App.is_displayed(self, locator)` | 72 | | is_displayed > elements | `App.is_displayed(self, locator, index=0)` | 73 | | is_exist | `App.is_exist(self, locator)` | 74 | | is_exist > elements | `App.is_exist(self, locator, index=0)` | 75 | | tap | `App.tap(self, locator)` | 76 | | tap > elements | `App.tap(self, locator, index=0)` | 77 | | double_tap | `App.double_tap(self, locator)` | 78 | | double_tap > elements | `App.double_tap(self, locator, index=0)` | 79 | | click | `App.click(self, locator)` | 80 | | click > elements | `App.click(self, locator, index=0)` | 81 | | swipe | `App.swipe(self, start=locator, dest=locator)` | 82 | | swipe > elements | `App.swipe(self, start=(locator, 2), dest=(locator, 1))` | 83 | | send_keys | `App.send_keys(self, locator, 'text')` | 84 | | send_keys > elements | `App.send_keys(self, locator, 'text', index=0)` | 85 | | get_screen_size | `App.get_screen_size(self)` | 86 | | back | `App.back(self)` | 87 | | close | `App.close(self)` | 88 | | reset | `App.reset(self)` | 89 | | launch_app | `App.send_keys(self, locator, 'text'` | 90 | | tap_by_coordinates | `App.tap_by_coordinates(self, x=338, y=204)` | 91 | | assert_text | `App.assert_text(self, 'actual', 'expected')` | 92 | | assert_text > elements | `App.assert_text(self, 'actual', 'expected', index=0)` | 93 | | assert_size | `App.assert_size(self, locator, 'more than 1')` | 94 | | | `App.assert_size(self, locator, 'greater than 1')` | 95 | | | `App.assert_size(self, locator, 'above 1')` | 96 | | | `App.assert_size(self, locator, '> 1')` | 97 | | | `App.assert_size(self, locator, 'less than 1')` | 98 | | | `App.assert_size(self, locator, 'below 1')` | 99 | | | `App.assert_size(self, locator, '< 1')` | 100 | | | `App.assert_size(self, locator, 'equal to 1')` | 101 | | | `App.assert_size(self, locator, '== 1')` | 102 | | assert_boolean | `App.assert_boolean(True, True)` | 103 | | swipe_until | `App.swipe_until(self, locator, start_x=144, start_y=434, count=20)` | 104 | 105 | ![](https://i.imgur.com/5vjklOb.png) -------------------------------------------------------------------------------- /report/6d01bfcc-98f1-4278-a4c5-6fc2b55772bb-result.json: -------------------------------------------------------------------------------- 1 | {"name": "test_home", "status": "passed", "start": 1568110276163, "stop": 1568110280537, "uuid": "3e181cfe-ab4e-4ea2-9b31-1232faae8524", "historyId": "69ffa3a2de0c03e2b51e0e5d26784d58", "testCaseId": "2b0e6fdfbc23c9f24893fcd242aaa5a7", "fullName": "src.spec.home_test.HomeTest#test_home", "labels": [{"name": "parentSuite", "value": "src.spec"}, {"name": "suite", "value": "home_test"}, {"name": "subSuite", "value": "HomeTest"}, {"name": "host", "value": "Prashanth-Rajjapa-MacBook-Pro.local"}, {"name": "thread", "value": "49965-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "src.spec.home_test"}]} -------------------------------------------------------------------------------- /report/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica, Arial, sans-serif; 3 | font-size: 12px; 4 | min-width: 1200px; 5 | color: #999; 6 | } 7 | 8 | h1 { 9 | font-size: 24px; 10 | color: black; 11 | } 12 | 13 | h2 { 14 | font-size: 16px; 15 | color: black; 16 | } 17 | 18 | p { 19 | color: black; 20 | } 21 | 22 | a { 23 | color: #999; 24 | } 25 | 26 | table { 27 | border-collapse: collapse; 28 | } 29 | 30 | /****************************** 31 | * SUMMARY INFORMATION 32 | ******************************/ 33 | 34 | #environment td { 35 | padding: 5px; 36 | border: 1px solid #E6E6E6; 37 | } 38 | 39 | #environment tr:nth-child(odd) { 40 | background-color: #f6f6f6; 41 | } 42 | 43 | /****************************** 44 | * TEST RESULT COLORS 45 | ******************************/ 46 | span.passed, .passed .col-result { 47 | color: green; 48 | } 49 | span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result { 50 | color: orange; 51 | } 52 | span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result { 53 | color: red; 54 | } 55 | 56 | 57 | /****************************** 58 | * RESULTS TABLE 59 | * 60 | * 1. Table Layout 61 | * 2. Extra 62 | * 3. Sorting items 63 | * 64 | ******************************/ 65 | 66 | /*------------------ 67 | * 1. Table Layout 68 | *------------------*/ 69 | 70 | #results-table { 71 | border: 1px solid #e6e6e6; 72 | color: #999; 73 | font-size: 12px; 74 | width: 100% 75 | } 76 | 77 | #results-table th, #results-table td { 78 | padding: 5px; 79 | border: 1px solid #E6E6E6; 80 | text-align: left 81 | } 82 | #results-table th { 83 | font-weight: bold 84 | } 85 | 86 | /*------------------ 87 | * 2. Extra 88 | *------------------*/ 89 | 90 | .log:only-child { 91 | height: inherit 92 | } 93 | .log { 94 | background-color: #e6e6e6; 95 | border: 1px solid #e6e6e6; 96 | color: black; 97 | display: block; 98 | font-family: "Courier New", Courier, monospace; 99 | height: 230px; 100 | overflow-y: scroll; 101 | padding: 5px; 102 | white-space: pre-wrap 103 | } 104 | div.image { 105 | border: 1px solid #e6e6e6; 106 | float: right; 107 | height: 240px; 108 | margin-left: 5px; 109 | overflow: hidden; 110 | width: 320px 111 | } 112 | div.image img { 113 | width: 320px 114 | } 115 | .collapsed { 116 | display: none; 117 | } 118 | .expander::after { 119 | content: " (show details)"; 120 | color: #BBB; 121 | font-style: italic; 122 | cursor: pointer; 123 | } 124 | .collapser::after { 125 | content: " (hide details)"; 126 | color: #BBB; 127 | font-style: italic; 128 | cursor: pointer; 129 | } 130 | 131 | /*------------------ 132 | * 3. Sorting items 133 | *------------------*/ 134 | .sortable { 135 | cursor: pointer; 136 | } 137 | 138 | .sort-icon { 139 | font-size: 0px; 140 | float: left; 141 | margin-right: 5px; 142 | margin-top: 5px; 143 | /*triangle*/ 144 | width: 0; 145 | height: 0; 146 | border-left: 8px solid transparent; 147 | border-right: 8px solid transparent; 148 | } 149 | 150 | .inactive .sort-icon { 151 | /*finish triangle*/ 152 | border-top: 8px solid #E6E6E6; 153 | } 154 | 155 | .asc.active .sort-icon { 156 | /*finish triangle*/ 157 | border-bottom: 8px solid #999; 158 | } 159 | 160 | .desc.active .sort-icon { 161 | /*finish triangle*/ 162 | border-top: 8px solid #999; 163 | } 164 | -------------------------------------------------------------------------------- /report/c5704f6f-6816-476a-83df-b5b8b491dee2-container.json: -------------------------------------------------------------------------------- 1 | {"uuid": "e2a6491c-034f-4e80-9361-a478aba9f06d", "children": ["3e181cfe-ab4e-4ea2-9b31-1232faae8524"], "befores": [{"name": "_UnitTestCase__pytest_class_setup", "status": "passed", "start": 1568110276162, "stop": 1568110276162}], "afters": [{"name": "_UnitTestCase__pytest_class_setup::0", "status": "passed", "start": 1568110280538, "stop": 1568110280538}], "start": 1568110276162, "stop": 1568110280538} -------------------------------------------------------------------------------- /report/report.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Report 6 | 7 | 8 | 243 |

report.html

244 |

Report generated on 10-Sep-2019 at 15:47:45 by pytest-html v2.0.0

245 |

Environment

246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 |
Packages{'pytest': '5.1.1', 'py': '1.8.0', 'pluggy': '0.12.0'}
PlatformDarwin-18.6.0-x86_64-i386-64bit
Plugins{'html': '2.0.0', 'allure-pytest': '2.8.4', 'metadata': '1.8.0'}
Python3.7.3
259 |

Summary

260 |

1 tests ran in 5.77 seconds.

261 | 1 passed, 0 skipped, 0 failed, 0 errors, 0 expected failures, 0 unexpected passes 262 |

Results

263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 |
ResultTestDurationLinks
Passedsrc/spec/home_test.py::HomeTest::test_home5.62
280 |
No log output captured.
-------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Appium-Python-Client~=1.0.2 2 | selenium~=3.141.0 3 | pytest~=6.1.1 4 | allure-pytest 5 | pytest-parallel 6 | pytest-xdist 7 | pytest-rerunfailures 8 | pytest-sugar 9 | pytest-json 10 | pymysql~=0.10.1 11 | sshtunnel~=0.1.5 12 | requests~=2.24.0 13 | invoke~=1.4.1 14 | python-dotenv 15 | pytest-html-reporter~=0.2.3 -------------------------------------------------------------------------------- /runner/android/smoke_run.sh: -------------------------------------------------------------------------------- 1 | invoke test --env='staging' --lang='en' --app='android' --device='emulator' 2 | invoke slack --env='staging' --lang='en' --slack='on' --app='android' -------------------------------------------------------------------------------- /runner/ios/smoke_run.sh: -------------------------------------------------------------------------------- 1 | invoke test --env='staging' --lang='en' --app='ios' --device='simulator' 2 | invoke slack --env='staging' --lang='en' --slack='on' --app='ios' -------------------------------------------------------------------------------- /runner/ios/smoke_run_bitrise.sh: -------------------------------------------------------------------------------- 1 | invoke test --env='staging' --lang='en' --app='ios' --device='bitrise' 2 | invoke slack --env='staging' --lang='en' --slack='off' --app='ios' -------------------------------------------------------------------------------- /screenshots/test_home_2019-09-10_13-29-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashanth-sams/python-appium-framework/7b75bd44366758192a385acbec9a64ec987d3afe/screenshots/test_home_2019-09-10_13-29-38.png -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os.path import join, dirname 3 | from dotenv import load_dotenv 4 | 5 | dotenv_path = join(dirname(__file__), '.env') 6 | load_dotenv(dotenv_path) 7 | 8 | SLACK_TOKEN = os.getenv('SLACK_TOKEN') 9 | UDID = os.getenv('UDID') -------------------------------------------------------------------------------- /src/helpers/app.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.support.wait import WebDriverWait 2 | from src.helpers.appiumdriver import Driver 3 | from appium.webdriver.common.touch_action import TouchAction 4 | from selenium.common.exceptions import NoSuchElementException 5 | from selenium.webdriver.support import expected_conditions as EC 6 | import time 7 | 8 | 9 | def keyword_check(kwargs): 10 | kc = {} 11 | if 'index' in kwargs: kc['index'] = 'elements' 12 | if 'index' not in kwargs: kc['index'] = 'element' 13 | return ''.join(kc.values()) 14 | 15 | 16 | class App(Driver): 17 | 18 | def __init__(self, driver): 19 | super().__init__(driver) 20 | 21 | def element(self, locator, n=3): 22 | """ 23 | locate an element by polling if element not found 24 | maximum poll #2 with approx. ~10 secs 25 | """ 26 | wait = WebDriverWait(self.driver, 20) 27 | 28 | x = iter(CustomCall()) 29 | while n > 1: 30 | try: 31 | wait.until(EC.visibility_of_element_located(locator)) 32 | return self.driver.find_element(*locator) 33 | except Exception as e: 34 | self.logger.error(f"element failed attempt {next(x)} - {locator}") 35 | n -= 1 36 | if n == 1: raise NoSuchElementException("Could not locate element with value: %s" % str(locator)) 37 | 38 | def elements(self, locator, n=3): 39 | """ 40 | locate element list by polling if the element list is not found 41 | maximum poll #2 with approx. ~10 secs 42 | """ 43 | wait = WebDriverWait(self.driver, 20) 44 | 45 | x = iter(CustomCall()) 46 | while n > 1: 47 | try: 48 | wait.until(EC.visibility_of_any_elements_located(locator)) 49 | return self.driver.find_elements(*locator) 50 | except Exception as e: 51 | self.logger.error(f"element list failed attempt {next(x)} - {locator}") 52 | n -= 1 53 | if n == 1: raise NoSuchElementException("Could not locate element list with value: %s" % str(locator)) 54 | 55 | def is_displayed(self, locator, expected=True, n=3, **kwargs): 56 | """ 57 | assert boolean value by polling if match is not found 58 | maximum poll #3 with approx. ~10 secs 59 | """ 60 | wait = WebDriverWait(self.driver, 20) 61 | 62 | x = iter(CustomCall()) 63 | while n > 1: 64 | try: 65 | if len(kwargs) == 0: 66 | wait.until(EC.visibility_of_element_located(locator)) 67 | assert self.driver.find_element(*locator).is_displayed() == expected 68 | else: 69 | assert self.driver.find_elements(*locator)[kwargs['index']].is_displayed() == expected 70 | break 71 | except Exception as e: 72 | self.logger.error(f'is_displayed failed attempt {next(x)}- {locator}') 73 | time.sleep(0.5) 74 | n -= 1 75 | if n == 1: assert False == expected 76 | 77 | def is_exist(self, locator, expected=True, n=3, **kwargs): 78 | """ 79 | returns boolean value by polling if match is not found or not 80 | maximum poll #3 with approx. ~10 secs 81 | """ 82 | while n > 1: 83 | try: 84 | if len(kwargs) == 0 and self.driver.find_element(*locator).is_displayed() == expected: 85 | return True 86 | elif self.driver.find_elements(*locator)[kwargs['index']].is_displayed() == expected: 87 | return True 88 | except Exception as e: 89 | n -= 1 90 | if n == 1: return False 91 | 92 | def tap(self, locator, **kwargs): 93 | """ 94 | custom wrapped single tap method 95 | -> wait until display 96 | -> element(s) 97 | """ 98 | App.is_displayed(self, locator, True) 99 | 100 | actions = TouchAction(self.driver) 101 | return { 102 | 'element': lambda x: actions.tap(App.element(self, locator)).perform(), 103 | 'elements': lambda x: actions.tap(App.elements(self, locator)[kwargs['index']]).perform() 104 | }[keyword_check(kwargs)]('x') 105 | 106 | def double_tap(self, locator, n=3, **kwargs): 107 | """ 108 | custom wrapped double tap method 109 | -> wait for element until display 110 | -> element(s) 111 | """ 112 | App.is_displayed(self, locator, True, n=n) 113 | 114 | actions = TouchAction(self.driver) 115 | return { 116 | 'element': lambda x: actions.tap(App.element(self, locator), count=2).perform(), 117 | 'elements': lambda x: actions.tap(App.elements(self, locator)[kwargs['index']], count=2).perform() 118 | }[keyword_check(kwargs)]('x') 119 | 120 | def click(self, locator, n=3, **kwargs): 121 | """ 122 | custom wrapped click method 123 | -> wait for element until display 124 | -> element(s) 125 | """ 126 | App.sleep(kwargs) 127 | App.is_displayed(self, locator, True, n=n) 128 | 129 | return { 130 | 'element': lambda x: App.element(self, locator).click(), 131 | 'elements': lambda x: App.elements(self, locator)[kwargs['index']].click() 132 | }[keyword_check(kwargs)]('x') 133 | 134 | def wait_until_disappear(self, locator, n=3, **kwargs): 135 | wait = WebDriverWait(self.driver, 25) 136 | wait.until(EC.invisibility_of_element_located(locator)) 137 | 138 | @staticmethod 139 | def sleep(kwargs): 140 | try: 141 | time.sleep(kwargs['sleep']) 142 | except KeyError: 143 | pass 144 | 145 | def send_keys(self, locator, text='', **kwargs): 146 | """ 147 | custom wrapped send_keys method 148 | -> wait for element until display 149 | -> element(s) 150 | """ 151 | App.is_displayed(self, locator, True) 152 | 153 | return { 154 | 'element': lambda text: App.element(self, locator).clear() and App.element(self, locator).send_keys(text), 155 | 'elements': lambda text: App.elements(self, locator)[kwargs['index']].clear() and App.elements(self, locator)[kwargs['index']].send_keys(text) 156 | }[keyword_check(kwargs)](text) 157 | 158 | def get_screen_size(self): 159 | return self.driver.get_window_size() 160 | 161 | def back(self): 162 | """ 163 | generally minimize app 164 | """ 165 | self.driver.back() 166 | 167 | def close(self): 168 | self.driver.close_app() 169 | 170 | def reset(self): 171 | self.driver.reset() 172 | 173 | def launch_app(self): 174 | self.driver.launch_app() 175 | 176 | def swipe(self, start, dest): 177 | """ 178 | custom wrapped swipe / scroll method 179 | -> wait for element until display - source and destination 180 | -> element(s) 181 | """ 182 | if type(start[1]) is not int: 183 | source_element = App.element(self, start) 184 | else: 185 | source_element = App.elements(self, start[0])[int(start[1])] 186 | 187 | if type(dest[1]) is not int: 188 | target_element = App.element(self, dest) 189 | else: 190 | target_element = App.elements(self, dest[0])[int(dest[1])] 191 | 192 | self.driver.scroll(source_element, target_element) 193 | 194 | def tap_by_coordinates(self, x, y): 195 | time.sleep(2) 196 | actions = TouchAction(self.driver) 197 | actions.tap(x=x, y=y).perform() 198 | 199 | # need refactor on condition 200 | def assert_text(self, locator, text, n=20, **kwargs): 201 | """ 202 | assert element's text by polling if match is not found 203 | maximum poll #20 with approx. ~10 secs 204 | """ 205 | App.is_displayed(self, locator, True) 206 | 207 | x = iter(CustomCall()) 208 | while n > 1: 209 | try: 210 | if len(kwargs) == 0: 211 | assert App.element(self, locator).text == text 212 | else: 213 | assert App.elements(self, locator)[kwargs['index']].text == text 214 | break 215 | except Exception as e: 216 | self.logger.error(f'assert_text failed attempt {next(x)}- {locator}') 217 | time.sleep(0.5) 218 | n -= 1 219 | if len(kwargs) == 0: 220 | if n == 1: assert App.element(self, locator).text == text 221 | else: 222 | if n == 1: assert App.elements(self, locator)[kwargs['index']].text == text 223 | 224 | def assert_size(self, locator, param): 225 | """ 226 | assert elements size by polling if match is found 227 | maximum poll #20 with approx. ~10 secs 228 | """ 229 | App.is_displayed(self, locator, True, index=0) 230 | 231 | case = param.rsplit(None, 1)[0] 232 | value = int(param.rsplit(None, 1)[1]) 233 | 234 | if case in ['more than', 'greater than', 'above', '>']: 235 | assert App.elements(self, locator).__len__() > value 236 | elif case in ['less than', 'below', '<']: 237 | assert App.elements(self, locator).__len__() < value 238 | elif case in ['equal to', '==']: 239 | assert App.elements(self, locator).__len__() == value 240 | 241 | def swipe_until(self, locator, start_x=100, start_y=200, end_x=0, end_y=0, duration=0, count=10): 242 | self.driver.implicitly_wait(0.5) # waits half a second 243 | for i in range(count): 244 | try: 245 | self.driver.find_element(*locator).is_displayed() 246 | break 247 | except Exception as e: 248 | self.driver.swipe(start_x, start_y, end_x, end_y, duration) 249 | 250 | self.driver.implicitly_wait(5) # waits 5 seconds 251 | 252 | def assert_equal(self, actual, expected, n=5): 253 | x = iter(CustomCall()) 254 | while n > 1: 255 | try: 256 | assert actual == expected 257 | break 258 | except Exception as e: 259 | self.logger.error(f"assert equal attempt {next(x)} - {actual} not matching {expected}") 260 | time.sleep(2) 261 | n -= 1 262 | if n == 1: assert actual == expected 263 | 264 | def assert_equal_ab(self, actual, expected_a, expected_b, n=5): 265 | x = iter(CustomCall()) 266 | while n > 1: 267 | try: 268 | try: 269 | assert actual == expected_a 270 | except Exception as e: 271 | assert actual == expected_b 272 | break 273 | except Exception as e: 274 | self.logger.error(f"assert equal attempt {next(x)} - {actual} not matching {expected_a} or {expected_b}") 275 | time.sleep(2) 276 | n -= 1 277 | if n == 1: assert actual == expected_a 278 | 279 | @staticmethod 280 | def assert_boolean(actual, expected=True): 281 | assert actual == expected 282 | 283 | 284 | class CustomCall: 285 | 286 | def __iter__(self): 287 | self.a = 1 288 | return self 289 | 290 | def __next__(self): 291 | k = self.a 292 | self.a += 1 293 | return k -------------------------------------------------------------------------------- /src/helpers/appiumdriver.py: -------------------------------------------------------------------------------- 1 | from appium import webdriver 2 | import unittest 3 | import os 4 | from datetime import datetime 5 | import pytest 6 | from src.helpers.business import * 7 | from pytest_html_reporter import attach 8 | 9 | 10 | class Driver(unittest.TestCase): 11 | 12 | def __init__(self, driver): 13 | super().__init__(driver) 14 | 15 | def setUp(self): 16 | """ 17 | This method instantiates the appium driver 18 | """ 19 | global desired_caps 20 | 21 | self.logger.info("Configuring desired capabilities") 22 | if os.getenv('PYTEST_XDIST_WORKER'): 23 | if self.app == 'ios': 24 | desired_caps = { 25 | 'deviceName': 'iPhone 8', 26 | 'platformName': 'iOS', 27 | 'platformVersion': '13.3', 28 | 'automationName': 'XCUITest', 29 | 'app': f'{os.popen("pwd").read().rstrip()}/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app' 30 | } 31 | 32 | elif self.app == 'android': 33 | desired_caps = { 34 | 'platformName': 'Android', 35 | 'platformVersion': '', 36 | 'deviceName': 'PF', 37 | 'wdaLocalPort': Driver.wda_port(self), 38 | 'udid': Driver.android_device_name(self), 39 | 'app': f'{os.popen("pwd").read().rstrip()}/data/apps/app-staging-debug.apk', 40 | 'noReset': True 41 | } 42 | 43 | else: 44 | if self.app == 'ios': 45 | desired_caps = self.ios() 46 | 47 | elif self.app == 'android': 48 | desired_caps = self.android() 49 | 50 | self.logger.info("Initiating Appium driver") 51 | self.driver = webdriver.Remote("http://0.0.0.0:4723/wd/hub", desired_caps) 52 | 53 | # set waits 54 | self.driver.implicitly_wait(5) # waits 5 seconds 55 | 56 | def android(self): 57 | if self.device == 'emulator': 58 | return dict(platformName='Android', platformVersion='', deviceName='PF', 59 | app=f'{os.popen("pwd").read().rstrip()}/data/apps/Android-NativeDemoApp-0.2.1.apk', noReset=True) 60 | elif self.device == 'real device': 61 | return dict(platformName='Android', platformVersion='', deviceName='PF', 62 | app=f'{os.popen("pwd").read().rstrip()}/data/apps/Android-NativeDemoApp-0.2.1.apk', noReset=True) 63 | 64 | def ios(self): 65 | if self.device == 'simulator': 66 | return dict(platformName='iOS', platformVersion='13.3', deviceName='iPhone 11', 67 | app=f'{os.popen("pwd").read().rstrip()}/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app', 68 | automationName='XCUITest') 69 | elif self.device == 'real device': 70 | return dict(platformName='iOS', platformVersion='14.0', deviceName='iPhone X', 71 | udid=f'{UDID}', useNewWDA=True, 72 | app=f'{os.popen("pwd").read().rstrip()}/data/apps/iOS-RealDevice-NativeDemoApp-0.2.1.ipa', 73 | automationName='XCUITest') 74 | elif self.device == 'bitrise': 75 | return dict(platformName='iOS', platformVersion='13.0', deviceName='iPhone-11', 76 | udid='E04A6F53-4C3B-4810-B210-DD2015D0D064', useNewWDA=True, 77 | app=f'{os.popen("pwd").read().rstrip()}/data/apps/iOS-Simulator-NativeDemoApp-0.2.1.app', automationName='XCUITest') 78 | 79 | def tearDown(self): 80 | Driver.screenshot_on_failure(self) 81 | attach(data=self.driver.get_screenshot_as_png()) 82 | self.driver.quit() 83 | 84 | def screenshot_on_failure(self): 85 | now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S') 86 | test_name = self._testMethodName 87 | for self._testMethodName, error in self._outcome.errors: 88 | if error: 89 | self.logger.error("Taking screenshot on failure") 90 | if not os.path.exists('screenshots'): 91 | os.makedirs('screenshots') 92 | 93 | self.driver.save_screenshot(f"screenshots/{test_name}_{now}.png") 94 | 95 | @pytest.fixture(autouse=True) 96 | def cli(self, app, device, get_logger): 97 | self.app = app 98 | self.device = device 99 | self.logger = get_logger 100 | 101 | def wda_port(self): 102 | if os.getenv('PYTEST_XDIST_WORKER') == 'gw1': 103 | return 8101 104 | else: # include 'master' and 'gw0' 105 | return 8100 106 | 107 | def android_device_name(self): 108 | if os.getenv('PYTEST_XDIST_WORKER') == 'gw0': 109 | return 'emulator-5554' 110 | elif os.getenv('PYTEST_XDIST_WORKER') == 'gw1': 111 | return 'emulator-5556' 112 | else: # default 113 | return 'emulator-5554' 114 | 115 | 116 | if __name__ == '__main__': 117 | unittest.main() 118 | -------------------------------------------------------------------------------- /src/helpers/business.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import pymysql 3 | import requests 4 | import json 5 | import random 6 | from sshtunnel import SSHTunnelForwarder 7 | from settings import * 8 | 9 | 10 | def db(query): 11 | with SSHTunnelForwarder( 12 | ('', 22), 13 | ssh_username="", 14 | ssh_pkey="/Users/prashanth/.ssh/id_rsa", 15 | remote_bind_address=('', 3306) 16 | ) as tunnel: 17 | conn = pymysql.connect(host='127.0.0.1', user='', password='', db='', 18 | port=tunnel.local_bind_port) 19 | cur = conn.cursor() 20 | cur.execute(query) 21 | conn.close() 22 | return get_db_results(cur) 23 | 24 | 25 | def get_db_results(db_cursor): 26 | desc = [d[0] for d in db_cursor.description] 27 | results = [dotdict(dict(zip(desc, res))) for res in db_cursor.fetchall()] 28 | return results 29 | 30 | 31 | def notify_slack(): 32 | """ 33 | modify web_hook_url with apt data 34 | """ 35 | web_hook_url = f'https://hooks.slack.com/services/{SLACK_TOKEN}' 36 | 37 | with open("./report/json/report.json") as json_file: 38 | json_object = json.load(json_file) 39 | json_file.close() 40 | 41 | passed = int(status_count(json_object, 'passed')) 42 | failed = int(status_count(json_object, 'failed')) 43 | color = '#36a64f' if failed == 0 else '#a30001' 44 | text = "#Build Passed" if failed == 0 else "#Build Failed" 45 | 46 | slack_msg = { 47 | "attachments": [ 48 | { 49 | "fallback": "Excuse Me! I've something for you!", 50 | "color": f"{color}", 51 | "pretext": f"@here {quote()}", 52 | "author_name": "Mobile Automation Results", 53 | "author_link": "https://twitter.com/prashanthsams", 54 | "author_icon": "https://avatars3.githubusercontent.com/u/2948696?s=460&v=4", 55 | "title": "Your App - Android", 56 | "title_link": "https://twitter.com/prashanthsams", 57 | "text": f"{text}", 58 | "fields": [ 59 | { 60 | "title": f"AE => :white_check_mark: {str(passed)} Passed :exclamation: {str(failed)} Failed", 61 | # "value": "3", 62 | "short": False 63 | }, 64 | { 65 | "title": f"SA => :white_check_mark: {str(passed)} Passed :exclamation: {str(failed)} Failed", 66 | "short": False 67 | } 68 | ], 69 | "image_url": "http://my-website.com/path/to/image.jpg", 70 | "thumb_url": "http://example.com/path/to/thumb.png", 71 | "footer": "Appium Framework", 72 | "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png", 73 | "ts": int(datetime.datetime.now().strftime("%s")) 74 | } 75 | ] 76 | } 77 | requests.post(web_hook_url, data=json.dumps(slack_msg)) 78 | 79 | 80 | def quote(): 81 | quotes = [ 82 | "Tests without assertions are not tests - Prashanth Sams", 83 | "In God we Trust for the rest we Test" 84 | ] 85 | return random.choice(quotes) 86 | 87 | 88 | def status_count(json_object, status): 89 | try: 90 | return json_object['report']['summary'][f'{status}'] 91 | except KeyError as e: 92 | try: 93 | return json_object['data'][0]['attributes']['summary'][f'{status}'] 94 | except KeyError as e: 95 | return 0 96 | 97 | 98 | class dotdict(dict): 99 | __getattr__ = dict.get 100 | __setattr__ = dict.__setitem__ 101 | __delattr__ = dict.__delitem__ -------------------------------------------------------------------------------- /src/helpers/constants.py: -------------------------------------------------------------------------------- 1 | EN = { 2 | 'USERNAME': 'value', 3 | 'PASSWORD': 'value' 4 | } 5 | 6 | AR = { 7 | 'USERNAME': 'vallue', 8 | 'PASSWORD': 'value' 9 | } -------------------------------------------------------------------------------- /src/screens/android/base_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class BaseScreen(Driver): 6 | """ 7 | common screen locators 8 | """ 9 | 10 | def __init__(self, driver): 11 | super().__init__(driver) -------------------------------------------------------------------------------- /src/screens/android/home_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class HomeScreen(Driver): 6 | """ 7 | home screen locators 8 | """ 9 | loginMenu = (MobileBy.XPATH, "//android.view.ViewGroup[@content-desc='Login']/android.widget.TextView") 10 | formsMenu = (MobileBy.ACCESSIBILITY_ID, "Forms") 11 | homeMenu = (MobileBy.ACCESSIBILITY_ID, "Home") 12 | swipeMenu = (MobileBy.ACCESSIBILITY_ID, "Swipe") 13 | supportLink = (MobileBy.XPATH, '//android.widget.ScrollView[@content-desc="Home-screen"]/android.view.ViewGroup/android.view.ViewGroup[2]/android.widget.TextView[3]') 14 | 15 | # swipeMenu = {'ANDROID': (MobileBy.ACCESSIBILITY_ID, "Swipe"),'IOS': (MobileBy.ACCESSIBILITY_ID, "Swipe")} 16 | 17 | def __init__(self, driver): 18 | super().__init__(driver) -------------------------------------------------------------------------------- /src/screens/android/login_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class LoginScreen(Driver): 6 | """ 7 | login screen locators 8 | """ 9 | inputField = (MobileBy.XPATH, '//android.widget.EditText[@content-desc="input-email"]') 10 | passwordField = (MobileBy.ACCESSIBILITY_ID, 'input-password') 11 | loginButton = (MobileBy.XPATH, '//android.view.ViewGroup[@content-desc="button-LOGIN"]/android.view.ViewGroup') 12 | 13 | def __init__(self, driver): 14 | super().__init__(driver) -------------------------------------------------------------------------------- /src/screens/ios/base_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class BaseScreen(Driver): 6 | """ 7 | common screen locators 8 | """ 9 | 10 | def __init__(self, driver): 11 | super().__init__(driver) -------------------------------------------------------------------------------- /src/screens/ios/home_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class HomeScreen(Driver): 6 | """ 7 | home screen locators 8 | """ 9 | loginMenu = (MobileBy.ID, "Login") 10 | formsMenu = (MobileBy.ID, "Forms") 11 | homeMenu = (MobileBy.ID, "Home") 12 | swipeMenu = (MobileBy.ID, "Swipe") 13 | 14 | # swipeMenu = {'ANDROID': (MobileBy.ACCESSIBILITY_ID, "Swipe"),'IOS': (MobileBy.ACCESSIBILITY_ID, "Swipe")} 15 | 16 | def __init__(self, driver): 17 | super().__init__(driver) -------------------------------------------------------------------------------- /src/screens/ios/login_screen.py: -------------------------------------------------------------------------------- 1 | from appium.webdriver.common.mobileby import MobileBy 2 | from src.helpers.appiumdriver import Driver 3 | 4 | 5 | class LoginScreen(Driver): 6 | """ 7 | login screen locators 8 | """ 9 | inputField = (MobileBy.ACCESSIBILITY_ID, 'input-email') 10 | passwordField = (MobileBy.ACCESSIBILITY_ID, 'input-password') 11 | loginButton = (MobileBy.XPATH, '//XCUIElementTypeStaticText[@name="LOGIN"]') 12 | 13 | def __init__(self, driver): 14 | super().__init__(driver) -------------------------------------------------------------------------------- /src/spec/android/home_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.helpers.appiumdriver import Driver 3 | from src.screens.android.home_screen import HomeScreen 4 | from src.helpers.app import App 5 | 6 | 7 | class TestHome(Driver): 8 | 9 | def __init__(self, driver): 10 | super().__init__(driver) 11 | 12 | @pytest.mark.home 13 | def test_home_1(self): 14 | App.element(self, HomeScreen.homeMenu) 15 | App.element(self, HomeScreen.loginMenu) 16 | App.element(self, HomeScreen.formsMenu) 17 | App.element(self, HomeScreen.swipeMenu) 18 | App.swipe_until(self, HomeScreen.supportLink, start_x=144, start_y=434) 19 | # App.assert_text(self, HomeLocators.loginMenu, 'Leads') 20 | 21 | @pytest.mark.home 22 | def test_home_2(self): 23 | App.element(self, HomeScreen.homeMenu) 24 | App.element(self, HomeScreen.loginMenu) -------------------------------------------------------------------------------- /src/spec/android/login_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.helpers.appiumdriver import Driver 3 | from src.screens.android.home_screen import HomeScreen 4 | from src.screens.android.login_screen import LoginScreen 5 | from src.helpers.app import App 6 | 7 | 8 | class TestLogin(Driver): 9 | 10 | def __init__(self, driver): 11 | super().__init__(driver) 12 | 13 | @pytest.mark.login 14 | def test_login(self): 15 | App.click(self, HomeScreen.loginMenu) 16 | App.send_keys(self, LoginScreen.inputField, "johnsmith@gmail.com") 17 | App.send_keys(self, LoginScreen.passwordField, "password", index=0) 18 | App.tap(self, LoginScreen.inputField) -------------------------------------------------------------------------------- /src/spec/ios/home_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.helpers.appiumdriver import Driver 3 | from src.screens.ios.home_screen import HomeScreen 4 | from src.helpers.app import App 5 | 6 | 7 | class TestHome(Driver): 8 | 9 | def __init__(self, driver): 10 | super().__init__(driver) 11 | 12 | @pytest.mark.home 13 | def test_home_1(self): 14 | App.is_displayed(self, HomeScreen.homeMenu, True) 15 | App.is_displayed(self, HomeScreen.loginMenu, True) 16 | App.is_displayed(self, HomeScreen.formsMenu, True) 17 | App.is_displayed(self, HomeScreen.swipeMenu, True) 18 | 19 | @pytest.mark.home 20 | def test_home_2(self): 21 | App.is_displayed(self, HomeScreen.homeMenu, True) 22 | App.is_displayed(self, HomeScreen.loginMenu, True) -------------------------------------------------------------------------------- /src/spec/ios/login_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from src.helpers.appiumdriver import Driver 3 | from src.screens.ios.home_screen import HomeScreen 4 | from src.screens.ios.login_screen import LoginScreen 5 | from src.helpers.app import App 6 | 7 | 8 | class TestLogin(Driver): 9 | 10 | def __init__(self, driver): 11 | super().__init__(driver) 12 | 13 | @pytest.mark.login 14 | def test_login(self): 15 | App.click(self, HomeScreen.loginMenu) 16 | App.send_keys(self, LoginScreen.inputField, "johnsmith@gmail.com") 17 | App.send_keys(self, LoginScreen.passwordField, "password", index=0) 18 | App.tap(self, LoginScreen.inputField) -------------------------------------------------------------------------------- /tasks.py: -------------------------------------------------------------------------------- 1 | from src.helpers.business import notify_slack 2 | from invoke import task 3 | import os 4 | 5 | 6 | @task 7 | def test(c, env='staging', lang='en', app='android', device='emulator'): 8 | """ 9 | update local storage 10 | Enable and modify this to add local storage 11 | """ 12 | # os.system("adb push $(pwd)/data/.xml /data/data//shared_prefs") 13 | c.run(f'python3 -m pytest src/spec/{app}/*.py --app={app} --device={device}') 14 | 15 | @task 16 | def slack(c, env='staging', country='AE', slack='on', app='android'): 17 | if slack == 'on': notify_slack() 18 | --------------------------------------------------------------------------------