Skip to content

Commit 11b3f9f

Browse files
committed
Merge branch 'main' into Pat/edit_bookmarks
2 parents 6d1415e + 65b0a32 commit 11b3f9f

22 files changed

+221
-42
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ tests/test_scratch.py
194194

195195
# Credentials
196196
credentials.json
197+
testrail_credentials.env
197198

198199
# Do not ignore
199200
!data/goomy.png

modules/browser_object_panel_ui.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ def loaded(self):
3939
]
4040
return all([EC.presence_of_element_located(el) for el in targeted])
4141

42+
@BasePage.context_chrome
4243
def open_panel_menu(self) -> BasePage:
4344
"""
4445
Opens the PanelUi menu.
4546
"""
46-
with self.driver.context(self.driver.CONTEXT_CHROME):
47-
panel_root = self.get_element("panel-ui-button")
48-
panel_root.click()
49-
self.menu = self.Menu(self, root=panel_root)
47+
panel_root = self.get_element("panel-ui-button")
48+
panel_root.click()
49+
self.menu = self.Menu(self, root=panel_root)
5050
return self
5151

5252
def select_panel_setting(self, name: str, *labels) -> BasePage:
@@ -181,13 +181,13 @@ def get_all_history(self) -> List[WebElement]:
181181
history_items = self.get_elements("bookmark-item")
182182
return history_items
183183

184+
@BasePage.context_chrome
184185
def redirect_to_about_logins_page(self) -> BasePage:
185186
"""
186187
Opens the about:logins page by clicking the Password option in Hamburger Menu"
187188
"""
188189
self.open_panel_menu()
189-
with self.driver.context(self.driver.CONTEXT_CHROME):
190-
self.get_element("password-button").click()
190+
self.get_element("password-button").click()
191191
return self
192192

193193
# Bookmarks section

modules/page_object_about_pages.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from modules.page_base import BasePage
1414
from modules.util import BrowserActions
15+
from selenium.webdriver import Firefox
1516

1617

1718
class AboutConfig(BasePage):
@@ -133,6 +134,10 @@ class AboutLogins(BasePage):
133134

134135
URL_TEMPLATE = "about:logins"
135136

137+
def __init__(self, driver: Firefox, **kwargs):
138+
super().__init__(driver, **kwargs)
139+
self.ba = BrowserActions(self.driver)
140+
136141
def click_add_login_button(self) -> Page:
137142
"""Click the Add Login button"""
138143
self.get_element("create-login-button").click()
@@ -144,11 +149,10 @@ def create_new_login(self, form_info: dict) -> Page:
144149
Given a dict with keys that match the valid item types in the
145150
new login dialog, create a new login with those values through UI.
146151
"""
147-
ba = BrowserActions(self.driver)
148152
try:
149153
for item_type, value in form_info.items():
150154
logging.info(f"Filling {item_type} with {value}")
151-
ba.clear_and_fill(
155+
self.ba.clear_and_fill(
152156
self.get_element("login-item-type", labels=[item_type]), value
153157
)
154158
logging.info("Clicking submit...")
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import logging
2+
import os
3+
4+
from dotenv import load_dotenv
5+
6+
from modules.testrail_integration import testrail_init
7+
8+
# Set up logging
9+
logging.basicConfig(
10+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
11+
)
12+
13+
# Load env file from project root
14+
script_dir = os.path.dirname(__file__)
15+
project_root = os.path.abspath(os.path.join(script_dir, ".."))
16+
env_file_path = os.path.join(project_root, "testrail_credentials.env")
17+
load_dotenv(dotenv_path=env_file_path)
18+
19+
# TestRail project ID (Fx Desktop)
20+
PROJECT_ID = 17
21+
22+
23+
def get_all_suites(tr, project_id):
24+
"""Get all suites from the project"""
25+
suites = tr.client.send_get(f"get_suites/{project_id}")
26+
logging.info(f"Found {len(suites)} suites in project {project_id}")
27+
return suites
28+
29+
30+
# Set limit below maximum value as a precaution to avoid API errors
31+
def get_all_test_cases(tr, project_id, suite_id):
32+
"""Fetch all test cases from a suite by handling pagination."""
33+
all_cases = []
34+
offset = 0
35+
limit = 240 # Default limit for TestRail API is 250
36+
37+
while True:
38+
# Build endpoint with pagination parameters
39+
endpoint = (
40+
f"get_cases/{project_id}&suite_id={suite_id}&limit={limit}&offset={offset}"
41+
)
42+
43+
response = tr.client.send_get(endpoint)
44+
cases = response.get("cases", [])
45+
if not cases:
46+
break
47+
all_cases.extend(cases)
48+
# If the number of cases returned is less than the limit, we've reached the last page.
49+
if len(cases) < limit:
50+
break
51+
offset += limit
52+
53+
logging.info(f"Total cases fetched from suite {suite_id}: {len(all_cases)}")
54+
return all_cases
55+
56+
57+
def update_null_automation_status(tr, project_id, dry_run=True):
58+
"""Update test cases with None automation status to Untriaged"""
59+
try:
60+
# Get all suites in the project
61+
suites = get_all_suites(tr, project_id)
62+
63+
# Track statistics
64+
total_null_cases = 0
65+
updated_count = 0
66+
67+
# Process each suite
68+
for suite in suites:
69+
suite_id = suite["id"]
70+
suite_name = suite["name"]
71+
logging.info(f"Processing suite {suite_name} (ID: {suite_id})...")
72+
73+
# Retrieve test cases for this suite
74+
try:
75+
cases = get_all_test_cases(tr, project_id, suite_id)
76+
77+
# Filter cases with null automation status
78+
null_status_cases = [
79+
case
80+
for case in cases
81+
if case.get("custom_automation_status") is None
82+
]
83+
84+
suite_null_count = len(null_status_cases)
85+
total_null_cases += suite_null_count
86+
87+
logging.info(
88+
f"Found {suite_null_count} cases with null automation status in suite {suite_name}"
89+
)
90+
91+
# Update each case that meets the criteria
92+
for case in null_status_cases:
93+
case_id = case["id"]
94+
try:
95+
if dry_run:
96+
logging.info(
97+
f"[DRY RUN] Would update case {case_id}: set automation status to Untriaged (1)"
98+
)
99+
else:
100+
# Perform the update
101+
tr.update_case_field(
102+
case_id, "custom_automation_status", "1"
103+
)
104+
logging.info(
105+
f"Updated case {case_id}: set automation status to Untriaged (1)"
106+
)
107+
updated_count += 1
108+
except Exception as e:
109+
logging.error(f"Error updating case {case_id}: {e}")
110+
except Exception as e:
111+
logging.error(f"Error processing suite {suite_id}: {e}")
112+
continue
113+
114+
# Log summary
115+
logging.info(
116+
f"Summary: Found {total_null_cases} cases with null automation status across all suites"
117+
)
118+
if not dry_run:
119+
logging.info(f"Updated {updated_count} cases to Untriaged")
120+
else:
121+
logging.info(
122+
f"Would update {total_null_cases} cases to Untriaged (dry run)"
123+
)
124+
125+
except Exception as e:
126+
logging.error(f"Error processing cases: {e}")
127+
128+
129+
def main():
130+
# Read credentials from environment
131+
base_url = os.environ.get("TESTRAIL_BASE_URL")
132+
username = os.environ.get("TESTRAIL_USERNAME")
133+
api_key = os.environ.get("TESTRAIL_API_KEY")
134+
135+
if not all([base_url, username, api_key]):
136+
logging.error("Missing TestRail credentials. Check your .env file.")
137+
return
138+
139+
logging.info(f"Loaded credentials for user: {username}")
140+
logging.info(f"Base URL: {base_url}")
141+
142+
tr = testrail_init()
143+
144+
# Safe approach to not accidentally update cases
145+
dry_run = True
146+
147+
# Process all cases in the project
148+
logging.info(f"Processing project ID: {PROJECT_ID}...")
149+
update_null_automation_status(tr, PROJECT_ID, dry_run)
150+
151+
152+
if __name__ == "__main__":
153+
main()

tests/password_manager/test_about_logins_navigation_from_context_menu.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def test_about_logins_navigation_from_login_form_context_menu(driver: Firefox):
1616
C2241087 - Verify that right-clicking the Username field in a login form and then the Manage Passwords option
1717
from context menu opens about:logins page in a new tab
1818
"""
19-
19+
# Instantiate objects
2020
context_menu = ContextMenu(driver)
2121
tabs = TabBar(driver)
2222
login = LoginAutofill(driver).open()

