issues/289/user_tool.py (125 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) import re import random import string from imaplib import IMAP4_SSL import email from email.header import decode_header from playwright.sync_api import sync_playwright, expect, Browser, Page from playwright.sync_api._context_manager import PlaywrightContextManager URL = "https://dev.new.expensify.com:8082/" IMAP_SERVER = "imap.gmail.com" MAX_TRIES = 2 USERNAME = "doorsqueaky@gmail.com" PASSWORD = "" def login_to_email(email: str=USERNAME, password: str=PASSWORD): imap = IMAP4_SSL(IMAP_SERVER) imap.login(email, password) return imap def logout_email(imap: IMAP4_SSL): imap.logout() def clear_inbox(imap: IMAP4_SSL): imap.select("inbox") status, messages = imap.search(None, 'ALL') email_ids = messages[0].split() for email_id in email_ids: imap.store(email_id, "+FLAGS", "\\Deleted") imap.expunge() def generate_random_string(length: int) -> str: random_string = ''.join(random.choice(string.ascii_letters) for i in range(length)) return random_string def get_otp(imap: IMAP4_SSL): imap.select("inbox") # Use "inbox" or other folder name status, messages = imap.search(None, 'ALL') email_ids = messages[0].split() for email_id in email_ids: status, msg_data = imap.fetch(email_id, "(RFC822)") for response_part in msg_data: if isinstance(response_part, tuple): msg = email.message_from_bytes(response_part[1]) subject, encoding = decode_header(msg["Subject"])[0] if isinstance(subject, bytes): subject = subject.decode(encoding if encoding else "utf-8") r = re.search(r"Expensify magic sign-in code:.*", subject, re.IGNORECASE) if not r: return temp = subject.split(":") otp_code = temp[-1].strip() return otp_code return None def launch_app(pw: PlaywrightContextManager, headless: bool=False) -> tuple[Browser, Page]: """ Launch the Expensify app. """ browser = pw.chromium.launch(headless=headless, args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"]) page = browser.new_page() return browser, page def login(page: Page, imap: IMAP4_SSL, email: str=USERNAME): """ Login to the Expensify app and complete the onboarding. """ page.goto(URL) page.get_by_role("textbox", name="Phone or email").fill(email) page.locator("div:nth-child(3) > div:nth-child(2) > div > div").first.click() otp = None tries = 0 while not otp and tries < MAX_TRIES: otp = get_otp(imap) tries += 1 page.wait_for_timeout(3000) if not otp: otp = "123456" page.locator('input[name="validateCode"]').fill(otp) try: page.locator("div").filter(has_text=re.compile(r"^Sign in$")).nth(1).click(timeout=1000) except: pass def cleanup(browser: Browser, page: Page) -> None: page.wait_for_timeout(1000) browser.close() def create_workspace(page: Page) -> str: page.locator('button[aria-label="My settings"]').click() page.locator('div[aria-label="Workspaces"][role="menuitem"]').click() page.locator('button[aria-label="New workspace"]').first.click() page.locator(r'div[role="menuitem"]', has_text="Name").last.click() input_field = page.locator('input[aria-label="Name"]') input_field.clear() workspace_name = generate_random_string(3) + " Workspace" input_field.fill(workspace_name) page.get_by_role('button', name="Save").click() page.locator('button[aria-label="Back"]').click() page.locator('button[aria-label="Inbox"]').click() return workspace_name def switch_workspace(page: Page, workspace_name: str): page.locator('button[aria-label="Workspaces"]').click() page.locator(f'button[aria-label="{workspace_name}"]').last.click() title_inbox = page.get_by_text("Inbox").first inbox_parent = title_inbox.locator('..') title_workspace = inbox_parent.filter(has_text=f"{workspace_name}") expect(title_workspace).to_be_visible() def check_title_post_reload(page: Page, workspace_name: str): page.reload() title_inbox = page.get_by_text("Inbox").first inbox_parent = title_inbox.locator('..') title_workspace = inbox_parent.filter(has_text=f"{workspace_name}") expect(title_workspace).to_be_visible() def test_workspace_switch_on_reload(): """ Demonstrate the Expensify app email login verification, now with tracing. """ from utils.trace_cleaner import trace_cleaner trace_path = "/app/expensify/user_tool/output_browser1.zip" with sync_playwright() as pw: browser = pw.chromium.launch(headless=False, args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"]) context = browser.new_context() context.tracing.start(screenshots=True, snapshots=True, sources=True) page = context.new_page() imap = None try: imap = login_to_email() clear_inbox(imap) login(page, imap, USERNAME) workspace_name = create_workspace(page) switch_workspace(page, workspace_name) check_title_post_reload(page, workspace_name) except Exception as e: raise e finally: context.tracing.stop(path=trace_path) trace_cleaner(trace_path) if imap: logout_email(imap) cleanup(browser, page)