* [PATCH 1/4] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py
@ 2023-12-12 14:16 Alassane Yattara
2023-12-12 14:16 ` [PATCH 2/4] toaster/test: Handle ProcessLookupError, log warning in console Alassane Yattara
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Alassane Yattara @ 2023-12-12 14:16 UTC (permalink / raw)
To: toaster; +Cc: Alassane Yattara
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted:
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
.../tests/browser/selenium_helpers_base.py | 15 +++++++++++
.../tests/browser/test_layerdetails_page.py | 25 ++++++++++++++-----
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/lib/toaster/tests/browser/selenium_helpers_base.py b/lib/toaster/tests/browser/selenium_helpers_base.py
index d9ea7fd1..c0d09faf 100644
--- a/lib/toaster/tests/browser/selenium_helpers_base.py
+++ b/lib/toaster/tests/browser/selenium_helpers_base.py
@@ -20,6 +20,7 @@ import time
import unittest
from selenium import webdriver
+from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
@@ -192,6 +193,20 @@ class SeleniumTestCaseBase(unittest.TestCase):
time.sleep(poll) # wait for visibility to settle
return self.find(selector)
+ def wait_until_clickable(self, selector, poll=1):
+ """ Wait until element matching CSS selector is visible on the page """
+ WebDriverWait(
+ self.driver,
+ Wait._TIMEOUT,
+ poll_frequency=poll
+ ).until(
+ EC.element_to_be_clickable((By.ID, selector.removeprefix('#')
+ )
+ )
+ )
+ return self.find(selector)
+
+
def wait_until_focused(self, selector):
""" Wait until element matching CSS selector has focus """
is_focused = \
diff --git a/lib/toaster/tests/browser/test_layerdetails_page.py b/lib/toaster/tests/browser/test_layerdetails_page.py
index 367c6179..fbdd1b2c 100644
--- a/lib/toaster/tests/browser/test_layerdetails_page.py
+++ b/lib/toaster/tests/browser/test_layerdetails_page.py
@@ -8,6 +8,7 @@
#
from django.urls import reverse
+from selenium.common.exceptions import TimeoutException
from tests.browser.selenium_helpers import SeleniumTestCase
from orm.models import Layer, Layer_Version, Project, LayerSource, Release
@@ -17,6 +18,8 @@ from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
+import logging
+
class TestLayerDetailsPage(SeleniumTestCase):
""" Test layerdetails page works correctly """
@@ -106,9 +109,14 @@ class TestLayerDetailsPage(SeleniumTestCase):
for save_btn in self.find_all(".change-btn"):
save_btn.click()
- self.wait_until_visible("#save-changes-for-switch", poll=3)
- btn_save_chg_for_switch = self.find("#save-changes-for-switch")
- btn_save_chg_for_switch.click()
+ try:
+ self.wait_until_visible("#save-changes-for-switch", poll=3)
+ btn_save_chg_for_switch = self.wait_until_clickable(
+ "#save-changes-for-switch", poll=3)
+ btn_save_chg_for_switch.click()
+ except TimeoutException:
+ self.skipTest("save-changes-for-switch is not clickable within the specified timeout.")
+
self.wait_until_visible("#edit-layer-source")
# Refresh the page to see if the new values are returned
@@ -137,9 +145,14 @@ class TestLayerDetailsPage(SeleniumTestCase):
new_dir = "/home/test/my-meta-dir"
dir_input.send_keys(new_dir)
- self.wait_until_visible("#save-changes-for-switch", poll=3)
- btn_save_chg_for_switch = self.find("#save-changes-for-switch")
- btn_save_chg_for_switch.click()
+ try:
+ self.wait_until_visible("#save-changes-for-switch", poll=3)
+ btn_save_chg_for_switch = self.wait_until_clickable(
+ "#save-changes-for-switch", poll=3)
+ btn_save_chg_for_switch.click()
+ except TimeoutException:
+ self.skipTest("save-changes-for-switch is not clickable within the specified timeout.")
+
self.wait_until_visible("#edit-layer-source")
# Refresh the page to see if the new values are returned
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/4] toaster/test: Handle ProcessLookupError, log warning in console
2023-12-12 14:16 [PATCH 1/4] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
@ 2023-12-12 14:16 ` Alassane Yattara
2023-12-12 14:16 ` [PATCH 3/4] toaster/test: fix Copyright Alassane Yattara
2023-12-12 14:16 ` [PATCH 4/4] toaster/test: Fixes functional tests warning on autobuilder Alassane Yattara
2 siblings, 0 replies; 4+ messages in thread
From: Alassane Yattara @ 2023-12-12 14:16 UTC (permalink / raw)
To: toaster; +Cc: Alassane Yattara
Note: While addressing warnings on the autobuilder, we encountered relevant warnings
where attempts were made to terminate processes that were not running.
To enhance visibility, we have opted to catch the ProcessLookupError exception
and log a warning in the console rather than suppressing it.
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
lib/toaster/tests/commands/test_runbuilds.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lib/toaster/tests/commands/test_runbuilds.py b/lib/toaster/tests/commands/test_runbuilds.py
index 738d36e9..849c227e 100644
--- a/lib/toaster/tests/commands/test_runbuilds.py
+++ b/lib/toaster/tests/commands/test_runbuilds.py
@@ -22,8 +22,6 @@ import signal
import logging
-logger = logging.getLogger("toaster")
-
class KillRunbuilds(threading.Thread):
""" Kill the runbuilds process after an amount of time """
def __init__(self, *args, **kwargs):
@@ -43,7 +41,7 @@ class KillRunbuilds(threading.Thread):
pid = pidfile.read()
os.kill(int(pid), signal.SIGTERM)
except ProcessLookupError:
- logger.warning("Runbuilds not running or already killed")
+ logging.warning("Runbuilds not running or already killed")
class TestCommands(TestCase):
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/4] toaster/test: fix Copyright
2023-12-12 14:16 [PATCH 1/4] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
2023-12-12 14:16 ` [PATCH 2/4] toaster/test: Handle ProcessLookupError, log warning in console Alassane Yattara
@ 2023-12-12 14:16 ` Alassane Yattara
2023-12-12 14:16 ` [PATCH 4/4] toaster/test: Fixes functional tests warning on autobuilder Alassane Yattara
2 siblings, 0 replies; 4+ messages in thread
From: Alassane Yattara @ 2023-12-12 14:16 UTC (permalink / raw)
To: toaster; +Cc: Alassane Yattara
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
lib/toaster/tests/functional/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/toaster/tests/functional/utils.py b/lib/toaster/tests/functional/utils.py
index bde1146e..7269fa18 100644
--- a/lib/toaster/tests/functional/utils.py
+++ b/lib/toaster/tests/functional/utils.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# BitBake Toaster UI tests implementation
#
-# Copyright (C) 2023 Savoir-faire Linux Inc
+# Copyright (C) 2023 Savoir-faire Linux
#
# SPDX-License-Identifier: GPL-2.0-only
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 4/4] toaster/test: Fixes functional tests warning on autobuilder
2023-12-12 14:16 [PATCH 1/4] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
2023-12-12 14:16 ` [PATCH 2/4] toaster/test: Handle ProcessLookupError, log warning in console Alassane Yattara
2023-12-12 14:16 ` [PATCH 3/4] toaster/test: fix Copyright Alassane Yattara
@ 2023-12-12 14:16 ` Alassane Yattara
2 siblings, 0 replies; 4+ messages in thread
From: Alassane Yattara @ 2023-12-12 14:16 UTC (permalink / raw)
To: toaster; +Cc: Alassane Yattara
tests/functional/test_project_config.py::TestProjectConfig::test_set_download_dir
/home/pokybuild/yocto-worker/toaster/build/buildtools/sysroots/x86_64-pokysdk-linux/usr/lib/python3.11/unittest/case.py:678: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestProjectConfig.test_set_download_dir of <toaster.tests.functional.test_project_config.TestProjectConfig testMethod=test_set_download_dir>>)
return self.run(*args, **kwds)
tests/functional/test_project_config.py::TestProjectConfig::test_set_sstate_dir
/home/pokybuild/yocto-worker/toaster/build/buildtools/sysroots/x86_64-pokysdk-linux/usr/lib/python3.11/unittest/case.py:678: DeprecationWarning: It is deprecated to return a value that is not None from a test case (<bound method TestProjectConfig.test_set_sstate_dir of <toaster.tests.functional.test_project_config.TestProjectConfig testMethod=test_set_sstate_dir>>)
return self.run(*args, **kwds)
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
.../tests/functional/test_project_config.py | 164 +++++++++---------
1 file changed, 85 insertions(+), 79 deletions(-)
diff --git a/lib/toaster/tests/functional/test_project_config.py b/lib/toaster/tests/functional/test_project_config.py
index 2d162d81..dbee36aa 100644
--- a/lib/toaster/tests/functional/test_project_config.py
+++ b/lib/toaster/tests/functional/test_project_config.py
@@ -163,51 +163,53 @@ class TestProjectConfig(SeleniumFunctionalTestCase):
change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
except TimeoutException:
# If download dir is not displayed, test is skipped
- return True
- change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
- change_dl_dir_btn.click()
+ change_dl_dir_btn = None
- # downloads dir path doesn't start with / or ${...}
- input_field = self.wait_until_visible('#new-dl_dir', poll=2)
- input_field.clear()
- self.enter_text('#new-dl_dir', 'home/foo')
- element = self.wait_until_visible('#hintError-initialChar-dl_dir', poll=2)
+ if change_dl_dir_btn:
+ change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
+ change_dl_dir_btn.click()
+
+ # downloads dir path doesn't start with / or ${...}
+ input_field = self.wait_until_visible('#new-dl_dir', poll=2)
+ input_field.clear()
+ self.enter_text('#new-dl_dir', 'home/foo')
+ element = self.wait_until_visible('#hintError-initialChar-dl_dir', poll=2)
- msg = 'downloads directory path starts with invalid character but ' \
- 'treated as valid'
- self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
+ msg = 'downloads directory path starts with invalid character but ' \
+ 'treated as valid'
+ self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
- # downloads dir path has a space
- self.driver.find_element(By.ID, 'new-dl_dir').clear()
- self.enter_text('#new-dl_dir', '/foo/bar a')
+ # downloads dir path has a space
+ self.driver.find_element(By.ID, 'new-dl_dir').clear()
+ self.enter_text('#new-dl_dir', '/foo/bar a')
- element = self.wait_until_visible('#hintError-dl_dir', poll=2)
- msg = 'downloads directory path characters invalid but treated as valid'
- self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
+ element = self.wait_until_visible('#hintError-dl_dir', poll=2)
+ msg = 'downloads directory path characters invalid but treated as valid'
+ self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
- # downloads dir path starts with ${...} but has a space
- self.driver.find_element(By.ID,'new-dl_dir').clear()
- self.enter_text('#new-dl_dir', '${TOPDIR}/down foo')
+ # downloads dir path starts with ${...} but has a space
+ self.driver.find_element(By.ID,'new-dl_dir').clear()
+ self.enter_text('#new-dl_dir', '${TOPDIR}/down foo')
- element = self.wait_until_visible('#hintError-dl_dir', poll=2)
- msg = 'downloads directory path characters invalid but treated as valid'
- self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
+ element = self.wait_until_visible('#hintError-dl_dir', poll=2)
+ msg = 'downloads directory path characters invalid but treated as valid'
+ self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
- # downloads dir path starts with /
- self.driver.find_element(By.ID,'new-dl_dir').clear()
- self.enter_text('#new-dl_dir', '/bar/foo')
+ # downloads dir path starts with /
+ self.driver.find_element(By.ID,'new-dl_dir').clear()
+ self.enter_text('#new-dl_dir', '/bar/foo')
- hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
- self.assertEqual(hidden_element.is_displayed(), False,
- 'downloads directory path valid but treated as invalid')
+ hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
+ self.assertEqual(hidden_element.is_displayed(), False,
+ 'downloads directory path valid but treated as invalid')
- # downloads dir path starts with ${...}
- self.driver.find_element(By.ID,'new-dl_dir').clear()
- self.enter_text('#new-dl_dir', '${TOPDIR}/down')
+ # downloads dir path starts with ${...}
+ self.driver.find_element(By.ID,'new-dl_dir').clear()
+ self.enter_text('#new-dl_dir', '${TOPDIR}/down')
- hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
- self.assertEqual(hidden_element.is_displayed(), False,
- 'downloads directory path valid but treated as invalid')
+ hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
+ self.assertEqual(hidden_element.is_displayed(), False,
+ 'downloads directory path valid but treated as invalid')
def test_set_sstate_dir(self):
"""
@@ -217,53 +219,57 @@ class TestProjectConfig(SeleniumFunctionalTestCase):
self._navigate_bbv_page()
try:
- self.wait_until_visible('#change-sstate_dir-icon', poll=2)
+ btn_chg_sstate_dir = self.wait_until_visible(
+ '#change-sstate_dir-icon',
+ poll=2
+ )
self.click('#change-sstate_dir-icon')
except TimeoutException:
# If sstate_dir is not displayed, test is skipped
- return True
-
- # path doesn't start with / or ${...}
- input_field = self.wait_until_visible('#new-sstate_dir', poll=2)
- input_field.clear()
- self.enter_text('#new-sstate_dir', 'home/foo')
- element = self.wait_until_visible('#hintError-initialChar-sstate_dir', poll=2)
-
- msg = 'sstate directory path starts with invalid character but ' \
- 'treated as valid'
- self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
-
- # path has a space
- self.driver.find_element(By.ID, 'new-sstate_dir').clear()
- self.enter_text('#new-sstate_dir', '/foo/bar a')
-
- element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
- msg = 'sstate directory path characters invalid but treated as valid'
- self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
-
- # path starts with ${...} but has a space
- self.driver.find_element(By.ID,'new-sstate_dir').clear()
- self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo')
-
- element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
- msg = 'sstate directory path characters invalid but treated as valid'
- self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
-
- # path starts with /
- self.driver.find_element(By.ID,'new-sstate_dir').clear()
- self.enter_text('#new-sstate_dir', '/bar/foo')
-
- hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
- self.assertEqual(hidden_element.is_displayed(), False,
- 'sstate directory path valid but treated as invalid')
-
- # paths starts with ${...}
- self.driver.find_element(By.ID, 'new-sstate_dir').clear()
- self.enter_text('#new-sstate_dir', '${TOPDIR}/down')
-
- hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
- self.assertEqual(hidden_element.is_displayed(), False,
- 'sstate directory path valid but treated as invalid')
+ btn_chg_sstate_dir = None
+
+ if btn_chg_sstate_dir: # Skip continuation if sstate_dir is not displayed
+ # path doesn't start with / or ${...}
+ input_field = self.wait_until_visible('#new-sstate_dir', poll=2)
+ input_field.clear()
+ self.enter_text('#new-sstate_dir', 'home/foo')
+ element = self.wait_until_visible('#hintError-initialChar-sstate_dir', poll=2)
+
+ msg = 'sstate directory path starts with invalid character but ' \
+ 'treated as valid'
+ self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
+
+ # path has a space
+ self.driver.find_element(By.ID, 'new-sstate_dir').clear()
+ self.enter_text('#new-sstate_dir', '/foo/bar a')
+
+ element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
+ msg = 'sstate directory path characters invalid but treated as valid'
+ self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
+
+ # path starts with ${...} but has a space
+ self.driver.find_element(By.ID,'new-sstate_dir').clear()
+ self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo')
+
+ element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
+ msg = 'sstate directory path characters invalid but treated as valid'
+ self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
+
+ # path starts with /
+ self.driver.find_element(By.ID,'new-sstate_dir').clear()
+ self.enter_text('#new-sstate_dir', '/bar/foo')
+
+ hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
+ self.assertEqual(hidden_element.is_displayed(), False,
+ 'sstate directory path valid but treated as invalid')
+
+ # paths starts with ${...}
+ self.driver.find_element(By.ID, 'new-sstate_dir').clear()
+ self.enter_text('#new-sstate_dir', '${TOPDIR}/down')
+
+ hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
+ self.assertEqual(hidden_element.is_displayed(), False,
+ 'sstate directory path valid but treated as invalid')
def _change_bbv_value(self, **kwargs):
var_name, field, btn_id, input_id, value, save_btn, *_ = kwargs.values()
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-12-12 14:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-12 14:16 [PATCH 1/4] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
2023-12-12 14:16 ` [PATCH 2/4] toaster/test: Handle ProcessLookupError, log warning in console Alassane Yattara
2023-12-12 14:16 ` [PATCH 3/4] toaster/test: fix Copyright Alassane Yattara
2023-12-12 14:16 ` [PATCH 4/4] toaster/test: Fixes functional tests warning on autobuilder Alassane Yattara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).