tests/password_manager/test_about_logins_navigation_from_hamburger_menu.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_about_logins_navigation_from_password_hamburger_menu(driver: Firefox):
1313
"""
1414
C2241082 - Verify that clicking the Password option in Hamburger Menu opens about:logins page in a new tab
1515
"""
16-
16+
# Instantiate objects
1717
panel_ui = PanelUi(driver)
1818
tabs = TabBar(driver)
1919

tests/password_manager/test_about_logins_search_username.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ def test_about_logins_search_username(driver_and_saved_logins):
1616
"""
1717
# Initializing objects
1818
(driver, usernames, logins) = driver_and_saved_logins
19-
about_logins = AboutLogins(driver).open()
19+
about_logins = AboutLogins(driver)
2020
ba = BrowserActions(driver)
2121

22-
# Search for a username with 2 results
22+
# Open about:logins and search for a username with 2 results
23+
about_logins.open()
2324
ba.clear_and_fill(about_logins.get_element("login-filter-input"), usernames[-1])
2425

2526
# Check that only the correct 2 results are shown

tests/password_manager/test_about_logins_search_website.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ def test_about_logins_search_website(origins, driver_and_saved_logins):
1616
"""
1717
# Initializing objects
1818
(driver, usernames, logins) = driver_and_saved_logins
19-
about_logins = AboutLogins(driver).open()
19+
about_logins = AboutLogins(driver)
2020
ba = BrowserActions(driver)
2121

22-
# Search for a website
22+
# Open about:logins and search for a website
23+
about_logins.open()
2324
ba.clear_and_fill(about_logins.get_element("login-filter-input"), origins[1])
2425

2526
# Check that only the correct 1 result is shown

tests/password_manager/test_add_password_non_ascii_chars.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ def test_add_password_non_ascii_chars(driver: Firefox):
1313
"""
1414
C2241113 Add password - non-ascii characters
1515
"""
16-
# instantiate object
17-
about_logins = AboutLogins(driver).open()
16+
# Instantiate object
17+
about_logins = AboutLogins(driver)
1818

19-
# Click on the "Add password" button
19+
# Open about:logins and click on the "Add password" button
20+
about_logins.open()
2021
about_logins.click_add_login_button()
2122

2223
# Complete all the fields with valid data and click the "Save" button.

tests/password_manager/test_add_password_save_valid_data.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ def test_add_password_save_valid_data(driver: Firefox):
1515
C2241112 Verify that a password can be added and saved
1616
"""
1717
# instantiate object
18-
about_logins = AboutLogins(driver).open()
18+
about_logins = AboutLogins(driver)
1919

20-
# Click on the "Add password" button
20+
# Open about:logins and click on the "Add password" button
21+
about_logins.open()
2122
about_logins.click_add_login_button()
2223

2324
# Complete all the fields with valid data and click the "Save" button.

0 commit comments

Comments
 (0)