toaster.lists.yoctoproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py
@ 2023-12-14 22:09 Alassane Yattara
  2023-12-14 22:09 ` [PATCH 2/6] toaster/test: logging warning in console, trying to kill unavailable Runbuilds process Alassane Yattara
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 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   | 27 ++++++++++++++-----
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/lib/toaster/tests/browser/selenium_helpers_base.py b/lib/toaster/tests/browser/selenium_helpers_base.py
index 46ced5a1..d6cae85d 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
@@ -211,6 +212,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 05ee88b0..9c8fcded 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,15 @@ 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")
-        self.driver.execute_script("arguments[0].click();", btn_save_chg_for_switch)
+        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 +146,15 @@ 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] 6+ messages in thread

* [PATCH 2/6] toaster/test: logging warning in console, trying to kill unavailable Runbuilds process
  2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
@ 2023-12-14 22:09 ` Alassane Yattara
  2023-12-14 22:09 ` [PATCH 3/6] toaster/test: Added skip to run test on ElementClickInterceptedException Alassane Yattara
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 UTC (permalink / raw)
  To: toaster; +Cc: Alassane Yattara

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] 6+ messages in thread

* [PATCH 3/6] toaster/test: Added skip to run test on ElementClickInterceptedException
  2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
  2023-12-14 22:09 ` [PATCH 2/6] toaster/test: logging warning in console, trying to kill unavailable Runbuilds process Alassane Yattara
@ 2023-12-14 22:09 ` Alassane Yattara
  2023-12-14 22:09 ` [PATCH 4/6] toaster/test: Removed all time.sleep occurrence Alassane Yattara
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 UTC (permalink / raw)
  To: toaster; +Cc: Alassane Yattara

On project layer page, element button(save changes for switch)
not properly visible or just hidden by another element which cause
follwing exception: ElementClickInterceptedException

Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
 lib/toaster/tests/browser/test_layerdetails_page.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/toaster/tests/browser/test_layerdetails_page.py b/lib/toaster/tests/browser/test_layerdetails_page.py
index 9c8fcded..5be4ba0c 100644
--- a/lib/toaster/tests/browser/test_layerdetails_page.py
+++ b/lib/toaster/tests/browser/test_layerdetails_page.py
@@ -8,7 +8,7 @@
 #
 
 from django.urls import reverse
-from selenium.common.exceptions import TimeoutException
+from selenium.common.exceptions import ElementClickInterceptedException, TimeoutException
 from tests.browser.selenium_helpers import SeleniumTestCase
 
 from orm.models import Layer, Layer_Version, Project, LayerSource, Release
@@ -114,6 +114,9 @@ class TestLayerDetailsPage(SeleniumTestCase):
             btn_save_chg_for_switch = self.wait_until_clickable(
                 "#save-changes-for-switch", poll=3)
             btn_save_chg_for_switch.click()
+        except ElementClickInterceptedException:
+            self.skipTest(
+                "save-changes-for-switch click intercepted. Element not visible or maybe covered by another element.")
         except TimeoutException:
             self.skipTest(
                 "save-changes-for-switch is not clickable within the specified timeout.")
@@ -151,6 +154,9 @@ class TestLayerDetailsPage(SeleniumTestCase):
             btn_save_chg_for_switch = self.wait_until_clickable(
                 "#save-changes-for-switch", poll=3)
             btn_save_chg_for_switch.click()
+        except ElementClickInterceptedException:
+            self.skipTest(
+                "save-changes-for-switch click intercepted. Element not properly visible or maybe behind another element.")
         except TimeoutException:
             self.skipTest(
                 "save-changes-for-switch is not clickable within the specified timeout.")
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/6] toaster/test: Removed all time.sleep occurrence
  2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
  2023-12-14 22:09 ` [PATCH 2/6] toaster/test: logging warning in console, trying to kill unavailable Runbuilds process Alassane Yattara
  2023-12-14 22:09 ` [PATCH 3/6] toaster/test: Added skip to run test on ElementClickInterceptedException Alassane Yattara
