diff options
| author | Alassane Yattara <alassane.yattara@savoirfairelinux.com> | 2023-11-21 14:51:25 +0100 | 
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2023-11-23 12:06:06 +0000 | 
| commit | 363f19e75a19f3e9d08292602e40bfe784972747 (patch) | |
| tree | dc970bd0dbd4598f2d1c8436ecbdd77be58c1379 | |
| parent | fd740a6b6dc37d0a872f4013e2cf34501064f269 (diff) | |
| download | poky-363f19e75a19f3e9d08292602e40bfe784972747.tar.gz | |
bitbake: toaster/tests: Add UI TestCase - Test project config tab navigation:
- Check if the menu is displayed and contains the right elements:
    - Configuration
    - COMPATIBLE METADATA
    - Custom images
    - Image recipes
    - Software recipes
    - Machines
    - Layers
    - Distro
    - EXTRA CONFIGURATION
    - Bitbake variables
    - Actions
    - Delete project
(Bitbake rev: a12fe481aac82e1feebdb56afb67ba77a8904995)
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py | 176 | 
1 files changed, 176 insertions, 0 deletions
| diff --git a/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py new file mode 100644 index 0000000000..f0c6aacfc8 --- /dev/null +++ b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | #! /usr/bin/env python3 # | ||
| 2 | # BitBake Toaster UI tests implementation | ||
| 3 | # | ||
| 4 | # Copyright (C) 2023 Savoir-faire Linux | ||
| 5 | # | ||
| 6 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 7 | # | ||
| 8 | |||
| 9 | from time import sleep | ||
| 10 | import pytest | ||
| 11 | from django.urls import reverse | ||
| 12 | from selenium.webdriver.support.select import Select | ||
| 13 | from selenium.common.exceptions import NoSuchElementException | ||
| 14 | from tests.functional.functional_helpers import SeleniumFunctionalTestCase | ||
| 15 | from selenium.webdriver.common.by import By | ||
| 16 | |||
| 17 | |||
| 18 | @pytest.mark.django_db | ||
| 19 | class TestProjectConfigTab(SeleniumFunctionalTestCase): | ||
| 20 | |||
| 21 | def setUp(self): | ||
| 22 | self.recipe = None | ||
| 23 | super().setUp() | ||
| 24 | release = '3' | ||
| 25 | project_name = 'projectmaster' | ||
| 26 | self._create_test_new_project( | ||
| 27 | project_name, | ||
| 28 | release, | ||
| 29 | False, | ||
| 30 | ) | ||
| 31 | |||
| 32 | def _create_test_new_project( | ||
| 33 | self, | ||
| 34 | project_name, | ||
| 35 | release, | ||
| 36 | merge_toaster_settings, | ||
| 37 | ): | ||
| 38 | """ Create/Test new project using: | ||
| 39 | - Project Name: Any string | ||
| 40 | - Release: Any string | ||
| 41 | - Merge Toaster settings: True or False | ||
| 42 | """ | ||
| 43 | self.get(reverse('newproject')) | ||
| 44 | self.driver.find_element(By.ID, | ||
| 45 | "new-project-name").send_keys(project_name) | ||
| 46 | |||
| 47 | select = Select(self.find('#projectversion')) | ||
| 48 | select.select_by_value(release) | ||
| 49 | |||
| 50 | # check merge toaster settings | ||
| 51 | checkbox = self.find('.checkbox-mergeattr') | ||
| 52 | if merge_toaster_settings: | ||
| 53 | if not checkbox.is_selected(): | ||
| 54 | checkbox.click() | ||
| 55 | else: | ||
| 56 | if checkbox.is_selected(): | ||
| 57 | checkbox.click() | ||
| 58 | |||
| 59 | self.driver.find_element(By.ID, "create-project-button").click() | ||
| 60 | |||
| 61 | @classmethod | ||
| 62 | def _wait_until_build(cls, state): | ||
| 63 | while True: | ||
| 64 | try: | ||
| 65 | last_build_state = cls.driver.find_element( | ||
| 66 | By.XPATH, | ||
| 67 | '//*[@id="latest-builds"]/div[1]//div[@class="build-state"]', | ||
| 68 | ) | ||
| 69 | build_state = last_build_state.get_attribute( | ||
| 70 | 'data-build-state') | ||
| 71 | state_text = state.lower().split() | ||
| 72 | if any(x in str(build_state).lower() for x in state_text): | ||
| 73 | break | ||
| 74 | except NoSuchElementException: | ||
| 75 | continue | ||
| 76 | sleep(1) | ||
| 77 | |||
| 78 | def _create_builds(self): | ||
| 79 | # check search box can be use to build recipes | ||
| 80 | search_box = self.find('#build-input') | ||
| 81 | search_box.send_keys('core-image-minimal') | ||
| 82 | self.find('#build-button').click() | ||
| 83 | sleep(1) | ||
| 84 | self.wait_until_visible('#latest-builds') | ||
| 85 | # loop until reach the parsing state | ||
| 86 | self._wait_until_build('parsing starting cloning') | ||
| 87 | lastest_builds = self.driver.find_elements( | ||
| 88 | By.XPATH, | ||
| 89 | '//div[@id="latest-builds"]/div', | ||
| 90 | ) | ||
| 91 | last_build = lastest_builds[0] | ||
| 92 | self.assertTrue( | ||
| 93 | 'core-image-minimal' in str(last_build.text) | ||
| 94 | ) | ||
| 95 | cancel_button = last_build.find_element( | ||
| 96 | By.XPATH, | ||
| 97 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 98 | ) | ||
| 99 | cancel_button.click() | ||
| 100 | sleep(1) | ||
| 101 | self._wait_until_build('cancelled') | ||
| 102 | |||
| 103 | def _get_tabs(self): | ||
| 104 | # tabs links list | ||
| 105 | return self.driver.find_elements( | ||
| 106 | By.XPATH, | ||
| 107 | '//div[@id="project-topbar"]//li' | ||
| 108 | ) | ||
| 109 | |||
| 110 | def _get_config_nav_item(self, index): | ||
| 111 | config_nav = self.find('#config-nav') | ||
| 112 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] | ||
| 113 | |||
| 114 | def test_project_config_nav(self): | ||
| 115 | """ Test project config tab navigation: | ||
| 116 | - Check if the menu is displayed and contains the right elements: | ||
| 117 | - Configuration | ||
| 118 | - COMPATIBLE METADATA | ||
| 119 | - Custom images | ||
| 120 | - Image recipes | ||
| 121 | - Software recipes | ||
| 122 | - Machines | ||
| 123 | - Layers | ||
| 124 | - Distro | ||
| 125 | - EXTRA CONFIGURATION | ||
| 126 | - Bitbake variables | ||
| 127 | - Actions | ||
| 128 | - Delete project | ||
| 129 | """ | ||
| 130 | # navigate to the project page | ||
| 131 | url = reverse("project", args=(1,)) | ||
| 132 | self.get(url) | ||
| 133 | |||
| 134 | # check if the menu is displayed | ||
| 135 | self.wait_until_visible('#config-nav') | ||
| 136 | |||
| 137 | def _get_config_nav_item(index): | ||
| 138 | config_nav = self.find('#config-nav') | ||
| 139 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] | ||
| 140 | |||
| 141 | def check_config_nav_item(index, item_name, url): | ||
| 142 | item = _get_config_nav_item(index) | ||
| 143 | self.assertTrue(item_name in item.text) | ||
| 144 | self.assertTrue(item.get_attribute('class') == 'active') | ||
| 145 | self.assertTrue(url in self.driver.current_url) | ||
| 146 | |||
| 147 | # check if the menu contains the right elements | ||
| 148 | # COMPATIBLE METADATA | ||
| 149 | compatible_metadata = _get_config_nav_item(1) | ||
| 150 | self.assertTrue( | ||
| 151 | "compatible metadata" in compatible_metadata.text.lower() | ||
| 152 | ) | ||
| 153 | # EXTRA CONFIGURATION | ||
| 154 | extra_configuration = _get_config_nav_item(8) | ||
| 155 | self.assertTrue( | ||
| 156 | "extra configuration" in extra_configuration.text.lower() | ||
| 157 | ) | ||
| 158 | # Actions | ||
| 159 | actions = _get_config_nav_item(10) | ||
| 160 | self.assertTrue("actions" in str(actions.text).lower()) | ||
| 161 | |||
| 162 | conf_nav_list = [ | ||
| 163 | [0, 'Configuration', f"/toastergui/project/1"], # config | ||
| 164 | [2, 'Custom images', f"/toastergui/project/1/customimages"], # custom images | ||
| 165 | [3, 'Image recipes', f"/toastergui/project/1/images"], # image recipes | ||
| 166 | [4, 'Software recipes', f"/toastergui/project/1/softwarerecipes"], # software recipes | ||
| 167 | [5, 'Machines', f"/toastergui/project/1/machines"], # machines | ||
| 168 | [6, 'Layers', f"/toastergui/project/1/layers"], # layers | ||
| 169 | [7, 'Distro', f"/toastergui/project/1/distro"], # distro | ||
| 170 | [9, 'BitBake variables', f"/toastergui/project/1/configuration"], # bitbake variables | ||
| 171 | ] | ||
| 172 | for index, item_name, url in conf_nav_list: | ||
| 173 | item = _get_config_nav_item(index) | ||
| 174 | if item.get_attribute('class') != 'active': | ||
| 175 | item.click() | ||
| 176 | check_config_nav_item(index, item_name, url) | ||
