Skip to content

Commit 446b8c4

Browse files
authored
Fix flaky functional tests (appium#473)
* Run all tests * Fix apk file path * Skip find_element_by_image test cases * Skip context switching test * Skip multi tap test on CI * Change strategy for waiting element * Add functions for same steps * Restore unexpected changes * Fix touch_action_tests * Fix * Fix Fix test_driver_swipe * fix * Create _move_to_[target_view] * [test_driver_swipe] Add wait
1 parent f14291b commit 446b8c4

File tree

9 files changed

+69
-110
lines changed

9 files changed

+69
-110
lines changed

ci-jobs/functional_test.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ parameters:
55
xcodeForIOS: 11.3
66
CI: true
77

8-
# [Android] Need to fix and add flaky tests for activities_tests, find_by_uiautomator_tests
9-
108
jobs:
119
- template: ./functional/run_ios_test.yml
1210
parameters:
@@ -70,7 +68,7 @@ jobs:
7068
name: 'func_test_android6'
7169
vmImage: ${{ parameters.vmImage }}
7270
pytestOpt: ${{ parameters.pytestOpt }}
73-
testFiles: 'common_tests.py'
71+
testFiles: 'common_tests.py multi_action_tests.py webelement_tests.py'
7472
sdkVer: ${{ parameters.androidSdkVer }}
7573
CI: ${{ parameters.ci }}
7674
- template: ./functional/run_android_test.yml
@@ -86,6 +84,6 @@ jobs:
8684
name: 'func_test_android8'
8785
vmImage: ${{ parameters.vmImage }}
8886
pytestOpt: ${{ parameters.pytestOpt }}
89-
testFiles: 'network_connection_tests.py log_event_tests.py'
87+
testFiles: 'network_connection_tests.py log_event_tests.py activities_tests.py hw_actions_tests.py touch_action_tests.py'
9088
sdkVer: ${{ parameters.androidSdkVer }}
9189
CI: ${{ parameters.ci }}

test/functional/android/applications_tests.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
import os
1617
import unittest
1718
from time import sleep
1819

1920
from appium.webdriver.applicationstate import ApplicationState
2021

22+
from .helper.desired_capabilities import PATH
2123
from .helper.test_helper import APIDEMO_PKG_NAME, BaseTestCase
2224

2325

@@ -33,9 +35,8 @@ def test_is_app_installed(self):
3335
self.assertTrue(self.driver.is_app_installed(APIDEMO_PKG_NAME))
3436

3537
def test_install_app(self):
36-
self.skipTest('This causes the server to crash. no idea why')
3738
self.assertFalse(self.driver.is_app_installed('io.selendroid.testapp'))
38-
self.driver.install_app('/Users/isaac/code/python-client/test/apps/selendroid-test-app.apk')
39+
self.driver.install_app(PATH(os.path.join('../..', 'apps', 'selendroid-test-app.apk')))
3940
self.assertTrue(self.driver.is_app_installed('io.selendroid.testapp'))
4041

4142
def test_remove_app(self):

test/functional/android/common_tests.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ def test_end_test_coverage(self):
3939
sleep(5)
4040

4141
def test_open_notifications(self):
42-
if is_ci():
43-
# TODO Due to unexpected dialog, "System UI isn't responding"
44-
self.skipTest('Need to fix flaky test during running on CI.')
4542
for word in ['App', 'Notification', 'Status Bar', ':-|']:
4643
wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR,
4744
'new UiSelector().text("{}")'.format(word)).click()

test/functional/android/context_switching_tests.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,31 @@
2222
from .helper import desired_capabilities
2323

2424

25-
@pytest.mark.skip(reason="Need to fix broken test")
2625
class ContextSwitchingTests(unittest.TestCase):
2726
def setUp(self):
2827
desired_caps = desired_capabilities.get_desired_capabilities('selendroid-test-app.apk')
2928
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
3029

3130
def test_contexts_list(self):
31+
self.skipTest('Need to replace with apk which has WEBVIEW as context')
3232
self._enter_webview()
3333
contexts = self.driver.contexts
3434
self.assertEqual(2, len(contexts))
3535

3636
def test_move_to_correct_context(self):
37+
self.skipTest('Need to replace with apk which has WEBVIEW as context')
3738
self._enter_webview()
3839
self.assertEqual('WEBVIEW_io.selendroid.testapp', self.driver.current_context)
3940