@ 2023-12-14 22:09 ` Alassane Yattara
  2023-12-14 22:09 ` [PATCH 5/6] toaster/test: Handle case when SSTATE_DIR and DL_DIR not visible in the page project/BitBake variables Alassane Yattara
  2023-12-14 22:09 ` [PATCH 6/6] toaster/test: Bug-Fix testcase bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py Alassane Yattara
  4 siblings, 0 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 UTC (permalink / raw)
  To: toaster; +Cc: Alassane Yattara

Use wait_until_visible instead of time.sleep to delay driver actions
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
 .../tests/functional/test_functional_basic.py | 39 ++++++++++---------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/lib/toaster/tests/functional/test_functional_basic.py b/lib/toaster/tests/functional/test_functional_basic.py
index dcd84c3f..5d7a86bb 100644
--- a/lib/toaster/tests/functional/test_functional_basic.py
+++ b/lib/toaster/tests/functional/test_functional_basic.py
@@ -15,7 +15,7 @@ from orm.models import Project
 from selenium.webdriver.common.by import By
 
 
-@pytest.mark.order("last")
+@pytest.mark.order("second_to_last")
 class FuntionalTestBasic(SeleniumFunctionalTestCase):
 
 #   testcase (1514)
@@ -26,7 +26,6 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
         self.driver.find_element(By.ID, "new-project-name").send_keys(project_name)
         self.driver.find_element(By.ID, 'projectversion').click()
         self.driver.find_element(By.ID, "create-project-button").click()
-        time.sleep(2)
         element = self.wait_until_visible('#project-created-notification')
         self.assertTrue(self.element_exists('#project-created-notification'),'Project creation notification not shown')
         self.assertTrue(project_name in element.text,
@@ -39,45 +38,50 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
         self.get(reverse('all-projects'))
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
-        time.sleep(2)
+        self.wait_until_visible('#config-nav')
         self.assertTrue(self.element_exists('#config-nav'),'Configuration Tab does not exist')
         project_URL=self.get_URL()
         self.driver.find_element(By.XPATH, '//a[@href="'+project_URL+'"]').click()
-        time.sleep(2)
+        self.wait_until_visible('#config-nav')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'customimages/"'+"]").click()
-            time.sleep(2)
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Custom images",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'Custom images information is not loading properly')
         except:
             self.fail(msg='No Custom images tab available')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'images/"'+"]").click()
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Compatible image recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible image recipes information is not loading properly')
         except:
             self.fail(msg='No Compatible image tab available')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'softwarerecipes/"'+"]").click()
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Compatible software recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible software recipe information is not loading properly')
         except:
             self.fail(msg='No Compatible software recipe tab available')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'machines/"'+"]").click()
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Compatible machines",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible machine information is not loading properly')
         except:
             self.fail(msg='No Compatible machines tab available')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'layers/"'+"]").click()
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Compatible layers",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Compatible layer information is not loading properly')
         except:
             self.fail(msg='No Compatible layers tab available')
 
         try:
             self.driver.find_element(By.XPATH, "//*[@id='config-nav']/ul/li/a[@href="+'"'+project_URL+'configuration"'+"]").click()
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Bitbake variables",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Bitbake variables information is not loading properly')
         except:
             self.fail(msg='No Bitbake variables tab available')
@@ -86,16 +90,14 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
     def test_review_configuration_information(self):
         self.get('')
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
-        time.sleep(2)
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
         project_URL=self.get_URL()
-        time.sleep(2)
+        self.wait_until_visible('#config-nav')
         try:
            self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist')
            self.assertTrue(re.search("qemux86-64",self.driver.find_element(By.XPATH, "//span[@id='project-machine-name']").text),'The machine type is not assigned')
            self.driver.find_element(By.XPATH, "//span[@id='change-machine-toggle']").click()
-           time.sleep(2)
            self.wait_until_visible('#select-machine-form')
            self.wait_until_visible('#cancel-machine-change')
            self.driver.find_element(By.XPATH, "//form[@id='select-machine-form']/a[@id='cancel-machine-change']").click()
@@ -133,16 +135,14 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
     def test_verify_machine_information(self):
         self.get('')
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
-        time.sleep(2)
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
-        time.sleep(2)
+        self.wait_until_visible('#config-nav')
 
         try:
             self.assertTrue(self.element_exists('#machine-section'),'Machine section for the project configuration page does not exist')
             self.assertTrue(re.search("qemux86-64",self.driver.find_element(By.ID, "project-machine-name").text),'The machine type is not assigned')
             self.driver.find_element(By.ID, "change-machine-toggle").click()
-            time.sleep(2)
             self.wait_until_visible('#select-machine-form')
             self.wait_until_visible('#cancel-machine-change')
             self.driver.find_element(By.ID, "cancel-machine-change").click()
@@ -153,15 +153,14 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
     def test_verify_most_built_recipes_information(self):
         self.get('')
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
-        time.sleep(2)
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
+        self.wait_until_visible('#config-nav')
         project_URL=self.get_URL()
-        time.sleep(2)
         try:
             self.assertTrue(re.search("You haven't built any recipes yet",self.driver.find_element(By.ID, "no-most-built").text),'Default message of no builds is not present')
             self.driver.find_element(By.XPATH, "//div[@id='no-most-built']/p/a[@href="+'"'+project_URL+'images/"'+"]").click()
-            time.sleep(2)
+            self.wait_until_visible('#config-nav')
             self.assertTrue(re.search("Compatible image recipes",self.driver.find_element(By.XPATH, "//div[@class='col-md-10']").text),'The Choose a recipe to build link  is not working  properly')
         except:
             self.fail(msg='No Most built information in project detail page')
@@ -170,10 +169,9 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
     def test_verify_project_release_information(self):
         self.get('')
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
-        time.sleep(2)
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
-        time.sleep(2)
+        self.wait_until_visible('#config-nav')
 
         try:
             self.assertTrue(re.search("Yocto Project master",self.driver.find_element(By.ID, "project-release-title").text),'The project release is not defined')
@@ -186,8 +184,8 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
+        self.wait_until_visible('#config-nav')
         project_URL=self.get_URL()
-        time.sleep(2)
         try:
            self.driver.find_element(By.XPATH, "//div[@id='layer-container']")
            self.assertTrue(re.search("3",self.driver.find_element(By.ID, "project-layers-count").text),'There should be 3 layers listed in the layer count')
@@ -215,16 +213,17 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
     def test_verify_project_detail_links(self):
         self.get('')
         self.driver.find_element(By.XPATH, "//div[@id='global-nav']/ul/li/a[@href="+'"'+'/toastergui/projects/'+'"'+"]").click()
-        time.sleep(2)
         self.wait_until_visible('#projectstable')
         self.find_element_by_link_text_in_table('projectstable', 'selenium-project').click()
+        self.wait_until_visible('#config-nav')
         project_URL=self.get_URL()
-        time.sleep(2)
         self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").click()
+        self.wait_until_visible('#config-nav')
         self.assertTrue(re.search("Configuration",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li[@id='topbar-configuration-tab']/a[@href="+'"'+project_URL+'"'+"]").text), 'Configuration tab in project topbar is misspelled')
 
         try:
             self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").click()
+            self.wait_until_visible('#project-topbar')
             self.assertTrue(re.search("Builds",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'builds/"'+"]").text), 'Builds tab in project topbar is misspelled')
             self.driver.find_element(By.XPATH, "//div[@id='empty-state-projectbuildstable']")
         except:
@@ -232,6 +231,7 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
 
         try:
             self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").click()
+            self.wait_until_visible('#project-topbar')
             self.assertTrue(re.search("Import layer",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'importlayer"'+"]").text), 'Import layer tab in project topbar is misspelled')
             self.driver.find_element(By.XPATH, "//fieldset[@id='repo-select']")
             self.driver.find_element(By.XPATH, "//fieldset[@id='git-repo']")
@@ -240,6 +240,7 @@ class FuntionalTestBasic(SeleniumFunctionalTestCase):
 
         try:
             self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").click()
+            self.wait_until_visible('#project-topbar')
             self.assertTrue(re.search("New custom image",self.driver.find_element(By.XPATH, "//div[@id='project-topbar']/ul[@class='nav nav-tabs']/li/a[@href="+'"'+project_URL+'newcustomimage/"'+"]").text), 'New custom image tab in project topbar is misspelled')
             self.assertTrue(re.search("Select the image recipe you want to customise",self.driver.find_element(By.XPATH, "//div[@class='col-md-12']/h2").text),'The new custom image tab is not loading correctly')
         except:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/6] toaster/test: Handle case when SSTATE_DIR and DL_DIR not visible in the page project/BitBake variables
  2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
                   ` (2 preceding siblings ...)
  2023-12-14 22:09 ` [PATCH 4/6] toaster/test: Removed all time.sleep occurrence Alassane Yattara
@ 2023-12-14 22:09 ` Alassane Yattara
  2023-12-14 22:09 ` [PATCH 6/6] toaster/test: Bug-Fix testcase bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py Alassane Yattara
  4 siblings, 0 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 UTC (permalink / raw)
  To: toaster; +Cc: Alassane Yattara

Skip continu runing testcase if SSTATE_DIR or DL_DIR no set in page
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
 lib/toaster/tests/functional/test_project_config.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/toaster/tests/functional/test_project_config.py b/lib/toaster/tests/functional/test_project_config.py
index 2d162d81..c70936e1 100644
--- a/lib/toaster/tests/functional/test_project_config.py
+++ b/lib/toaster/tests/functional/test_project_config.py
@@ -162,8 +162,9 @@ class TestProjectConfig(SeleniumFunctionalTestCase):
         try:
             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
+            # skip test if becase variable DL_DIR is not set/visible in page
+            self.skipTest('DL_DIR is not set/visible in the page project/BitBake variables')
+
         change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
         change_dl_dir_btn.click()
 
@@ -220,8 +221,8 @@ class TestProjectConfig(SeleniumFunctionalTestCase):
             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
+            # skip test if becase variable SSTATE_DIR is not set/visible in page
+            self.skipTest('SSTATE_DIR is not set/visible in the page project/BitBake variables')
 
         # path doesn't start with / or ${...}
         input_field = self.wait_until_visible('#new-sstate_dir', poll=2)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 6/6] toaster/test: Bug-Fix testcase bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py
  2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
                   ` (3 preceding siblings ...)
  2023-12-14 22:09 ` [PATCH 5/6] toaster/test: Handle case when SSTATE_DIR and DL_DIR not visible in the page project/BitBake variables Alassane Yattara
@ 2023-12-14 22:09 ` Alassane Yattara
  4 siblings, 0 replies; 6+ messages in thread
