From 683533fa35eac768f3fa8f094e2e2e18d3e91489 Mon Sep 17 00:00:00 2001 From: =?utf8?q?M=C3=A9ven=20Car?= Date: Tue, 23 Apr 2024 18:06:32 +0000 Subject: [PATCH] Add two first appium tests that run on CI Based upon @mart https://invent.kde.org/system/dolphin/-/merge_requests/492/diffs Co-authored-by: Marco Martin --- .kde-ci.yml | 5 ++ CMakeLists.txt | 1 + appiumtests/CMakeLists.txt | 24 +++++++ appiumtests/Readme.md | 7 ++ appiumtests/dolphintest.py | 127 +++++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 appiumtests/CMakeLists.txt create mode 100644 appiumtests/Readme.md create mode 100755 appiumtests/dolphintest.py diff --git a/.kde-ci.yml b/.kde-ci.yml index 6e9b82854..3c0b4deaf 100644 --- a/.kde-ci.yml +++ b/.kde-ci.yml @@ -38,3 +38,8 @@ Dependencies: - 'on': ['Linux/Qt6', 'Windows/Qt6', 'macOS/Qt6'] 'require': 'network/kio-extras': '@latest-kf6' + +RuntimeDependencies: +- 'on': ['Linux'] + 'require': + 'sdk/selenium-webdriver-at-spi': '@latest-kf6' diff --git a/CMakeLists.txt b/CMakeLists.txt index 529776933..bd6269398 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,7 @@ endif() add_subdirectory(src) add_subdirectory(doc) +add_subdirectory(appiumtests) # CMake files set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/DolphinVcs") diff --git a/appiumtests/CMakeLists.txt b/appiumtests/CMakeLists.txt new file mode 100644 index 000000000..3c1bb8c21 --- /dev/null +++ b/appiumtests/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: BSD-3-Clause +# SPDX-FileCopyrightText: 2022 Harald Sitter + +if(NOT BUILD_TESTING OR NOT CMAKE_SYSTEM_NAME MATCHES "Linux") + return() +endif() + +find_package(SeleniumWebDriverATSPI) +set_package_properties(SeleniumWebDriverATSPI PROPERTIES + DESCRIPTION "Server component for selenium tests using Linux accessibility infrastructure" + PURPOSE "Needed for GUI tests" + URL "https://invent.kde.org/sdk/selenium-webdriver-at-spi" + TYPE OPTIONAL +) +if(NOT SeleniumWebDriverATSPI_FOUND AND NOT DEFINED ENV{KDECI_BUILD}) + return() +endif() + +add_test( + NAME dolphintest + COMMAND selenium-webdriver-at-spi-run ${CMAKE_CURRENT_SOURCE_DIR}/dolphintest.py +) +set_tests_properties(dolphintest PROPERTIES TIMEOUT 300 ENVIRONMENT "CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR}/bin") + diff --git a/appiumtests/Readme.md b/appiumtests/Readme.md new file mode 100644 index 000000000..eac841e58 --- /dev/null +++ b/appiumtests/Readme.md @@ -0,0 +1,7 @@ + +Instructions: + +chmod u+x dolphintest.py +python3 -m venv .venv +source .venv/bin/activate +selenium-webdriver-at-spi-run ./dolphintest.py diff --git a/appiumtests/dolphintest.py b/appiumtests/dolphintest.py new file mode 100755 index 000000000..f0df3941e --- /dev/null +++ b/appiumtests/dolphintest.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2022 Harald Sitter +# SPDX-FileCopyrightText: 2023 Marco Martin + +import unittest +from appium import webdriver +from appium.webdriver.common.appiumby import AppiumBy +from appium.options.common.base import AppiumOptions +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.by import By +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.support import expected_conditions as EC +import time +import os +import sys + +import time + +class DolphinTests(unittest.TestCase): + @classmethod + def setUpClass(self): + options = AppiumOptions() + options.set_capability("timeouts", {'implicit': 10000}) + options.set_capability("app", "org.kde.dolphin.desktop") + options.set_capability("environ", { + "LC_ALL": "en_US.UTF-8", + }) + + self.driver = webdriver.Remote( + command_executor='http://127.0.0.1:4723', + options=options) + self.driver.implicitly_wait = 10 + filename = "{}/testDir/test1.txt".format(os.environ["HOME"]) + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, "w") as f: + f.write("Test File 1") + filename = "{}/testDir/test2.txt".format(os.environ["HOME"]) + with open(filename, "w") as f: + f.write("Test File 2") + + def tearDown(self): + if not self._outcome.result.wasSuccessful(): + self.driver.get_screenshot_as_file("failed_test_shot_{}.png".format(self.id())) + + @classmethod + def tearDownClass(self): + os.remove("{}/testDir/test1.txt".format(os.environ["HOME"])) + os.remove("{}/testDir/test2.txt".format(os.environ["HOME"])) + os.rmdir("{}/testDir".format(os.environ["HOME"])) + self.driver.quit() + + def assertResult(self, actual, expected): + wait = WebDriverWait(self.driver, 20) + wait.until(lambda x: self.getresults() == expected) + self.assertEqual(self.getresults(), expected) + + def test_1_location(self): + editButton = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="KUrlNavigatorToggleButton") + editButton.click() + + # clear contents + self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="DolphinUrlNavigator.KUrlComboBox.KLineEdit.QLineEditIconButton").click() + + locationBar = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="DolphinUrlNavigator.KUrlComboBox.KLineEdit") + locationBar.send_keys("{}/testDir".format(os.environ["HOME"])) + editButton.click() + + elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell") + self.assertEqual(len(elements), 2) + self.assertEqual(elements[0].text, "test1.txt") + self.assertEqual(elements[1].text, "test2.txt") + + def test_2_filter_bar(self): + ActionChains(self.driver).send_keys(Keys.DIVIDE).perform() + + searchField = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="Filter.QScrollArea.qt_scrollarea_viewport.QWidget.FilterLineEdit") + searchField.send_keys("test2.txt") + self.assertEqual(searchField.text, "test2.txt") + elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell") + self.assertEqual(len(elements), 1) + self.assertEqual(elements[0].text, "test2.txt") + + # should see both files now + buttons = self.driver.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value="Filter.QScrollArea.qt_scrollarea_viewport.QWidget.QToolButton") + self.assertEqual(len(buttons), 2) + # close buttion is the second QToolButton + close_button=buttons[1] + self.assertIsNotNone(close_button) + close_button.click() + + elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell") + self.assertEqual(len(elements), 2) + self.assertEqual(elements[0].text, "test1.txt") + self.assertEqual(elements[1].text, "test2.txt") + + +""" + def test_search_bar(self): + ActionChains(self.driver).key_down(Keys.CONTROL).send_keys("f").key_up(Keys.CONTROL).perform() + + #self.driver.pause(0.1) + searchField = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="DolphinSearchBox.QScrollArea.qt_scrollarea_viewport.QWidget.searchField") + searchField.send_keys("test1.txt") + self.assertEqual(searchField.text, "test1.txt") + + + # TODO the search does not work, filenamesearch:/ does not return any result + time.sleep(1) + elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell") + self.assertEqual(len(elements), 1) + self.assertEqual(elements[0].text, "test1.txt") + + # click on leave search + self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="DolphinSearchBox.QScrollArea.qt_scrollarea_viewport.QWidget.QToolButton").click() + # should see both files now + elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell") + self.assertEqual(len(elements), 2) + self.assertEqual(elements[0].text, "test2.txt") + self.assertEqual(elements[1].text, "test1.txt") +""" + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(DolphinTests) + unittest.TextTestRunner(verbosity=2).run(suite) -- 2.47.3