4041
def test_actually_in_webview(self):
42+
self.skipTest('Need to replace with apk which has WEBVIEW as context')
4143
self._enter_webview()
4244
self.driver.find_element_by_css_selector('input[type=submit]').click()
4345
el = self.driver.find_element_by_xpath("//h1[contains(., 'This is my way')]")
4446
self.assertIsNot(None, el)
4547

4648
def test_move_back_to_native_context(self):
49+
self.skipTest('Need to replace with apk which has WEBVIEW as context')
4750
self._enter_webview()
4851
self.driver.switch_to.context(None)
4952
self.assertEqual('NATIVE_APP', self.driver.current_context)
@@ -55,7 +58,7 @@ def tearDown(self):
5558
self.driver.quit()
5659

5760
def _enter_webview(self):
58-
btn = self.driver.find_element_by_name('buttonStartWebviewCD')
61+
btn = self.driver.find_element_by_accessibility_id('buttonStartWebviewCD')
5962
btn.click()
6063
self.driver.switch_to.context('WEBVIEW')
6164

test/functional/android/multi_action_tests.py

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,13 @@
1919
from appium.webdriver.common.multi_action import MultiAction
2020
from appium.webdriver.common.touch_action import TouchAction
2121

22-
from .helper.test_helper import BaseTestCase, wait_for_element
22+
from .helper.test_helper import BaseTestCase, is_ci, wait_for_element
2323

2424

2525
class MultiActionTests(BaseTestCase):
2626
def test_parallel_actions(self):
27-
el1 = self.driver.find_element_by_accessibility_id('Content')
28-
el2 = self.driver.find_element_by_accessibility_id('Animation')
29-
self.driver.scroll(el1, el2)
30-
31-
el = self.driver.find_element_by_accessibility_id('Views')
32-
action = TouchAction(self.driver)
33-
action.tap(el).perform()
34-
35-
# simulate a swipe/scroll
36-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
37-
action.press(el).move_to(x=100, y=-1000).release().perform()
38-
el = self.driver.find_element_by_accessibility_id('Layouts')
39-
action.press(el).move_to(x=100, y=-1000).release().perform()
27+
self._move_to_splitting_touches_accros_views()
4028

41-
el = self.driver.find_element_by_accessibility_id('Splitting Touches across Views')
42-
action.tap(el).perform()
43-
44-
wait_for_element(self.driver, MobileBy.CLASS_NAME, 'android.widget.ListView')
4529
els = self.driver.find_elements_by_class_name('android.widget.ListView')
4630
a1 = TouchAction()
4731
a1.press(els[0]) \
@@ -56,24 +40,8 @@ def test_parallel_actions(self):
5640
ma.perform()
5741

5842
def test_actions_with_waits(self):
59-
el1 = self.driver.find_element_by_accessibility_id('Content')
60-
el2 = self.driver.find_element_by_accessibility_id('Animation')
61-
self.driver.scroll(el1, el2)
62-
63-
el = self.driver.find_element_by_accessibility_id('Views')
64-
action = TouchAction(self.driver)
65-
action.tap(el).perform()
66-
67-
# simulate a swipe/scroll
68-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
69-
action.press(el).move_to(x=100, y=-1000).release().perform()
70-
el = self.driver.find_element_by_accessibility_id('Layouts')
71-
action.press(el).move_to(x=100, y=-1000).release().perform()
72-
73-
el = self.driver.find_element_by_accessibility_id('Splitting Touches across Views')
74-
action.tap(el).perform()
43+
self._move_to_splitting_touches_accros_views()
7544

76-
wait_for_element(self.driver, MobileBy.CLASS_NAME, 'android.widget.ListView')
7745
els = self.driver.find_elements_by_class_name('android.widget.ListView')
7846
a1 = TouchAction()
7947
a1.press(els[0]) \
@@ -95,7 +63,29 @@ def test_actions_with_waits(self):
9563
ma.add(a1, a2)
9664
ma.perform()
9765