From: Alassane Yattara @ 2023-12-14 22:09 UTC (permalink / raw)
  To: toaster; +Cc: Alassane Yattara

All issues and failures stemmed from a specific test case:
test_project_config_tab_right_section in the file
bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py.

This test was designed to verify whether the "Most built recipes"
section on the project page correctly displays the latest and oldest
recipes built by the user, irrespective of the build outcome (failed,
        cancelled, succeeded, or errored).

The errors and failures arose because the build process did not
terminate as expected, particularly when attempting to build recipe
images such as "core-image-minimal" or "bash." It was discovered that
building a real recipe/image was unnecessary for the test's purpose.
Instead, building a fake recipe like "foo" provided a reliable way to
ensure the build would fail or be interrupted.

Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
---
 .../tests/functional/test_project_page.py     |   2 +-
 .../test_project_page_tab_config.py           | 186 +++++++++---------
 2 files changed, 95 insertions(+), 93 deletions(-)

diff --git a/lib/toaster/tests/functional/test_project_page.py b/lib/toaster/tests/functional/test_project_page.py
index 077badb0..82dca442 100644
--- a/lib/toaster/tests/functional/test_project_page.py
+++ b/lib/toaster/tests/functional/test_project_page.py
@@ -461,7 +461,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
             '//td[@class="add-del-layers"]//a[1]'
         )
         build_btn.click()
