diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 034fe5f1..bf8ac123 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -18,8 +18,12 @@ jobs: fail-fast: false matrix: test_targets: - - target: search_context/find_by_*.py remote_fs_tests.py safari_tests.py execute_driver_tests.py + - target: test/functional/ios/search_context/find_by_*.py test/functional/ios/remote_fs_tests.py test/functional/ios/safari_tests.py test/functional/ios/execute_driver_tests.py name: func_test_ios1 + - target: test/functional/ios/applications_tests.py test/functional/ios/hw_actions_tests.py test/functional/ios/keyboard_tests.py + name: func_test_ios2 + - target: test/functional/ios/screen_record_tests.py test/functional/ios/webdriver_tests.py + name: func_test_ios3 runs-on: macos-14 @@ -43,21 +47,29 @@ jobs: model: 'iPhone 15 Plus' os_version: '17.4' + # needed? + - run: brew install ffmpeg + # Start Appium - run: npm install -g appium - run: | appium driver install xcuitest appium plugin install images appium plugin install execute-driver - nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors --base-path=/wd/hub > appium.log & + nohup appium --use-plugins=images,execute-driver --relaxed-security --log-timestamp --log-no-colors > appium.log & - name: Set up Python 3.9 uses: actions/setup-python@v3 with: python-version: 3.9 - - run: python -m pytest ${{ test_targets.target}} --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - working-directory: test/functional/ios + - run: | + # Separate 'run' creates differnet pipenv env. Does them in one run for now. + pip install --upgrade pip + pip install --upgrade pipenv + pipenv lock --clear + pipenv install -d --system + pytest ${{ matrix.test_targets.target}} --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html - name: Save server output if: ${{ always() }} diff --git a/ci-jobs/functional_test.yml b/ci-jobs/functional_test.yml index b64a0b8e..e4cdf3cb 100644 --- a/ci-jobs/functional_test.yml +++ b/ci-jobs/functional_test.yml @@ -6,22 +6,6 @@ parameters: CI: true jobs: - - template: ./functional/run_ios_test.yml - parameters: - name: 'func_test_ios1' - vmImage: ${{ parameters.vmImage }} - pytestOpt: ${{ parameters.pytestOpt }} - testFiles: 'search_context/find_by_*.py remote_fs_tests.py safari_tests.py execute_driver_tests.py' - CI: ${{ parameters.ci }} - xcodeForIOS: ${{ parameters.xcodeForIOS }} - - template: ./functional/run_ios_test.yml - parameters: - name: 'func_test_ios2' - vmImage: ${{ parameters.vmImage }} - pytestOpt: ${{ parameters.pytestOpt }} - testFiles: 'applications_tests.py hw_actions_tests.py keyboard_tests.py screen_record_tests.py webdriver_tests.py' - CI: ${{ parameters.ci }} - xcodeForIOS: ${{ parameters.xcodeForIOS }} - template: ./functional/run_android_test.yml parameters: name: 'func_test_android1' diff --git a/test/apps/UICatalog.app.zip b/test/apps/UICatalog.app.zip index 0b112d2e..479d92e5 100644 Binary files a/test/apps/UICatalog.app.zip and b/test/apps/UICatalog.app.zip differ diff --git a/test/functional/ios/helper/desired_capabilities.py b/test/functional/ios/helper/desired_capabilities.py index fc9aa0b7..b0687c35 100644 --- a/test/functional/ios/helper/desired_capabilities.py +++ b/test/functional/ios/helper/desired_capabilities.py @@ -28,7 +28,7 @@ def get_desired_capabilities(app: Optional[str] = None) -> Dict[str, Any]: desired_caps: Dict[str, Any] = { 'deviceName': iphone_device_name(), 'platformName': 'iOS', - 'platformVersion': '15.5', + 'platformVersion': '17.4', 'automationName': 'XCUITest', 'allowTouchIdEnroll': True, 'wdaLocalPort': wda_port(), @@ -70,7 +70,7 @@ def wda_port() -> int: def iphone_device_name() -> str: - prefix = 'iPhone 12' + prefix = 'iPhone 15 Plus' if PytestXdistWorker.NUMBER == PytestXdistWorker.gw(0): return f'{prefix} - 8100' elif PytestXdistWorker.NUMBER == PytestXdistWorker.gw(1): diff --git a/test/functional/ios/helper/test_helper.py b/test/functional/ios/helper/test_helper.py index c3397d7d..0a30de0a 100644 --- a/test/functional/ios/helper/test_helper.py +++ b/test/functional/ios/helper/test_helper.py @@ -24,6 +24,8 @@ class BaseTestCase(object): + IOS_UICATALOG_APP_NAME = 'UIKitCatalog' + def setup_method(self) -> None: desired_caps = desired_capabilities.get_desired_capabilities('UICatalog.app.zip') self.driver = webdriver.Remote(SERVER_URL_BASE, options=XCUITestOptions().load_capabilities(desired_caps)) diff --git a/test/functional/ios/safari_tests.py b/test/functional/ios/safari_tests.py index ed71a19a..47df9b1d 100644 --- a/test/functional/ios/safari_tests.py +++ b/test/functional/ios/safari_tests.py @@ -24,18 +24,44 @@ class TestSafari: def setup_method(self) -> None: caps = get_desired_capabilities() - caps.update({'browserName': 'safari', 'nativeWebTap': True, 'safariIgnoreFraudWarning': True}) + caps.update( + { + 'bundleId': 'com.apple.mobilesafari', + 'nativeWebTap': True, + 'safariIgnoreFraudWarning': True, + 'webviewConnectTimeout': 100000, + } + ) self.driver = webdriver.Remote(SERVER_URL_BASE, options=AppiumOptions().load_capabilities(caps)) + # Fresh iOS 17.4 simulator may not show up the webview context with "safari" + # after a fresh simlator instance creation. + # Re-launch the process could be a workaround in my debugging. + self.driver.terminate_app('com.apple.mobilesafari') + self.driver.activate_app('com.apple.mobilesafari') + def teardown_method(self) -> None: self.driver.quit() def test_context(self) -> None: - assert 'NATIVE_APP' == self.driver.contexts[0] - assert self.driver.contexts[1].startswith('WEBVIEW_') + contexts = self.driver.contexts + assert 'NATIVE_APP' == contexts[0] + assert contexts[1].startswith('WEBVIEW_') + self.driver.switch_to.context(contexts[1]) assert 'WEBVIEW_' in self.driver.current_context def test_get(self) -> None: + ok = False + contexts = self.driver.contexts + for context in contexts: + if context.startswith('WEBVIEW_'): + self.driver.switch_to.context(context) + ok = True + break + + if ok is False: + assert False, 'Could not set WEBVIEW context' + self.driver.get('http://google.com') for _ in range(5): time.sleep(0.5) diff --git a/test/functional/ios/search_context/find_by_element_webelement_tests.py b/test/functional/ios/search_context/find_by_element_webelement_tests.py index 94ee552e..163c2320 100644 --- a/test/functional/ios/search_context/find_by_element_webelement_tests.py +++ b/test/functional/ios/search_context/find_by_element_webelement_tests.py @@ -18,14 +18,14 @@ class TestFindByElementWebelement(BaseTestCase): def test_find_element_by_path(self) -> None: - el = self.driver.find_element(by=AppiumBy.IOS_PREDICATE, value='wdName == "UICatalog"') - assert 'UICatalog' == el.get_attribute('name') + el = self.driver.find_element(by=AppiumBy.IOS_PREDICATE, value='wdName == "UIKitCatalog"') + assert self.IOS_UICATALOG_APP_NAME == el.get_attribute('name') - c_el = el.find_elements(by=AppiumBy.IOS_PREDICATE, value='label == "Action Sheets"') # type: list - assert 'Action Sheets' == c_el[0].get_attribute('name') + c_el = el.find_elements(by=AppiumBy.IOS_PREDICATE, value='label == "UIKitCatalog"') # type: list + assert self.IOS_UICATALOG_APP_NAME == c_el[0].get_attribute('name') c_el = el.find_elements(by=AppiumBy.IOS_CLASS_CHAIN, value='**/XCUIElementTypeStaticText') - assert 'UICatalog' == c_el[0].get_attribute('name') + assert self.IOS_UICATALOG_APP_NAME == c_el[0].get_attribute('name') - c_el = el.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value='UICatalog') - assert 'UICatalog' == c_el[0].get_attribute('name') + c_el = el.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value='UIKitCatalog') + assert self.IOS_UICATALOG_APP_NAME == c_el[0].get_attribute('name') diff --git a/test/functional/ios/search_context/find_by_ios_class_chain_tests.py b/test/functional/ios/search_context/find_by_ios_class_chain_tests.py index 39549065..6836ffc7 100644 --- a/test/functional/ios/search_context/find_by_ios_class_chain_tests.py +++ b/test/functional/ios/search_context/find_by_ios_class_chain_tests.py @@ -18,14 +18,12 @@ class TestFindByIOClassChain(BaseTestCase): def test_find_element_by_path(self) -> None: + el = self.driver.find_element(by=AppiumBy.IOS_CLASS_CHAIN, value='**/XCUIElementTypeNavigationBar') + assert self.IOS_UICATALOG_APP_NAME == el.get_attribute('name') + + def test_find_multiple_elements_by_path(self) -> None: els = self.driver.find_elements( by=AppiumBy.IOS_CLASS_CHAIN, value='XCUIElementTypeWindow/**/XCUIElementTypeStaticText' ) - assert 35 == len(els) - assert 'UICatalog' == els[0].get_attribute('name') - - def test_find_multiple_elements_by_path(self) -> None: - el = self.driver.find_elements(by=AppiumBy.IOS_CLASS_CHAIN, value='XCUIElementTypeWindow/*/*/*') - assert 2 == len(el) - assert 'UICatalog' == el[0].get_attribute('name') - assert el[1].get_attribute('name') is None + assert 37 == len(els) + assert self.IOS_UICATALOG_APP_NAME == els[0].get_attribute('name')