66+
def _move_to_splitting_touches_accros_views(self):
67+
el1 = self.driver.find_element_by_accessibility_id('Content')
68+
el2 = self.driver.find_element_by_accessibility_id('Animation')
69+
self.driver.scroll(el1, el2)
70+
71+
el = self.driver.find_element_by_accessibility_id('Views')
72+
action = TouchAction(self.driver)
73+
action.tap(el).perform()
74+
75+
# simulate a swipe/scroll
76+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
77+
action.press(el).move_to(x=100, y=-1000).release().perform()
78+
el = self.driver.find_element_by_accessibility_id('Layouts')
79+
action.press(el).move_to(x=100, y=-1000).release().perform()
80+
81+
el = self.driver.find_element_by_accessibility_id('Splitting Touches across Views')
82+
action.tap(el).perform()
83+
84+
wait_for_element(self.driver, MobileBy.ID, 'io.appium.android.apis:id/list1')
85+
9886
def test_driver_multi_tap(self):
87+
if is_ci():
88+
self.skipTest('Skip since the test must be watched to check if it works')
9989
el = self.driver.find_element_by_accessibility_id('Graphics')
10090
action = TouchAction(self.driver)
10191
action.tap(el).perform()

test/functional/android/network_connection_tests.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
from appium.webdriver.connectiontype import ConnectionType
1919

20-
from ..test_helper import is_ci
2120
from .helper.test_helper import BaseTestCase
2221

2322

@@ -27,8 +26,6 @@ def test_get_network_connection(self):
2726
self.assertIsInstance(nc, int)
2827

2928
def test_set_network_connection(self):
30-
if is_ci():
31-
self.skipTest('Need to fix flaky test during running on CI')
3229
nc = self.driver.set_network_connection(ConnectionType.DATA_ONLY)
3330
self.assertIsInstance(nc, int)
3431
self.assertEqual(nc, ConnectionType.DATA_ONLY)

test/functional/android/search_context/find_by_accessibility_id_tests.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
BaseTestCase,
2020
wait_for_element
2121
)
22-
from test.functional.test_helper import is_ci
2322

2423

2524
class FindByAccessibilityIDTests(BaseTestCase):
@@ -35,12 +34,10 @@ def test_find_multiple_elements(self):
3534
self.assertIsInstance(els, list)
3635

3736
def test_element_find_single_element(self):
38-
if is_ci():
39-
self.skipTest('Need to fix flaky test during running on CI')
4037
wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("Accessibility")').click()
4138
wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR,
4239
'new UiSelector().text("Accessibility Node Querying")').click()
43-
el = wait_for_element(self.driver, MobileBy.CLASS_NAME, 'android.widget.ListView')
40+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Task Take out Trash')
4441

4542
sub_el = el.find_element_by_accessibility_id('Task Take out Trash')
4643
self.assertIsNotNone(sub_el)

test/functional/android/search_context/find_by_uiautomator_tests.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from test.functional.android.helper.test_helper import BaseTestCase
2020

2121

22-
@pytest.mark.skip(reason="Need to fix flaky test")
2322
class FindByUIAutomatorTests(BaseTestCase):
2423
def test_find_single_element(self):
2524
el = self.driver.find_element_by_android_uiautomator('new UiSelector().text("Animation")')

test/functional/android/touch_action_tests.py

Lines changed: 33 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .helper.test_helper import (
2323
APIDEMO_PKG_NAME,
2424
BaseTestCase,
25+
is_ci,
2526
wait_for_element
2627
)
2728

@@ -73,20 +74,8 @@ def test_press_and_immediately_release_x_y(self):
7374
self.assertIsNotNone(el)
7475

7576
def test_press_and_wait(self):
76-
el1 = self.driver.find_element_by_accessibility_id('Content')
77-
el2 = self.driver.find_element_by_accessibility_id('Animation')
78-
77+
self._move_to_custom_adapter()
7978
action = TouchAction(self.driver)
80-
action.press(el1).move_to(el2).perform()
81-
82-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views')
83-
action.tap(el).perform()
84-
85-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
86-
action.tap(el).perform()
87-
88-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, '1. Custom Adapter')
89-
action.tap(el).perform()
9079

9180
el = wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR,
9281
'new UiSelector().text("People Names")')
@@ -118,20 +107,8 @@ def test_press_and_moveto_x_y(self):
118107
self.assertIsNotNone(el)
119108

120109
def test_long_press(self):
121-
el1 = self.driver.find_element_by_accessibility_id('Content')
122-
el2 = self.driver.find_element_by_accessibility_id('Animation')
123-
110+
self._move_to_custom_adapter()
124111
action = TouchAction(self.driver)
125-
action.press(el1).move_to(el2).perform()
126-
127-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views')
128-
action.tap(el).perform()
129-
130-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
131-
action.tap(el).perform()
132-
133-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, '1. Custom Adapter')
134-
action.tap(el).perform()
135112

