Skip to content

Commit

Permalink
add case for advance search: Sort search result by extended sortable …
Browse files Browse the repository at this point in the history
…fields
  • Loading branch information
RichardXuan committed Dec 20, 2024
1 parent 6a2d5f2 commit 903919c
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 30 deletions.
5 changes: 5 additions & 0 deletions features/advance_search.feature
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,10 @@ Feature: Flaw advance search testing
Given I go to the advanced search page
Then I am able to search flaws with osidb related models in query filter

Scenario: Sort search result by extended sortable fields
Given I go to the advanced search page
When I sort search result by extended sortable field
Then I got search result sorted by extended field

Scenario: Search flaws with both query filter and selected field
Then I am able to search flaws with both query filter and selected field
66 changes: 65 additions & 1 deletion features/pages/advanced_search_page.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from features.pages.base import BasePage
import time

from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

from features.pages.base import BasePage
from features.pages.flaw_detail_page import FlawDetailPage


class AdvancedSearchPage(BasePage):
Expand Down Expand Up @@ -32,6 +39,11 @@ def __init__(self, driver):
"embargoedFlag": ("XPATH", "(//span[contains(text(), 'Embargoed')])[1]"),
"queryFilterInput": ("XPATH", "(//div[@class='input-group my-1'])[1]/textarea"),
"defaultFilterSavedMsg": ("XPATH", "//div[contains(text(), 'default filter saved')]"),

"createdBtn": ("XPATH", "//thead[@class='sticky-top']/tr/th[contains(text(), 'Created')]"),
"extendSortSelect": ("XPATH", "//select[@title='When using this sorting with active table column sort,"
" the table column field will be used as secondary sorting key']"),
"extendSortOrderBtn": ("XPATH", "//button[@class='sort-by-order btn btn-sm']"),
}

def first_flaw_exist(self):
Expand Down Expand Up @@ -74,3 +86,55 @@ def set_query_filter(self, value):
if value:
self.driver.execute_script("arguments[0].value = '';", filter_input)
filter_input.send_keys(value)

def get_specified_field_search_result(self, field_name, n=5):
flaws = self.driver.find_elements(By.XPATH, "//tbody[@class='table-group-divider']/tr")
count = 0
result = []

flaw_detail_page = FlawDetailPage(self.driver)

wait = WebDriverWait(self.driver, 10)

for flaw in flaws:
if count == n:
break
tds = flaw.find_elements(By.XPATH, './td')
if len(tds) < 6:
continue

# Store the ID of the original window
original_window = self.driver.current_window_handle

link = tds[0].find_element(By.XPATH, './a')

# open link with a new tab
(ActionChains(self.driver).key_down(Keys.LEFT_CONTROL).
click(link).key_up(Keys.LEFT_CONTROL).perform())

# Wait for the new window or tab
wait.until(EC.number_of_windows_to_be(2))

# switch to new tab
self.driver.switch_to.window(self.driver.window_handles[1])
time.sleep(5)

# get data
value = ""
if field_name == "cvss_scores__score":
value = flaw_detail_page.get_cvssV3_score()
elif field_name == "cwe_id":
value = flaw_detail_page.get_input_field_value_using_relative_locator("cweidText")
elif field_name == "major_incident_state":
value = flaw_detail_page.get_select_value_using_relative_locator("incidentStateText")
elif field_name == "source":
value = flaw_detail_page.get_select_value_using_relative_locator("sourceText")

# close tab and back to search page
self.driver.close()
self.driver.switch_to.window(original_window)

result.append(value)
count += 1

return result
36 changes: 25 additions & 11 deletions features/pages/flaw_detail_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def __init__(self, driver):
"createFlawLink": ("LINK_TEXT", "Create Flaw"),
"createNewFlawBtn": ("XPATH", '//button[contains(text(), "Create New Flaw")]'),
"embargeodCheckBox": ("XPATH", "//input[@class='form-check-input']"),
"muteNotificationIcon": (
"XPATH", "//i[@class='bi notification-icon text-white osim-notification-icon bi-bell-slash-fill']"),

