diff --git a/.gitignore b/.gitignore index cb5660a3..43968fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -173,4 +173,9 @@ poetry.toml # LSP config files pyrightconfig.json -# End of https://www.toptal.com/developers/gitignore/api/python \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/python +jenkins.war + +# allure +allure-results +allure-results/ \ No newline at end of file diff --git a/conftest.py b/conftest.py index ae323290..bf89d95c 100644 --- a/conftest.py +++ b/conftest.py @@ -5,11 +5,10 @@ from dotenv import load_dotenv from data.user.user import create_user_script, delete_user_script -from pages.base_configuration_page import BaseConfigurationPage -from pages.base_project_page import BaseProjectPage from utils.functions import load_xml, execute_user_groovy_script from utils.generators.user_generator import UserGenerator from utils.jenkins_client import JenkinsAPI +import allure load_dotenv() user_generator = UserGenerator() @@ -72,13 +71,16 @@ def page(playwright: Playwright, get_cookie): @pytest.fixture def create_job(jenkins): def _create(name, job_type=None, folder=None): - xml = load_xml(job_type) - jenkins.create_item_from_file( - name=name, - config_xml=xml, - folder=folder - ) - return name + with allure.step(f"Create job: {name}"): + xml = load_xml(job_type) + jenkins.create_item_from_file( + name=name, + config_xml=xml, + folder=folder + ) + + return name + return _create def get_all_jobs(): @@ -135,7 +137,9 @@ def create_user_fixture(): @pytest.fixture def open_page(page): def _open(page_class, url): - class_page = page_class(page, url) - class_page.open() - return class_page + with allure.step(f"Open page with URL: {url}"): + class_page = page_class(page, url) + class_page.open() + return class_page + return _open \ No newline at end of file diff --git a/data/data.py b/data/data.py index efe8b49d..0d96d78e 100644 --- a/data/data.py +++ b/data/data.py @@ -6,4 +6,18 @@ class BaseConfigurationPageData: class ManageJenkinsData: STATUS_INFORMATION = ["System Information", "System Log", "Load Statistics", "About Jenkins"] - TOOLS_AND_ACTIONS = ["Reload Configuration from Disk", "Jenkins CLI", "Script Console", "Prepare for Shutdown"] \ No newline at end of file + TOOLS_AND_ACTIONS = ["Reload Configuration from Disk", "Jenkins CLI", "Script Console", "Prepare for Shutdown"] + + +class ItemTypesData: + ITEM_TYPES = [ + "Freestyle project", + "Pipeline", + "Multi-configuration project", + "Folder", + "Multibranch Pipeline", + "Organization Folder", + ] + +class NewItemPageData: + EMPTY_ITEM_NAME_VALIDATION_TEXT = "» This field cannot be empty, please enter a valid name" \ No newline at end of file diff --git a/data/endpoints.py b/data/endpoints.py index 1caacd9c..0d6d8824 100644 --- a/data/endpoints.py +++ b/data/endpoints.py @@ -5,4 +5,5 @@ class Endpoints: JOB_STATUS_PAGE_URL = lambda self, job_name: f"/job/{job_name}" MANAGE_URL = "/manage" SECURITY_REALM_URL = "/securityRealm/" - VIEW_ALL_PAGE_URL = "/view/all/" \ No newline at end of file + VIEW_ALL_PAGE_URL = "/view/all/" + ALL_NEW_JOB_URL = "/view/all/newJob" \ No newline at end of file diff --git a/locators/new_item_locators.py b/locators/new_item_locators.py index a5dabef6..7240b27f 100644 --- a/locators/new_item_locators.py +++ b/locators/new_item_locators.py @@ -5,4 +5,7 @@ class NewItemLocators(BaseLocators): NEW_ITEM_BTN = "a[href='/view/all/newJob']" SELECT_ITEM_TYPE_SECTION = 'div#items' - ITEM_TYPES = 'div#items li' \ No newline at end of file + ITEM_TYPES = 'div#items li' + + NAME_FIELD = "input#name" + PIPELINE_TYPE = "li.org_jenkinsci_plugins_workflow_job_WorkflowJob" \ No newline at end of file diff --git a/pages/base_configuration_page.py b/pages/base_configuration_page.py index 8d7ad35a..6c561015 100644 --- a/pages/base_configuration_page.py +++ b/pages/base_configuration_page.py @@ -1,3 +1,5 @@ +import allure + from data.data import BaseConfigurationPageData from pages.base_page import BasePage from locators.base_locators import BaseLocators @@ -24,7 +26,8 @@ def disable_project(self): ) def save_configuration(self): - self.click(self.locators.SAVE_BUTTON) + with allure.step("Save changes on configuration page"): + self.click(self.locators.SAVE_BUTTON) def assert_project_disabled_message_is_displayed(self): assert self.is_visible( diff --git a/pytest.ini b/pytest.ini index 91d0eeda..7261b981 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,6 @@ [pytest] addopts = --tracing=retain-on-failure + --alluredir allure-results + --clean-alluredir cache_dir = /dev/null \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index bb257e7f..509b2184 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,5 @@ pytest-playwright==0.7.2 requests==2.32.5 python-dotenv==1.2.1 faker==39.0.0 +allure-pytest==2.15.3 + diff --git a/tests/di_trial_test.py b/tests/di_trial_test.py new file mode 100644 index 00000000..5c8e34c1 --- /dev/null +++ b/tests/di_trial_test.py @@ -0,0 +1,18 @@ +import os +import time + +import pytest +from playwright.sync_api import Playwright, ViewportSize +from dotenv import load_dotenv + +def test_empty_field(page): + page.goto("/") + new_item_link_loc = "a[href='/view/all/newJob']" + page.locator(new_item_link_loc).click() + page.get_by_text("Folder", exact=True).click() + time.sleep(4) + locator_error = "div[id='itemname-required']" + assert page.locator(locator_error).inner_text() =="» This field cannot be empty, please enter a valid name" + + + diff --git a/tests/folder_project/test_new_folder_can_be_created_from_dashboard_ya.py b/tests/folder_project/test_new_folder_can_be_created_from_dashboard_ya.py new file mode 100644 index 00000000..78703e6b --- /dev/null +++ b/tests/folder_project/test_new_folder_can_be_created_from_dashboard_ya.py @@ -0,0 +1,7 @@ +from pages.base_configuration_page import BaseConfigurationPage + +def test_tc_01_002_02_new_folder_can_be_created_from_dashboard(page, new_folder, open_page): + """TC_01.002.02 | New Item > Folder > Verify new folder can be created from dashboard""" + + config_page = open_page(BaseConfigurationPage, f"/job/{new_folder}/configure") + assert new_folder in config_page.page.title() diff --git a/tests/img.png b/tests/img.png new file mode 100644 index 00000000..23fdfdaf Binary files /dev/null and b/tests/img.png differ diff --git a/tests/manage_jenkins_project/test_security_block_buttons_kk.py b/tests/manage_jenkins_project/test_security_block_buttons_kk.py new file mode 100644 index 00000000..60e923ee --- /dev/null +++ b/tests/manage_jenkins_project/test_security_block_buttons_kk.py @@ -0,0 +1,29 @@ +def test_security_block_buttons(page): + page.goto("/manage/") + + security_block_expected_content = [ + "Security", + "Credentials", + "Credential Providers", + "Users" + ] + + security_block_actual_content = [] + + page_blocks = page.locator("section[class='jenkins-section jenkins-section--bottom-padding']").all() + + + items_missed = [] + + for block in page_blocks: + if block.locator("h2[class='jenkins-section__title']").text_content() == "Security": + block_items = block.locator("div[class='jenkins-section__item']").all() + + for item in block_items: + security_block_actual_content.append(item.locator("dt").text_content()) + + for item in security_block_expected_content: + if item not in security_block_actual_content: + items_missed.append(item) + + assert items_missed == [], f"Items missed: {', '.join(items_missed)}" \ No newline at end of file diff --git a/tests/manage_jenkins_project/test_status_information_buttons_kk.py b/tests/manage_jenkins_project/test_status_information_buttons_kk.py new file mode 100644 index 00000000..38b15085 --- /dev/null +++ b/tests/manage_jenkins_project/test_status_information_buttons_kk.py @@ -0,0 +1,29 @@ +def test_status_information_block_buttons(page): + page.goto("/manage/") + + status_information_block_expected_content = [ + "System Information", + "System Log", + "Load Statistics", + "About Jenkins" + ] + + status_information_block_actual_content = [] + + page_blocks = page.locator("section[class='jenkins-section jenkins-section--bottom-padding']").all() + + + items_missed = [] + + for block in page_blocks: + if block.locator("h2[class='jenkins-section__title']").text_content() == "Status Information": + block_items = block.locator("div[class='jenkins-section__item']").all() + + for item in block_items: + status_information_block_actual_content.append(item.locator("dt").text_content()) + + for item in status_information_block_expected_content: + if item not in status_information_block_actual_content: + items_missed.append(item) + + assert items_missed == [], f"Items missed: {', '.join(items_missed)}" \ No newline at end of file diff --git a/tests/manage_jenkins_project/test_tools_and_actions_block_buttons_kk.py b/tests/manage_jenkins_project/test_tools_and_actions_block_buttons_kk.py new file mode 100644 index 00000000..512dd92a --- /dev/null +++ b/tests/manage_jenkins_project/test_tools_and_actions_block_buttons_kk.py @@ -0,0 +1,29 @@ +def test_tools_and_actions_block_buttons(page): + page.goto("/manage/") + + tools_and_actions_block_expected_content = [ + "Reload Configuration from Disk", + "Jenkins CLI", + "Script Console", + "Prepare for Shutdown" + ] + + tools_and_actions_block_actual_content = [] + + page_blocks = page.locator("section[class='jenkins-section jenkins-section--bottom-padding']").all() + + + items_missed = [] + + for block in page_blocks: + if block.locator("h2[class='jenkins-section__title']").text_content() == "Tools and Actions": + block_items = block.locator("div[class='jenkins-section__item']").all() + + for item in block_items: + tools_and_actions_block_actual_content.append(item.locator("dt").text_content()) + + for item in tools_and_actions_block_expected_content: + if item not in tools_and_actions_block_actual_content: + items_missed.append(item) + + assert items_missed == [], f"Items missed: {', '.join(items_missed)}" \ No newline at end of file diff --git a/tests/manage_jenkins_project/test_troubleshooting_block_buttons_kk.py b/tests/manage_jenkins_project/test_troubleshooting_block_buttons_kk.py new file mode 100644 index 00000000..3c1857ba --- /dev/null +++ b/tests/manage_jenkins_project/test_troubleshooting_block_buttons_kk.py @@ -0,0 +1,26 @@ +def test_troubleshooting_block_buttons(page): + page.goto("/manage/") + + troubleshooting_block_expected_content = [ + "Manage Old Data" + ] + + troubleshooting_block_actual_content = [] + + page_blocks = page.locator("section[class='jenkins-section jenkins-section--bottom-padding']").all() + + + items_missed = [] + + for block in page_blocks: + if block.locator("h2[class='jenkins-section__title']").text_content() == "Troubleshooting": + block_items = block.locator("div[class='jenkins-section__item']").all() + + for item in block_items: + troubleshooting_block_actual_content.append(item.locator("dt").text_content()) + + for item in troubleshooting_block_expected_content: + if item not in troubleshooting_block_actual_content: + items_missed.append(item) + + assert items_missed == [], f"Items missed: {', '.join(items_missed)}" \ No newline at end of file diff --git a/tests/new_item/test_blank_item_name_field_validation_rf_tn.py b/tests/new_item/test_blank_item_name_field_validation_rf_tn.py new file mode 100644 index 00000000..89808e8e --- /dev/null +++ b/tests/new_item/test_blank_item_name_field_validation_rf_tn.py @@ -0,0 +1,26 @@ +from playwright.sync_api import expect +from locators.base_locators import BaseLocators +from locators.new_item_locators import NewItemLocators +from data.endpoints import Endpoints +from conftest import open_page +from pages.base_page import BasePage +from data.data import NewItemPageData +from data.data import ItemTypesData +import pytest + + + + +class TestBlankFieldValidation: + locators = BaseLocators(), NewItemLocators() + endpoints = Endpoints() + + + @pytest.mark.parametrize("item_type", ItemTypesData.ITEM_TYPES) + def test_tc_01_001_04_blank_item_name_validation_1(self, open_page, page, item_type): + """TC_01.001.04 | New Item > Create a new item > Validation error when "Enter an item name" field is blank""" + + open_page(BasePage, self.endpoints.ALL_NEW_JOB_URL) + page.get_by_text(item_type, exact=True).click() + expect(page.get_by_text(NewItemPageData.EMPTY_ITEM_NAME_VALIDATION_TEXT, exact=True)).to_be_visible() + expect(page.locator(BaseLocators.OK_BUTTON)).to_be_disabled() diff --git a/tests/new_item/test_verify_visual_selection_ya.py b/tests/new_item/test_verify_visual_selection_ya.py new file mode 100644 index 00000000..3f069357 --- /dev/null +++ b/tests/new_item/test_verify_visual_selection_ya.py @@ -0,0 +1,16 @@ +from pages.new_item_page import NewItemPage +from locators.new_item_locators import NewItemLocators +from utils.generators.project_generator import ProjectGenerator + + +def test_tc_01_004_02_pipeline_type_visual_selection(page, open_page): + """TC_01.004.02 | New Item > Select an Item type > Verify visual selection of Pipeline type""" + + new_item_page = open_page(NewItemPage, "/view/all/newJob") + new_item_page.fill(NewItemLocators.NAME_FIELD, ProjectGenerator.generate_pipeline_name()) + new_item_page.click(NewItemLocators.PIPELINE_TYPE) + + pipeline_element = new_item_page.page.locator(NewItemLocators.PIPELINE_TYPE) + assert "active" in pipeline_element.get_attribute("class") + + diff --git a/tests/old_tests/test_entire_list_visible_ev.py b/tests/old_tests/test_entire_list_visible_ev.py new file mode 100644 index 00000000..be54137a --- /dev/null +++ b/tests/old_tests/test_entire_list_visible_ev.py @@ -0,0 +1,31 @@ +import time + +from playwright.sync_api import expect + +def test_entire_list_visible(page): + page.goto('/') + time.sleep(2) + + page.locator("a[href='/view/all/newJob']").click() + + label1 = page.locator('//label/span[contains(@class, "label") and contains(text(), "Freestyle project")]') + expect(label1).to_have_text("Freestyle project") + + label2 = page.locator('(//span[contains(text(), "Pipeline")])[1]') + expect(label2).to_have_text("Pipeline") + + label3 = page.locator('(//span[contains(text(), "Multi-configuration project")])') + expect(label3).to_have_text("Multi-configuration project") + + label4 = page.locator('(//span[contains(text(), "Folder")])[1]') + expect(label4).to_have_text("Folder") + + label5 = page.locator('(//span[contains(text(), "Multibranch Pipeline")])') + expect(label5).to_have_text("Multibranch Pipeline") + + label6 = page.locator('(//span[contains(text(), "Organization Folder")])') + expect(label6).to_have_text("Organization Folder") + + + + diff --git a/tests/old_tests/test_verify_an_input_field_ev.py b/tests/old_tests/test_verify_an_input_field_ev.py new file mode 100644 index 00000000..3e17699f --- /dev/null +++ b/tests/old_tests/test_verify_an_input_field_ev.py @@ -0,0 +1,15 @@ +import time +from playwright.sync_api import expect + +def test_verify_an_input_field(page): + page.goto('/') + time.sleep(2) + + page.locator("a[href='/view/all/newJob']").click() + + label = page.locator('//label[@for="name"]') + + expect(label).to_have_text("Enter an item name") + + + diff --git a/tests/old_tests/test_verify_visual_selection_ya.py b/tests/old_tests/test_verify_visual_selection_ya.py deleted file mode 100644 index 35621fef..00000000 --- a/tests/old_tests/test_verify_visual_selection_ya.py +++ /dev/null @@ -1,17 +0,0 @@ - - -def test_verify_visual_selection(page): - - page.goto("/view/all/newJob") - page.fill("#name", "Test_Pipeline") - - - pipeline_locator = page.locator("li.org_jenkinsci_plugins_workflow_job_WorkflowJob") - pipeline_locator.click() - - assert "active" in pipeline_locator.get_attribute("class") - - ok_button = page.locator("button#ok-button") - assert ok_button.is_enabled() - - diff --git a/tests/pipeline_project/test_pipeline_project.py b/tests/pipeline_project/test_pipeline_project.py index 94760cfc..bb841a03 100644 --- a/tests/pipeline_project/test_pipeline_project.py +++ b/tests/pipeline_project/test_pipeline_project.py @@ -1,3 +1,5 @@ +import allure + from data.enums import ItemType from data.endpoints import Endpoints from pages.base_configuration_page import BaseConfigurationPage @@ -5,12 +7,14 @@ from pages.jenkins_base_page import JenkinsBasePage from utils.generators.project_generator import ProjectGenerator - +@allure.epic("Pipeline") +@allure.feature("Essential features in pipeline") class TestPipeline: generator = ProjectGenerator() endpoints = Endpoints() item_type = ItemType + @allure.story("Create pipeline") def test_create_pipeline_project(self, create_job, open_page): job_name = create_job(self.generator.generate_folder_name(), ItemType.PIPELINE) folder_project = open_page(JenkinsBasePage, self.endpoints.VIEW_ALL_PAGE_URL) @@ -18,6 +22,7 @@ def test_create_pipeline_project(self, create_job, open_page): assert name == job_name + @allure.story("Create pipeline with description") def test_tc_03_002_01_create_project_with_description(self, page, create_job, open_page): """Add description to the new project""" description_text = self.generator.generate_random_text(10) # generate random text for description @@ -32,6 +37,7 @@ def test_tc_03_002_01_create_project_with_description(self, page, create_job, op assert text == description_text + @allure.story("Add description to the existing pipeline job") def test_rf_tc_03_002_02_add_description(self, create_job, open_page): """Add description to the existing project""" description_text = self.generator.generate_random_text(10) # generate random text for description