issues/49492_670/user_tool.py (136 lines of code) (raw):

import sys, os base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, base_path) from utils.trace_cleaner import trace_cleaner import imaplib import email import re import random import time from typing import Any from playwright.sync_api import sync_playwright from playwright.sync_api._context_manager import PlaywrightContextManager from playwright._impl._browser import Browser from playwright._impl._page import Page master_email_address = "brighturing926+49492@gmail.com" master_app_password = "" dev_base_url = "https://dev.new.expensify.com:8082" class EmailHandler: def __init__(self, email_address, password) -> Any: if not self._validate_email(email_address): raise ValueError("Invalid email address format.") self.original_email = email_address self.password = password random_suffix = random.randint(1000, 9999) current_timestamp = int(time.time()) random_suffix = f"{current_timestamp}{random_suffix}" self.new_email = email_address def _validate_email(self, email_address) -> Any: return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) def get_email_address(self) -> Any: return self.new_email def check_for_otp(self) -> Any: try: mail = imaplib.IMAP4_SSL("imap.gmail.com") mail.login(self.original_email, self.password) mail.select("inbox") status, messages = mail.search(None, "UNSEEN") if status != "OK": print("No unread emails found.") return None email_ids = messages[0].split() email_ids = email_ids[::-1] # Reverse order to process latest first for email_id in email_ids: status, msg_data = mail.fetch(email_id, '(RFC822)') if status != "OK": print("Error fetching email.") continue for response_part in msg_data: if isinstance(response_part, tuple): msg = email.message_from_bytes(response_part[1]) if msg["To"] == self.new_email: otp_code = self._extract_otp_from_email(msg) if otp_code: mail.store(email_id, '+FLAGS', '\\Deleted') mail.expunge() # Permanently removes deleted emails from the mailbox mail.close() mail.logout() return otp_code mail.close() mail.logout() print("No OTP found in unread emails.") return None except imaplib.IMAP4.error: print("Failed to connect to Gmail. Please check your email address or password.") return None def _extract_otp_from_email(self, msg) -> Any: if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == "text/plain": email_body = part.get_payload(decode=True).decode() otp_code = self._extract_otp(email_body) if otp_code: return otp_code else: email_body = msg.get_payload(decode=True).decode() otp_code = self._extract_otp(email_body) if otp_code: return otp_code return None def _extract_otp(self, text) -> Any: match = re.search(r"\b\d{6}\b", text) return match.group(0) if match else None def login_user(p: PlaywrightContextManager, user_email: str) -> tuple[Browser, Page]: browser = p.chromium.launch(headless=True, args=["--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"], proxy={"server": "http://localhost:8080"}, slow_mo=500) context = browser.new_context() page: Page = context.new_page() page.goto(dev_base_url) page.locator('input[type="email"]').fill(user_email) page.locator('button[tabindex="0"]').click() page.wait_for_timeout(5000) my_otp_code = "111111" page.get_by_test_id("validateCode").fill(my_otp_code) try: page.get_by_role("button", name="Sign in").click() except Exception: pass return browser, page def test_enter_key_to_delete() -> None: with sync_playwright() as p: browser, page = login_user(p, master_email_address) context = page.context context.tracing.start(screenshots=True, snapshots=True, sources=True) try: page.get_by_test_id("CustomBottomTabNavigator").get_by_label("Search").click() page.wait_for_timeout(1000) page.get_by_role("button", name="Filters").click() page.wait_for_timeout(1000) page.get_by_test_id("SearchAdvancedFiltersPage").get_by_role("menuitem", name="Category").click() page.wait_for_timeout(1000) page.locator("#Equipment").click() page.get_by_role("button", name="Save").click() page.wait_for_timeout(1000) page.get_by_test_id("SearchAdvancedFiltersPage").get_by_role("menuitem", name="Currency").click() page.wait_for_timeout(1000) page.get_by_test_id("selection-list-text-input").fill("usd") page.locator("[id=\"USD\\ -\\ $\"]").click() page.wait_for_timeout(1000) page.get_by_role("button", name="Save").click() page.get_by_role("button", name="Save search").click() page.wait_for_timeout(1000) page.get_by_label("More").first.click() page.get_by_label("Delete").click() page.wait_for_timeout(1000) page.locator("body").press("Enter") page.wait_for_timeout(1000) delete_model = page.get_by_role("button", name="Delete") assert not delete_model.is_visible(), "Enter key not working, Delete modal is still visible" finally: trace_zip_path = "/app/expensify/user_tool/output_browser1.zip" context.tracing.stop(path=trace_zip_path) trace_cleaner(trace_zip_path) browser.close() if __name__ == "__main__": test_enter_key_to_delete()