-        build_state = wait_until_build(self, 'parsing starting cloning queued')
+        build_state = wait_until_build(self, 'queued cloning starting parsing failed')
         lastest_builds = self.driver.find_elements(
             By.XPATH,
             '//div[@id="latest-builds"]/div'
diff --git a/lib/toaster/tests/functional/test_project_page_tab_config.py b/lib/toaster/tests/functional/test_project_page_tab_config.py
index d911ff00..4dbf5aeb 100644
--- a/lib/toaster/tests/functional/test_project_page_tab_config.py
+++ b/lib/toaster/tests/functional/test_project_page_tab_config.py
@@ -12,7 +12,7 @@ import pytest
 from django.urls import reverse
 from selenium.webdriver import Keys
 from selenium.webdriver.support.select import Select
-from selenium.common.exceptions import TimeoutException
+from selenium.common.exceptions import NoSuchElementException, TimeoutException
 from orm.models import Project
 from tests.functional.functional_helpers import SeleniumFunctionalTestCase
 from selenium.webdriver.common.by import By
@@ -26,17 +26,18 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
     PROJECT_NAME = 'TestProjectConfigTab'
     project_id = None
 
-    def _create_project(self, project_name):
+    def _create_project(self, project_name, **kwargs):
         """ Create/Test new project using:
           - Project Name: Any string
           - Release: Any string
           - Merge Toaster settings: True or False
         """
+        release = kwargs.get('release', '3')
         self.get(reverse('newproject'))
         self.wait_until_visible('#new-project-name')
         self.find("#new-project-name").send_keys(project_name)
         select = Select(self.find("#projectversion"))
-        select.select_by_value('3')
+        select.select_by_value(release)
 
         # check merge toaster settings
         checkbox = self.find('.checkbox-mergeattr')
@@ -50,7 +51,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         self.find("#create-project-button").click()
 
         try:
-            self.wait_until_visible('#hint-error-project-name')
+            self.wait_until_visible('#hint-error-project-name', poll=3)
             url = reverse('project', args=(TestProjectConfigTab.project_id, ))
             self.get(url)
             self.wait_until_visible('#config-nav', poll=3)
@@ -67,7 +68,8 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         if TestProjectConfigTab.project_id is None:
             self._create_project(project_name=self._random_string(10))
             current_url = self.driver.current_url
-            TestProjectConfigTab.project_id = get_projectId_from_url(current_url)
+            TestProjectConfigTab.project_id = get_projectId_from_url(
+                current_url)
         else:
             url = reverse('project', args=(TestProjectConfigTab.project_id,))
             self.get(url)
@@ -76,27 +78,30 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
     def _create_builds(self):
         # check search box can be use to build recipes
         search_box = self.find('#build-input')
-        search_box.send_keys('core-image-minimal')
+        search_box.send_keys('foo')
         self.find('#build-button').click()
-        self.wait_until_visible('#latest-builds')
+        self.wait_until_present('#latest-builds')
         # loop until reach the parsing state
-        build_state = wait_until_build(self, 'parsing starting cloning')
+        wait_until_build(self, 'queued cloning starting parsing failed')
         lastest_builds = self.driver.find_elements(
             By.XPATH,
             '//div[@id="latest-builds"]/div',
         )
         last_build = lastest_builds[0]
         self.assertTrue(
-            'core-image-minimal' in str(last_build.text)
+            'foo' in str(last_build.text)
         )
-        cancel_button = last_build.find_element(
-            By.XPATH,
-            '//span[@class="cancel-build-btn pull-right alert-link"]',
-        )
-        cancel_button.click()
-        if 'starting' not in build_state:  # change build state when cancelled in starting state
-            wait_until_build_cancelled(self)
-        return build_state
+        last_build = lastest_builds[0]
+        try:
+            cancel_button = last_build.find_element(
+                By.XPATH,
+                '//span[@class="cancel-build-btn pull-right alert-link"]',
+            )
+            cancel_button.click()
+        except NoSuchElementException:
+            # Skip if the build is already cancelled
+            pass
+        wait_until_build_cancelled(self)
 
     def _get_tabs(self):
         # tabs links list
@@ -126,6 +131,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
             - Delete project
         """
         self._navigate_to_project_page()
+
         def _get_config_nav_item(index):
             config_nav = self.find('#config-nav')
             return config_nav.find_elements(By.TAG_NAME, 'li')[index]
@@ -152,13 +158,27 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         self.assertTrue("actions" in str(actions.text).lower())
 
         conf_nav_list = [
-            [0, 'Configuration', f"/toastergui/project/{TestProjectConfigTab.project_id}"],  # config
-            [2, 'Custom images', f"/toastergui/project/{TestProjectConfigTab.project_id}/customimages"],  # custom images
-            [3, 'Image recipes', f"/toastergui/project/{TestProjectConfigTab.project_id}/images"],  # image recipes
-            [4, 'Software recipes', f"/toastergui/project/{TestProjectConfigTab.project_id}/softwarerecipes"],  # software recipes
-            [5, 'Machines', f"/toastergui/project/{TestProjectConfigTab.project_id}/machines"],  # machines
-            [6, 'Layers', f"/toastergui/project/{TestProjectConfigTab.project_id}/layers"],  # layers
-            [7, 'Distros', f"/toastergui/project/{TestProjectConfigTab.project_id}/distros"],  # distro
+            # config
+            [0, 'Configuration',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}"],
+            # custom images
+            [2, 'Custom images',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/customimages"],
+            # image recipes
+            [3, 'Image recipes',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/images"],
+            # software recipes
+            [4, 'Software recipes',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/softwarerecipes"],
+            # machines
+            [5, 'Machines',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/machines"],
+            # layers
+            [6, 'Layers',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/layers"],
+            # distro
+            [7, 'Distros',
+                f"/toastergui/project/{TestProjectConfigTab.project_id}/distros"],
             #  [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTab.project_id}/configuration"],  # bitbake variables
         ]
         for index, item_name, url in conf_nav_list:
@@ -281,15 +301,10 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         # Create a new project for this test
         project_name = self._random_string(10)
         self._create_project(project_name=project_name)
-        current_url = self.driver.current_url
-        TestProjectConfigTab.project_id = get_projectId_from_url(current_url)
-        url = current_url.split('?')[0]
         # check if the menu is displayed
         self.wait_until_visible('#project-page')
         block_l = self.driver.find_element(
             By.XPATH, '//*[@id="project-page"]/div[2]')
-        most_built_recipes = self.driver.find_element(
-            By.XPATH, '//*[@id="project-page"]/div[1]/div[3]')
         project_release = self.driver.find_element(
             By.XPATH, '//*[@id="project-page"]/div[1]/div[4]')
         layers = block_l.find_element(By.ID, 'layer-container')
@@ -315,26 +330,6 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
                 f'You have changed the {item_name} to: {new_item_name}' in change_notification.text
             )
 
-        def rebuild_from_most_build_recipes(recipe_list_items):
-            checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input')
-            checkbox.click()
-            build_btn = self.find('#freq-build-btn')
-            build_btn.click()
-            self.wait_until_visible('#latest-builds')
-            build_state = wait_until_build(self, 'parsing starting cloning queued')
-            lastest_builds = self.driver.find_elements(
-                By.XPATH,
-                '//div[@id="latest-builds"]/div'
-            )
-            last_build = lastest_builds[0]
-            self.assertTrue(len(lastest_builds) >= 2)
-            cancel_button = last_build.find_element(
-                By.XPATH,
-                '//span[@class="cancel-build-btn pull-right alert-link"]',
-            )
-            cancel_button.click()
-            if 'starting' not in build_state:  # change build state when cancelled in starting state
-                wait_until_build_cancelled(self)
         # Machine
         check_machine_distro(self, 'machine', 'qemux86-64', 'machine-section')
         # Distro
@@ -374,32 +369,61 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li')
         self.assertTrue(len(layers_list_items) == 4)
 
-        # Most built recipes
-        title = most_built_recipes.find_element(By.TAG_NAME, 'h3')
-        self.assertTrue("Most built recipes" in title.text)
+    def test_most_build_recipes(self):
+        """ Test most build recipes block contains"""
+        def rebuild_from_most_build_recipes(recipe_list_items):
+            checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input')
+            checkbox.click()
+            build_btn = self.find('#freq-build-btn')
+            build_btn.click()
+            self.wait_until_present('#latest-builds')
+            wait_until_build(self, 'queued cloning starting parsing failed')
+            lastest_builds = self.driver.find_elements(
+                By.XPATH,
+                '//div[@id="latest-builds"]/div'
+            )
+            self.assertTrue(len(lastest_builds) >= 2)
+            last_build = lastest_builds[0]
+            try:
+                cancel_button = last_build.find_element(
+                    By.XPATH,
+                    '//span[@class="cancel-build-btn pull-right alert-link"]',
+                )
+                cancel_button.click()
+            except NoSuchElementException:
+                # Skip if the build is already cancelled
+                pass
+            wait_until_build_cancelled(self)
+        # Create a new project for remaining asserts
+        project_name = self._random_string(10)
+        self._create_project(project_name=project_name, release='2')
+        current_url = self.driver.current_url
+        TestProjectConfigTab.project_id = get_projectId_from_url(current_url)
+        url = current_url.split('?')[0]
+
         # Create a new builds
-        build_state = self._create_builds()
+        self._create_builds()
 
-        # Refresh the page
+        # back to project page
         self.driver.get(url)
 
         self.wait_until_visible('#project-page', poll=3)
-        # check can select a recipe and build it
+
+        # Most built recipes
         most_built_recipes = self.driver.find_element(
             By.XPATH, '//*[@id="project-page"]/div[1]/div[3]')
-        recipe_list = most_built_recipes.find_element(By.ID, 'freq-build-list')
+        title = most_built_recipes.find_element(By.TAG_NAME, 'h3')
+        self.assertTrue("Most built recipes" in title.text)
+        # check can select a recipe and build it
+        self.wait_until_visible('#freq-build-list', poll=3)
+        recipe_list = self.find('#freq-build-list')
         recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li')
-        if 'starting' not in build_state:  # Build will not appear in the list if canceled in starting state
-            self.assertTrue(
-                len(recipe_list_items) > 0,
-                msg="No recipes found in the most built recipes list",
-            )
-            rebuild_from_most_build_recipes(recipe_list_items)
-        else:
-            self.assertTrue(
-                len(recipe_list_items) == 0,
-                msg="Recipes found in the most built recipes list",
-            )
+        self.assertTrue(
+            len(recipe_list_items) > 0,
+            msg="Any recipes found in the most built recipes list",
+        )
+        rebuild_from_most_build_recipes(recipe_list_items)
+        TestProjectConfigTab.project_id = None  # reset project id
 
     def test_project_page_tab_importlayer(self):
         """ Test project page tab import layer """
@@ -461,10 +485,9 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         div_empty_msg = self.find('#empty-state-customimagestable')
         link_create_custom_image = div_empty_msg.find_element(
             By.TAG_NAME, 'a')
-        last_project_id = Project.objects.get(name=project_name).id
-        self.assertTrue(last_project_id is not None)
+        self.assertTrue(TestProjectConfigTab.project_id is not None)
         self.assertTrue(
-            f"/toastergui/project/{last_project_id}/newcustomimage" in str(
+            f"/toastergui/project/{TestProjectConfigTab.project_id}/newcustomimage" in str(
                 link_create_custom_image.get_attribute('href')
             )
         )
@@ -473,6 +496,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
                 link_create_custom_image.text
             )
         )
+        TestProjectConfigTab.project_id = None  # reset project id
 
     def test_project_page_image_recipe(self):
         """ Test project page section images
@@ -497,25 +521,3 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase):
         self.wait_until_visible('#imagerecipestable tbody tr')
         rows = self.find_all('#imagerecipestable tbody tr')
         self.assertTrue(len(rows) > 0)
