From 04f915df758a1239d1d963ec0c4c71d93705fb20 Mon Sep 17 00:00:00 2001 From: szymon-kellton <130459593+szymon-kellton@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:58:16 +0100 Subject: [PATCH] Selenium - feedback (#3694) * Added fixture * Smoke tests added * Added tests * Enebale tests * Test Automation: Fixed locator for Grievance * Added tests; black & isort & flake8 & mypy. * Fixed tests * Fixed BA creation in conftest.py --- .../accountability/fixtures/data-cypress.json | 8 +- .../apps/core/fixtures/data-selenium.json | 17 + .../apps/household/fixtures/data-cypress.json | 1 - backend/selenium_tests/conftest.py | 20 + .../girevance/feedback/test_feedback.py | 361 ++++++++++++++++++ backend/selenium_tests/helpers/helper.py | 56 ++- .../page_object/base_components.py | 20 + backend/selenium_tests/page_object/filters.py | 5 + .../grievance/details_feedback_page.py | 4 + .../page_object/grievance/feedback.py | 42 +- .../page_object/grievance/new_feedback.py | 79 +++- 11 files changed, 566 insertions(+), 47 deletions(-) create mode 100644 backend/hct_mis_api/apps/core/fixtures/data-selenium.json create mode 100644 backend/selenium_tests/girevance/feedback/test_feedback.py create mode 100644 backend/selenium_tests/page_object/filters.py diff --git a/backend/hct_mis_api/apps/accountability/fixtures/data-cypress.json b/backend/hct_mis_api/apps/accountability/fixtures/data-cypress.json index 9ca4b86af9..b2a2b4f6b3 100644 --- a/backend/hct_mis_api/apps/accountability/fixtures/data-cypress.json +++ b/backend/hct_mis_api/apps/accountability/fixtures/data-cypress.json @@ -16,9 +16,7 @@ "area": "", "language": "", "consent": true, - "created_by": "4196c2c5-c2dd-48d2-887f-3a9d39e78916", - "linked_grievance": null, - "program": "de3a43bf-a755-41ff-a5c0-acd02cf3d244" + "linked_grievance": null } }, { @@ -38,9 +36,7 @@ "area": "", "language": "", "consent": false, - "created_by": "4196c2c5-c2dd-48d2-887f-3a9d39e78916", - "linked_grievance": null, - "program": "de3a43bf-a755-41ff-a5c0-acd02cf3d244" + "linked_grievance": null } } ] \ No newline at end of file diff --git a/backend/hct_mis_api/apps/core/fixtures/data-selenium.json b/backend/hct_mis_api/apps/core/fixtures/data-selenium.json new file mode 100644 index 0000000000..a1eac6294c --- /dev/null +++ b/backend/hct_mis_api/apps/core/fixtures/data-selenium.json @@ -0,0 +1,17 @@ +[{ + "model": "core.datacollectingtype", + "pk": 1, + "fields": { + "created": "2023-09-25T17:57:16.284Z", + "modified": "2023-09-25T17:57:16.284Z", + "label": "Full_TEST", + "code": "full_test", + "description": "Full individual collected", + "active": true, + "individual_filters_available": true, + "household_filters_available": true, + "compatible_types": [], + "limit_to": [] + } + } +] diff --git a/backend/hct_mis_api/apps/household/fixtures/data-cypress.json b/backend/hct_mis_api/apps/household/fixtures/data-cypress.json index 0fa4b09cbb..555312b1c2 100644 --- a/backend/hct_mis_api/apps/household/fixtures/data-cypress.json +++ b/backend/hct_mis_api/apps/household/fixtures/data-cypress.json @@ -493,7 +493,6 @@ "model": "household.individualidentity", "pk": 7, "fields": { - "partner": 1, "individual": "bc5a5b20-74a4-4d48-ab63-99a0c913850d", "number": "johniak pany", "country": "d1eb1574-8146-4c70-a804-caf163d451a6" diff --git a/backend/selenium_tests/conftest.py b/backend/selenium_tests/conftest.py index 56e8b843e2..583de81727 100644 --- a/backend/selenium_tests/conftest.py +++ b/backend/selenium_tests/conftest.py @@ -9,6 +9,9 @@ from _pytest.nodes import Item from _pytest.runner import CallInfo from page_object.admin_panel.admin_panel import AdminPanel +from page_object.grievance.details_feedback_page import FeedbackDetailsPage +from page_object.grievance.feedback import Feedback +from page_object.grievance.new_feedback import NewFeedback from page_object.programme_details.programme_details import ProgrammeDetails from page_object.programme_management.programme_management import ProgrammeManagement from pytest_django.live_server_helper import LiveServer @@ -89,10 +92,26 @@ def pageAdminPanel(request: FixtureRequest, browser: Chrome) -> AdminPanel: yield AdminPanel(browser) +@pytest.fixture +def pageFeedback(request: FixtureRequest, browser: Chrome) -> Feedback: + yield Feedback(browser) + + +@pytest.fixture +def pageFeedbackDetails(request: FixtureRequest, browser: Chrome) -> FeedbackDetailsPage: + yield FeedbackDetailsPage(browser) + + +@pytest.fixture +def pageNewFeedback(request: FixtureRequest, browser: Chrome) -> NewFeedback: + yield NewFeedback(browser) + + @pytest.fixture def business_area() -> BusinessArea: business_area, _ = BusinessArea.objects.get_or_create( **{ + "pk": "c259b1a0-ae3a-494e-b343-f7c8eb060c68", "code": "0060", "name": "Afghanistan", "long_name": "THE ISLAMIC REPUBLIC OF AFGHANISTAN", @@ -131,6 +150,7 @@ def create_super_user(business_area: BusinessArea) -> User: country = Country.objects.get(name="Afghanistan") business_area.countries.add(country) user = UserFactory.create( + pk="4196c2c5-c2dd-48d2-887f-3a9d39e78916", is_superuser=True, is_staff=True, username="superuser", diff --git a/backend/selenium_tests/girevance/feedback/test_feedback.py b/backend/selenium_tests/girevance/feedback/test_feedback.py new file mode 100644 index 0000000000..96b533c73c --- /dev/null +++ b/backend/selenium_tests/girevance/feedback/test_feedback.py @@ -0,0 +1,361 @@ +from django.conf import settings +from django.core.management import call_command + +import pytest +from page_object.grievance.details_feedback_page import FeedbackDetailsPage +from page_object.grievance.feedback import Feedback +from page_object.grievance.new_feedback import NewFeedback +from page_object.programme_details.programme_details import ProgrammeDetails +from selenium.webdriver import Keys + +pytestmark = pytest.mark.django_db(transaction=True) + + +@pytest.fixture +def add_feedbacks() -> None: + call_command("loaddata", f"{settings.PROJECT_ROOT}/apps/accountability/fixtures/data-cypress.json") + return + + +@pytest.fixture +def add_households() -> None: + call_command("loaddata", f"{settings.PROJECT_ROOT}/apps/registration_data/fixtures/data-cypress.json") + call_command("loaddata", f"{settings.PROJECT_ROOT}/apps/household/fixtures/data-cypress.json") + return + + +@pytest.fixture +def create_programs() -> None: + call_command("loaddata", f"{settings.PROJECT_ROOT}/apps/core/fixtures/data-selenium.json") + call_command("loaddata", f"{settings.PROJECT_ROOT}/apps/program/fixtures/data-cypress.json") + return + + +@pytest.mark.usefixtures("login") +class TestSmokeFeedback: + def test_check_feedback_page( + self, + pageFeedback: Feedback, + ) -> None: + """ + Go to Grievance page + Go to Feedback page + Check if all elements on page exist + """ + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Check Feedback page + pageFeedback.getTitlePage() + pageFeedback.getButtonSubmitNewFeedback() + pageFeedback.getFilterSearch() + pageFeedback.getFilterIssueType() + pageFeedback.getFilterCreatedBy() + pageFeedback.getFilterCreationDateFrom() + pageFeedback.getFilterCreationDateTo() + pageFeedback.getButtonClear() + pageFeedback.getButtonApply() + assert pageFeedback.textTableTitle in pageFeedback.getTableTitle().text + assert pageFeedback.textFeedbackID in pageFeedback.getFeedbackID().text + assert pageFeedback.textIssueType in pageFeedback.getIssueType().text + assert pageFeedback.textHouseholdID in pageFeedback.getHouseholdID().text + assert pageFeedback.textLinkedGrievance in pageFeedback.getLinkedGrievance().text + assert pageFeedback.textCreatedBy in pageFeedback.getCreatedBy().text + assert pageFeedback.textCreationDate in pageFeedback.getCreationDate().text + + def test_check_feedback_details_page( + self, + add_feedbacks: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + ) -> None: + """ + Go to Grievance page + Go to Feedback page + Choose Feedback + Check if all elements on page exist + """ + # Go to Feedback + pageFeedback.driver.refresh() + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + pageFeedback.getRow(0).click() + # Check Feedback details page + assert pageFeedbackDetails.textTitle in pageFeedbackDetails.getTitlePage().text + pageFeedbackDetails.getButtonEdit() + assert pageFeedbackDetails.textCategory in pageFeedbackDetails.getCategory().text + assert pageFeedbackDetails.textIssueType in pageFeedbackDetails.getIssueType().text + pageFeedbackDetails.getHouseholdID() + pageFeedbackDetails.getIndividualID() + pageFeedbackDetails.getCreatedBy() + pageFeedbackDetails.getDateCreated() + pageFeedbackDetails.getLastModifiedDate() + pageFeedbackDetails.getAdministrativeLevel2() + + +@pytest.mark.skip(reason="ToDo: Filters") +@pytest.mark.usefixtures("login") +class TestFeedbackFilters: + def feedback_search_filter(self) -> None: + pass + + def feedback_programme_filter(self) -> None: + pass + + def feedback_issue_type_filter(self) -> None: + pass + + def feedback_created_by_filter(self) -> None: + pass + + def feedback_creation_date_filter(self) -> None: + pass + + def feedback_programme_state_filter(self) -> None: + pass + + def feedback_clear_button(self) -> None: + pass + + +@pytest.mark.usefixtures("login") +class TestFeedback: + @pytest.mark.parametrize("issue_type", ["Positive", "Negative"]) + def test_create_feedback_mandatory_fields( + self, + issue_type: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Create Feedback + pageFeedback.getButtonSubmitNewFeedback().click() + pageNewFeedback.chooseOptionByName(issue_type) + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getHouseholdTab() + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getReceivedConsent().click() + pageNewFeedback.getButtonNext().click() + assert "Feedback" in pageNewFeedback.getLabelCategory().text + pageNewFeedback.getDescription().send_keys("Test") + pageNewFeedback.check_page_after_click(pageNewFeedback.getButtonNext(), "=") + # Check Details page + assert pageFeedbackDetails.textCategory in pageFeedbackDetails.getCategory().text + assert issue_type in pageFeedbackDetails.getIssueType().text + assert "-" in pageFeedbackDetails.getHouseholdID().text + assert "-" in pageFeedbackDetails.getIndividualID().text + assert "-" in pageFeedbackDetails.getProgramme().text + assert "Test" in pageFeedbackDetails.getDescription().text + pageFeedbackDetails.getLastModifiedDate() + pageFeedbackDetails.getAdministrativeLevel2() + + @pytest.mark.parametrize("issue_type", ["Positive", "Negative"]) + def test_create_feedback_optional_fields( + self, + issue_type: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Create Feedback + pageFeedback.getButtonSubmitNewFeedback().click() + pageNewFeedback.chooseOptionByName(issue_type) + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getHouseholdTab() + pageNewFeedback.getIndividualTab() + pageFeedback.getTableRowLoading() + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getReceivedConsent().click() + pageNewFeedback.getButtonNext().click() + assert "Feedback" in pageNewFeedback.getLabelCategory().text + pageNewFeedback.getDescription().send_keys("Test") + pageNewFeedback.check_page_after_click(pageNewFeedback.getButtonNext(), "=") + # Check Details page + assert pageFeedbackDetails.textCategory in pageFeedbackDetails.getCategory().text + assert issue_type in pageFeedbackDetails.getIssueType().text + assert "-" in pageFeedbackDetails.getHouseholdID().text + assert "-" in pageFeedbackDetails.getIndividualID().text + assert "-" in pageFeedbackDetails.getProgramme().text + assert "Test" in pageFeedbackDetails.getDescription().text + pageFeedbackDetails.getLastModifiedDate() + pageFeedbackDetails.getAdministrativeLevel2() + + def test_check_feedback_filtering_by_chosen_programme( + self, + create_programs: None, + add_feedbacks: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + pageProgrammeDetails: ProgrammeDetails, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Edit field Programme in Feedback + pageFeedback.getRow(0).click() + assert "-" in pageFeedbackDetails.getProgramme().text + pageFeedbackDetails.getButtonEdit().click() + pageNewFeedback.selectProgramme("Test Programm").click() + pageNewFeedback.getButtonNext().click() + # Check Feedback filtering by chosen Programme + assert "Test Programm" in pageFeedbackDetails.getProgramme().text + assert pageFeedback.globalProgramFilterText in pageFeedback.getGlobalProgramFilter().text + pageFeedback.selectGlobalProgramFilter("Test Programm").click() + assert "Test Programm" in pageProgrammeDetails.getHeaderTitle().text + pageFeedback.wait_for_disappear(pageFeedback.navGrievanceDashboard) + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + pageFeedback.disappearTableRowLoading() + assert 1 == len(pageFeedback.getRows()) + assert "Negative Feedback" in pageFeedback.getRow(0).find_elements("tag name", "td")[1].text + + pageFeedback.selectGlobalProgramFilter("Draft Program").click() + assert "Draft Program" in pageProgrammeDetails.getHeaderTitle().text + pageFeedback.wait_for_disappear(pageFeedback.navGrievanceDashboard) + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + assert 0 == len(pageFeedback.getRows()) + + pageFeedback.selectGlobalProgramFilter("All Programmes").click() + assert "Programme Management" in pageProgrammeDetails.getHeaderTitle().text + pageFeedback.wait_for_disappear(pageFeedback.navGrievanceDashboard) + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + pageFeedback.disappearTableRowLoading() + assert 2 == len(pageFeedback.getRows()) + + def test_create_feedback_with_household( + self, + create_programs: None, + add_households: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Create Feedback + pageFeedback.getButtonSubmitNewFeedback().click() + pageNewFeedback.chooseOptionByName("Negative feedback") + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getHouseholdTab() + pageNewFeedback.getHouseholdTableRows(1).click() + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getReceivedConsent().click() + pageNewFeedback.getButtonNext().click() + assert "Feedback" in pageNewFeedback.getLabelCategory().text + pageNewFeedback.getDescription().send_keys("Test") + pageNewFeedback.check_page_after_click(pageNewFeedback.getButtonNext(), "=") + # Check Details page + assert "Test Programm" in pageFeedbackDetails.getProgramme().text + pageFeedback.getNavFeedback().click() + pageFeedback.getRows() + + def test_create_feedback_with_household_and_individual( + self, + create_programs: None, + add_households: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Create Feedback + pageFeedback.getButtonSubmitNewFeedback().click() + pageNewFeedback.chooseOptionByName("Negative feedback") + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getHouseholdTab() + pageNewFeedback.getHouseholdTableRows(1).click() + pageNewFeedback.getIndividualTab().click() + pageNewFeedback.getIndividualTableRow(2).click() + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getReceivedConsent().click() + pageNewFeedback.getButtonNext().click() + assert "Feedback" in pageNewFeedback.getLabelCategory().text + pageNewFeedback.getDescription().send_keys("Test") + pageNewFeedback.check_page_after_click(pageNewFeedback.getButtonNext(), "=") + # Check Details page + assert "Test Programm" in pageFeedbackDetails.getProgramme().text + pageFeedback.getNavFeedback().click() + pageFeedback.getRows() + + def test_create_feedback_with_individual( + self, + create_programs: None, + add_households: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Create Feedback + pageFeedback.getButtonSubmitNewFeedback().click() + pageNewFeedback.chooseOptionByName("Negative feedback") + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getHouseholdTab() + pageNewFeedback.getHouseholdTableRows(1).click() + pageNewFeedback.getIndividualTab().click() + pageNewFeedback.getIndividualTableRow(2).click() + pageNewFeedback.getButtonNext().click() + pageNewFeedback.getReceivedConsent().click() + pageNewFeedback.getButtonNext().click() + assert "Feedback" in pageNewFeedback.getLabelCategory().text + pageNewFeedback.getDescription().send_keys("Test") + pageNewFeedback.check_page_after_click(pageNewFeedback.getButtonNext(), "=") + # Check Details page + assert "Test Programm" in pageFeedbackDetails.getProgramme().text + pageFeedback.getNavFeedback().click() + pageFeedback.getRows() + + def test_edit_feedback( + self, + create_programs: None, + add_feedbacks: None, + pageFeedback: Feedback, + pageFeedbackDetails: FeedbackDetailsPage, + pageNewFeedback: NewFeedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() + # Edit field Programme in Feedback + pageFeedback.getRow(0).click() + assert "-" in pageFeedbackDetails.getProgramme().text + pageFeedbackDetails.getButtonEdit().click() + pageNewFeedback.selectProgramme("Draft Program").click() + pageNewFeedback.getDescription().click() + pageNewFeedback.getDescription().send_keys(Keys.CONTROL, "a") + pageNewFeedback.getDescription().send_keys("New description") + pageNewFeedback.getComments().send_keys("New comment, new comment. New comment?") + pageNewFeedback.getInputArea().send_keys("Abkamari") + pageNewFeedback.getInputLanguage().send_keys("English") + # ToDo: Enable after Fix bug + # pageNewFeedback.selectArea("Abband").click() + pageNewFeedback.getButtonNext().click() + # Check edited Feedback + assert "Draft Program" in pageFeedbackDetails.getProgramme().text + assert "New description" in pageFeedbackDetails.getDescription().text + assert "New comment, new comment. New comment?" in pageFeedbackDetails.getComments().text + assert "Abkamari" in pageFeedbackDetails.getAreaVillagePayPoint().text + assert "English" in pageFeedbackDetails.getLanguagesSpoken().text + + @pytest.mark.skip(reason="Create during Grievance tickets creation tests") + def test_create_linked_ticket( + self, + pageFeedback: Feedback, + ) -> None: + # Go to Feedback + pageFeedback.getNavGrievance().click() + pageFeedback.getNavFeedback().click() diff --git a/backend/selenium_tests/helpers/helper.py b/backend/selenium_tests/helpers/helper.py index 0fd67daf33..beeb042852 100644 --- a/backend/selenium_tests/helpers/helper.py +++ b/backend/selenium_tests/helpers/helper.py @@ -1,3 +1,4 @@ +import os from time import sleep from typing import Literal, Union @@ -10,24 +11,36 @@ class Common: + DEFAULT_TIMEOUT = 100 + def __init__(self, driver: Chrome): self.driver = driver self.action = ActionChains(self.driver) - self._wait = WebDriverWait(self.driver, 60) + + def _wait(self, timeout: int = DEFAULT_TIMEOUT) -> WebDriverWait: + return WebDriverWait(self.driver, timeout) def get(self, locator: str, element_type: str = By.CSS_SELECTOR) -> WebElement: return self.driver.find_element(element_type, locator) - def get_elements(self, locator: str, element_type: str = By.CSS_SELECTOR) -> list[WebElement]: - return self.driver.find_elements(element_type, locator) + def get_elements(self, locator: str, element_type: str = By.CSS_SELECTOR, attempts: int = 1) -> list[WebElement]: + for _ in range(attempts): + try: + elements = self.driver.find_elements(element_type, locator) + except (ValueError, IndexError): + sleep(1) + else: + return elements + else: + raise Exception("No elements found") - def wait_for(self, locator: str, element_type: str = By.CSS_SELECTOR) -> WebElement: - return self._wait.until(EC.visibility_of_element_located((element_type, locator))) + def wait_for(self, locator: str, element_type: str = By.CSS_SELECTOR, timeout: int = DEFAULT_TIMEOUT) -> WebElement: + return self._wait(timeout).until(EC.visibility_of_element_located((element_type, locator))) def wait_for_disappear( - self, locator: str, element_type: str = By.CSS_SELECTOR + self, locator: str, element_type: str = By.CSS_SELECTOR, timeout: int = DEFAULT_TIMEOUT ) -> Union[Literal[False, True], WebElement]: - return self._wait.until_not(EC.visibility_of_element_located((element_type, locator))) + return self._wait(timeout).until_not(EC.visibility_of_element_located((element_type, locator))) def wait_for_new_url(self, old_url: str, retry: int = 5) -> str: for _ in range(retry): @@ -36,6 +49,35 @@ def wait_for_new_url(self, old_url: str, retry: int = 5) -> str: break return self.driver.current_url + def select_listbox_element( + self, name: str, listbox: str = 'ul[role="listbox"]', tag_name: str = "li" + ) -> WebElement: + select_element = self.wait_for(listbox) + items = select_element.find_elements("tag name", tag_name) + for item in items: + if name in item.text: + return item + return select_element + + def check_page_after_click(self, button: WebElement, url_fragment: str) -> None: + programme_creation_url = self.driver.current_url + button.click() + assert url_fragment in self.wait_for_new_url(programme_creation_url).split("/")[-1] + + @staticmethod + def choose_option(list_options: list, name: str) -> bool: + for option in list_options: + if name in option.text: + option.click() + return True + return False + @staticmethod def find_in_element(element: WebElement, locator: str, element_type: str = By.CSS_SELECTOR) -> list[WebElement]: return element.find_elements(element_type, locator) + + def screenshot( + self, file_name: str = "test", file_type: str = "png", file_path: str = "screenshot", delay_sec: int = 1 + ) -> None: + sleep(delay_sec) + self.driver.get_screenshot_as_file(os.path.join(f"{file_path}", f"{file_name}.{file_type}")) diff --git a/backend/selenium_tests/page_object/base_components.py b/backend/selenium_tests/page_object/base_components.py index da7781de28..e2d08dfd69 100644 --- a/backend/selenium_tests/page_object/base_components.py +++ b/backend/selenium_tests/page_object/base_components.py @@ -3,7 +3,27 @@ class BaseComponents(Common): + globalProgramFilter = 'div[data-cy="global-program-filter"]' navProgrammeManagement = 'a[data-cy="nav-Programme Management"]' + navGrievance = 'a[data-cy="nav-Grievance"]' + navFeedback = 'a[data-cy="nav-Feedback"]' + navGrievanceTicket = 'a[data-cy="nav-Grievance Tickets"]' + navGrievanceDashboard = 'a[data-cy="nav-Grievance Dashboard"]' + + globalProgramFilterText = "All Programmes" def getNavProgrammeManagement(self) -> WebElement: return self.wait_for(self.navProgrammeManagement) + + def getNavFeedback(self) -> WebElement: + return self.wait_for(self.navFeedback) + + def getNavGrievance(self) -> WebElement: + return self.wait_for(self.navGrievance) + + def getGlobalProgramFilter(self) -> WebElement: + return self.wait_for(self.globalProgramFilter) + + def selectGlobalProgramFilter(self, name: str) -> WebElement: + self.getGlobalProgramFilter().click() + return self.select_listbox_element(name) diff --git a/backend/selenium_tests/page_object/filters.py b/backend/selenium_tests/page_object/filters.py new file mode 100644 index 0000000000..8f75ace036 --- /dev/null +++ b/backend/selenium_tests/page_object/filters.py @@ -0,0 +1,5 @@ +from helpers.helper import Common + + +class Filters(Common): + search = "" diff --git a/backend/selenium_tests/page_object/grievance/details_feedback_page.py b/backend/selenium_tests/page_object/grievance/details_feedback_page.py index 69d1e7d6a9..854ef82144 100644 --- a/backend/selenium_tests/page_object/grievance/details_feedback_page.py +++ b/backend/selenium_tests/page_object/grievance/details_feedback_page.py @@ -11,6 +11,7 @@ class FeedbackDetailsPage(BaseComponents): labelIssueType = 'div[data-cy="label-Issue Type"]' labelHouseholdID = 'div[data-cy="label-Household ID"]' labelIndividualID = 'div[data-cy="label-Individual ID"]' + labelProgramme = 'div[data-cy="label-Programme"]' labelCreatedBy = 'div[data-cy="label-Created By"]' labelDateCreated = 'div[data-cy="label-Date Created"]' labelLastModifiedDate = 'div[data-cy="label-Last Modified Date"]' @@ -50,6 +51,9 @@ def getHouseholdID(self) -> WebElement: def getIndividualID(self) -> WebElement: return self.wait_for(self.labelIndividualID) + def getProgramme(self) -> WebElement: + return self.wait_for(self.labelProgramme) + def getCreatedBy(self) -> WebElement: return self.wait_for(self.labelCreatedBy) diff --git a/backend/selenium_tests/page_object/grievance/feedback.py b/backend/selenium_tests/page_object/grievance/feedback.py index 79358d62f8..571a4ebeb8 100644 --- a/backend/selenium_tests/page_object/grievance/feedback.py +++ b/backend/selenium_tests/page_object/grievance/feedback.py @@ -1,3 +1,5 @@ +from time import sleep + from page_object.base_components import BaseComponents from selenium.webdriver.remote.webelement import WebElement @@ -8,9 +10,9 @@ class Feedback(BaseComponents): buttonSubmitNewFeedback = 'a[data-cy="button-submit-new-feedback"]' filterSearch = 'div[data-cy="filters-search"]' filterIssueType = 'div[data-cy="filters-issue-type"]' - filterCreatedBy = 'div[data-cy="filters-created-by"]' - filterCreationDateFrom = 'div[data-cy="filters-creation-date-from"]' - filterCreationDateTo = 'div[data-cy="filters-creation-date-to"]' + filterCreatedBy = 'div[data-cy="Created by-input"]' + filterCreationDateFrom = 'div[data-cy="date-picker-filter"]' + filterCreationDateTo = 'div[data-cy="date-picker-filter"]' buttonClear = 'button[data-cy="button-filters-clear"]' buttonApply = 'button[data-cy="button-filters-apply"]' tableTitle = 'h6[data-cy="table-title"]' @@ -24,6 +26,7 @@ class Feedback(BaseComponents): dateTitleFilterPopup = 'div[class="MuiPaper-root MuiPopover-paper MuiPaper-elevation8 MuiPaper-rounded"]' issueTypeFilter = 'div[data-cy="filters-issue-type"]' option = 'li[role="option"]' + tableRowLoading = 'tr[data-cy="table-row"]' # Texts textTitle = "Feedback" @@ -52,10 +55,10 @@ def getFilterCreatedBy(self) -> WebElement: return self.wait_for(self.filterCreatedBy) def getFilterCreationDateFrom(self) -> WebElement: - return self.wait_for(self.filterCreationDateFrom) + return self.get_elements(self.filterCreationDateFrom)[0] def getFilterCreationDateTo(self) -> WebElement: - return self.wait_for(self.filterCreationDateTo) + return self.get_elements(self.filterCreationDateTo)[1] def getButtonClear(self) -> WebElement: return self.wait_for(self.buttonClear) @@ -70,25 +73,32 @@ def getTableTitle(self) -> WebElement: return self.wait_for(self.tableTitle) def getFeedbackID(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(0) + return self.get_elements(self.tableColumns)[0] def getIssueType(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(1) + return self.get_elements(self.tableColumns)[1] def getHouseholdID(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(2) + return self.get_elements(self.tableColumns)[2] def getLinkedGrievance(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(3) + return self.get_elements(self.tableColumns)[3] def getCreatedBy(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(4) + return self.get_elements(self.tableColumns)[4] def getCreationDate(self) -> WebElement: - return self.wait_for(self.tableColumns).eq(5) + return self.get_elements(self.tableColumns)[5] + + def getRows(self) -> list[WebElement]: + return self.get_elements(self.tableRow) - def getRows(self) -> WebElement: - return self.wait_for(self.tableRow) + def getRow(self, number: int) -> WebElement: + for _ in range(10): + if len(self.get_elements(self.tableRow)) == number + 1: + break + sleep(1) + return self.get_elements(self.tableRow)[number] def getDaysFilterPopup(self) -> WebElement: return self.wait_for(self.daysFilterPopup) @@ -102,5 +112,11 @@ def getDateTitleFilterPopup(self) -> WebElement: def getIssueTypeFilter(self) -> WebElement: return self.wait_for(self.issueTypeFilter) + def disappearTableRowLoading(self) -> WebElement: + return self.wait_for_disappear(self.tableRowLoading) + + def getTableRowLoading(self) -> WebElement: + return self.wait_for(self.tableRowLoading) + def getOption(self) -> WebElement: return self.wait_for(self.option) diff --git a/backend/selenium_tests/page_object/grievance/new_feedback.py b/backend/selenium_tests/page_object/grievance/new_feedback.py index 741b91bf07..a99b06e656 100644 --- a/backend/selenium_tests/page_object/grievance/new_feedback.py +++ b/backend/selenium_tests/page_object/grievance/new_feedback.py @@ -1,3 +1,5 @@ +from time import sleep + from page_object.base_components import BaseComponents from selenium.webdriver.remote.webelement import WebElement @@ -14,14 +16,18 @@ class NewFeedback(BaseComponents): buttonNext = 'button[data-cy="button-submit"]' option = 'li[role="option"]' householdTableRow = 'tr[data-cy="household-table-row"]' - individualTableRow = 'tr[data-cy="individual-table-row"' - lookUpTabs = 'button[role="tab"]' + individualTableRow = 'tr[data-cy="individual-table-row"]' + lookUpTabsHouseHold = 'button[role="tab"]' + lookUpTabsIndividual = 'button[role="tab"]' receivedConsent = 'span[data-cy="input-consent"]' description = 'textarea[data-cy="input-description"]' comments = 'textarea[data-cy="input-comments"]' - adminAreaAutocomplete = 'div[data-cy="input-admin2"]' + adminAreaAutocomplete = 'div[data-cy="admin-area-autocomplete"]' inputLanguage = 'textarea[data-cy="input-language"]' inputArea = 'input[data-cy="input-area"]' + programmeSelect = 'div[data-cy="select-program"]' + hhRadioButton = 'span[data-cy="input-radio-household"]' + individualRadioButton = 'span[data-cy="input-radio-individual"]' # Texts textTitle = "New Feedback" @@ -49,20 +55,42 @@ def getButtonBack(self) -> WebElement: def getButtonNext(self) -> WebElement: return self.wait_for(self.buttonNext) - def getOption(self) -> WebElement: - return self.wait_for(self.option) - - def getHouseholdTab(self) -> WebElement: - return self.wait_for(self.lookUpTabs).contains(self.textLookUpHousehold) - - def getLookUpIndividual(self) -> WebElement: - return self.wait_for(self.lookUpTabs).contains(self.textLookUpIndividual) + def getOptions(self) -> list[WebElement]: + return self.get_elements(self.option) + + def getHouseholdTab(self) -> None: + try: + household_tab = self.get_elements(self.lookUpTabsHouseHold)[0] + except IndexError: + sleep(1) + household_tab = self.get_elements(self.lookUpTabsHouseHold)[0] + assert self.textLookUpHousehold in household_tab.text + return household_tab + + def getIndividualTab(self) -> WebElement: + try: + individual_tab = self.get_elements(self.lookUpTabsIndividual, attempts=5)[1] + except IndexError: + sleep(1) + individual_tab = self.get_elements(self.lookUpTabsIndividual, attempts=5)[1] + assert self.textLookUpIndividual in individual_tab.text + return individual_tab def getHouseholdTableRows(self, number: int) -> WebElement: - return self.wait_for(self.householdTableRow).eq(number) + self.get_elements(self.hhRadioButton) + try: + return self.get_elements(self.householdTableRow, attempts=5)[number] + except IndexError: + sleep(1) + return self.get_elements(self.householdTableRow, attempts=5)[number] def getIndividualTableRow(self, number: int) -> WebElement: - return self.wait_for(self.individualTableRow).eq(number) + self.get_elements(self.individualRadioButton) + try: + return self.get_elements(self.individualTableRow, attempts=5)[number] + except IndexError: + sleep(1) + return self.get_elements(self.individualTableRow, attempts=5)[number] def getReceivedConsent(self) -> WebElement: return self.wait_for(self.receivedConsent) @@ -82,20 +110,31 @@ def getInputArea(self) -> WebElement: def getAdminAreaAutocomplete(self) -> WebElement: return self.wait_for(self.adminAreaAutocomplete) + def selectArea(self, name: str) -> WebElement: + self.getAdminAreaAutocomplete().click() + return self.select_listbox_element(name) + def getIssueType(self) -> WebElement: return self.wait_for(self.issueType) def getInputIssueType(self) -> WebElement: return self.wait_for(self.inputIssueType) + def getProgrammeSelect(self) -> WebElement: + return self.wait_for(self.programmeSelect) + + def selectProgramme(self, name: str) -> WebElement: + self.getProgrammeSelect().click() + return self.select_listbox_element(name) + def checkElementsOnPage(self) -> None: - self.getTitlePage().contains(self.textTitle) - self.getLabelCategory().contains(self.textCategory) - self.getSelectIssueType().should("be.visible") - self.getButtonCancel().should("be.visible") - self.getButtonBack().should("be.visible") - self.getButtonNext().should("be.visible") + assert self.textTitle in self.getTitlePage().text + assert self.textCategory in self.getLabelCategory().text + self.getSelectIssueType() + self.getButtonCancel() + self.getButtonBack() + self.getButtonNext() def chooseOptionByName(self, name: str) -> None: self.getSelectIssueType().click() - self.getOption().contains(name).click() + self.select_listbox_element(name).click()