"comment#0Text": ("XPATH", "//span[text()=' Comment#0']"),
"descriptionBtn": ("XPATH", "//button[contains(text(), 'Add Description')]"),
Expand Down Expand Up @@ -127,6 +129,7 @@ def __init__(self, driver):
"referenceUpdatedMsg": ("XPATH", "//div[text()='Reference updated.']"),
"rhsbReferenceLinkFormatErrorMsg": ("XPATH", '//div[contains(text(), "A flaw reference of the ARTICLE type does not begin with https://access.redhat.com")]'),
"firstReferenceDescriptionValue": ("XPATH", "(//div[@class='osim-list-edit'])[1]/div/div/div/div/span"),
"referenceTypeText": ("XPATH", "//span[text()='Reference type']"),

"bottomBar": ("XPATH", "//div[@class='osim-action-buttons sticky-bottom d-grid gap-2 d-flex justify-content-end']"),
"bottomFooter": ("XPATH", "//footer[@class='fixed-bottom osim-status-bar']"),
Expand Down Expand Up @@ -195,6 +198,7 @@ def __init__(self, driver):
"addFlawTabButton": ("XPATH", "//button[@class='nav-link osim-add-tab']"),
"trackerMangerSearchFlawInput": ("XPATH", "//input[@placeholder='Search...']"),
"trackerManagerAddFlawBtn": ("XPATH", "//button[text()='Add']"),
"confirmFileLowSeverityBtn": ("XPATH", "//button[text()=' Confirm ']"),

"msgClose": ("XPATH", "(//button[@class='osim-toast-close-btn btn-close'])[1]"),
"unembargoBtn": ("XPATH", "//button[contains(text(), 'Unembargo')]"),
Expand Down Expand Up @@ -507,7 +511,6 @@ def delete_all_reference(self):
self.referenceDelConfirmBtn.click_button()
self.wait_msg("referenceDeletedMsg")
self.close_all_toast_msg()
time.sleep(2)

def add_reference_select_external_type(self):
try:
Expand All @@ -516,21 +519,18 @@ def add_reference_select_external_type(self):
except ElementNotVisibleException:
pass

self.referenceTypeText.execute_script(
"arguments[0].scrollIntoView({behavior: 'auto',block: 'center',inline: 'center'});")

add_reference_select = self.driver.find_elements(
locate_with(By.TAG_NAME, "select").
below(self.referenceCountLabel))[0]
near(self.referenceTypeText))[0]

select = Select(add_reference_select)

WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable(
(By.XPATH, "//select[@value='ARTICLE']//option[contains(.,'External')]")))

self.driver.execute_script(
"arguments[0].scrollIntoView({behavior: 'auto',block: 'center',inline: 'center'});",
add_reference_select)

time.sleep(2)

select.select_by_visible_text("External")

def add_reference_set_link_url(self, value):
Expand Down Expand Up @@ -766,8 +766,11 @@ def set_reject_reason(self, value):
def get_select_value_using_relative_locator(self, field):
element = getattr(self, field)
field_select = self.driver.find_elements(
locate_with(By.XPATH, "//select[@class='form-select']").near(element))[0]
selected_item = field_select.get_list_selected_item()
locate_with(By.XPATH, "//select[@class='form-select']").near(element))
if not field_select:
field_select = self.driver.find_elements(
locate_with(By.XPATH, "//select[@class='form-select is-invalid']").near(element))
selected_item = field_select[0].get_list_selected_item()
current_value = selected_item[0] if selected_item else None
return current_value

Expand Down Expand Up @@ -823,8 +826,12 @@ def check_owner_value_exist(self, value):
return self.driver.find_element(By.XPATH, f"//span[text()='{value}']")

def close_all_toast_msg(self):
for toast_msg in find_elements_in_page_factory(self, 'toastMsgCloseBtn'):
notifications = find_elements_in_page_factory(self, 'toastMsgCloseBtn')
if not notifications:
return
for toast_msg in notifications:
self.click_button_with_js(toast_msg)
time.sleep(1)