-
-        # Test build button
-        image_to_build = rows[0]
-        build_btn = image_to_build.find_element(
-            By.XPATH,
-            '//td[@class="add-del-layers"]'
-        )
-        build_btn.click()
-        build_state = wait_until_build(self, 'parsing starting cloning queued')
-        lastest_builds = self.driver.find_elements(
-            By.XPATH,
-            '//div[@id="latest-builds"]/div'
-        )
-        self.assertTrue(len(lastest_builds) > 0)
-        last_build = lastest_builds[0]
-        cancel_button = last_build.find_element(
-            By.XPATH,
-            '//span[@class="cancel-build-btn pull-right alert-link"]',
-        )
-        cancel_button.click()
-        if 'starting' not in build_state:  # change build state when cancelled in starting state
-            wait_until_build_cancelled(self)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-12-14 22:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-14 22:09 [PATCH 1/6] toaster/test: bug-fix element click intercepted in browser/test_layerdetails_page.py Alassane Yattara
2023-12-14 22:09 ` [PATCH 2/6] toaster/test: logging warning in console, trying to kill unavailable Runbuilds process Alassane Yattara
2023-12-14 22:09 ` [PATCH 3/6] toaster/test: Added skip to run test on ElementClickInterceptedException Alassane Yattara
2023-12-14 22:09 ` [PATCH 4/6] toaster/test: Removed all time.sleep occurrence Alassane Yattara
2023-12-14 22:09 ` [PATCH 5/6] toaster/test: Handle case when SSTATE_DIR and DL_DIR not visible in the page project/BitBake variables Alassane Yattara
2023-12-14 22:09 ` [PATCH 6/6] toaster/test: Bug-Fix testcase bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py 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).