From f2b17475e168892d2d0e3b8e6afb297675c40568 Mon Sep 17 00:00:00 2001 From: Hani Yacoub Date: Wed, 12 Nov 2025 13:22:40 +0200 Subject: [PATCH 1/3] Stabilize csv tests --- modules/page_object_about_pages.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/modules/page_object_about_pages.py b/modules/page_object_about_pages.py index 8a98fa5b2..f0e87140c 100644 --- a/modules/page_object_about_pages.py +++ b/modules/page_object_about_pages.py @@ -200,28 +200,39 @@ def verify_csv_export(self, downloads_folder: str, filename: str, timeout: int = Wait until the exported CSV file is present, non-empty, and readable. """ csv_file = os.path.join(downloads_folder, filename) + partial_file = csv_file + ".part" def file_ready(_): - # Check if the file path exists. If not, continue + # Checks if partial file exists + if os.path.exists(partial_file): + logging.debug(f"[verify_csv_export] Found partial file: {partial_file}") + return False + + # File must exist if not os.path.exists(csv_file): + logging.debug(f"[verify_csv_export] CSV not yet found at {csv_file}") return False + try: - # Verify that the file isn't empty - if os.path.getsize(csv_file) == 0: + # Checks file must have non-zero size + size = os.path.getsize(csv_file) + if size == 0: + logging.debug("[verify_csv_export] CSV file is empty.") return False - # Attempt to read a few bytes to ensure the file is unlocked - # and readable (handles cases where the OS is still writing). + # Try to read the first few bytes to ensure it's fully written and unlocked with open(csv_file, "r", encoding="utf-8") as f: f.read(10) + logging.debug(f"[verify_csv_export] CSV ready (size={size} bytes).") return True except (OSError, PermissionError) as e: - # Log and retry until timeout instead of failing immediately + # File is not yet fully written or locked — retry logging.debug(f"[verify_csv_export] File not ready yet: {e}") return False - WebDriverWait(self.driver, timeout).until(file_ready) + # Poll every 0.5s for up to 40 seconds + WebDriverWait(self.driver, timeout, poll_frequency=0.5).until(file_ready) return csv_file def add_login(self, origin: str, username: str, password: str): From 37eaa37becfa971fb49fae8b3e17f6d02a3ea90f Mon Sep 17 00:00:00 2001 From: Hani Yacoub Date: Wed, 12 Nov 2025 14:07:11 +0200 Subject: [PATCH 2/3] Change timeout time --- modules/page_object_about_pages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/page_object_about_pages.py b/modules/page_object_about_pages.py index f0e87140c..d470f7fcd 100644 --- a/modules/page_object_about_pages.py +++ b/modules/page_object_about_pages.py @@ -195,7 +195,7 @@ def remove_password_csv(self, downloads_dir): if delete_files_regex.match(file): os.remove(passwords_csv) - def verify_csv_export(self, downloads_folder: str, filename: str, timeout: int = 20): + def verify_csv_export(self, downloads_folder: str, filename: str, timeout: int = 40): """ Wait until the exported CSV file is present, non-empty, and readable. """ From b6cd89f45e2c97507b5c894fc43a572530c29315 Mon Sep 17 00:00:00 2001 From: Hani Yacoub Date: Wed, 12 Nov 2025 15:39:48 +0200 Subject: [PATCH 3/3] Edit method --- modules/page_object_about_pages.py | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/modules/page_object_about_pages.py b/modules/page_object_about_pages.py index d470f7fcd..c02df0cf8 100644 --- a/modules/page_object_about_pages.py +++ b/modules/page_object_about_pages.py @@ -197,41 +197,49 @@ def remove_password_csv(self, downloads_dir): def verify_csv_export(self, downloads_folder: str, filename: str, timeout: int = 40): """ - Wait until the exported CSV file is present, non-empty, and readable. + Wait until the exported CSV file is fully written, non-empty, and readable. """ + import time + csv_file = os.path.join(downloads_folder, filename) partial_file = csv_file + ".part" def file_ready(_): - # Checks if partial file exists + # If Firefox still writes .part, not done yet if os.path.exists(partial_file): - logging.debug(f"[verify_csv_export] Found partial file: {partial_file}") + logging.debug(f"[verify_csv_export] Partial file still present: {partial_file}") return False - # File must exist + # Check existence if not os.path.exists(csv_file): logging.debug(f"[verify_csv_export] CSV not yet found at {csv_file}") return False try: - # Checks file must have non-zero size - size = os.path.getsize(csv_file) - if size == 0: - logging.debug("[verify_csv_export] CSV file is empty.") + # Check file size stabilization + size1 = os.path.getsize(csv_file) + time.sleep(1) + size2 = os.path.getsize(csv_file) + if size1 != size2: + logging.debug( + f"[verify_csv_export] File size changing ({size1} → {size2}), waiting..." + ) return False - # Try to read the first few bytes to ensure it's fully written and unlocked + # Check readability with open(csv_file, "r", encoding="utf-8") as f: - f.read(10) - logging.debug(f"[verify_csv_export] CSV ready (size={size} bytes).") + head = f.read(20) + if not head: + logging.debug("[verify_csv_export] File empty after read attempt.") + return False + + logging.debug(f"[verify_csv_export] CSV ready (size={size2} bytes).") return True except (OSError, PermissionError) as e: - # File is not yet fully written or locked — retry logging.debug(f"[verify_csv_export] File not ready yet: {e}") return False - # Poll every 0.5s for up to 40 seconds WebDriverWait(self.driver, timeout, poll_frequency=0.5).until(file_ready) return csv_file