def set_cvss_score_explanation(self, value):
cvss_comment_dropdown = self.driver.find_elements(
Expand Down Expand Up @@ -1036,6 +1043,13 @@ def file_tracker(self, row=1):
self.select_unfiled_tracker(row=row)
# file tracker
self.driver.find_element(By.XPATH, "//button[text()=' File 1 Trackers ']").click()
# confirm if current flaw is low impact
try:
self.driver.find_element(By.XPATH, "//*[contains(text(), ' Filing Low Severity Trackers ')]")
except NoSuchElementException:
pass
else:
self.confirmFileLowSeverityBtn.click_button()
self.wait_msg("trackersFiledMsg")
self.close_all_toast_msg()
# close tracker manager window
Expand Down
44 changes: 41 additions & 3 deletions features/steps/advance_search.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import time
from pprint import pprint

from behave import *

from features.pages.advanced_search_page import AdvancedSearchPage
from features.pages.flaw_detail_page import FlawDetailPage
from features.common_utils import get_data_from_tmp_data_file
from features.steps.common_steps import go_to_specific_flaw_detail_page
from features.constants import EMBARGOED_FLAW_UUID_KEY, FLAW_ID_KEY
from features.utils import go_to_advanced_search_page

from features.constants import EMBARGOED_FLAW_UUID_KEY
from features.utils import go_to_advanced_search_page, is_sorted

EMPTY_FIELDS = [
"cve_description",
Expand Down Expand Up @@ -220,6 +220,44 @@ def step_impl(context):
flaw_page.check_text_exist(v)


@when('I sort search result by extended sortable field')
def step_impl(context):
advanced_search_page = AdvancedSearchPage(context.browser)
# click created order twice, let result not sort by table column
advanced_search_page.click_btn("createdBtn")
advanced_search_page.click_btn('createdBtn')
advanced_search_page.first_flaw_exist()

select_value_list = ["cvss_scores__score", "cwe_id", "major_incident_state", "source"]
# select_value_list = ["cvss_scores__score", "major_incident_state", "source"]
result_dict = {}

# ascending
for select_value in select_value_list:
advanced_search_page.extendSortSelect.select_element_by_value(select_value)
time.sleep(3)
res = advanced_search_page.get_specified_field_search_result(select_value)
result_dict[select_value] = {"asce": res}

advanced_search_page.extendSortOrderBtn.click_button()
# descending
for select_value in select_value_list:
advanced_search_page.extendSortSelect.select_element_by_value(select_value)
time.sleep(3)
res = advanced_search_page.get_specified_field_search_result(select_value)
result_dict[select_value]["desc"] = res

context.result_dict = result_dict
pprint(context.result_dict, indent=4)


@then('I got search result sorted by extended field')
def step_impl(context):
for k, v in context.result_dict.items():
for order, values in v.items():
assert is_sorted(values, order) is True, f"Sort by field {k} in {order} failed. Get: {values}"


@then('I am able to search flaws with both query filter and selected field')
def step_impl(context):
# get flaw data for search
Expand Down
2 changes: 0 additions & 2 deletions features/steps/common_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ def step_impl(context):
@given('I set the bugzilla api key and jira api key')
def step_impl(context):
set_api_keys(context.browser)
# wait osim getting username from jira
time.sleep(2)


@given('I am on the flaw list')
Expand Down
2 changes: 2 additions & 0 deletions features/steps/flaw_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def create_flaw_with_valid_data(context, embargoed=False, with_optional=False):
flaw_create_page.click_btn('createNewFlawBtn')
flaw_create_page.wait_msg('flawCreatedMsg')

flaw_create_page.close_all_toast_msg()


def check_created_flaw_exist(context, embargoed=False):
go_to_advanced_search_page(context.browser)
Expand Down
25 changes: 12 additions & 13 deletions features/steps/flaw_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from datetime import date, datetime

from behave import when, then
from selenium.common import NoSuchElementException
from selenium.webdriver.common.by import By

from features.common_utils import get_data_from_tmp_data_file
Expand Down Expand Up @@ -321,7 +322,6 @@ def step_impl(context):

def add_a_reference_to_first_flaw(context, value, wait_msg, external=True):
flaw_detail_page = FlawDetailPage(context.browser)
go_to_specific_flaw_detail_page(context.browser)
flaw_detail_page.click_button_with_js("addReferenceBtn")
if external:
flaw_detail_page.add_reference_select_external_type()
Expand All @@ -330,6 +330,7 @@ def add_a_reference_to_first_flaw(context, value, wait_msg, external=True):
flaw_detail_page.click_button_with_js("saveReferenceBtn")
flaw_detail_page.wait_msg(wait_msg)
flaw_detail_page.click_btn("toastMsgCloseBtn")
time.sleep(2)


@when("I add two external references to the flaw")
Expand All @@ -344,7 +345,6 @@ def step_impl(context):

@then("Two external references added")
def step_impl(context):
go_to_specific_flaw_detail_page(context.browser)
flaw_detail_page = FlawDetailPage(context.browser)
flaw_detail_page.click_reference_dropdown_button()
flaw_detail_page.check_text_exist(context.first_value)
Expand Down Expand Up @@ -643,12 +643,10 @@ def step_impl(context):
flaw_detail_page.wait_msg('flawSavedMsg')
flaw_detail_page.check_text_exist(f"{current_affects_number} Affect(s) Deleted.")
flaw_detail_page.close_all_toast_msg()
time.sleep(2)

# add a new affect for filing tracker
context.component = flaw_detail_page.add_new_affect(affectedness_value='AFFECTED')
flaw_detail_page.close_all_toast_msg()
time.sleep(2)


@when('I file a tracker for new added affect')
Expand Down Expand Up @@ -847,7 +845,6 @@ def step_impl(context):
flaw_page = FlawDetailPage(context.browser)
flaw_page.add_new_affect(affectedness_value="NEW", component=generate_random_text())
flaw_page.close_all_toast_msg()
time.sleep(2)
context.check_result = flaw_page.bulk_update_affects()


Expand Down Expand Up @@ -890,13 +887,9 @@ def step_impl(context):
if all_affects_number < 6:
diff = 6 - all_affects_number
for _ in range(diff):
flaw_detail_page.add_new_affect(component=generate_random_text(), affectedness_value="NEW", save=False)

flaw_detail_page.click_btn('saveBtn')
flaw_detail_page.wait_msg('flawSavedMsg')
flaw_detail_page.wait_msg("affectCreatedMsg")
flaw_detail_page.check_element_exists(
By.XPATH, f"//div[text()='{diff} CVSS score(s) saved on {diff} affect(s).']")
flaw_detail_page.add_new_affect(component=generate_random_text(), affectedness_value="NEW")
flaw_detail_page.close_all_toast_msg()
time.sleep(2)

# change affect pagination to 5
flaw_detail_page.change_affect_pagination(5)
Expand Down Expand Up @@ -1004,9 +997,15 @@ def step_impl(context):
def step_impl(context):
flaw_detail_page = FlawDetailPage(context.browser)
flaw_detail_page.driver.find_element(By.XPATH, "//button[text()=' File 1 Trackers ']").click()
# confirm if current flaw is low impact
try:
flaw_detail_page.driver.find_element(By.XPATH, "//*[contains(text(), ' Filing Low Severity Trackers ')]")
except NoSuchElementException:
pass
else:
flaw_detail_page.confirmFileLowSeverityBtn.click_button()
flaw_detail_page.wait_msg("trackersFiledMsg")
flaw_detail_page.close_all_toast_msg()
time.sleep(2)


@then('Tracker filed for multiple flaw')
Expand Down
15 changes: 15 additions & 0 deletions features/utils.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import json
import os
import re
import time

import rstr
import random
import string
import urllib.parse

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.common.exceptions import NoSuchElementException

from constants import (
OSIDB_URL,
Expand Down Expand Up @@ -67,6 +70,18 @@ def set_api_keys(browser):
settings_page.set_api_key('bugzilla', BUGZILLA_API_KEY)
settings_page.set_api_key('jira', JIRA_API_KEY)

# wait osim getting username from jira
time.sleep(2)

# open notification so that we can judge if operation succeed
flaw_detail_page = FlawDetailPage(browser)
try:
flaw_detail_page.muteNotificationIcon.click()
except NoSuchElementException:
pass

flaw_detail_page.close_all_toast_msg()


def go_to_home_page(browser):
home_page = HomePage(browser)
Expand Down

0 comments on commit 903919c

Please sign in to comment.