mirror of
https://git.yoctoproject.org/poky
synced 2026-04-30 03:32:12 +02:00
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.
(Bitbake rev: 5162db5305826235c09d9fcd38b5fb48ded31622)
Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
783 lines
32 KiB
Python
783 lines
32 KiB
Python
#! /usr/bin/env python3 #
|
|
# BitBake Toaster UI tests implementation
|
|
#
|
|
# Copyright (C) 2023 Savoir-faire Linux
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
#
|
|
|
|
import os
|
|
import random
|
|
import string
|
|
from unittest import skip
|
|
import pytest
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
from selenium.webdriver.common.keys import Keys
|
|
from selenium.webdriver.support.select import Select
|
|
from selenium.common.exceptions import TimeoutException
|
|
from tests.functional.functional_helpers import SeleniumFunctionalTestCase
|
|
from orm.models import Build, Project, Target
|
|
from selenium.webdriver.common.by import By
|
|
|
|
from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@pytest.mark.order("last")
|
|
class TestProjectPage(SeleniumFunctionalTestCase):
|
|
project_id = None
|
|
PROJECT_NAME = 'TestProjectPage'
|
|
|
|
def _create_project(self, project_name):
|
|
""" Create/Test new project using:
|
|
- Project Name: Any string
|
|
- Release: Any string
|
|
- Merge Toaster settings: True or False
|
|
"""
|
|
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')
|
|
|
|
# check merge toaster settings
|
|
checkbox = self.find('.checkbox-mergeattr')
|
|
if not checkbox.is_selected():
|
|
checkbox.click()
|
|
|
|
if self.PROJECT_NAME != 'TestProjectPage':
|
|
# Reset project name if it's not the default one
|
|
self.PROJECT_NAME = 'TestProjectPage'
|
|
|
|
self.find("#create-project-button").click()
|
|
|
|
try:
|
|
self.wait_until_visible('#hint-error-project-name')
|
|
url = reverse('project', args=(TestProjectPage.project_id, ))
|
|
self.get(url)
|
|
self.wait_until_visible('#config-nav', poll=3)
|
|
except TimeoutException:
|
|
self.wait_until_visible('#config-nav', poll=3)
|
|
|
|
def _random_string(self, length):
|
|
return ''.join(
|
|
random.choice(string.ascii_letters) for _ in range(length)
|
|
)
|
|
|
|
def _navigate_to_project_page(self):
|
|
# Navigate to project page
|
|
if TestProjectPage.project_id is None:
|
|
self._create_project(project_name=self._random_string(10))
|
|
current_url = self.driver.current_url
|
|
TestProjectPage.project_id = get_projectId_from_url(current_url)
|
|
else:
|
|
url = reverse('project', args=(TestProjectPage.project_id,))
|
|
self.get(url)
|
|
self.wait_until_visible('#config-nav')
|
|
|
|
def _get_create_builds(self, **kwargs):
|
|
""" Create a build and return the build object """
|
|
# parameters for builds to associate with the projects
|
|
now = timezone.now()
|
|
self.project1_build_success = {
|
|
'project': Project.objects.get(id=TestProjectPage.project_id),
|
|
'started_on': now,
|
|
'completed_on': now,
|
|
'outcome': Build.SUCCEEDED
|
|
}
|
|
|
|
self.project1_build_failure = {
|
|
'project': Project.objects.get(id=TestProjectPage.project_id),
|
|
'started_on': now,
|
|
'completed_on': now,
|
|
'outcome': Build.FAILED
|
|
}
|
|
build1 = Build.objects.create(**self.project1_build_success)
|
|
build2 = Build.objects.create(**self.project1_build_failure)
|
|
|
|
# add some targets to these builds so they have recipe links
|
|
# (and so we can find the row in the ToasterTable corresponding to
|
|
# a particular build)
|
|
Target.objects.create(build=build1, target='foo')
|
|
Target.objects.create(build=build2, target='bar')
|
|
|
|
if kwargs:
|
|
# Create kwargs.get('success') builds with success status with target
|
|
# and kwargs.get('failure') builds with failure status with target
|
|
for i in range(kwargs.get('success', 0)):
|
|
now = timezone.now()
|
|
self.project1_build_success['started_on'] = now
|
|
self.project1_build_success[
|
|
'completed_on'] = now - timezone.timedelta(days=i)
|
|
build = Build.objects.create(**self.project1_build_success)
|
|
Target.objects.create(build=build,
|
|
target=f'{i}_success_recipe',
|
|
task=f'{i}_success_task')
|
|
|
|
for i in range(kwargs.get('failure', 0)):
|
|
now = timezone.now()
|
|
self.project1_build_failure['started_on'] = now
|
|
self.project1_build_failure[
|
|
'completed_on'] = now - timezone.timedelta(days=i)
|
|
build = Build.objects.create(**self.project1_build_failure)
|
|
Target.objects.create(build=build,
|
|
target=f'{i}_fail_recipe',
|
|
task=f'{i}_fail_task')
|
|
return build1, build2
|
|
|
|
def _mixin_test_table_edit_column(
|
|
self,
|
|
table_id,
|
|
edit_btn_id,
|
|
list_check_box_id: list
|
|
):
|
|
# Check edit column
|
|
edit_column = self.find(f'#{edit_btn_id}')
|
|
self.assertTrue(edit_column.is_displayed())
|
|
edit_column.click()
|
|
# Check dropdown is visible
|
|
self.wait_until_visible('ul.dropdown-menu.editcol')
|
|
for check_box_id in list_check_box_id:
|
|
# Check that we can hide/show table column
|
|
check_box = self.find(f'#{check_box_id}')
|
|
th_class = str(check_box_id).replace('checkbox-', '')
|
|
if check_box.is_selected():
|
|
# check if column is visible in table
|
|
self.assertTrue(
|
|
self.find(
|
|
f'#{table_id} thead th.{th_class}'
|
|
).is_displayed(),
|
|
f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
|
|
)
|
|
check_box.click()
|
|
# check if column is hidden in table
|
|
self.assertFalse(
|
|
self.find(
|
|
f'#{table_id} thead th.{th_class}'
|
|
).is_displayed(),
|
|
f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
|
|
)
|
|
else:
|
|
# check if column is hidden in table
|
|
self.assertFalse(
|
|
self.find(
|
|
f'#{table_id} thead th.{th_class}'
|
|
).is_displayed(),
|
|
f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
|
|
)
|
|
check_box.click()
|
|
# check if column is visible in table
|
|
self.assertTrue(
|
|
self.find(
|
|
f'#{table_id} thead th.{th_class}'
|
|
).is_displayed(),
|
|
f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
|
|
)
|
|
|
|
def _get_config_nav_item(self, index):
|
|
config_nav = self.find('#config-nav')
|
|
return config_nav.find_elements(By.TAG_NAME, 'li')[index]
|
|
|
|
def _navigate_to_config_nav(self, nav_id, nav_index):
|
|
# navigate to the project page
|
|
self._navigate_to_project_page()
|
|
# click on "Software recipe" tab
|
|
soft_recipe = self._get_config_nav_item(nav_index)
|
|
soft_recipe.click()
|
|
self.wait_until_visible(f'#{nav_id}')
|
|
|
|
def _mixin_test_table_show_rows(self, table_selector, **kwargs):
|
|
""" Test the show rows feature in the builds table on the all builds page """
|
|
def test_show_rows(row_to_show, show_row_link):
|
|
# Check that we can show rows == row_to_show
|
|
show_row_link.select_by_value(str(row_to_show))
|
|
self.wait_until_visible(f'#{table_selector} tbody tr', poll=2)
|
|
self.assertTrue(
|
|
len(self.find_all(f'#{table_selector} tbody tr')) == row_to_show
|
|
)
|
|
self.wait_until_present(f'#{table_selector} tbody tr')
|
|
show_rows = self.driver.find_elements(
|
|
By.XPATH,
|
|
f'//select[@class="form-control pagesize-{table_selector}"]'
|
|
)
|
|
rows_to_show = [10, 25, 50, 100, 150]
|
|
to_skip = kwargs.get('to_skip', [])
|
|
# Check show rows
|
|
for show_row_link in show_rows:
|
|
show_row_link = Select(show_row_link)
|
|
for row_to_show in rows_to_show:
|
|
if row_to_show not in to_skip:
|
|
test_show_rows(row_to_show, show_row_link)
|
|
|
|
def _mixin_test_table_search_input(self, **kwargs):
|
|
input_selector, input_text, searchBtn_selector, table_selector, *_ = kwargs.values()
|
|
# Test search input
|
|
self.wait_until_visible(f'#{input_selector}')
|
|
recipe_input = self.find(f'#{input_selector}')
|
|
recipe_input.send_keys(input_text)
|
|
self.find(f'#{searchBtn_selector}').click()
|
|
self.wait_until_visible(f'#{table_selector} tbody tr')
|
|
rows = self.find_all(f'#{table_selector} tbody tr')
|
|
self.assertTrue(len(rows) > 0)
|
|
|
|
def test_create_project(self):
|
|
""" Create/Test new project using:
|
|
- Project Name: Any string
|
|
- Release: Any string
|
|
- Merge Toaster settings: True or False
|
|
"""
|
|
self._create_project(project_name=self.PROJECT_NAME)
|
|
|
|
def test_image_recipe_editColumn(self):
|
|
""" Test the edit column feature in image recipe table on project page """
|
|
self._get_create_builds(success=10, failure=10)
|
|
|
|
url = reverse('projectimagerecipes', args=(TestProjectPage.project_id,))
|
|
self.get(url)
|
|
self.wait_until_present('#imagerecipestable tbody tr')
|
|
|
|
column_list = [
|
|
'get_description_or_summary', 'layer_version__get_vcs_reference',
|
|
'layer_version__layer__name', 'license', 'recipe-file', 'section',
|
|
'version'
|
|
]
|
|
|
|
# Check that we can hide the edit column
|
|
self._mixin_test_table_edit_column(
|
|
'imagerecipestable',
|
|
'edit-columns-button',
|
|
[f'checkbox-{column}' for column in column_list]
|
|
)
|
|
|
|
def test_page_header_on_project_page(self):
|
|
""" Check page header in project page:
|
|
- AT LEFT -> Logo of Yocto project, displayed, clickable
|
|
- "Toaster"+" Information icon", displayed, clickable
|
|
- "Server Icon" + "All builds", displayed, clickable
|
|
- "Directory Icon" + "All projects", displayed, clickable
|
|
- "Book Icon" + "Documentation", displayed, clickable
|
|
- AT RIGHT -> button "New project", displayed, clickable
|
|
"""
|
|
# navigate to the project page
|
|
self._navigate_to_project_page()
|
|
|
|
# check page header
|
|
# AT LEFT -> Logo of Yocto project
|
|
logo = self.driver.find_element(
|
|
By.XPATH,
|
|
"//div[@class='toaster-navbar-brand']",
|
|
)
|
|
logo_img = logo.find_element(By.TAG_NAME, 'img')
|
|
self.assertTrue(logo_img.is_displayed(),
|
|
'Logo of Yocto project not found')
|
|
self.assertTrue(
|
|
'/static/img/logo.png' in str(logo_img.get_attribute('src')),
|
|
'Logo of Yocto project not found'
|
|
)
|
|
# "Toaster"+" Information icon", clickable
|
|
toaster = self.driver.find_element(
|
|
By.XPATH,
|
|
"//div[@class='toaster-navbar-brand']//a[@class='brand']",
|
|
)
|
|
self.assertTrue(toaster.is_displayed(), 'Toaster not found')
|
|
self.assertTrue(toaster.text == 'Toaster')
|
|
info_sign = self.find('.glyphicon-info-sign')
|
|
self.assertTrue(info_sign.is_displayed())
|
|
|
|
# "Server Icon" + "All builds"
|
|
all_builds = self.find('#navbar-all-builds')
|
|
all_builds_link = all_builds.find_element(By.TAG_NAME, 'a')
|
|
self.assertTrue("All builds" in all_builds_link.text)
|
|
self.assertTrue(
|
|
'/toastergui/builds/' in str(all_builds_link.get_attribute('href'))
|
|
)
|
|
server_icon = all_builds.find_element(By.TAG_NAME, 'i')
|
|
self.assertTrue(
|
|
server_icon.get_attribute('class') == 'glyphicon glyphicon-tasks'
|
|
)
|
|
self.assertTrue(server_icon.is_displayed())
|
|
|
|
# "Directory Icon" + "All projects"
|
|
all_projects = self.find('#navbar-all-projects')
|
|
all_projects_link = all_projects.find_element(By.TAG_NAME, 'a')
|
|
self.assertTrue("All projects" in all_projects_link.text)
|
|
self.assertTrue(
|
|
'/toastergui/projects/' in str(all_projects_link.get_attribute(
|
|
'href'))
|
|
)
|
|
dir_icon = all_projects.find_element(By.TAG_NAME, 'i')
|
|
self.assertTrue(
|
|
dir_icon.get_attribute('class') == 'icon-folder-open'
|
|
)
|
|
self.assertTrue(dir_icon.is_displayed())
|
|
|
|
# "Book Icon" + "Documentation"
|
|
toaster_docs_link = self.find('#navbar-docs')
|
|
toaster_docs_link_link = toaster_docs_link.find_element(By.TAG_NAME,
|
|
'a')
|
|
self.assertTrue("Documentation" in toaster_docs_link_link.text)
|
|
self.assertTrue(
|
|
toaster_docs_link_link.get_attribute('href') == 'http://docs.yoctoproject.org/toaster-manual/index.html#toaster-user-manual'
|
|
)
|
|
book_icon = toaster_docs_link.find_element(By.TAG_NAME, 'i')
|
|
self.assertTrue(
|
|
book_icon.get_attribute('class') == 'glyphicon glyphicon-book'
|
|
)
|
|
self.assertTrue(book_icon.is_displayed())
|
|
|
|
# AT RIGHT -> button "New project"
|
|
new_project_button = self.find('#new-project-button')
|
|
self.assertTrue(new_project_button.is_displayed())
|
|
self.assertTrue(new_project_button.text == 'New project')
|
|
new_project_button.click()
|
|
self.assertTrue(
|
|
'/toastergui/newproject/' in str(self.driver.current_url)
|
|
)
|
|
|
|
def test_edit_project_name(self):
|
|
""" Test edit project name:
|
|
- Click on "Edit" icon button
|
|
- Change project name
|
|
- Click on "Save" button
|
|
- Check project name is changed
|
|
"""
|
|
# navigate to the project page
|
|
self._navigate_to_project_page()
|
|
|
|
# click on "Edit" icon button
|
|
self.wait_until_visible('#project-name-container')
|
|
edit_button = self.find('#project-change-form-toggle')
|
|
edit_button.click()
|
|
project_name_input = self.find('#project-name-change-input')
|
|
self.assertTrue(project_name_input.is_displayed())
|
|
project_name_input.clear()
|
|
project_name_input.send_keys('New Name')
|
|
self.find('#project-name-change-btn').click()
|
|
|
|
# check project name is changed
|
|
self.wait_until_visible('#project-name-container')
|
|
self.assertTrue(
|
|
'New Name' in str(self.find('#project-name-container').text)
|
|
)
|
|
|
|
def test_project_page_tabs(self):
|
|
""" Test project tabs:
|
|
- "configuration" tab
|
|
- "Builds" tab
|
|
- "Import layers" tab
|
|
- "New custom image" tab
|
|
Check search box used to build recipes
|
|
"""
|
|
# navigate to the project page
|
|
self._navigate_to_project_page()
|
|
|
|
# check "configuration" tab
|
|
self.wait_until_visible('#topbar-configuration-tab')
|
|
config_tab = self.find('#topbar-configuration-tab')
|
|
self.assertTrue(config_tab.get_attribute('class') == 'active')
|
|
self.assertTrue('Configuration' in str(config_tab.text))
|
|
self.assertTrue(
|
|
f"/toastergui/project/{TestProjectPage.project_id}" in str(self.driver.current_url)
|
|
)
|
|
|
|
def get_tabs():
|
|
# tabs links list
|
|
return self.driver.find_elements(
|
|
By.XPATH,
|
|
'//div[@id="project-topbar"]//li'
|
|
)
|
|
|
|
def check_tab_link(tab_index, tab_name, url):
|
|
tab = get_tabs()[tab_index]
|
|
tab_link = tab.find_element(By.TAG_NAME, 'a')
|
|
self.assertTrue(url in tab_link.get_attribute('href'))
|
|
self.assertTrue(tab_name in tab_link.text)
|
|
self.assertTrue(tab.get_attribute('class') == 'active')
|
|
|
|
# check "Builds" tab
|
|
builds_tab = get_tabs()[1]
|
|
builds_tab.find_element(By.TAG_NAME, 'a').click()
|
|
check_tab_link(
|
|
1,
|
|
'Builds',
|
|
f"/toastergui/project/{TestProjectPage.project_id}/builds"
|
|
)
|
|
|
|
# check "Import layers" tab
|
|
import_layers_tab = get_tabs()[2]
|
|
import_layers_tab.find_element(By.TAG_NAME, 'a').click()
|
|
check_tab_link(
|
|
2,
|
|
'Import layer',
|
|
f"/toastergui/project/{TestProjectPage.project_id}/importlayer"
|
|
)
|
|
|
|
# check "New custom image" tab
|
|
new_custom_image_tab = get_tabs()[3]
|
|
new_custom_image_tab.find_element(By.TAG_NAME, 'a').click()
|
|
check_tab_link(
|
|
3,
|
|
'New custom image',
|
|
f"/toastergui/project/{TestProjectPage.project_id}/newcustomimage"
|
|
)
|
|
|
|
# check search box can be use to build recipes
|
|
search_box = self.find('#build-input')
|
|
search_box.send_keys('core-image-minimal')
|
|
self.find('#build-button').click()
|
|
self.wait_until_visible('#latest-builds')
|
|
lastest_builds = self.driver.find_elements(
|
|
By.XPATH,
|
|
'//div[@id="latest-builds"]',
|
|
)
|
|
last_build = lastest_builds[0]
|
|
self.assertTrue(
|
|
'core-image-minimal' in str(last_build.text)
|
|
)
|
|
|
|
def test_softwareRecipe_page(self):
|
|
""" Test software recipe page
|
|
- Check title "Compatible software recipes" is displayed
|
|
- Check search input
|
|
- Check "build recipe" button works
|
|
- Check software recipe table feature(show/hide column, pagination)
|
|
"""
|
|
self._navigate_to_config_nav('softwarerecipestable', 4)
|
|
# check title "Compatible software recipes" is displayed
|
|
self.assertTrue("Compatible software recipes" in self.get_page_source())
|
|
# Test search input
|
|
self._mixin_test_table_search_input(
|
|
input_selector='search-input-softwarerecipestable',
|
|
input_text='busybox',
|
|
searchBtn_selector='search-submit-softwarerecipestable',
|
|
table_selector='softwarerecipestable'
|
|
)
|
|
# check "build recipe" button works
|
|
rows = self.find_all('#softwarerecipestable tbody tr')
|
|
image_to_build = rows[0]
|
|
build_btn = image_to_build.find_element(
|
|
By.XPATH,
|
|
'//td[@class="add-del-layers"]//a[1]'
|
|
)
|
|
build_btn.click()
|
|
build_state = 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) > 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)
|
|
|
|
# check software recipe table feature(show/hide column, pagination)
|
|
self._navigate_to_config_nav('softwarerecipestable', 4)
|
|
column_list = [
|
|
'get_description_or_summary',
|
|
'layer_version__get_vcs_reference',
|
|
'layer_version__layer__name',
|
|
'license',
|
|
'recipe-file',
|
|
'section',
|
|
'version',
|
|
]
|
|
self._mixin_test_table_edit_column(
|
|
'softwarerecipestable',
|
|
'edit-columns-button',
|
|
[f'checkbox-{column}' for column in column_list]
|
|
)
|
|
self._navigate_to_config_nav('softwarerecipestable', 4)
|
|
# check show rows(pagination)
|
|
self._mixin_test_table_show_rows(table_selector='softwarerecipestable')
|
|
|
|
def test_machines_page(self):
|
|
""" Test Machine page
|
|
- Check if title "Compatible machines" is displayed
|
|
- Check search input
|
|
- Check "Select machine" button works
|
|
- Check "Add layer" button works
|
|
- Check Machine table feature(show/hide column, pagination)
|
|
"""
|
|
self._navigate_to_config_nav('machinestable', 5)
|
|
# check title "Compatible software recipes" is displayed
|
|
self.assertTrue("Compatible machines" in self.get_page_source())
|
|
# Test search input
|
|
self._mixin_test_table_search_input(
|
|
input_selector='search-input-machinestable',
|
|
input_text='qemux86-64',
|
|
searchBtn_selector='search-submit-machinestable',
|
|
table_selector='machinestable'
|
|
)
|
|
# check "Select machine" button works
|
|
rows = self.find_all('#machinestable tbody tr')
|
|
machine_to_select = rows[0]
|
|
select_btn = machine_to_select.find_element(
|
|
By.XPATH,
|
|
'//td[@class="add-del-layers"]//a[1]'
|
|
)
|
|
select_btn.send_keys(Keys.RETURN)
|
|
self.wait_until_visible('#config-nav')
|
|
project_machine_name = self.find('#project-machine-name')
|
|
self.assertTrue(
|
|
'qemux86-64' in project_machine_name.text
|
|
)
|
|
# check "Add layer" button works
|
|
self._navigate_to_config_nav('machinestable', 5)
|
|
# Search for a machine whit layer not in project
|
|
self._mixin_test_table_search_input(
|
|
input_selector='search-input-machinestable',
|
|
input_text='qemux86-64-tpm2',
|
|
searchBtn_selector='search-submit-machinestable',
|
|
table_selector='machinestable'
|
|
)
|
|
self.wait_until_visible('#machinestable tbody tr', poll=3)
|
|
rows = self.find_all('#machinestable tbody tr')
|
|
machine_to_add = rows[0]
|
|
add_btn = machine_to_add.find_element(By.XPATH, '//td[@class="add-del-layers"]')
|
|
add_btn.click()
|
|
self.wait_until_visible('#change-notification')
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have added 1 layer to your project' in str(change_notification.text)
|
|
)
|
|
# check Machine table feature(show/hide column, pagination)
|
|
self._navigate_to_config_nav('machinestable', 5)
|
|
column_list = [
|
|
'description',
|
|
'layer_version__get_vcs_reference',
|
|
'layer_version__layer__name',
|
|
'machinefile',
|
|
]
|
|
self._mixin_test_table_edit_column(
|
|
'machinestable',
|
|
'edit-columns-button',
|
|
[f'checkbox-{column}' for column in column_list]
|
|
)
|
|
self._navigate_to_config_nav('machinestable', 5)
|
|
# check show rows(pagination)
|
|
self._mixin_test_table_show_rows(table_selector='machinestable')
|
|
|
|
def test_layers_page(self):
|
|
""" Test layers page
|
|
- Check if title "Compatible layerss" is displayed
|
|
- Check search input
|
|
- Check "Add layer" button works
|
|
- Check "Remove layer" button works
|
|
- Check layers table feature(show/hide column, pagination)
|
|
"""
|
|
self._navigate_to_config_nav('layerstable', 6)
|
|
# check title "Compatible layers" is displayed
|
|
self.assertTrue("Compatible layers" in self.get_page_source())
|
|
# Test search input
|
|
input_text='meta-tanowrt'
|
|
self._mixin_test_table_search_input(
|
|
input_selector='search-input-layerstable',
|
|
input_text=input_text,
|
|
searchBtn_selector='search-submit-layerstable',
|
|
table_selector='layerstable'
|
|
)
|
|
# check "Add layer" button works
|
|
self.wait_until_visible('#layerstable tbody tr', poll=3)
|
|
rows = self.find_all('#layerstable tbody tr')
|
|
layer_to_add = rows[0]
|
|
add_btn = layer_to_add.find_element(
|
|
By.XPATH,
|
|
'//td[@class="add-del-layers"]'
|
|
)
|
|
add_btn.click()
|
|
# check modal is displayed
|
|
self.wait_until_visible('#dependencies-modal', poll=3)
|
|
list_dependencies = self.find_all('#dependencies-list li')
|
|
# click on add-layers button
|
|
add_layers_btn = self.driver.find_element(
|
|
By.XPATH,
|
|
'//form[@id="dependencies-modal-form"]//button[@class="btn btn-primary"]'
|
|
)
|
|
add_layers_btn.click()
|
|
self.wait_until_visible('#change-notification')
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have added {len(list_dependencies)+1} layers to your project: {input_text} and its dependencies' in str(change_notification.text)
|
|
)
|
|
# check "Remove layer" button works
|
|
self.wait_until_visible('#layerstable tbody tr', poll=3)
|
|
rows = self.find_all('#layerstable tbody tr')
|
|
layer_to_remove = rows[0]
|
|
remove_btn = layer_to_remove.find_element(
|
|
By.XPATH,
|
|
'//td[@class="add-del-layers"]'
|
|
)
|
|
remove_btn.click()
|
|
self.wait_until_visible('#change-notification', poll=2)
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have removed 1 layer from your project: {input_text}' in str(change_notification.text)
|
|
)
|
|
# check layers table feature(show/hide column, pagination)
|
|
self._navigate_to_config_nav('layerstable', 6)
|
|
column_list = [
|
|
'dependencies',
|
|
'revision',
|
|
'layer__vcs_url',
|
|
'git_subdir',
|
|
'layer__summary',
|
|
]
|
|
self._mixin_test_table_edit_column(
|
|
'layerstable',
|
|
'edit-columns-button',
|
|
[f'checkbox-{column}' for column in column_list]
|
|
)
|
|
self._navigate_to_config_nav('layerstable', 6)
|
|
# check show rows(pagination)
|
|
self._mixin_test_table_show_rows(table_selector='layerstable')
|
|
|
|
def test_distro_page(self):
|
|
""" Test distros page
|
|
- Check if title "Compatible distros" is displayed
|
|
- Check search input
|
|
- Check "Add layer" button works
|
|
- Check distro table feature(show/hide column, pagination)
|
|
"""
|
|
self._navigate_to_config_nav('distrostable', 7)
|
|
# check title "Compatible distros" is displayed
|
|
self.assertTrue("Compatible Distros" in self.get_page_source())
|
|
# Test search input
|
|
input_text='poky-altcfg'
|
|
self._mixin_test_table_search_input(
|
|
input_selector='search-input-distrostable',
|
|
input_text=input_text,
|
|
searchBtn_selector='search-submit-distrostable',
|
|
table_selector='distrostable'
|
|
)
|
|
# check "Add distro" button works
|
|
rows = self.find_all('#distrostable tbody tr')
|
|
distro_to_add = rows[0]
|
|
add_btn = distro_to_add.find_element(
|
|
By.XPATH,
|
|
'//td[@class="add-del-layers"]//a[1]'
|
|
)
|
|
add_btn.click()
|
|
self.wait_until_visible('#change-notification', poll=2)
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have changed the distro to: {input_text}' in str(change_notification.text)
|
|
)
|
|
# check distro table feature(show/hide column, pagination)
|
|
self._navigate_to_config_nav('distrostable', 7)
|
|
column_list = [
|
|
'description',
|
|
'templatefile',
|
|
'layer_version__get_vcs_reference',
|
|
'layer_version__layer__name',
|
|
]
|
|
self._mixin_test_table_edit_column(
|
|
'distrostable',
|
|
'edit-columns-button',
|
|
[f'checkbox-{column}' for column in column_list]
|
|
)
|
|
self._navigate_to_config_nav('distrostable', 7)
|
|
# check show rows(pagination)
|
|
self._mixin_test_table_show_rows(
|
|
table_selector='distrostable',
|
|
to_skip=[150]
|
|
)
|
|
|
|
def test_single_layer_page(self):
|
|
""" Test layer page
|
|
- Check if title is displayed
|
|
- Check add/remove layer button works
|
|
- Check tabs(layers, recipes, machines) are displayed
|
|
- Check left section is displayed
|
|
- Check layer name
|
|
- Check layer summary
|
|
- Check layer description
|
|
"""
|
|
url = reverse("layerdetails", args=(TestProjectPage.project_id, 8))
|
|
self.get(url)
|
|
self.wait_until_visible('.page-header')
|
|
# check title is displayed
|
|
self.assertTrue(self.find('.page-header h1').is_displayed())
|
|
|
|
# check add layer button works
|
|
remove_layer_btn = self.find('#add-remove-layer-btn')
|
|
remove_layer_btn.click()
|
|
self.wait_until_visible('#change-notification', poll=2)
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have removed 1 layer from your project' in str(change_notification.text)
|
|
)
|
|
# check add layer button works, 18 is the random layer id
|
|
add_layer_btn = self.find('#add-remove-layer-btn')
|
|
add_layer_btn.click()
|
|
self.wait_until_visible('#change-notification')
|
|
change_notification = self.find('#change-notification')
|
|
self.assertTrue(
|
|
f'You have added 1 layer to your project' in str(change_notification.text)
|
|
)
|
|
# check tabs(layers, recipes, machines) are displayed
|
|
tabs = self.find_all('.nav-tabs li')
|
|
self.assertEqual(len(tabs), 3)
|
|
# Check first tab
|
|
tabs[0].click()
|
|
self.assertTrue(
|
|
'active' in str(self.find('#information').get_attribute('class'))
|
|
)
|
|
# Check second tab
|
|
tabs[1].click()
|
|
self.assertTrue(
|
|
'active' in str(self.find('#recipes').get_attribute('class'))
|
|
)
|
|
# Check third tab
|
|
tabs[2].click()
|
|
self.assertTrue(
|
|
'active' in str(self.find('#machines').get_attribute('class'))
|
|
)
|
|
# Check left section is displayed
|
|
section = self.find('.well')
|
|
# Check layer name
|
|
self.assertTrue(
|
|
section.find_element(By.XPATH, '//h2[1]').is_displayed()
|
|
)
|
|
# Check layer summary
|
|
self.assertTrue("Summary" in section.text)
|
|
# Check layer description
|
|
self.assertTrue("Description" in section.text)
|
|
|
|
def test_single_recipe_page(self):
|
|
""" Test recipe page
|
|
- Check if title is displayed
|
|
- Check add recipe layer displayed
|
|
- Check left section is displayed
|
|
- Check recipe: name, summary, description, Version, Section,
|
|
License, Approx. packages included, Approx. size, Recipe file
|
|
"""
|
|
url = reverse("recipedetails", args=(TestProjectPage.project_id, 53428))
|
|
self.get(url)
|
|
self.wait_until_visible('.page-header')
|
|
# check title is displayed
|
|
self.assertTrue(self.find('.page-header h1').is_displayed())
|
|
# check add recipe layer displayed
|
|
add_recipe_layer_btn = self.find('#add-layer-btn')
|
|
self.assertTrue(add_recipe_layer_btn.is_displayed())
|
|
# check left section is displayed
|
|
section = self.find('.well')
|
|
# Check recipe name
|
|
self.assertTrue(
|
|
section.find_element(By.XPATH, '//h2[1]').is_displayed()
|
|
)
|
|
# Check recipe sections details info are displayed
|
|
self.assertTrue("Summary" in section.text)
|
|
self.assertTrue("Description" in section.text)
|
|
self.assertTrue("Version" in section.text)
|
|
self.assertTrue("Section" in section.text)
|
|
self.assertTrue("License" in section.text)
|
|
self.assertTrue("Approx. packages included" in section.text)
|
|
self.assertTrue("Approx. package size" in section.text)
|
|
self.assertTrue("Recipe file" in section.text)
|