issues/257/user_tool.py (121 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 pytest from playwright.sync_api import sync_playwright, Page from utils.trace_cleaner import trace_cleaner static_email = "testuserexpensify1+82@gmail.com" @pytest.fixture def setup_playwright(): playwright = sync_playwright().start() browser = playwright.chromium.launch( headless=True, slow_mo=1000, args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"] ) page = browser.new_page() # Yield page, browser, and playwright so that the test can manage tracing and cleanup yield page, browser, playwright # No cleanup here: test function is responsible for stopping tracing, exporting, cleaning trace, and closing browser/playwright def login_user(page: Page, email: str, first_name: str, last_name: str): page.goto("https://dev.new.expensify.com:8082/") page.locator('input[type="email"]').fill(email) page.locator('button[tabindex="0"]').click() join_button = page.get_by_role("button", name="Join") join_button.click() page.locator("text='Track and budget expenses'").click() page.get_by_role("button", name="Continue").click() page.locator('input[name="fname"]').fill(first_name) page.locator('input[name="lname"]').fill(last_name) page.get_by_role("button", name="Continue").last.click() def create_workspace_and_add_member(page: Page, member_email: str): page.locator('button[aria-label="Workspaces"]').click() page.get_by_test_id("WorkspaceSwitcherPage").get_by_role( "button", name="New workspace" ).click() page.locator('div[aria-label="Members"]').click() page.locator("button", has_text="Invite member").click() page.locator('input[aria-label="Name, email, or phone number"]').fill(member_email) page.locator("button", has_text=member_email).click() page.locator('button[data-listener="Enter"]', has_text="Next").click() page.locator('button[data-listener="Enter"]', has_text="Invite").click() page.locator('button[aria-label="Back"]').click() page.locator('button[aria-label="Back"]').click() def browse_to_workspace(page: Page, workspace_name: str): page.locator('button[aria-label="Workspaces"]').click() try: page.locator(f'button[aria-label="{workspace_name}"]').click() except Exception: page.locator(f'button[aria-label="{workspace_name}"]').nth(1).click() page.locator( 'button[aria-label="Navigates to a chat"]', has_text=workspace_name ).nth(0).click() def submit_expense(page: Page, amount: int, merchant: str): page.locator('button[aria-label="Create"]').nth(2).click() page.locator('div[aria-label="Submit expense"]').click() page.locator('button[aria-label="Manual"]').click() page.locator('input[placeholder="0"]').fill(str(amount)) page.locator('button[data-listener="Enter"]', has_text="Next").nth(0).click() page.locator('div[role="menuitem"]', has_text="Merchant").click() page.locator('input[aria-label="Merchant"]').fill(merchant) page.locator('button[data-listener="Enter"]', has_text="Save").click() page.locator('button[data-listener="Enter"]', has_text="Submit").click() def wait_for_text_with_assertion( page: Page, locator, text: str, max_retries=10, interval=1, assertion_message="Text not found", ): for attempt in range(max_retries): try: if text in locator.inner_text(): print(f"'{text}' found in the inner text.") return except Exception as e: print(f"Attempt {attempt + 1} failed with exception: {e}") page.wait_for_timeout(1000) raise AssertionError(assertion_message) @pytest.mark.usefixtures("setup_playwright") def test_duplicate_and_hold_expense(setup_playwright): page, browser, playwright = setup_playwright # Start tracing with desired options page.context.tracing.start(screenshots=True, snapshots=True, sources=True) try: user1_email = static_email user2_email = "testuser@gmail.com" first_name1, last_name1 = "Chris", "Brown" workspace_name = f"{first_name1} {last_name1}'s Workspace" login_user(page, user1_email, first_name1, last_name1) create_workspace_and_add_member(page, user2_email) browse_to_workspace(page, workspace_name) submit_expense(page, 100, "Merchant 1") submit_expense(page, 200, "Merchant 2") submit_expense(page, 100, "Merchant 1") page.locator( 'button[aria-label="View details"]', has_text=f"{workspace_name} owes:" ).last.click() first_message = page.locator('div[aria-label="Cash"][data-tag="pressable"]').first wait_for_text_with_assertion( page, first_message, "Duplicate", max_retries=10, interval=1, assertion_message="Expected 'Duplicate' text not found in the first message.", ) first_message.hover() page.locator('button[aria-label="Menu"]').click() page.locator('div[aria-label="Hold"]').click() page.locator('input[aria-label="Reason"]').fill("Random reason") page.locator('button[data-listener="Enter"]', has_text="Hold expense").click() wait_for_text_with_assertion( page, first_message, "Hold", max_retries=5, interval=1, assertion_message="Expense's text not updated to 'Hold' from 'Duplicate'.", ) finally: trace_file = "/app/expensify/user_tool/output_browser1.zip" page.context.tracing.stop(path=trace_file) trace_cleaner(trace_file) browser.close() playwright.stop()