136113
el = wait_for_element(self.driver, MobileBy.ANDROID_UIAUTOMATOR,
137114
'new UiSelector().text("People Names")')
@@ -143,20 +120,10 @@ def test_long_press(self):
143120
self.assertIsNotNone(el)
144121

145122
def test_long_press_x_y(self):
146-
el1 = self.driver.find_element_by_accessibility_id('Content')
147-
el2 = self.driver.find_element_by_accessibility_id('Animation')
148-
123+
if is_ci():
124+
self.skipTest("Skip since this check is low robust due to hard-coded position.")
125+
self._move_to_custom_adapter()
149126
action = TouchAction(self.driver)
150-
action.press(el1).move_to(el2).perform()
151-
152-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views')
153-
action.tap(el).perform()
154-
155-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
156-
action.tap(el).perform()
157-
158-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, '1. Custom Adapter')
159-
action.tap(el).perform()
160127

161128
# the element "People Names" is located at 430:310 (top left corner)
162129
# location can be changed by phone resolusion, OS version
@@ -168,13 +135,8 @@ def test_long_press_x_y(self):
168135
self.assertIsNotNone(el)
169136

170137
def test_drag_and_drop(self):
171-
el1 = self.driver.find_element_by_accessibility_id('Content')
172-
el2 = self.driver.find_element_by_accessibility_id('Animation')
173-
self.driver.scroll(el1, el2)
174-
175-
el = self.driver.find_element_by_accessibility_id('Views')
138+
self._move_to_views()
176139
action = TouchAction(self.driver)
177-
action.tap(el).perform()
178140

179141
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Drag and Drop')
180142
action.tap(el).perform()
@@ -185,17 +147,12 @@ def test_drag_and_drop(self):
185147
# dnd is stimulated by longpress-move_to-release
186148
action.long_press(dd3).move_to(dd2).release().perform()
187149

188-
el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_text'.format(APIDEMO_PKG_NAME))
189-
self.assertTrue('drag_dot_3' in el.text)
150+
el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_result_text'.format(APIDEMO_PKG_NAME))
151+
self.assertTrue('Dropped!' in el.text)
190152

191153
def test_driver_drag_and_drop(self):
192-
el1 = self.driver.find_element_by_accessibility_id('Content')
193-
el2 = self.driver.find_element_by_accessibility_id('Animation')
194-
self.driver.scroll(el1, el2)
195-
196-
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views')
154+
self._move_to_views()
197155
action = TouchAction(self.driver)
198-
action.tap(el).perform()
199156

200157
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Drag and Drop')
201158
action.tap(el).perform()
@@ -205,20 +162,40 @@ def test_driver_drag_and_drop(self):
205162

206163
self.driver.drag_and_drop(dd3, dd2)
207164

208-
el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_text'.format(APIDEMO_PKG_NAME))
209-
self.assertTrue('drag_dot_3' in el.text)
165+
el = wait_for_element(self.driver, MobileBy.ID, '{}:id/drag_result_text'.format(APIDEMO_PKG_NAME))
166+
self.assertTrue('Dropped!' in el.text)
210167

211168
def test_driver_swipe(self):
212169
el = self.driver.find_element_by_accessibility_id('Views')
213170
action = TouchAction(self.driver)
214171
action.tap(el).perform()
215172

173+
wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Animation')
216174
self.assertRaises(NoSuchElementException, self.driver.find_element_by_accessibility_id, 'ImageView')
217175

218176
self.driver.swipe(100, 1000, 100, 100, 800)
219-
el = self.driver.find_element_by_accessibility_id('ImageView')
177+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'ImageView')
220178
self.assertIsNotNone(el)
221179

180+
def _move_to_views(self):
181+
el1 = self.driver.find_element_by_accessibility_id('Content')
182+
el2 = self.driver.find_element_by_accessibility_id('Animation')
183+
self.driver.scroll(el1, el2)
184+
185+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Views')
186+
action = TouchAction(self.driver)
187+
action.tap(el).perform()
188+
189+
def _move_to_custom_adapter(self):
190+
self._move_to_views()
191+
action = TouchAction(self.driver)
192+
193+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, 'Expandable Lists')
194+
action.tap(el).perform()
195+
196+
el = wait_for_element(self.driver, MobileBy.ACCESSIBILITY_ID, '1. Custom Adapter')
197+
action.tap(el).perform()
198+
222199

223200
if __name__ == '__main__':
224201
suite = unittest.TestLoader().loadTestsFromTestCase(TouchActionTests)

0 commit comments

Comments
 (0)