├── requirements.txt ├── .gitignore ├── README.md ├── tests ├── macaca-desktop-sample.test.py ├── macaca-ios-sample.test.py └── macaca-android-sample.test.py └── .travis.yml /requirements.txt: -------------------------------------------------------------------------------- 1 | wd 2 | retrying 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/* 3 | Thumbs.db 4 | coverage/ 5 | .project 6 | build/ 7 | macaca-logs/ 8 | *.sw* 9 | *.un~ 10 | *.png 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sample-python 2 | 3 | ## CI Sample 4 | 5 | [![build status][travis-image-0]][travis-url-0] 6 | 7 | [travis-image-0]: https://img.shields.io/travis/macaca-sample/sample-python/master.svg?style=flat-square 8 | [travis-url-0]: https://travis-ci.org/macaca-sample/sample-python 9 | 10 | ## Install 11 | 12 | ``` bash 13 | $ npm install -g macaca-cli macaca-electron macaca-ios macaca-android 14 | $ pip install -r requirements.txt 15 | ``` 16 | 17 | ## Run test 18 | 19 | ``` bash 20 | $ macaca server --verbose 21 | $ python tests/macaca-desktop-sample.test.py 22 | $ python tests/macaca-ios-sample.test.py 23 | $ python tests/macaca-android-sample.test.py 24 | ``` 25 | 26 | 27 | 28 | ## Contributors 29 | 30 | |[
ziczhu](https://github.com/ziczhu)
|[
xudafeng](https://github.com/xudafeng)
31 | | :---: | :---: | 32 | 33 | 34 | This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto upated at `Tue Apr 17 2018 00:49:24 GMT+0800`. 35 | 36 | 37 | 38 | ## License 39 | 40 | The MIT License (MIT) 41 | -------------------------------------------------------------------------------- /tests/macaca-desktop-sample.test.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | import unittest 4 | import time 5 | from macaca import WebDriver 6 | 7 | desired_caps = { 8 | 'platformName': 'desktop', 9 | 'browserName': 'electron' 10 | } 11 | 12 | server_url = { 13 | 'hostname': 'localhost', 14 | 'port': 3456 15 | } 16 | 17 | class MacacaTest(unittest.TestCase): 18 | @classmethod 19 | def setUpClass(cls): 20 | cls.driver = WebDriver(desired_caps, server_url) 21 | cls.driver.init() 22 | 23 | @classmethod 24 | def tearDownClass(cls): 25 | cls.driver.quit() 26 | 27 | def test_get_url(self): 28 | self.driver \ 29 | .set_window_size(1280, 800) \ 30 | .get('https://www.baidu.com') 31 | 32 | def test_search_macaca(self): 33 | self.driver \ 34 | .element_by_id('kw') \ 35 | .send_keys('macaca') 36 | self.driver \ 37 | .element_by_id('su') \ 38 | .click() 39 | time.sleep(3) 40 | html = self.driver.source 41 | self.assertTrue('macaca' in html) 42 | self.assertTrue( 43 | self.driver.element_by_css_selector_if_exists( 44 | '#head > div.head_wrapper')) 45 | self.driver \ 46 | .element_by_xpath_or_none('//*[@id="kw"]') \ 47 | .send_keys(' elementByXPath') 48 | self.driver \ 49 | .element_by_id('su') \ 50 | .click() 51 | self.driver.take_screenshot() 52 | 53 | 54 | if __name__ == '__main__': 55 | unittest.main() 56 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - osx 3 | - linux 4 | env: 5 | - TEST_SUITE=ios 6 | - TEST_SUITE=android 7 | - TEST_SUITE=pc-browser 8 | matrix: 9 | fast_finish: true 10 | exclude: 11 | - os: osx 12 | env: TEST_SUITE=ios 13 | - os: osx 14 | env: TEST_SUITE=android 15 | - os: osx 16 | env: TEST_SUITE=pc-browser 17 | - os: linux 18 | env: TEST_SUITE=ios 19 | - os: linux 20 | env: TEST_SUITE=android 21 | - os: linux 22 | env: TEST_SUITE=pc-browser 23 | include: 24 | - os: osx 25 | env: TEST_SUITE=ios 26 | osx_image: xcode9 27 | language: generic 28 | before_install: 29 | - brew update 30 | - brew install carthage > /dev/null 2>&1 31 | - brew install ios-webkit-debug-proxy > /dev/null 2>&1 32 | - brew install nvm > /dev/null 2>&1 33 | - brew install python3 34 | - pip install virtualenv 35 | - virtualenv env -p python3 36 | - source env/bin/activate 37 | install: 38 | - echo Hello Macaca! 39 | - source $(brew --prefix nvm)/nvm.sh 40 | - nvm install 7 41 | - nvm use 7 42 | - npm i ios-simulator macaca-cli macaca-ios -g 43 | - open -a Simulator --args -CurrentDeviceUDID `ios-simulator -n 'iPhone 6s'` > /dev/null 2>&1 44 | - pip install -r requirements.txt 45 | script: 46 | - macaca server --verbose & 47 | - sleep 10 48 | - python tests/macaca-ios-sample.test.py 49 | - os: linux 50 | env: TEST_SUITE=android 51 | jdk: oraclejdk8 52 | language: android 53 | android: 54 | components: 55 | - tools 56 | - build-tools-25.0.2 57 | - platform-tools 58 | - extra-android-m2repository 59 | - extra-google-android-support 60 | - android-25 61 | sudo: required 62 | addons: 63 | apt: 64 | sources: 65 | - deadsnakes 66 | packages: 67 | - python3.5 68 | before_install: 69 | - export CHROME_BIN=chromium-browser 70 | - wget http://services.gradle.org/distributions/gradle-3.3-all.zip 71 | - unzip gradle-3.3-all.zip > /dev/null 72 | - export GRADLE_HOME=$PWD/gradle-3.3 73 | - export PATH=$GRADLE_HOME/bin:$PATH 74 | - export JAVA_HOME=/usr/lib/jvm/java-8-oracle 75 | - export ANDROID_HOME=/usr/local/android-sdk 76 | - . $HOME/.nvm/nvm.sh 77 | - export DISPLAY=:99.0 78 | - sh -e /etc/init.d/xvfb start 79 | before_script: 80 | - echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a 81 | - emulator -avd test -no-audio -no-window & 82 | - android-wait-for-emulator 83 | - adb shell input keyevent 82 & 84 | install: 85 | - echo Hello Macaca! 86 | - nvm install 7 87 | - nvm use 7 88 | - npm install -g macaca-cli macaca-android 89 | - pip install virtualenv 90 | - virtualenv env -p python3.5 91 | - source env/bin/activate 92 | - pip install -r requirements.txt 93 | script: 94 | - macaca server --verbose & 95 | - sleep 10 96 | - python3 tests/macaca-android-sample.test.py 97 | - os: linux 98 | env: 99 | - TEST_SUITE=pc-browser 100 | language: python 101 | sudo: false 102 | python: 3.5 103 | addons: 104 | apt: 105 | packages: 106 | - xvfb 107 | before_install: 108 | - . $HOME/.nvm/nvm.sh 109 | - export DISPLAY=':99.0' 110 | - Xvfb :99 -screen 0 1366x768x24 > /dev/null 2>&1 & 111 | install: 112 | - echo Hello Macaca! 113 | - nvm install 7 114 | - nvm use 7 115 | - npm install -g macaca-cli macaca-electron 116 | - pip install -r requirements.txt 117 | script: 118 | - macaca server --verbose & 119 | - sleep 10 120 | - python3 tests/macaca-desktop-sample.test.py 121 | -------------------------------------------------------------------------------- /tests/macaca-ios-sample.test.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | import unittest 4 | import os 5 | import time 6 | from macaca import WebDriver 7 | from retrying import retry 8 | 9 | desired_caps = { 10 | 'platformName': 'iOS', 11 | 'deviceName': 'iPhone 6s', 12 | 'app': 'https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip', 13 | } 14 | 15 | 16 | server_url = { 17 | 'hostname': 'localhost', 18 | 'port': 3456 19 | } 20 | 21 | def switch_to_webview(driver): 22 | contexts = driver.contexts 23 | driver.context = contexts[-1] 24 | return driver 25 | 26 | def switch_to_native(driver): 27 | contexts = driver.contexts 28 | driver.context = contexts[0] 29 | return driver 30 | 31 | class MacacaTest(unittest.TestCase): 32 | @classmethod 33 | def setUpClass(cls): 34 | cls.driver = WebDriver(desired_caps, server_url) 35 | cls.initDriver() 36 | 37 | @classmethod 38 | def tearDownClass(cls): 39 | cls.driver.quit() 40 | 41 | @classmethod 42 | @retry 43 | def initDriver(cls): 44 | print("Retry connecting server...") 45 | cls.driver.init() 46 | 47 | def test_01_login(self): 48 | self.driver \ 49 | .element_by_xpath('//XCUIElementTypeTextField[1]') \ 50 | .send_keys('中文+Test+12345678') \ 51 | 52 | self.driver \ 53 | .element_by_xpath('//XCUIElementTypeSecureTextField[1]') \ 54 | .send_keys('111111') \ 55 | 56 | time.sleep(1) 57 | 58 | self.driver \ 59 | .send_keys('\n') 60 | 61 | self.driver \ 62 | .element_by_name('Login') \ 63 | .click() 64 | 65 | def test_02_scroll_tableview(self): 66 | self.driver \ 67 | .element_by_name('HOME') \ 68 | .click() 69 | 70 | self.driver \ 71 | .element_by_name('list') \ 72 | .click() 73 | 74 | def test_03_gesture(self): 75 | self.driver \ 76 | .touch('drag', { 77 | 'fromX': 200, 78 | 'fromY': 400, 79 | 'toX': 200, 80 | 'toY': 100, 81 | 'duration': 2 82 | }) 83 | 84 | time.sleep(1) 85 | 86 | self.driver \ 87 | .touch('drag', { 88 | 'fromX': 100, 89 | 'fromY': 100, 90 | 'toX': 100, 91 | 'toY': 400, 92 | 'duration': 2 93 | }) 94 | 95 | time.sleep(1) 96 | 97 | self.driver \ 98 | .element_by_name('Gesture') \ 99 | .click() 100 | 101 | self.driver \ 102 | .touch('tap', { 103 | 'x': 100, 104 | 'y': 100 105 | }) 106 | 107 | time.sleep(1) 108 | 109 | self.driver \ 110 | .touch('press', { 111 | 'x': 100, 112 | 'y': 100, 113 | 'duration': 1 114 | }) 115 | 116 | time.sleep(1) 117 | 118 | self.driver \ 119 | .element_by_id('info') \ 120 | .touch('pinch', { 121 | 'scale': 2, 122 | 'velocity': 1 123 | }) 124 | 125 | time.sleep(1) 126 | 127 | self.driver \ 128 | .touch('drag', { 129 | 'fromX': 100, 130 | 'fromY': 100, 131 | 'toX': 100, 132 | 'toY': 600, 133 | 'steps': 100 134 | }) 135 | 136 | def test_04_webview(self): 137 | self.driver \ 138 | .element_by_name('Webview') \ 139 | .click() 140 | 141 | time.sleep(3) 142 | self.driver.save_screenshot('./webView.png') # save screen shot 143 | 144 | switch_to_webview(self.driver) \ 145 | .element_by_id('pushView') \ 146 | .touch('tap') 147 | 148 | switch_to_webview(self.driver) \ 149 | .element_by_id('popView') \ 150 | .touch('tap') 151 | 152 | def test_05_web(self): 153 | switch_to_native(self.driver) \ 154 | .element_by_name('Baidu') \ 155 | .touch('tap') 156 | 157 | time.sleep(3) 158 | self.driver.save_screenshot("./baidu.png") 159 | 160 | switch_to_webview(self.driver) \ 161 | .element_by_id('index-kw') \ 162 | .send_keys('macaca') \ 163 | .element_by_id('index-bn') \ 164 | .touch('tap') 165 | 166 | def test_06_logout(self): 167 | switch_to_native(self.driver) \ 168 | .element_by_name('PERSONAL') \ 169 | .click() 170 | 171 | self.driver.element_by_name('Logout') \ 172 | .click() 173 | 174 | if __name__ == '__main__': 175 | unittest.main() 176 | -------------------------------------------------------------------------------- /tests/macaca-android-sample.test.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | import unittest 4 | import os 5 | import time 6 | from macaca import WebDriver 7 | from macaca import Keys 8 | from retrying import retry 9 | 10 | desired_caps = { 11 | 'platformName': 'android', 12 | 'app': 'https://npmcdn.com/android-app-bootstrap@latest/android_app_bootstrap/build/outputs/apk/android_app_bootstrap-debug.apk', 13 | } 14 | 15 | server_url = { 16 | 'hostname': 'localhost', 17 | 'port': 3456 18 | } 19 | 20 | def switch_to_webview(driver): 21 | contexts = driver.contexts 22 | driver.context = contexts[-1] 23 | return driver 24 | 25 | def switch_to_native(driver): 26 | contexts = driver.contexts 27 | driver.context = contexts[0] 28 | return driver 29 | 30 | class MacacaTest(unittest.TestCase): 31 | @classmethod 32 | def setUpClass(cls): 33 | cls.driver = WebDriver(desired_caps, server_url) 34 | cls.initDriver() 35 | 36 | @classmethod 37 | def tearDownClass(cls): 38 | cls.driver.quit() 39 | 40 | @classmethod 41 | @retry 42 | def initDriver(cls): 43 | print("Retry connecting server...") 44 | cls.driver.init() 45 | 46 | def test_01_login(self): 47 | el = self.driver \ 48 | .elements_by_class_name('android.widget.EditText')[0] \ 49 | .send_keys('中文+Test+12345678') \ 50 | 51 | el = self.driver \ 52 | .elements_by_class_name('android.widget.EditText')[1] \ 53 | .send_keys('111111') 54 | 55 | time.sleep(1) 56 | # self.driver.keys(Keys.ENTER.value + Keys.ESCAPE.value) 57 | 58 | self.driver \ 59 | .element_by_name('Login') \ 60 | .click() 61 | 62 | def test_02_scroll_tableview(self): 63 | self.driver \ 64 | .wait_for_element_by_name('HOME') \ 65 | .click() 66 | 67 | self.driver \ 68 | .wait_for_element_by_name('list') \ 69 | .click() 70 | 71 | def test_03_gesture(self): 72 | 73 | time.sleep(5) 74 | 75 | self.driver \ 76 | .wait_for_element_by_name('Alert') \ 77 | .click() 78 | 79 | time.sleep(5) 80 | 81 | self.driver \ 82 | .accept_alert() 83 | 84 | time.sleep(3) 85 | 86 | self.driver \ 87 | .back() 88 | 89 | time.sleep(3) 90 | 91 | self.driver \ 92 | .wait_for_element_by_name('Gesture') \ 93 | .click() 94 | 95 | time.sleep(3) 96 | 97 | self.driver \ 98 | .touch('tap', { 99 | 'x': 100, 100 | 'y': 100 101 | }) 102 | 103 | time.sleep(5) 104 | 105 | self.driver \ 106 | .touch('doubleTap', { 107 | 'x': 100, 108 | 'y': 100 109 | }) 110 | 111 | time.sleep(5) 112 | 113 | self.driver \ 114 | .touch('press', { 115 | 'x': 100, 116 | 'y': 100, 117 | 'steps': 100 118 | }) 119 | 120 | time.sleep(5) 121 | 122 | self.driver \ 123 | .touch('drag', { 124 | 'fromX': 100, 125 | 'fromY': 100, 126 | 'toX': 100, 127 | 'toY': 600, 128 | 'steps': 100 129 | }) 130 | 131 | time.sleep(5) 132 | 133 | self.driver.back() 134 | 135 | time.sleep(5) 136 | 137 | self.driver.back() 138 | 139 | def test_04_webview(self): 140 | self.driver \ 141 | .wait_for_element_by_name('Webview') \ 142 | .click() 143 | 144 | time.sleep(5) 145 | self.driver.save_screenshot('./webView.png') # save screen shot 146 | 147 | switch_to_webview(self.driver) \ 148 | .wait_for_element_by_id('pushView') \ 149 | .click() 150 | 151 | switch_to_webview(self.driver) \ 152 | .wait_for_element_by_id('popView') \ 153 | .click() 154 | 155 | def test_05_web(self): 156 | switch_to_native(self.driver) \ 157 | .wait_for_element_by_name('Baidu') \ 158 | .click() 159 | 160 | time.sleep(5) 161 | self.driver.save_screenshot("./baidu.png") 162 | 163 | switch_to_webview(self.driver) \ 164 | .wait_for_element_by_id('index-kw') \ 165 | .send_keys('macaca') 166 | 167 | self.driver \ 168 | .wait_for_element_by_id('index-bn') \ 169 | .click() 170 | 171 | def test_06_logout(self): 172 | switch_to_native(self.driver) \ 173 | .wait_for_element_by_name('PERSONAL') \ 174 | .click() 175 | 176 | self.driver.wait_for_element_by_name('Logout') \ 177 | .click() 178 | 179 | if __name__ == '__main__': 180 | unittest.main() 181 | --------------------------------------------------------------------------------