import os
import subprocess
import sys
import time
import unittest
from typing import Final
from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, os.pardir, "desktop"))
from desktoptest import name_has_owner, start_kactivitymanagerd
WIDGET_ID: Final = "org.kde.plasma.kickoff"
KDE_VERSION: Final = 6
class KickoffTests(unittest.TestCase):
driver: webdriver.Remote
kactivitymanagerd: subprocess.Popen | None = None
@classmethod
def setUpClass(cls) -> None:
cls.kactivitymanagerd = start_kactivitymanagerd()
options = AppiumOptions()
options.set_capability("environ", {
"LC_ALL": "en_US.UTF-8",
})
options.set_capability("app", f"plasmawindowed -p org.kde.plasma.desktop {WIDGET_ID}")
options.set_capability("timeouts", {'implicit': 10000})
cls.driver = webdriver.Remote(command_executor='http://127.0.0.1:4723', options=options)
@classmethod
def tearDownClass(self) -> None:
subprocess.check_call([f"kquitapp{KDE_VERSION}", "plasmawindowed"])
self.driver.quit()
if self.kactivitymanagerd is not None:
self.kactivitymanagerd.terminate()
self.kactivitymanagerd.wait()
def tearDown(self) -> None:
"""
Take screenshot when the current test fails
"""
if not self._outcome.result.wasSuccessful():
self.driver.get_screenshot_as_file(f"failed_test_shot_{WIDGET_ID}_#{self.id()}.png")
print(self.driver.page_source, file=sys.stderr)
def test_1_keyboard_navigation(self) -> None:
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
first_favorite = focused_elements[0].id
self.assertIn("KickoffGridDelegate", focused_elements[0].get_attribute('accessibility-id'))
ActionChains(self.driver).send_keys(Keys.RIGHT).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertNotEqual(first_favorite, focused_elements[0].id)
ActionChains(self.driver).send_keys(Keys.LEFT).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//table_cell[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertEqual(first_favorite, focused_elements[0].id)
ActionChains(self.driver).key_down(Keys.SHIFT).send_keys(Keys.TAB).key_up(Keys.ALT).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//list_item[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertNotEqual(first_favorite, focused_elements[0].id)
favorites_category = focused_elements[0].id
ActionChains(self.driver).send_keys(Keys.DOWN).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//list_item[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertNotEqual(favorites_category, focused_elements[0].id)
ActionChains(self.driver).send_keys(Keys.RIGHT).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//list_item[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertNotEqual(favorites_category, focused_elements[0].id)
self.assertNotEqual(first_favorite, focused_elements[0].id)
self.assertNotIn("KickoffGridDelegate", focused_elements[0].get_attribute('accessibility-id'))
first_all_app = focused_elements[0].id
ActionChains(self.driver).send_keys(Keys.DOWN).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//list_item[contains(@states, 'focused')]")
self.assertEqual(len(focused_elements), 1)
self.assertNotEqual(first_all_app, focused_elements[0].id)
ActionChains(self.driver).send_keys(Keys.TAB).perform()
focused_elements = self.driver.find_elements(by=AppiumBy.XPATH, value="//page_tab[contains(@states, 'focused') and @name='Applications']")
self.assertEqual(len(focused_elements), 1)
ActionChains(self.driver).send_keys(Keys.RIGHT).perform()
self.driver.find_element(AppiumBy.NAME, "Frequently Used")
ActionChains(self.driver).send_keys(Keys.RIGHT).perform()
try:
self.driver.find_element(by=AppiumBy.XPATH, value="//push_button_menu[contains(@states, 'focused') and @name='Session']")
except NoSuchElementException:
self.driver.find_element(by=AppiumBy.XPATH, value="//button[contains(@states, 'focused') and @name='Sleep']")
def test_2_search_calculator(self) -> None:
search_field = self.driver.find_element(by=AppiumBy.NAME, value="Search")
search_field.send_keys("1")
search_field.send_keys("2345+67890")
element = self.driver.find_element(by=AppiumBy.CLASS_NAME, value="[list item | 80235]")
search_field.clear()
WebDriverWait(self.driver, 5).until_not(lambda _: element.is_displayed())
def test_3_search_app(self) -> None:
search_field = self.driver.find_element(by=AppiumBy.NAME, value="Search")
search_field.send_keys("Emoji Selector")
element = self.driver.find_element(by=AppiumBy.CLASS_NAME, value="[list item | Emoji Selector]")
element.click()
WebDriverWait(self.driver, 5).until(lambda _: name_has_owner(None, "org.kde.plasma.emojier"))
subprocess.check_call([f"kquitapp{KDE_VERSION}", "plasma.emojier"])
search_field.clear()
WebDriverWait(self.driver, 5).until_not(lambda _: element.is_displayed())
if __name__ == '__main__':
unittest.main()