diff --git a/issues/1/test.py b/issues/1/test.py index 0ac25ba9..52a700a9 100644 --- a/issues/1/test.py +++ b/issues/1/test.py @@ -4,9 +4,15 @@ from email.header import decode_header from playwright.sync_api import sync_playwright, expect +<<<<<<< HEAD:issues/50163_1076/test.py + +GMAIL_NAME = "nomandevtur+50163" +GMAIL_APP_PASSWORD = "" +======= # Enter Gmail credentials for a disposable GMAIL_NAME = "nomandevtur+55827.2" GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +>>>>>>> main:issues/1/test.py def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/10/test.py b/issues/10/test.py index 7bd74ee1..4da236b2 100644 --- a/issues/10/test.py +++ b/issues/10/test.py @@ -5,7 +5,7 @@ from playwright.sync_api import sync_playwright, expect GMAIL_NAME = "nomandevtur+54916.2" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/103/user_tool.py b/issues/103/user_tool.py index 53a454ff..70350059 100644 --- a/issues/103/user_tool.py +++ b/issues/103/user_tool.py @@ -6,7 +6,7 @@ # Email login credentials EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" # Email username postfix EMAIL_USERNAME_POSTFIX = "52678.4" diff --git a/issues/110/test.py b/issues/110/test.py index 43a0bfbd..a186cd14 100644 --- a/issues/110/test.py +++ b/issues/110/test.py @@ -5,7 +5,7 @@ NEW_DOT_URL = "https://dev.new.expensify.com:8082" EMAIL = "testexpensifyturing+034@gmail.com" -PASSWORD = "qqdd pegp kagr emax" +PASSWORD = "" class EmailHandler: diff --git a/issues/110/user_tool.py b/issues/110/user_tool.py new file mode 100644 index 00000000..612c02bd --- /dev/null +++ b/issues/110/user_tool.py @@ -0,0 +1,87 @@ +import imaplib +import email +import re +from playwright.sync_api import sync_playwright, expect, Page +from utils.trace_cleaner import trace_cleaner + +EMAIL = "velmoner+479@gmail.com" +PASSWORD = "" +NEWDOT_URL = "https://dev.new.expensify.com:8082/" + + +def user_login(page: Page, email_id: str, password: str): + page.goto(NEWDOT_URL) + + page.locator('input[type="email"]').fill(email_id) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + otp = "123456" + page.wait_for_timeout(10000) + page.locator('input[data-testid="validateCode"]').fill(otp) + try: + page.get_by_role("button", name="Sign In").click() + except Exception as err: + pass + + +def test_payment_text(): + with sync_playwright() as p: + browser = p.chromium.launch(proxy={"server": "http://localhost:8080"}, headless=False, args=["--no-sandbox", "--disable-dev-shm-usage", "--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"], slow_mo=1000, channel="chromium") + page = browser.new_page() + # Get the context from the page to start tracing + context = page.context + context.tracing.start(screenshots=True, snapshots=True, sources=True) + try: + email1, dname1 = "velmoner+321@gmail.com", "fin land" + email2, dname2 = "velmoner+8992@gmail.com", "gargi dime" + + user_login(page=page, email_id=EMAIL, password=PASSWORD) + page.get_by_label("Start chat (Floating action)", exact=True).click() + page.get_by_label("Start chat", exact=True).click() + + page.get_by_test_id("selection-list-text-input").fill(email1) + page.get_by_label(dname1).get_by_role( + "button", name="Add to group").click() + + page.get_by_test_id("selection-list-text-input").fill(email2) + page.get_by_label(dname2).get_by_role( + "button", name="Add to group").click() + + page.get_by_role("button", name="Next").click() + page.get_by_role("button", name="Start group").click() + + chatroom_id = page.url.split("/")[-1] + search_text = f"type:chat status:all in:{chatroom_id}" + page.get_by_test_id( + f"report-screen-{chatroom_id}").get_by_text("fin, gargi, wii").click() + page.get_by_label("Leave").click() + + current_report_id = page.url.split("/")[-1] + page.get_by_test_id( + f"report-screen-{current_report_id}").get_by_label("Search").click() + page.get_by_test_id("search-router-text-input").fill(search_text) + page.wait_for_timeout(1500) + page.get_by_label(search_text).click() + page.wait_for_timeout(1000) + page.get_by_text("Filters").click() + page.get_by_test_id( + "SearchAdvancedFiltersPage").get_by_text("In").click() + + empty_item_exists = False + + # condition to find + for i in page.get_by_test_id("selection-list").get_by_role("button").all(): + if i.get_attribute("id") and i.get_attribute("id") == chatroom_id: + empty_item_exists = True + assert not empty_item_exists, "Empty entry found in search list with green check" + + finally: + output_zip = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=output_zip) + trace_cleaner(output_zip) + browser.close() + + +# If running as main, execute the test +if __name__ == "__main__": + test_payment_text() \ No newline at end of file diff --git a/issues/118/test.py b/issues/118/test.py index 2d3134db..e6a3d805 100644 --- a/issues/118/test.py +++ b/issues/118/test.py @@ -5,7 +5,7 @@ EMAIL = "velmoner+375@gmail.com" -PASSWORD = "aory ezrb qkmi qkas" +PASSWORD = "" NEWDOT_URL = "https://dev.new.expensify.com:8082/" def user_login(page: Page, email_id: str, password: str): diff --git a/issues/13/user_tool.py b/issues/13/user_tool.py index 420530cc..ad67499a 100644 --- a/issues/13/user_tool.py +++ b/issues/13/user_tool.py @@ -9,7 +9,7 @@ # Utility to generate a random email - def generate_random_email(): +def generate_random_email(): timestamp = 123456 return f"testuser+{timestamp}@gmail.com" diff --git a/issues/146/test.py b/issues/146/test.py index f4be079f..468ad54a 100644 --- a/issues/146/test.py +++ b/issues/146/test.py @@ -13,7 +13,7 @@ NEWDOT_URL = "http://dev.new.expensify.com:8082/" EXPENSIFY_EMAIL = "testingq186+52114@gmail.com" -EXPENSIFY_PASSWORD = "kkfr hqiv yuxq rbso" +EXPENSIFY_PASSWORD = "" TESTING_FLOW = True diff --git a/issues/14958/test.py b/issues/14958/test.py new file mode 100644 index 00000000..f8282e75 --- /dev/null +++ b/issues/14958/test.py @@ -0,0 +1,134 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +import re, time +import imaplib +import email +import random +import string + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +EMAIL = "pehlajrajput1+345@gmail.com" +PASSWORD = "" + + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(10000) + page.locator('input[data-testid="validateCode"]').fill("123456") + + +def zip_error(page, assertion_errors): + + try: + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_label("England's Lane, London,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("Maliebaan 87") + page.wait_for_timeout(1000) + page.get_by_text("Maliebaan").first.click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("1012 JS") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'Maliebaan 87': {str(e)}") + + try: + page.get_by_label("87 Maliebaan, Utrecht,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("tokyo") + page.wait_for_timeout(1000) + page.get_by_text("Tokyo Metro Marunouchi Line").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("100-0001") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'Tokyo Metro Marunouchi Line': {str(e)}") + + try: + page.get_by_label("Tokyo Metro Marunouchi Line,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("engla") + page.wait_for_timeout(1000) + page.get_by_text("England's Lane").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("SW1A 1AA") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'SW1A 1AA': {str(e)}") + + try: + page.get_by_label("England's Lane, London,").click() + page.get_by_role("textbox", name="Zip / Postcode").fill(",") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for ',': {str(e)}") + + try: + page.get_by_label("Back").click() + page.get_by_label("England's Lane, London,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").click() + page.get_by_label("Address line 1").get_by_role("textbox").fill("2574 Fairfield Road") + page.wait_for_timeout(1000) + page.get_by_text("Fairfield Road").first.click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("234GEs") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'England's Lane, London': {str(e)}") + + +def test_expensify_0000(): + assertion_errors = [] # List to store assertion errors + + with sync_playwright() as p: + browser = p.chromium.launch(proxy = {"server": "http://localhost:8080"}, headless = False, args = ["--no-sandbox", "--disable-dev-shm-usage", "--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"], slow_mo = None, channel = "chromium") + first_user_context = browser.new_context(ignore_https_errors=True) + page = first_user_context.new_page() + page.wait_for_timeout(2000) + + + new_dot_login(page, "pehlajrajput1+345@gmail.com") + + + zip_error(page, assertion_errors) + + browser.close() + + + if assertion_errors: + print("\nAssertion Errors:") + for error in assertion_errors: + print(f"- {error}") + raise AssertionError("One or more assertions failed. Check the logs above.") + + + +if __name__ == "__main__": + try: + test_expensify_0000() + except AssertionError as e: + print(str(e)) diff --git a/issues/14958/user_tool.py b/issues/14958/user_tool.py new file mode 100644 index 00000000..43f3a209 --- /dev/null +++ b/issues/14958/user_tool.py @@ -0,0 +1,140 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +import re, time +import imaplib +import email +import random +import string +from utils.trace_cleaner import trace_cleaner + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +EMAIL = "pehlajrajput1+345@gmail.com" +PASSWORD = "" + + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(10000) + page.locator('input[data-testid="validateCode"]').fill("123456") + + +def zip_error(page, assertion_errors): + + try: + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_label("England's Lane, London,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("Maliebaan 87") + page.wait_for_timeout(1000) + page.get_by_text("Maliebaan").first.click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("1012 JS") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'Maliebaan 87': {str(e)}") + + try: + page.get_by_label("87 Maliebaan, Utrecht,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("tokyo") + page.wait_for_timeout(1000) + page.get_by_text("Tokyo Metro Marunouchi Line").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("100-0001") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'Tokyo Metro Marunouchi Line': {str(e)}") + + try: + page.get_by_label("Tokyo Metro Marunouchi Line,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").fill("engla") + page.wait_for_timeout(1000) + page.get_by_text("England's Lane").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("SW1A 1AA") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).not_to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'SW1A 1AA': {str(e)}") + + try: + page.get_by_label("England's Lane, London,").click() + page.get_by_role("textbox", name="Zip / Postcode").fill(",") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for ',': {str(e)}") + + try: + page.get_by_label("Back").click() + page.get_by_label("England's Lane, London,").click() + page.wait_for_timeout(1000) + page.get_by_label("Address line 1").get_by_role("textbox").click() + page.get_by_label("Address line 1").get_by_role("textbox").fill("2574 Fairfield Road") + page.wait_for_timeout(1000) + page.get_by_text("Fairfield Road").first.click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Zip / Postcode").fill("234GEs") + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + expect(page.get_by_text("Incorrect zip code format.")).to_be_visible() + except AssertionError as e: + assertion_errors.append(f"Error: Zip code validation failed for 'England's Lane, London': {str(e)}") + + +def test_expensify_0000(): + assertion_errors = [] # List to store assertion errors + + with sync_playwright() as p: + browser = p.chromium.launch(proxy = {"server": "http://localhost:8080"}, headless = False, args = ["--no-sandbox", "--disable-dev-shm-usage", "--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"], slow_mo = None, channel = "chromium") + first_user_context = browser.new_context(ignore_https_errors=True) + first_user_context.tracing.start(screenshots=True, snapshots=True, sources=True) + page = first_user_context.new_page() + page.wait_for_timeout(2000) + + try: + + new_dot_login(page, "pehlajrajput1+345@gmail.com") + + + zip_error(page, assertion_errors) + finally: + first_user_context.tracing.stop() + first_user_context.tracing.export_trace("/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + browser.close() + + + if assertion_errors: + print("\nAssertion Errors:") + for error in assertion_errors: + print(f"- {error}") + raise AssertionError("One or more assertions failed. Check the logs above.") + + + +if __name__ == "__main__": + try: + test_expensify_0000() + except AssertionError as e: + print(str(e)) diff --git a/issues/15/test.py b/issues/15/test.py index bc518cfe..62bdf477 100644 --- a/issues/15/test.py +++ b/issues/15/test.py @@ -5,7 +5,7 @@ from playwright.sync_api import sync_playwright, expect GMAIL_NAME = "nomandevtur+54856.2" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/153/user_tool.py b/issues/153/user_tool.py index db7902b0..ddd4ac86 100644 --- a/issues/153/user_tool.py +++ b/issues/153/user_tool.py @@ -7,6 +7,15 @@ from playwright.async_api import Page, TimeoutError, async_playwright, expect from utils.trace_cleaner import trace_cleaner +<<<<<<< HEAD +# Utility function to generate a unique random email for testing +def generate_random_email(): + timestamp = int(time.time()) + return f"t1533148+{timestamp}@gmail.com" + +EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" +======= EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "kypqxmbx" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" @@ -15,6 +24,7 @@ PROXY_URL = os.getenv("PROXY_URL") WORKSPACE_NAME = "BltGot0t" +>>>>>>> main async def create_workspace(page: Page, workspace_name: str = WORKSPACE_NAME): @@ -162,6 +172,15 @@ async def enable_custom_fields_and_rules(page: Page): await rules.click() +<<<<<<< HEAD +# Test to verify opening distance receipt from another workspace opens without issue +def test_open_receipt_different_workspace(): + with sync_playwright() as p: + browser, context, page, user_email1 = login_user(p) + # Start tracing with screenshots, snapshots, and sources + context.tracing.start(screenshots=True, snapshots=True, sources=True) + trace_file = "/app/expensify/user_tool/output_browser1.zip" +======= async def add_custom_report_name(page: Page): await page.get_by_role("menuitem", name="Rules").click() custom_report_names = page.get_by_role( @@ -195,6 +214,7 @@ async def test_search_bar_spacing(): await context.tracing.start(screenshots=True, snapshots=True, sources=True) page = await context.new_page() +>>>>>>> main try: await login_or_create_user(page) await create_workspace(page) diff --git a/issues/16/user_tool.py b/issues/16/user_tool.py new file mode 100644 index 00000000..bded714c --- /dev/null +++ b/issues/16/user_tool.py @@ -0,0 +1,162 @@ +import os + +import pytest +from playwright.async_api import Browser, Page, TimeoutError, async_playwright +from utils.trace_cleaner import trace_cleaner + +EMAIL_USERNAME = "xecuycismfsga" +EMAIL_ALIAS = "r5p4hfur" +USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" +PASSWORD = "" +SLOW_MO: int | None = 500 +PROXY_URL = os.getenv("PROXY_URL") + +LONG_FIRSTNAME = "XzH9tXRklkFrTjMU" +LONG_LASTNAME = "MwuCGEtROJc5CZz9" +PARTICIPANT_ALIAS = "wzec6tou" +PARTICIPANT_EMAIL = f"{EMAIL_USERNAME}+{PARTICIPANT_ALIAS}@gmail.com" + + +async def get_magic_code( + _page: Page, _user_email: str = USER_EMAIL, _password: str = PASSWORD +): + return "123456" + + +async def create_user(page: Page, firstname: str = "User", lastname: str = EMAIL_ALIAS): + await page.get_by_role("button", name="Join").click() + + # Update profile + await page.get_by_text("Track and budget expenses").click() + await page.get_by_role("textbox", name="First name").fill(firstname) + await page.get_by_role("textbox", name="Last name").fill(lastname) + await page.get_by_role("button", name="Continue").click() + + +async def login(page: Page): + # get current timestamp + magic_code = await get_magic_code(page) + + if magic_code is None: + raise ValueError("Failed to retrieve magic code") + + await page.get_by_role("textbox").fill(magic_code) + + +async def login_or_create_user( + page: Page, + firstname: str = "User", + lastname: str = EMAIL_ALIAS, + user_email: str = USER_EMAIL, +): + await page.goto("https://dev.new.expensify.com:8082/") + await page.get_by_test_id("username").fill(user_email) + await page.get_by_role("button", name="Continue").click() + + try: + await page.get_by_role("button", name="Join").wait_for( + state="visible", timeout=2000 + ) + await create_user(page, firstname=firstname, lastname=lastname) + except TimeoutError: + await login(page) + + await page.get_by_label("Inbox").wait_for(state="visible", timeout=10000) + + +async def create_participant_account(browser: Browser): + context_1 = await browser.new_context() + await context_1.tracing.start(screenshots=True, snapshots=True, sources=True) + try: + page_1 = await context_1.new_page() + + await login_or_create_user( + page_1, + user_email=PARTICIPANT_EMAIL, + firstname=LONG_FIRSTNAME, + lastname=LONG_LASTNAME, + ) + + await page_1.close() + finally: + await context_1.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + await context_1.close() + + +async def submit_expense(page: Page): + await page.get_by_label("Create").last.click() + await page.get_by_label("Submit expense").click() + await page.get_by_label("Manual").click() + await page.get_by_placeholder("0").fill("1000000") + await ( + page.locator("#numPadContainerView").get_by_role("button", name="Next").click() + ) + await page.get_by_role("button", name="Submit").click() + + +@pytest.mark.asyncio +async def test_search_bar_spacing(): + async with async_playwright() as p: + browser = await p.chromium.launch( + proxy={"server": PROXY_URL} if PROXY_URL else None, + headless=False, + args=[ + "--no-sandbox", + "--disable-dev-shm-usage", + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process", + ], + slow_mo=SLOW_MO, + ) + try: + await create_participant_account(browser) + + iphone = p.devices["iPhone SE"] + context = await browser.new_context(**iphone) + await context.tracing.start(screenshots=True, snapshots=True, sources=True) + try: + page = await context.new_page() + + await login_or_create_user(page) + + participant_chat = page.locator( + 'button[aria-label="Navigates to a chat"]', + has_text=f"{LONG_FIRSTNAME} {LONG_LASTNAME}", + ).first + + try: + await participant_chat.click(timeout=3000) + except TimeoutError: + await page.get_by_label("Start chat (Floating action)").click() + await page.get_by_label("Start chat", exact=True).click() + await page.get_by_test_id("selection-list-text-input").fill( + PARTICIPANT_EMAIL + ) + await page.get_by_label(PARTICIPANT_EMAIL).click() + + expense_preview = ( + page.get_by_role("button", name="View details") + .filter(has_text=f"{LONG_FIRSTNAME} owes:") + .last + ) + + try: + await expense_preview.click(timeout=3000) + except TimeoutError: + await submit_expense(page) + + right_margin = await page.locator( + "div[id='searchButton'][aria-label='Search']" + ).last.evaluate("el => getComputedStyle(el).marginRight") + + assert right_margin != "0px", "Right margin should not be zero pixels" + + await page.close() + finally: + await context.tracing.stop(path="/app/expensify/user_tool/output_browser2.zip") + trace_cleaner("/app/expensify/user_tool/output_browser2.zip") + await context.close() + finally: + await browser.close() diff --git a/issues/166/test.py b/issues/166/test.py index 4bafcf0a..87b3b534 100644 --- a/issues/166/test.py +++ b/issues/166/test.py @@ -11,7 +11,7 @@ from playwright.sync_api import Page, TimeoutError, expect, sync_playwright USERNAME = "contributer0" -APP_PASSWORD = "ughk jfyj dyee mgrs" +APP_PASSWORD = "" USER_EMAIL = f"{USERNAME}+51388_1@gmail.com" NEW_DOT_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/166/user_tool.py b/issues/166/user_tool.py index 238c1b62..6f3405de 100644 --- a/issues/166/user_tool.py +++ b/issues/166/user_tool.py @@ -12,7 +12,7 @@ from utils.trace_cleaner import trace_cleaner USERNAME = "contributer0" -APP_PASSWORD = "ughk jfyj dyee mgrs" +APP_PASSWORD = "" USER_EMAIL = f"{USERNAME}+51388_1@gmail.com" NEW_DOT_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/186/test.py b/issues/186/test.py index ee30df2e..b9d00f52 100644 --- a/issues/186/test.py +++ b/issues/186/test.py @@ -9,8 +9,13 @@ # Constants for URLs and credentials NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" +<<<<<<< HEAD:issues/100/user_tool.py +EMAIL = "ikhanle001+81@gmail.com" +PASSWORD = "" +======= EMAIL = "ikhanle001+36@gmail.com" PASSWORD = "dzcr knad otxp bsuz" +>>>>>>> main:issues/186/test.py class IMAPOTPExtractor: diff --git a/issues/186/user_tool.py b/issues/186/user_tool.py index 0dcd30f0..90dfe3c9 100644 --- a/issues/186/user_tool.py +++ b/issues/186/user_tool.py @@ -11,7 +11,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "ikhanle001+36@gmail.com" -PASSWORD = "dzcr knad otxp bsuz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/187/test.py b/issues/187/test.py index ee30df2e..f7d29ef1 100644 --- a/issues/187/test.py +++ b/issues/187/test.py @@ -10,7 +10,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "ikhanle001+36@gmail.com" -PASSWORD = "dzcr knad otxp bsuz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/187/user_tool.py b/issues/187/user_tool.py index 7bc7391f..959eeb28 100644 --- a/issues/187/user_tool.py +++ b/issues/187/user_tool.py @@ -12,7 +12,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "ikhanle001+36@gmail.com" -PASSWORD = "dzcr knad otxp bsuz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/190/user_tool.py b/issues/190/user_tool.py index 7c5015cf..d768ed30 100644 --- a/issues/190/user_tool.py +++ b/issues/190/user_tool.py @@ -10,7 +10,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" EMAIL_ADDRESS = "t56826807@gmail.com" -PASSWORD = "wxck tsaw ocna tkfd" +PASSWORD = "" FIRST_NAME = "D" LAST_NAME = "C" diff --git a/issues/192/user_tool.py b/issues/192/user_tool.py index 2676b41d..7bf002d1 100644 --- a/issues/192/user_tool.py +++ b/issues/192/user_tool.py @@ -10,7 +10,7 @@ EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "kj56jrdw" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO: int | None = 500 PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/193/user_tool.py b/issues/193/user_tool.py index af92af77..8b6fa838 100644 --- a/issues/193/user_tool.py +++ b/issues/193/user_tool.py @@ -10,7 +10,7 @@ EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "kj56jrdw" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO: int | None = 500 PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/196/user_tool.py b/issues/196/user_tool.py index 1ae1dc2f..91334d7f 100644 --- a/issues/196/user_tool.py +++ b/issues/196/user_tool.py @@ -3,7 +3,7 @@ user_email = "totherandomuser+50963@gmail.com" -password = "umei djwi bfmp jntm" +password = "" def login(p, context): diff --git a/issues/20/user_tool.py b/issues/20/user_tool.py new file mode 100644 index 00000000..b7e5b963 --- /dev/null +++ b/issues/20/user_tool.py @@ -0,0 +1,261 @@ +import time +import imaplib +import email +import re +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager +from playwright._impl._browser import Browser +from playwright._impl._page import Page +from enum import Enum +from utils.trace_cleaner import trace_cleaner + + +TEST_URL = "https://dev.new.expensify.com:8082" +USER_NAME = "caraxxes555" +USER_PASSWORD = "" + + +RETRIES=3 +class TodayOptions(Enum): + TRACK_AND_BUDGET_EXPENSES = 1 + SOMETHING_ELSE = 4 + + +def get_test_user_info(seed=None): + """ + Get test user info using the seed: + - If `seed` is None, this function will return a fixed email and name. + - If `seed` is the `True` boolean value, this function will generate a random number based on the current timestamp and use it as the seed to return a random email and name. + - Otherwise, this function will return a derivative of the fixed email and corresponding name. + """ + if seed is None: + return {"email": f"{USER_NAME}@gmail.com", "password": USER_PASSWORD, "first_name": f"{USER_NAME}", + "last_name": "Test"} + + if type(seed) == type(True): + seed = int(time.time()) + + return {"email": f"{USER_NAME}+{seed}@gmail.com", "password": USER_PASSWORD, "first_name": f"{USER_NAME}+{seed}", + "last_name": "Test"} + + +def wait(page, for_seconds=2): + page.wait_for_timeout(for_seconds * 1000) + + +def get_magic_code(user_email, password, page, retries=RETRIES, delay=10): + # Connect to the server + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + if status == "OK": + email_ids = messages[0].split() + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + # Search for the magic code in the subject + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + wait(page) + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def choose_what_to_do_today_if_any(page, option: TodayOptions, retries=RETRIES, **kwargs): + try: + wait(page) + for _ in range(retries): + wdyw = page.locator("text=What do you want to do today?") + if wdyw.count() == 0: + print('"What do you want to do today?" dialog is not found. Wait and retry...') + wait(page) + else: + break + if wdyw.count() == 0: + print('"What do you want to do today?" dialog is not found.') + set_full_name(page=page, first_name=kwargs['first_name'], last_name=kwargs['last_name']) + return + expect(wdyw).to_be_visible() + text = 'Track and budget expenses' + page.locator(f"text='{text}'").click() + page.get_by_role("button", name="Continue").click() + # Enter first name, last name and click continue + wait(page) + page.locator('input[name="fname"]').fill(kwargs['first_name']) + page.locator('input[name="lname"]').fill(kwargs['last_name']) + wait(page) + page.get_by_role("button", name="Continue").last.click() + if page.get_by_label("Close").count() > 0: + page.get_by_label("Close").click() + except: + pass + + +def choose_link_if_any(page, link_text, retries=RETRIES): + try: + wait(page) + for _ in range(retries): + link = page.locator(f'text={link_text}') + if link.count() == 0: + print(f'"{link_text}" link is not found. Wait and retry...') + wait(page) + else: + break + if link.count() == 0: + print(f'"{link_text}" link is not found.') + return + expect(link).to_be_visible() + link.click() + except Exception as e: + print(e) + return + + +def login(p: PlaywrightContextManager, user_info, if_phone=False) -> tuple[Browser, Page, str]: + permissions = ['clipboard-read', 'clipboard-write'] + browser = p.chromium.launch( + channel="chrome", + headless=False, + args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process", + "--ignore-certificate-errors"], + proxy={"server": "http://localhost:8080"}, + slow_mo=500 + ) + if if_phone: + phone = p.devices['iPhone 12 Pro'] + context = browser.new_context(**phone, permissions=permissions, reduced_motion='no-preference') + else: + context = browser.new_context() + page = context.new_page() + page.goto(TEST_URL, timeout=120000) + phone_or_email_input = page.locator('input[type="email"]') + expect(phone_or_email_input).to_be_visible() + phone_or_email_input.fill(user_info["email"]) + continue_button = page.locator('button[tabindex="0"]') + expect(continue_button).to_be_visible() + continue_button.click() + # Click Join button if the user is new. Or, use Magic Code to sign in if the user is existing. + wait(page) + join_button = page.locator('button:has-text("Join")') + if join_button.count() > 0: + print("Join button found. This is a new user.") + join_button.click() + else: + print("Join button not found. This is an existing user. Use Magic Code to sign in.") + magic_code = get_magic_code(user_info["email"], user_info["password"], page, retries=3, delay=10) or "123456" + print(f"Magic code: {magic_code}") + + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(validate_code_input).to_be_visible() + validate_code_input.fill(magic_code) + return browser, page + + +def set_full_name(page, first_name, last_name): + if page.get_by_label("Close").count() > 0: + page.get_by_label("Close").click() + page.get_by_label("My settings").click() + page.get_by_role("menuitem", name="Profile").click() + page.get_by_text("Display name").click() + page.get_by_label("First name").get_by_role("textbox").click() + page.get_by_label("First name").get_by_role("textbox").fill(first_name) + page.get_by_label("Last name").get_by_role("textbox").click() + page.get_by_label("Last name").get_by_role("textbox").fill(last_name) + page.get_by_role("button", name="Save").click() + wait(page) + if page.get_by_label("Back").count() > 0: + page.get_by_label("Back").last.click() + page.get_by_label("Inbox").click() + + +def delete_expense(page: Page): + page.get_by_test_id("CustomBottomTabNavigator").get_by_label("Search").click() + wait(page) + checkbox_locator = page.locator('role=checkbox[name="Select all"]') + if checkbox_locator.count() > 0: + checkbox_locator.click() + page.get_by_role("button", name="selected").click() + page.get_by_label("Delete").click() + page.get_by_role("button", name="Delete").click() + wait(page) + page.get_by_label("Inbox").click() + + +def test_51127(): + with sync_playwright() as p: + browser = None + page = None + try: + # Login user + user_info = get_test_user_info(seed=511270) + # Step 1: Login + browser, page = login(p, user_info, False) + # Start tracing + context = page.context() + context.tracing.start(screenshots=True, snapshots=True, sources=True) + + # Step 2: Skip onboarding/start pages if any + choose_what_to_do_today_if_any(page, TodayOptions.SOMETHING_ELSE, **user_info) + # A new user will see this Get Started link on the first logon. + choose_link_if_any(page, "Get started") + # Somehow the user can be redirected to the not-found page. This step redirects the user back to the home page. + choose_link_if_any(page, "Go back to home page") + + delete_expense(page) + + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Submit expense").first.click() + page.get_by_label("Manual").click() + page.get_by_label("Select a currency").click() + page.get_by_test_id("selection-list-text-input").fill("usd") + page.get_by_label("USD - $").click() + page.get_by_placeholder("0").fill("10") + page.locator("#numPadContainerView").get_by_role("button", name="Next").click() + page.get_by_test_id("selection-list-text-input").fill("jay207803@gmail.com") + wait(page) + page.get_by_test_id("selection-list-text-input").press("Enter") + page.get_by_role("button", name="Submit $").click() + wait(page) + page.get_by_role("button", name="View details").click() + wait(page) + page.get_by_text("Description").click() + page.get_by_role("textbox", name="What's it for?").fill("hello") + page.get_by_role("button", name="Save").click() + page.evaluate("navigator.clipboard.writeText('');") + page.get_by_text("set the description to \"hello\"").last.click(button="right") + wait(page) + page.get_by_label("Copy to clipboard").first.click() + wait(page) + page.locator("#composer").last.click() + page.keyboard.press("ControlOrMeta+v") + expect(page.get_by_role("paragraph")).to_contain_text("set the description to \"hello\".") + finally: + if page is not None: + # Stop tracing and export the trace file + trace_path = "/app/expensify/user_tool/output_browser1.zip" + page.context().tracing.stop(path=trace_path) + trace_cleaner(trace_path) + if browser is not None: + browser.close() + + +if __name__ == "__main__": + test_51127() \ No newline at end of file diff --git a/issues/200/user_tool.py b/issues/200/user_tool.py index 4bef3be8..9bf9a46d 100644 --- a/issues/200/user_tool.py +++ b/issues/200/user_tool.py @@ -191,7 +191,7 @@ def submit_expense_in_workspace_chat( def login_user(p: PlaywrightContextManager, first_name="Milan", last_name="T") -> tuple[Browser, Page, str]: email_address = "rgarciatammy4@gmail.com" - password = "ezkm eepd sctl nanx" + password = "" account = IMAPOTPExtractor(email_address, password) new_email_address = account.get_new_email() diff --git a/issues/201/user_tool.py b/issues/201/user_tool.py index d9e4bbba..d3f39a05 100644 --- a/issues/201/user_tool.py +++ b/issues/201/user_tool.py @@ -190,7 +190,7 @@ def submit_expense_in_workspace_chat( def login_user(p: PlaywrightContextManager, first_name="Milan", last_name="T") -> tuple[Browser, object, Page, str]: email_address = "rgarciatammy4@gmail.com" - password = "ezkm eepd sctl nanx" + password = "" account = IMAPOTPExtractor(email_address, password) new_email_address = account.get_new_email() diff --git a/issues/203/test.py b/issues/203/test.py index f231445b..c00d144b 100644 --- a/issues/203/test.py +++ b/issues/203/test.py @@ -14,7 +14,7 @@ GMAIL_NAME = "nomandevtur+50577" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/203/user_tool.py b/issues/203/user_tool.py index e0300544..6d81ddda 100644 --- a/issues/203/user_tool.py +++ b/issues/203/user_tool.py @@ -15,7 +15,7 @@ GMAIL_NAME = "nomandevtur+50577" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed=None, first_name=None, last_name=None): diff --git a/issues/206/test.py b/issues/206/test.py index dbd8ef44..6aeb297f 100644 --- a/issues/206/test.py +++ b/issues/206/test.py @@ -10,7 +10,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" EMAIL = "gallahad.420@gmail.com" -PASSWORD = "ndbq rbvo honh lkke" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/206/user_tool.py b/issues/206/user_tool.py index 68017b7c..ca909e82 100644 --- a/issues/206/user_tool.py +++ b/issues/206/user_tool.py @@ -12,7 +12,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" EMAIL = "gallahad.420@gmail.com" -PASSWORD = "ndbq rbvo honh lkke" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/208/test.py b/issues/208/test.py index d9295110..47d4284e 100644 --- a/issues/208/test.py +++ b/issues/208/test.py @@ -12,7 +12,7 @@ import email EMAIL = "mancity9271+1005@gmail.com" -APP_PASSWORD = "aplp neek apqv cjbr" +APP_PASSWORD = "" NEWDOT_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/208/user_tool.py b/issues/208/user_tool.py index 6db60f20..68b167d5 100644 --- a/issues/208/user_tool.py +++ b/issues/208/user_tool.py @@ -14,7 +14,7 @@ from utils.trace_cleaner import trace_cleaner EMAIL = "mancity9271+1005@gmail.com" -APP_PASSWORD = "aplp neek apqv cjbr" +APP_PASSWORD = "" NEWDOT_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/209/test.py b/issues/209/test.py index 5980ed19..44cb98d9 100644 --- a/issues/209/test.py +++ b/issues/209/test.py @@ -14,7 +14,7 @@ GMAIL_NAME = "nomandevtur+50163" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/209/user_tool.py b/issues/209/user_tool.py index ce33c716..1463783a 100644 --- a/issues/209/user_tool.py +++ b/issues/209/user_tool.py @@ -15,7 +15,7 @@ GMAIL_NAME = "nomandevtur+50163" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/210/test.py b/issues/210/test.py index a7b0222a..087ab9e2 100644 --- a/issues/210/test.py +++ b/issues/210/test.py @@ -14,7 +14,7 @@ master_email_address = "brighturing926+50155@gmail.com" -master_app_password = "sijknxflhloopmta" +master_app_password = "" dev_base_url = "https://dev.new.expensify.com:8082" diff --git a/issues/210/user_tool.py b/issues/210/user_tool.py index 5c465250..d3d2cf62 100644 --- a/issues/210/user_tool.py +++ b/issues/210/user_tool.py @@ -15,7 +15,7 @@ logging.basicConfig(level=logging.INFO) master_email_address = "brighturing926+50155@gmail.com" -master_app_password = "sijknxflhloopmta" +master_app_password = "" dev_base_url = "https://dev.new.expensify.com:8082" diff --git a/issues/212/test.py b/issues/212/test.py index d04cfdf0..5e81b19f 100644 --- a/issues/212/test.py +++ b/issues/212/test.py @@ -14,7 +14,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "ikhanle001+34@gmail.com" -PASSWORD = "dzcr knad otxp bsuz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/212/user_tool.py b/issues/212/user_tool.py index 50c5a77c..4a8a44aa 100644 --- a/issues/212/user_tool.py +++ b/issues/212/user_tool.py @@ -15,7 +15,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "ikhanle001+34@gmail.com" -PASSWORD = "dzcr knad otxp bsuz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/213/test.py b/issues/213/test.py index de5e2482..4d769d3b 100644 --- a/issues/213/test.py +++ b/issues/213/test.py @@ -15,7 +15,7 @@ GMAIL_NAME = 'rgulraiz2000' -GMAIL_APP_PASSWORD = 'kepw uquj myoa npvj' +GMAIL_APP_PASSWORD = '' def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/213/user_tool.py b/issues/213/user_tool.py index 6f9e307e..d3da6699 100644 --- a/issues/213/user_tool.py +++ b/issues/213/user_tool.py @@ -17,7 +17,7 @@ GMAIL_NAME = 'rgulraiz2000' -GMAIL_APP_PASSWORD = 'kepw uquj myoa npvj' +GMAIL_APP_PASSWORD = '' def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/216/test.py b/issues/216/test.py index 9c93c6ab..db768f23 100644 --- a/issues/216/test.py +++ b/issues/216/test.py @@ -25,7 +25,7 @@ "xecuycismfsga+eawdvh@gmail.com", "xecuycismfsga+nzfgxzu@gmail.com", ] -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO = 1000 CACHED: bool = True PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/218/test.py b/issues/218/test.py index cefca26b..b75b60f7 100644 --- a/issues/218/test.py +++ b/issues/218/test.py @@ -17,7 +17,7 @@ TEST_URL = "https://dev.new.expensify.com:8082" USER_NAME = "caraxxes555" -USER_PASSWORD = 'wawm wmyw omkr dpmt' +USER_PASSWORD = '' class TodayOptions(Enum): diff --git a/issues/218/user_tool.py b/issues/218/user_tool.py index b8c73608..546141ad 100644 --- a/issues/218/user_tool.py +++ b/issues/218/user_tool.py @@ -17,7 +17,7 @@ TEST_URL = "https://dev.new.expensify.com:8082" USER_NAME = "caraxxes555" -USER_PASSWORD = 'wawm wmyw omkr dpmt' +USER_PASSWORD = '' class TodayOptions(Enum): diff --git a/issues/219/test.py b/issues/219/test.py index 5d676d72..96dd6125 100644 --- a/issues/219/test.py +++ b/issues/219/test.py @@ -11,7 +11,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" task_id = 49786 EMAIL = f"dev091197+{task_id}@gmail.com" -PASSWORD = "ptul fwbd fvze yzva" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/219/user_tool.py b/issues/219/user_tool.py index 3dece644..9034fa87 100644 --- a/issues/219/user_tool.py +++ b/issues/219/user_tool.py @@ -11,7 +11,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" task_id = 49786 EMAIL = f"dev091197+{task_id}@gmail.com" -PASSWORD = "ptul fwbd fvze yzva" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/227/test.py b/issues/227/test.py index a508f047..c75b2eb0 100644 --- a/issues/227/test.py +++ b/issues/227/test.py @@ -16,7 +16,7 @@ MAX_TRIES = 10 USERNAME = "expensify31+1943@gmail.com" -PASSWORD = "glss akzu qghd ylad" +PASSWORD = "" async def get_magic_code(user_email, password, retries=10, delay=10, since=None): if since is None: diff --git a/issues/227/user_tool.py b/issues/227/user_tool.py index b22d576e..5368b730 100644 --- a/issues/227/user_tool.py +++ b/issues/227/user_tool.py @@ -18,7 +18,7 @@ MAX_TRIES = 10 USERNAME = "expensify31+1943@gmail.com" -PASSWORD = "glss akzu qghd ylad" +PASSWORD = "" async def get_magic_code(user_email, password, retries=10, delay=10, since=None): if since is None: diff --git a/issues/229/test.py b/issues/229/test.py index d85d8297..08fe74b7 100644 --- a/issues/229/test.py +++ b/issues/229/test.py @@ -21,7 +21,7 @@ EXPENSIFY_EMAIL = "osaidtest5@gmail.com" NEW_DOT_URL = "https://dev.new.expensify.com:8082" OLD_DOT_URL = "http://localhost:9000/" -EXPENSIFY_PASSWORD = "ntvd acej mmaa qqmd" +EXPENSIFY_PASSWORD = "" DATA_DIR = 'browser_context' EXPENSIFY_DERIVED_EMAIL = "osaidtest5+49062_7@gmail.com" diff --git a/issues/229/user_tool.py b/issues/229/user_tool.py index ae34a49d..056c22bb 100644 --- a/issues/229/user_tool.py +++ b/issues/229/user_tool.py @@ -22,7 +22,7 @@ EXPENSIFY_EMAIL = "osaidtest5@gmail.com" NEW_DOT_URL = "https://dev.new.expensify.com:8082" OLD_DOT_URL = "http://localhost:9000/" -EXPENSIFY_PASSWORD = "ntvd acej mmaa qqmd" +EXPENSIFY_PASSWORD = "" DATA_DIR = 'browser_context' EXPENSIFY_DERIVED_EMAIL = "osaidtest5+49062_7@gmail.com" diff --git a/issues/231/test.py b/issues/231/test.py index dfb56f97..271a8148 100644 --- a/issues/231/test.py +++ b/issues/231/test.py @@ -12,7 +12,7 @@ EMAIL = "dev091197@gmail.com" task_id = 48694 EMAIL1 = f"dev091197+{task_id}@gmail.com" -PASSWORD = "ptul fwbd fvze yzva" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/231/user_tool.py b/issues/231/user_tool.py index 65de028c..4c75b02c 100644 --- a/issues/231/user_tool.py +++ b/issues/231/user_tool.py @@ -13,7 +13,7 @@ EMAIL = "dev091197@gmail.com" task_id = 48694 EMAIL1 = f"dev091197+{task_id}@gmail.com" -PASSWORD = "ptul fwbd fvze yzva" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/236/test.py b/issues/236/test.py index df40bbca..ac94bb75 100644 --- a/issues/236/test.py +++ b/issues/236/test.py @@ -11,7 +11,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "46528" diff --git a/issues/236/user_tool.py b/issues/236/user_tool.py index f5b78255..825b3e26 100644 --- a/issues/236/user_tool.py +++ b/issues/236/user_tool.py @@ -12,7 +12,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "46528" diff --git a/issues/240/test.py b/issues/240/test.py index 2be76899..b8a17a2a 100644 --- a/issues/240/test.py +++ b/issues/240/test.py @@ -12,7 +12,7 @@ def generate_random_email1(base_email="testerbro7077@gmail.com"): def login_user1(p, first_name="Yagna", slow_mo=1000, last_name="Sai") -> tuple: user_email1 = generate_random_email1() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', @@ -40,7 +40,7 @@ def generate_random_email2(base_email="testerbro7077@gmail.com"): def login_user2(p, first_name="Yagna", last_name="Sai") -> tuple: user_email2 = generate_random_email2() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', diff --git a/issues/240/user_tool.py b/issues/240/user_tool.py index 41b927af..136dbce9 100644 --- a/issues/240/user_tool.py +++ b/issues/240/user_tool.py @@ -15,7 +15,7 @@ def generate_random_email1(base_email="testerbro7077@gmail.com"): def login_user1(p, first_name="Yagna", slow_mo=1000, last_name="Sai") -> tuple: user_email1 = generate_random_email1() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', @@ -46,7 +46,7 @@ def generate_random_email2(base_email="testerbro7077@gmail.com"): def login_user2(p, first_name="Yagna", last_name="Sai") -> tuple: user_email2 = generate_random_email2() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', diff --git a/issues/245/test.py b/issues/245/test.py index fca7f7b2..f030e5d7 100644 --- a/issues/245/test.py +++ b/issues/245/test.py @@ -10,7 +10,7 @@ EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com -PASSWORD = "logb hzkg pkfk kskg" # it will be something like "sdib pxop ovyl uawy" +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" diff --git a/issues/245/user_tool.py b/issues/245/user_tool.py index 01ca00cb..7d1f017c 100644 --- a/issues/245/user_tool.py +++ b/issues/245/user_tool.py @@ -12,7 +12,7 @@ EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com -PASSWORD = "logb hzkg pkfk kskg" # it will be something like "sdib pxop ovyl uawy" +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" def generate_random_email(): diff --git a/issues/246/test.py b/issues/246/test.py index 3b6d9181..c014dc00 100644 --- a/issues/246/test.py +++ b/issues/246/test.py @@ -15,7 +15,7 @@ NEW_DOT_URL = "https://dev.new.expensify.com:8082" EXPENSIFY_EMAIL = "testingq186+45771_1@gmail.com" -EXPENSIFY_PASSWORD = "kkfr hqiv yuxq rbso" +EXPENSIFY_PASSWORD = "" TESTING_FLOW = True diff --git a/issues/246/user_tool.py b/issues/246/user_tool.py index cbecfdb7..3eb3f378 100644 --- a/issues/246/user_tool.py +++ b/issues/246/user_tool.py @@ -15,7 +15,7 @@ NEW_DOT_URL = "https://dev.new.expensify.com:8082" EXPENSIFY_EMAIL = "testingq186+45771_1@gmail.com" -EXPENSIFY_PASSWORD = "kkfr hqiv yuxq rbso" +EXPENSIFY_PASSWORD = "" TESTING_FLOW = True diff --git a/issues/247/test.py b/issues/247/test.py index cb7f4514..222b91b0 100644 --- a/issues/247/test.py +++ b/issues/247/test.py @@ -12,7 +12,7 @@ import pytest GMAIL_NAME = "rgulraiz2000" -GMAIL_APP_PASSWORD = "kepw uquj myoa npvj" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/247/user_tool.py b/issues/247/user_tool.py index 545996ae..d081a3c8 100644 --- a/issues/247/user_tool.py +++ b/issues/247/user_tool.py @@ -14,7 +14,7 @@ from utils.trace_cleaner import trace_cleaner GMAIL_NAME = "rgulraiz2000" -GMAIL_APP_PASSWORD = "kepw uquj myoa npvj" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/249/test.py b/issues/249/test.py index 3969d2e9..2b9e1388 100644 --- a/issues/249/test.py +++ b/issues/249/test.py @@ -11,9 +11,9 @@ USER_EMAILA = "doorsqueaky+3182311@gmail.com" USERNAME_A = 'John Doe' -PASSWORD_A = "eabcahqraatorpvt" +PASSWORD_A = "" USER_EMAILB = "windowsqueaky+3919211@gmail.com" -PASSWORD_B = "jeaqzqklzxxdetsh" +PASSWORD_B = "" USERNAME_B = 'Jane Doe' diff --git a/issues/249/user_tool.py b/issues/249/user_tool.py index b6281d21..7c5d5681 100644 --- a/issues/249/user_tool.py +++ b/issues/249/user_tool.py @@ -13,9 +13,9 @@ USER_EMAILA = "doorsqueaky+3182311@gmail.com" USERNAME_A = 'John Doe' -PASSWORD_A = "eabcahqraatorpvt" +PASSWORD_A = "" USER_EMAILB = "windowsqueaky+3919211@gmail.com" -PASSWORD_B = "jeaqzqklzxxdetsh" +PASSWORD_B = "" USERNAME_B = 'Jane Doe' diff --git a/issues/251/test.py b/issues/251/test.py index 3d5d7c55..c2bd3922 100644 --- a/issues/251/test.py +++ b/issues/251/test.py @@ -19,7 +19,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") LOGGER = logging.getLogger(__name__) diff --git a/issues/251/user_tool.py b/issues/251/user_tool.py index 39c44a1e..c22411bf 100644 --- a/issues/251/user_tool.py +++ b/issues/251/user_tool.py @@ -16,7 +16,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") LOGGER = logging.getLogger(__name__) diff --git a/issues/254/test.py b/issues/254/test.py index c50dc306..5d102793 100644 --- a/issues/254/test.py +++ b/issues/254/test.py @@ -117,7 +117,7 @@ def _extract_otp(self, text): TIMEOUT = 20000 NEWDOT_URL = "https://dev.new.expensify.com:8082/" TEST_EMAIL = "turingtemp+177125@gmail.com" -APP_PASSWORD = "rxyc esdd vdad pamq" +APP_PASSWORD = "" def login_user( diff --git a/issues/254/user_tool.py b/issues/254/user_tool.py index 92c6e457..a4040efe 100644 --- a/issues/254/user_tool.py +++ b/issues/254/user_tool.py @@ -117,7 +117,7 @@ def _extract_otp(self, text): TIMEOUT = 20000 NEWDOT_URL = "https://dev.new.expensify.com:8082/" TEST_EMAIL = "turingtemp+177125@gmail.com" -APP_PASSWORD = "rxyc esdd vdad pamq" +APP_PASSWORD = "" def login_user(p: PlaywrightContextManager, email: str) -> tuple[Browser, Page]: diff --git a/issues/26258_492/test.py b/issues/26258_492/test.py new file mode 100644 index 00000000..b5e89fdd --- /dev/null +++ b/issues/26258_492/test.py @@ -0,0 +1,356 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import re +import time +from playwright.sync_api import sync_playwright +import random +import imaplib +import email as email_lib +from playwright.sync_api import sync_playwright, expect +import os + + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + + 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) + random_suffix_2 = random_suffix + 1 + + current_timestamp = int(time.time()) + random_suffix = f"565439872" + random_suffix_2 = f"6552447256" + + self.new_email_1 = self._generate_new_email(email_address, random_suffix) + self.new_email_2 = self._generate_new_email(email_address, random_suffix_2) + + def _validate_email(self, email_address): + + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + + def _generate_new_email(self, email_address, suffix): + + username, domain = email_address.split('@') + return f"{username}+{suffix}@{domain}" + + def get_new_email_1(self): + + return self.new_email_1 + + def get_new_email_2(self): + + return self.new_email_2 + + def check_for_otp(self, email): + return "123456" + + +def create_simple_pdf(filename="sample.pdf"): + """ + Creates a simple PDF file in the current working directory without using any external libraries. + + Args: + - filename (str): The name of the PDF file to be created. + + Returns: + - str: The absolute path of the created PDF file. + """ + pdf_content = """%PDF-1.4 +1 0 obj +<< /Type /Catalog /Pages 2 0 R >> +endobj +2 0 obj +<< /Type /Pages /Kids [3 0 R] /Count 1 >> +endobj +3 0 obj +<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << >> >> +endobj +4 0 obj +<< /Length 44 >> +stream +BT +/F1 24 Tf +100 700 Td +(Hello, this is a simple PDF file) Tj +ET +endstream +endobj +5 0 obj +<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> +endobj +xref +0 6 +0000000000 65535 f +0000000010 00000 n +0000000079 00000 n +0000000178 00000 n +0000000328 00000 n +0000000407 00000 n +trailer +<< /Size 6 /Root 1 0 R >> +startxref +488 +%%EOF +""" + + + with open(filename, "wb") as file: + file.write(pdf_content.encode('latin1')) # PDF requires Latin-1 encoding + + return filename + + +def delete_pdf(filename="sample.pdf"): + """ + Deletes a PDF file in the current working directory. + + Args: + - filename (str): The name of the PDF file to be deleted. + + Returns: + - bool: True if the file was successfully deleted, False if the file does not exist. + """ + file_path = os.path.join(os.getcwd(), filename) + + if os.path.exists(file_path): + os.remove(file_path) + return True + else: + print(f"File not found, could not delete: {file_path}") + return False + + +def click_until_visible(page, button_selector: str, desired_selector: str, max_retries: int = 10, timeout: int = 30): + """ + Clicks a button until the desired element becomes visible or max retries are reached. + + :param page: Playwright Page instance. + :param button_selector: Selector for the button to click. + :param desired_selector: Selector for the element to wait for. + :param max_retries: Maximum number of clicks to attempt. + :param timeout: Maximum time to wait for the desired element to become visible. + + :return: Locator for the desired element. + """ + timeout = timeout * 1000 # Convert seconds to milliseconds + retries = 0 + while retries < max_retries: + + page.locator(button_selector).click(timeout=timeout) + + try: + + locator = page.locator(desired_selector).wait_for(state="visible", timeout=timeout) + return locator + except Exception: + + retries += 1 + + + raise Exception(f"Desired element '{desired_selector}' not found after {max_retries} clicks.") + + +def launch_app(pw, headless=True, device=None, geolocation=None): + browser = pw.chromium.launch( + channel="chrome", + headless=True, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + proxy={"server": "http://localhost:8080"}, + slow_mo=500 + ) + + context_args = {"viewport": {"width": 1024, "height": 640}} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def login_user_with_otp(page, email, email_extractor): + page.get_by_role("textbox", name="Phone or email").fill(email) + page.wait_for_timeout(1000) + + click_until_visible(page, 'button:has-text("Continue")', 'input[data-testid="validateCode"]', timeout=5) + + otp = None + print("Waiting for OTP email...") + page.wait_for_timeout(5000) # Wait for email to arrive + + for i in range(30): + print("Trying to fetch OTP from email, attempt:", i+1) + otp = email_extractor.check_for_otp(email) + if otp: + print("OTP found in email:", otp) + break + print("No OTP found yet. Waiting for 3 seconds...") + page.wait_for_timeout(3000) + + + if not otp: + print("No OTP found in unread emails.") + return + + otp_input = page.locator('input[data-testid="validateCode"]') + expect(otp_input).to_be_visible(timeout=10000) + otp_input.fill(otp) + + +def login_and_initial_setup(page, email, is_logout = False, is_first = False): + if is_first: + page.goto(NEWDOT_URL) + + page.get_by_role("textbox", name="Phone or email").fill(email) + page.wait_for_timeout(1000) + + continue_button = page.locator('button[tabindex="0"]') + continue_button.wait_for(state="visible", timeout=10000) + continue_button.click() + + page.wait_for_timeout(2000) + + try: + page.locator('button[tabindex="0"]').click() + except Exception: + page.wait_for_timeout(1000) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(2000) + + try: + expect(page.get_by_text("want to do today")).to_be_visible(timeout=15000) + except AssertionError: + page.wait_for_timeout(1000) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(2000) + + page.locator("text='Track and budget expenses'").wait_for(state="visible", timeout=10000) + page.locator("text='Track and budget expenses'").click() + page.get_by_role("button", name="Continue").click() + + page.locator('input[name="fname"]').fill("Test") + page.locator('input[name="lname"]').fill("User") + page.get_by_role("button", name="Continue").last.click() + page.wait_for_timeout(1000) + + if is_logout: + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_label("Sign out").click() + page.wait_for_timeout(1000) + + +def start_chat_and_send_file(page, emal_to_message): + try: + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Start chat", exact=True).click() + page.wait_for_timeout(1000) + + page.get_by_test_id("selection-list-text-input").fill(emal_to_message) + page.wait_for_timeout(1000) + + try: + page.get_by_label("Test").click() + except Exception: + page.wait_for_timeout(1000) + page.get_by_label(emal_to_message).click() + + page.wait_for_timeout(1000) + + page.get_by_label("Create").last.click() + page.wait_for_timeout(1000) + + add_attachment = page.get_by_label("Add attachment") + with page.expect_file_chooser() as file_chooser_info: + add_attachment.click() + + page.wait_for_timeout(2000) + + file_chooser = file_chooser_info.value + current_directory = os.getcwd() + file_path = os.path.join(current_directory, "sample.pdf") + file_chooser.set_files(file_path) + page.wait_for_timeout(2000) + + page.get_by_role("dialog").get_by_role("button", name="Send").click() + page.wait_for_timeout(2000) + + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + + page.get_by_label("Sign out").click() + page.wait_for_timeout(1000) + + + except Exception as e: + print(f"Error during workspace and chat setup: {e}") + + + +def check_dowload_button(page): + page.get_by_label("Navigates to a chat").last.click() + page.wait_for_timeout(2000) + + + page.context.set_offline(True) + page.get_by_label("View attachment").first.click() + download_button = 0 + + try: + download_button = page.get_by_label("Download").count() + except: + pass + + assert download_button == 0, "Download button is not hidden when offline, issue exists!" + + + +def test_download_button_visibility(): + with sync_playwright() as pw: + + email_address = "rgarciatammy4@gmail.com" + password = "" + + + email_extractor = IMAPOTPExtractor(email_address, password) + email_1 = email_extractor.get_new_email_1() + email_2 = email_extractor.get_new_email_2() + + browser, context, page = launch_app(pw) + + + create_simple_pdf("sample.pdf") + + + login_and_initial_setup(page, email_2, is_logout=True, is_first=True) + context.clear_cookies() + + login_and_initial_setup(page, email_1) + start_chat_and_send_file(page, email_2) + + login_user_with_otp(page, email_2, email_extractor) + check_dowload_button(page) + + + delete_pdf("sample.pdf") + + context.close() + browser.close() diff --git a/issues/26258_492/user_tool.py b/issues/26258_492/user_tool.py new file mode 100644 index 00000000..3662fb72 --- /dev/null +++ b/issues/26258_492/user_tool.py @@ -0,0 +1,371 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import re +import time +from playwright.sync_api import sync_playwright +import random +import imaplib +import email as email_lib +from playwright.sync_api import sync_playwright, expect +import os + + +from utils.trace_cleaner import trace_cleaner + + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + + 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) + random_suffix_2 = random_suffix + 1 + + current_timestamp = int(time.time()) + random_suffix = f"565439872" + random_suffix_2 = f"6552447256" + + self.new_email_1 = self._generate_new_email(email_address, random_suffix) + self.new_email_2 = self._generate_new_email(email_address, random_suffix_2) + + def _validate_email(self, email_address): + + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + + def _generate_new_email(self, email_address, suffix): + + username, domain = email_address.split('@') + return f"{username}+{suffix}@{domain}" + + def get_new_email_1(self): + + return self.new_email_1 + + def get_new_email_2(self): + + return self.new_email_2 + + def check_for_otp(self, email): + return "123456" + + +def create_simple_pdf(filename="sample.pdf"): + """ + Creates a simple PDF file in the current working directory without using any external libraries. + + Args: + - filename (str): The name of the PDF file to be created. + + Returns: + - str: The absolute path of the created PDF file. + """ + pdf_content = """%PDF-1.4 +1 0 obj +<< /Type /Catalog /Pages 2 0 R >> +endobj +2 0 obj +<< /Type /Pages /Kids [3 0 R] /Count 1 >> +endobj +3 0 obj +<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << >> >> +endobj +4 0 obj +<< /Length 44 >> +stream +BT +/F1 24 Tf +100 700 Td +(Hello, this is a simple PDF file) Tj +ET +endstream +endobj +5 0 obj +<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> +endobj +xref +0 6 +0000000000 65535 f +0000000010 00000 n +0000000079 00000 n +0000000178 00000 n +0000000328 00000 n +0000000407 00000 n +trailer +<< /Size 6 /Root 1 0 R >> +startxref +488 +%%EOF +""" + + + with open(filename, "wb") as file: + file.write(pdf_content.encode('latin1')) # PDF requires Latin-1 encoding + + return filename + + +def delete_pdf(filename="sample.pdf"): + """ + Deletes a PDF file in the current working directory. + + Args: + - filename (str): The name of the PDF file to be deleted. + + Returns: + - bool: True if the file was successfully deleted, False if the file does not exist. + """ + file_path = os.path.join(os.getcwd(), filename) + + if os.path.exists(file_path): + os.remove(file_path) + return True + else: + print(f"File not found, could not delete: {file_path}") + return False + + +def click_until_visible(page, button_selector: str, desired_selector: str, max_retries: int = 10, timeout: int = 30): + """ + Clicks a button until the desired element becomes visible or max retries are reached. + + :param page: Playwright Page instance. + :param button_selector: Selector for the button to click. + :param desired_selector: Selector for the element to wait for. + :param max_retries: Maximum number of clicks to attempt. + :param timeout: Maximum time to wait for the desired element to become visible. + + :return: Locator for the desired element. + """ + timeout = timeout * 1000 # Convert seconds to milliseconds + retries = 0 + while retries < max_retries: + + page.locator(button_selector).click(timeout=timeout) + + try: + + locator = page.locator(desired_selector).wait_for(state="visible", timeout=timeout) + return locator + except Exception: + + retries += 1 + + + raise Exception(f"Desired element '{desired_selector}' not found after {max_retries} clicks.") + + +def launch_app(pw, headless=True, device=None, geolocation=None): + browser = pw.chromium.launch( + channel="chrome", + headless=True, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + proxy={"server": "http://localhost:8080"}, + slow_mo=500 + ) + + context_args = {"viewport": {"width": 1024, "height": 640}} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def login_user_with_otp(page, email, email_extractor): + page.get_by_role("textbox", name="Phone or email").fill(email) + page.wait_for_timeout(1000) + + click_until_visible(page, 'button:has-text("Continue")', 'input[data-testid="validateCode"]', timeout=5) + + otp = None + print("Waiting for OTP email...") + page.wait_for_timeout(5000) # Wait for email to arrive + + for i in range(30): + print("Trying to fetch OTP from email, attempt:", i+1) + otp = email_extractor.check_for_otp(email) + if otp: + print("OTP found in email:", otp) + break + print("No OTP found yet. Waiting for 3 seconds...") + page.wait_for_timeout(3000) + + + if not otp: + print("No OTP found in unread emails.") + return + + otp_input = page.locator('input[data-testid="validateCode"]') + expect(otp_input).to_be_visible(timeout=10000) + otp_input.fill(otp) + + +def login_and_initial_setup(page, email, is_logout = False, is_first = False): + if is_first: + page.goto(NEWDOT_URL) + + page.get_by_role("textbox", name="Phone or email").fill(email) + page.wait_for_timeout(1000) + + continue_button = page.locator('button[tabindex="0"]') + continue_button.wait_for(state="visible", timeout=10000) + continue_button.click() + + page.wait_for_timeout(2000) + + try: + page.locator('button[tabindex="0"]').click() + except Exception: + page.wait_for_timeout(1000) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(2000) + + try: + expect(page.get_by_text("want to do today")).to_be_visible(timeout=15000) + except AssertionError: + page.wait_for_timeout(1000) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(2000) + + page.locator("text='Track and budget expenses'").wait_for(state="visible", timeout=10000) + page.locator("text='Track and budget expenses'").click() + page.get_by_role("button", name="Continue").click() + + page.locator('input[name="fname"]').fill("Test") + page.locator('input[name="lname"]').fill("User") + page.get_by_role("button", name="Continue").last.click() + page.wait_for_timeout(1000) + + if is_logout: + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_label("Sign out").click() + page.wait_for_timeout(1000) + + +def start_chat_and_send_file(page, emal_to_message): + try: + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Start chat", exact=True).click() + page.wait_for_timeout(1000) + + page.get_by_test_id("selection-list-text-input").fill(emal_to_message) + page.wait_for_timeout(1000) + + try: + page.get_by_label("Test").click() + except Exception: + page.wait_for_timeout(1000) + page.get_by_label(emal_to_message).click() + + page.wait_for_timeout(1000) + + page.get_by_label("Create").last.click() + page.wait_for_timeout(1000) + + add_attachment = page.get_by_label("Add attachment") + with page.expect_file_chooser() as file_chooser_info: + add_attachment.click() + + page.wait_for_timeout(2000) + + file_chooser = file_chooser_info.value + current_directory = os.getcwd() + file_path = os.path.join(current_directory, "sample.pdf") + file_chooser.set_files(file_path) + page.wait_for_timeout(2000) + + page.get_by_role("dialog").get_by_role("button", name="Send").click() + page.wait_for_timeout(2000) + + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + + page.get_by_label("Sign out").click() + page.wait_for_timeout(1000) + + + except Exception as e: + print(f"Error during workspace and chat setup: {e}") + + + +def check_dowload_button(page): + page.get_by_label("Navigates to a chat").last.click() + page.wait_for_timeout(2000) + + + page.context.set_offline(True) + page.get_by_label("View attachment").first.click() + download_button = 0 + + try: + download_button = page.get_by_label("Download").count() + except: + pass + + assert download_button == 0, "Download button is not hidden when offline, issue exists!" + + +def test_download_button_visibility(): + with sync_playwright() as pw: + browser, context, page = None, None, None + try: + + email_address = "rgarciatammy4@gmail.com" + password = "" + + + email_extractor = IMAPOTPExtractor(email_address, password) + email_1 = email_extractor.get_new_email_1() + email_2 = email_extractor.get_new_email_2() + + browser, context, page = launch_app(pw) + + context.tracing.start(screenshots=True, snapshots=True) + + + create_simple_pdf("sample.pdf") + + + login_and_initial_setup(page, email_2, is_logout=True, is_first=True) + context.clear_cookies() + + login_and_initial_setup(page, email_1) + start_chat_and_send_file(page, email_2) + + login_user_with_otp(page, email_2, email_extractor) + check_dowload_button(page) + + + delete_pdf("sample.pdf") + except Exception as e: + print(f"Test encountered an error: {e}") + raise + finally: + if context: + + context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + context.close() + if browser: + browser.close() diff --git a/issues/264/test.py b/issues/264/test.py index ac06f78c..a00ccd5c 100644 --- a/issues/264/test.py +++ b/issues/264/test.py @@ -20,7 +20,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "44165.1" diff --git a/issues/264/user_tool.py b/issues/264/user_tool.py index e1fbfe3c..40aade49 100644 --- a/issues/264/user_tool.py +++ b/issues/264/user_tool.py @@ -21,7 +21,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "44165.1" diff --git a/issues/265/test.py b/issues/265/test.py index 05c1bc84..fe55eca0 100644 --- a/issues/265/test.py +++ b/issues/265/test.py @@ -10,7 +10,7 @@ from playwright._impl._page import Page EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com -PASSWORD = "logb hzkg pkfk kskg" # it will be something like "sdib pxop ovyl uawy" +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" diff --git a/issues/267/test.py b/issues/267/test.py index d3ea373f..4d4d6d30 100644 --- a/issues/267/test.py +++ b/issues/267/test.py @@ -11,7 +11,7 @@ EMAIL_USERNAME1 = "testotpverif+111@gmail.com" EMAIL_USERNAME2 = "testotpverif+222@gmail.com" -EMAIL_PASSWORD = "ghka tmuf vpio patv" +EMAIL_PASSWORD = "" EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/268/test.py b/issues/268/test.py index 327fb2e5..5e1c6325 100644 --- a/issues/268/test.py +++ b/issues/268/test.py @@ -13,7 +13,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "43726" diff --git a/issues/268/user_tool.py b/issues/268/user_tool.py index 5f104ce0..d3c4a1a3 100644 --- a/issues/268/user_tool.py +++ b/issues/268/user_tool.py @@ -15,7 +15,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "43726" diff --git a/issues/273/test.py b/issues/273/test.py index d40c9579..68cc56ac 100644 --- a/issues/273/test.py +++ b/issues/273/test.py @@ -40,7 +40,7 @@ def login(page: Page, user_email: str): def test_open_report_requests(): with sync_playwright() as p: base_email = "namesomerandomemail@gmail.com" - password = "fkto mqnl wkuw ecgx" + password = "" first_name = "Test" last_name = "User" diff --git a/issues/273/user_tool.py b/issues/273/user_tool.py index 5c89c123..fe78b5a6 100644 --- a/issues/273/user_tool.py +++ b/issues/273/user_tool.py @@ -41,7 +41,7 @@ def login(page: Page, user_email: str): def test_open_report_requests(): with sync_playwright() as p: base_email = "namesomerandomemail@gmail.com" - password = "fkto mqnl wkuw ecgx" + password = "" first_name = "Test" last_name = "User" diff --git a/issues/27363_760/test.py b/issues/27363_760/test.py new file mode 100644 index 00000000..bc1307a8 --- /dev/null +++ b/issues/27363_760/test.py @@ -0,0 +1,129 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect + +GMAIL_NAME = "nomandevtur+27363" +GMAIL_APP_PASSWORD = "" + + +def get_test_user_info(seed = None, first_name = None, last_name = None): + if first_name is None: + first_name = GMAIL_NAME + + if last_name is None: + last_name = "" + + email = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + + return {"email": email, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + + + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + + + page.get_by_label(activity_text).click() + + + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + + +def login_user(page, user_info, activity_text="Track and budget expenses"): + + page.context.clear_cookies() + + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + + expect(page.get_by_label("Inbox")).to_be_visible(timeout=3000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + + if (join_button.is_visible()): + join_button.click(timeout=3000) + else: + magic_code = "123456" + print(f"Magic code: {magic_code}") + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + + +def launch_app(pw, headless=True, device=None, geolocation=None): + browser = pw.chromium.launch(headless=headless, slow_mo=500, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + ) + context_args = {"viewport": {"width": 1024, "height": 640}} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + +def test_assign_share_url(): + with sync_playwright() as p: + + user_info = get_test_user_info(first_name="abc", last_name="abc") + + browser, context, page = launch_app(p) + login_user(page, user_info) + + page.wait_for_timeout(3000) + + + locator = page.locator(f"span:has-text('random email (you)')").click() + + page.wait_for_timeout(1000) + screen_id = page.url.split('/')[-1] + + page.get_by_test_id(f"report-screen-{screen_id}").get_by_label("Create").click() + page.get_by_label("Assign task").click() + page.get_by_role("textbox", name="Title").fill("task99") + page.get_by_role("button", name="Next").click() + page.get_by_test_id("NewTaskPage").get_by_label("Back").click() + page.wait_for_timeout(1000) + page.get_by_label("Back").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox").fill("https://dev.new.expensify.com:8082/new/task/somewhere11") + + page.get_by_test_id(f"report-screen-{screen_id}").get_by_label("Send").click() + page.get_by_test_id(f"report-screen-{screen_id}").get_by_test_id("report-actions-list").get_by_text("https://dev.new.expensify.com:8082/new/task/somewhere11").click() + page.wait_for_timeout(3000) + + + locator = page.locator('div:has-text("Hmm... it\'s not here")') + + + assert locator.count() > 0, "The div with the text 'Hmm... it's not here' is not found." + + print("The message 'Hmm... it's not here' is visible on page") + + page.wait_for_timeout(4000) + page.close() + browser.close() + + diff --git a/issues/27363_760/user_tool.py b/issues/27363_760/user_tool.py new file mode 100644 index 00000000..2b7c076a --- /dev/null +++ b/issues/27363_760/user_tool.py @@ -0,0 +1 @@ +import sys, os\n\nbase_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))\nsys.path.insert(0, base_path)\n\nfrom playwright.sync_api import sync_playwright, expect\nfrom utils.trace_cleaner import trace_cleaner\n\nGMAIL_NAME = "nomandevtur+27363"\nGMAIL_APP_PASSWORD = ""\n\n\ndef get_test_user_info(seed = None, first_name = None, last_name = None):\n if first_name is None:\n first_name = GMAIL_NAME\n\n if last_name is None:\n last_name = ""\n\n email = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com"\n\n return {"email": email, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name}\n\n\ndef select_activity(page, first_name, last_name, activity_text):\n expect(page.get_by_text("What do you want to do today?")).to_be_visible()\n\n # Select activity in onboarding page and click Continue\n page.get_by_label(activity_text).click()\n\n # Enter first name, last name and click continue\n page.get_by_role("textbox", name="First name").fill(first_name)\n page.get_by_role("textbox", name="Last name").fill(last_name)\n page.get_by_role("button", name="Continue").last.click()\n\ndef login_user(page, user_info, activity_text="Track and budget expenses"):\n # Clear cookies, local storage, and session storage\n page.context.clear_cookies()\n\n page.goto('https://dev.new.expensify.com:8082/')\n page.wait_for_load_state('load')\n\n try:\n # If the user is already logged in, the inbox should be visible\n expect(page.get_by_label("Inbox")).to_be_visible(timeout=3000)\n return\n except:\n pass\n\n page.get_by_test_id("username").fill(user_info["email"])\n page.get_by_role("button", name="Continue").click()\n\n join_button = page.get_by_role("button", name="Join")\n validate_code_input = page.locator('input[data-testid="validateCode"]')\n\n if (join_button.is_visible()):\n join_button.click(timeout=3000)\n else:\n magic_code = "123456"\n print(f"Magic code: {magic_code}")\n validate_code_input.fill(magic_code)\n\n page.wait_for_timeout(3000)\n\n select_activity_dialog = page.get_by_text("What do you want to do today?")\n if select_activity_dialog.count() > 0:\n select_activity(page, user_info["first_name"], user_info["last_name"], activity_text)\n\ndef launch_app(pw, headless=True, device=None, geolocation=None):\n browser = pw.chromium.launch(headless=headless, slow_mo=500, args=[\n "--disable-web-security",\n "--disable-features=IsolateOrigins,site-per-process"\n ],\n )\n context_args = {"viewport": {"width": 1024, "height": 640}}\n if device:\n context_args.update(pw.devices[device])\n if geolocation:\n context_args["geolocation"] = geolocation\n context_args["permissions"] = ["geolocation"]\n context = browser.new_context(**context_args)\n page = context.new_page()\n return browser, context, page\n\ndef test_assign_share_url():\n with sync_playwright() as p:\n trace_path = "/app/expensify/user_tool/output_browser1.zip"\n browser, context, page = None, None, None\n\n try:\n browser, context, page = launch_app(p)\n context.tracing.start(screenshots=True, snapshots=True, sources=True)\n\n user_info = get_test_user_info(first_name="abc", last_name="abc")\n login_user(page, user_info)\n\n page.wait_for_timeout(3000)\n\n # move to personal chat\n locator = page.locator(f"span:has-text('random email (you)')").click()\n\n page.wait_for_timeout(1000)\n screen_id = page.url.split('/')[-1]\n\n page.get_by_test_id(f"report-screen-{screen_id}").get_by_label("Create").click()\n page.get_by_label("Assign task").click()\n page.get_by_role("textbox", name="Title").fill("task99")\n page.get_by_role("button", name="Next").click()\n page.get_by_test_id("NewTaskPage").get_by_label("Back").click()\n page.wait_for_timeout(1000)\n page.get_by_label("Back").click()\n page.wait_for_timeout(1000)\n page.get_by_role("textbox").fill("https://dev.new.expensify.com:8082/new/task/somewhere11")\n\n page.get_by_test_id(f"report-screen-{screen_id}").get_by_label("Send").click()\n page.get_by_test_id(f"report-screen-{screen_id}").get_by_test_id("report-actions-list").get_by_text("https://dev.new.expensify.com:8082/new/task/somewhere11").click()\n page.wait_for_timeout(3000)\n\n # Check if the div containing the text "Hmm... it's not here" is present\n locator = page.locator('div:has-text("Hmm... it\\'s not here")')\n\n # Assert that the div is present\n assert locator.count() > 0, "The div with the text 'Hmm... it's not here' is not found."\n\n print("The message 'Hmm... it's not here' is visible on page")\n\n page.wait_for_timeout(4000)\n\n except Exception as e:\n print("Test failed with exception:", e)\n raise e\n finally:\n if page and not page.is_closed():\n page.close()\n if browser:\n browser.close()\n if context:\n context.tracing.stop(path=trace_path)\n trace_cleaner(trace_path)\n \ No newline at end of file diff --git a/issues/274/user_tool.py b/issues/274/user_tool.py index d4cf63c0..5a1b8cc7 100644 --- a/issues/274/user_tool.py +++ b/issues/274/user_tool.py @@ -17,7 +17,7 @@ EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" EMAIL_USERNAME = "turingsampleopen@gmail.com" -EMAIL_PASSWORD = "dmyi iqgn znbg kqii" +EMAIL_PASSWORD = "" logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") LOGGER = logging.getLogger(__name__) diff --git a/issues/275/test.py b/issues/275/test.py index af640be6..76d8253c 100644 --- a/issues/275/test.py +++ b/issues/275/test.py @@ -22,7 +22,7 @@ BASE_EMAIL = "testerfreelancer555@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" ISSUE_NUMBER = "43094" SUFFIX_1 = f"{ISSUE_NUMBER}1" SUFFIX_2 = f"{ISSUE_NUMBER}2" diff --git a/issues/275/user_tool.py b/issues/275/user_tool.py index 4c0f3a24..62731815 100644 --- a/issues/275/user_tool.py +++ b/issues/275/user_tool.py @@ -24,7 +24,7 @@ BASE_EMAIL = "testerfreelancer555@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" ISSUE_NUMBER = "43094" SUFFIX_1 = f"{ISSUE_NUMBER}1" SUFFIX_2 = f"{ISSUE_NUMBER}2" diff --git a/issues/278/user_tool.py b/issues/278/user_tool.py index 0be136e4..3d222bcf 100644 --- a/issues/278/user_tool.py +++ b/issues/278/user_tool.py @@ -19,7 +19,7 @@ class TestSuite(unittest.TestCase): def setUp(cls): cls.username = 'testemail.ameen' # Email username email = cls.generate_random_email() - cls.password = "yjsp jfez uvmy gkgs" # App password + cls.password = "" # App password cls.url = 'https://dev.new.expensify.com:8082/' cls.playwright = sync_playwright().start() diff --git a/issues/279/test.py b/issues/279/test.py index bf735bcf..cebeed0f 100644 --- a/issues/279/test.py +++ b/issues/279/test.py @@ -20,7 +20,7 @@ EXPENSIFY_USERNAME = f"{EXPENSIFY_USERNAME_FIRSTNAME} {EXPENSIFY_USERNAME_LASTNAME}" EXPENSIFY_EMAIL_USERNAME = "osaidtest5" EXPENSIFY_EMAIL = f"osaidtest5+{STATIC_PREFIX}@gmail.com" -EXPENSIFY_PASSWORD = "ntvd acej mmaa qqmd" +EXPENSIFY_PASSWORD = "" DATA_DIR = "browser_context" WORKSPACE_NAME = "workspace_xero" SLOW_MO = 1000 diff --git a/issues/279/user_tool.py b/issues/279/user_tool.py index 5da66b01..bff20b13 100644 --- a/issues/279/user_tool.py +++ b/issues/279/user_tool.py @@ -21,7 +21,7 @@ EXPENSIFY_USERNAME = f"{EXPENSIFY_USERNAME_FIRSTNAME} {EXPENSIFY_USERNAME_LASTNAME}" EXPENSIFY_EMAIL_USERNAME = "osaidtest5" EXPENSIFY_EMAIL = f"osaidtest5+{STATIC_PREFIX}@gmail.com" -EXPENSIFY_PASSWORD = "ntvd acej mmaa qqmd" +EXPENSIFY_PASSWORD = "" DATA_DIR = "browser_context" WORKSPACE_NAME = "workspace_xero" SLOW_MO = 1000 diff --git a/issues/281/test.py b/issues/281/test.py index 2dfe6c6f..405219d5 100644 --- a/issues/281/test.py +++ b/issues/281/test.py @@ -33,7 +33,7 @@ USER_NAME = "expensify31" # TODO Change this to your Gmail username -USER_PASSWORD = "Pass@123456" # TODO Change this to your password +USER_PASSWORD = "" # TODO Change this to your password diff --git a/issues/281/user_tool.py b/issues/281/user_tool.py index 47ddea2e..1c615840 100644 --- a/issues/281/user_tool.py +++ b/issues/281/user_tool.py @@ -27,7 +27,7 @@ USER_NAME = "expensify31" # TODO Change this to your Gmail username -USER_PASSWORD = "Pass@123456" # TODO Change this to your password +USER_PASSWORD = "" # TODO Change this to your password class TodayOptions(Enum): diff --git a/issues/282/test.py b/issues/282/test.py index 55ab8cb1..1e2f0154 100644 --- a/issues/282/test.py +++ b/issues/282/test.py @@ -8,7 +8,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "randomturing@gmail.com" -PASSWORD = "ryfo zezf tmlq xybs" +PASSWORD = "" static_email = "randomturing+40121573@gmail.com" diff --git a/issues/282/user_tool.py b/issues/282/user_tool.py index c5eb0733..17064612 100644 --- a/issues/282/user_tool.py +++ b/issues/282/user_tool.py @@ -9,7 +9,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "randomturing@gmail.com" -PASSWORD = "ryfo zezf tmlq xybs" +PASSWORD = "" static_email = "randomturing+40121573@gmail.com" diff --git a/issues/283/test.py b/issues/283/test.py index 43e3ab1b..c70d83ba 100644 --- a/issues/283/test.py +++ b/issues/283/test.py @@ -16,7 +16,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "42525" diff --git a/issues/283/user_tool.py b/issues/283/user_tool.py index d8ed0e7c..716ecabe 100644 --- a/issues/283/user_tool.py +++ b/issues/283/user_tool.py @@ -18,7 +18,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "42525" diff --git a/issues/284/test.py b/issues/284/test.py index 9a3e9e0f..9caed371 100644 --- a/issues/284/test.py +++ b/issues/284/test.py @@ -25,7 +25,7 @@ BASE_EMAIL = "lucassandboxturing@gmail.com" -PASSWORD = "vvdc gwak mcee hkjj" +PASSWORD = "" PROXY_OTP = True # Set to True if you are replaying the recorded test flow WS_NAME = f"Lucassandboxturing+42284's" diff --git a/issues/284/user_tool.py b/issues/284/user_tool.py index a7a13c26..baf01987 100644 --- a/issues/284/user_tool.py +++ b/issues/284/user_tool.py @@ -1 +1 @@ -import sys, os\n\nbase_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))\nsys.path.insert(0, base_path)\n\n"""\nThis test script was written to test the issue #42284.\n\nPre-conditions:\n- Workspace is created.\n- Distance rate configuration is enabled.\n- Only default rate present.\n\nTest Steps:\n- Set a new distance rate.\n- Disable the default rate.\n- Submit a distance expense and check if the default rate is the new rate.\n"""\n\n# Library Imports\nimport pytest\nfrom playwright.async_api import async_playwright, Page\nfrom utils.email_handler import EmailHandler, get_specific_derived_email\nfrom utils.browser import close_browser, start_browser\nfrom utils.trace_cleaner import trace_cleaner\n\n# Constants\nBASE_EMAIL = "lucassandboxturing@gmail.com"\nPASSWORD = "vvdc gwak mcee hkjj"\nPROXY_OTP = True # Set to True if you are replaying the recorded test flow\nWS_NAME = f"Lucassandboxturing+42284's"\n\n# Set up browser\nasync def start_browser(headless=True, slow_mo=100, launch_args=None):\n """\n Start a browser instance with the given parameters.\n\n :param headless: Boolean to specify if the browser should run in headless mode.\n :param slow_mo: Slow down the browser operations by the specified amount of milliseconds.\n :param launch_args: List of arguments to pass to the browser instance.\n :return: A tuple of (context, page, playwright).\n """\n\n if launch_args is None:\n launch_args = ["--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"]\n\n # Initialize Playwright\n playwright = await async_playwright().start()\n context, page = None, None\n\n # Start browser\n browser = await playwright.chromium.launch(headless=headless, args=launch_args, slow_mo=slow_mo)\n context = await browser.new_context(ignore_https_errors=True)\n page = await context.new_page()\n\n return context, page, playwright\n\n# Sign In to Expensify\nasync def sign_in_new_dot(page: Page, email: str, password: str):\n """\n Sign in into the new Expensify dot.\n """\n\n # Go to the URL\n url = "https://dev.new.expensify.com:8082"\n await page.goto(url)\n\n # Sign In\n with EmailHandler(email, password) as email_handler:\n if not PROXY_OTP:\n email_handler.clean_inbox() # Clean inbox\n\n # Enter email\n await page.get_by_test_id("username").fill(email)\n await page.get_by_role("button", name="Continue").click()\n \n # Await OTP\n otp = "123456" if PROXY_OTP else email_handler.read_otp_code()\n await page.get_by_test_id("validateCode").fill(otp)\n\n # Wait sign in to complete\n await page.get_by_text("Please enter the magic code").wait_for(state="hidden")\n\n# Set distance rate\nasync def set_distance_rate(page: Page) -> None:\n\n # Go to workspace distance rate settings\n await page.get_by_label("My settings").click()\n await page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").get_by_text("Workspaces").click()\n await page.locator(f"text={WS_NAME} Workspace").last.click()\n await page.get_by_text("Distance rates").click()\n\n # Add a new distance rate\n await page.get_by_role("button", name="Add rate").click()\n await page.get_by_placeholder("0").fill("0.5")\n await page.get_by_role("button", name="Save").click()\n\n # Disable the default rate\n await page.locator("[id=\"\\32 17EA6359859B\"]").get_by_label("R$0.6700 / mile").click()\n await page.get_by_role("button", name="selected").click()\n await page.get_by_text("Disable rate").click()\n\n # Go back to the inbox\n await page.get_by_label("Back").click()\n await page.get_by_label("Inbox").click()\n await page.locator("text=Bob Bill (you)").click()\n\n# Set submit expense\nasync def set_submit_expense(page: Page) -> None:\n\n # Click on submit expense\n await page.get_by_label("Start chat (Floating action)").click()\n await page.get_by_text("Submit expense", exact=True).click()\n\n # Select distance\n await page.get_by_label("Distance").click()\n\n # Set start and end waypoints\n await page.get_by_test_id("IOURequestStartPage").get_by_role("button", name="Start").click()\n await page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("NYC")\n await page.get_by_text("NYC", exact=True).click()\n await page.get_by_role("button", name="Stop").click()\n await page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Liberty")\n await page.get_by_text("Liberty State Park").click()\n\n # Click next\n await page.locator("text=Next").last.click()\n\n # Select workspace\n await page.get_by_label(WS_NAME).click()\n\n# Reproduce scenario\nasync def reproduce_scenario(page: Page) -> None:\n\n # Step 1: Set distance rate\n await set_distance_rate(page)\n\n # Step 2: Set submit expense\n await set_submit_expense(page)\n\n # Assert that the default rate is the new rate\n assert await page.get_by_text("mi @ R$0.50 / mi").is_visible()\n\n@pytest.mark.asyncio\nasync def test_disabled_rate_test() -> None:\n trace_path = '/app/expensify/user_tool/output_browser1.zip'\n context, page, playwright = await start_browser(slow_mo=500)\n try:\n await context.tracing.start(screenshots=True, snapshots=True, sources=True)\n # Step 1: Login user\n user_email = get_specific_derived_email(BASE_EMAIL, 42284)\n await sign_in_new_dot(page, user_email, PASSWORD)\n\n # Step 3: Reproduce scenario\n await page.wait_for_timeout(2000)\n await reproduce_scenario(page)\n except Exception as e:\n raise e\n finally:\n await context.tracing.stop(path=trace_path)\n trace_cleaner(trace_path)\n await close_browser(context, page, playwright)\n \ No newline at end of file +import sys, os\n\nbase_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))\nsys.path.insert(0, base_path)\n\n"""\nThis test script was written to test the issue #42284.\n\nPre-conditions:\n- Workspace is created.\n- Distance rate configuration is enabled.\n- Only default rate present.\n\nTest Steps:\n- Set a new distance rate.\n- Disable the default rate.\n- Submit a distance expense and check if the default rate is the new rate.\n"""\n\n# Library Imports\nimport pytest\nfrom playwright.async_api import async_playwright, Page\nfrom utils.email_handler import EmailHandler, get_specific_derived_email\nfrom utils.browser import close_browser, start_browser\nfrom utils.trace_cleaner import trace_cleaner\n\n# Constants\nBASE_EMAIL = "lucassandboxturing@gmail.com"\nPASSWORD = ""\nPROXY_OTP = True # Set to True if you are replaying the recorded test flow\nWS_NAME = f"Lucassandboxturing+42284's"\n\n# Set up browser\nasync def start_browser(headless=True, slow_mo=100, launch_args=None):\n """\n Start a browser instance with the given parameters.\n\n :param headless: Boolean to specify if the browser should run in headless mode.\n :param slow_mo: Slow down the browser operations by the specified amount of milliseconds.\n :param launch_args: List of arguments to pass to the browser instance.\n :return: A tuple of (context, page, playwright).\n """\n\n if launch_args is None:\n launch_args = ["--ignore-certificate-errors", "--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"]\n\n # Initialize Playwright\n playwright = await async_playwright().start()\n context, page = None, None\n\n # Start browser\n browser = await playwright.chromium.launch(headless=headless, args=launch_args, slow_mo=slow_mo)\n context = await browser.new_context(ignore_https_errors=True)\n page = await context.new_page()\n\n return context, page, playwright\n\n# Sign In to Expensify\nasync def sign_in_new_dot(page: Page, email: str, password: str):\n """\n Sign in into the new Expensify dot.\n """\n\n # Go to the URL\n url = "https://dev.new.expensify.com:8082"\n await page.goto(url)\n\n # Sign In\n with EmailHandler(email, password) as email_handler:\n if not PROXY_OTP:\n email_handler.clean_inbox() # Clean inbox\n\n # Enter email\n await page.get_by_test_id("username").fill(email)\n await page.get_by_role("button", name="Continue").click()\n \n # Await OTP\n otp = "123456" if PROXY_OTP else email_handler.read_otp_code()\n await page.get_by_test_id("validateCode").fill(otp)\n\n # Wait sign in to complete\n await page.get_by_text("Please enter the magic code").wait_for(state="hidden")\n\n# Set distance rate\nasync def set_distance_rate(page: Page) -> None:\n\n # Go to workspace distance rate settings\n await page.get_by_label("My settings").click()\n await page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").get_by_text("Workspaces").click()\n await page.locator(f"text={WS_NAME} Workspace").last.click()\n await page.get_by_text("Distance rates").click()\n\n # Add a new distance rate\n await page.get_by_role("button", name="Add rate").click()\n await page.get_by_placeholder("0").fill("0.5")\n await page.get_by_role("button", name="Save").click()\n\n # Disable the default rate\n await page.locator("[id=\"\\32 17EA6359859B\"]").get_by_label("R$0.6700 / mile").click()\n await page.get_by_role("button", name="selected").click()\n await page.get_by_text("Disable rate").click()\n\n # Go back to the inbox\n await page.get_by_label("Back").click()\n await page.get_by_label("Inbox").click()\n await page.locator("text=Bob Bill (you)").click()\n\n# Set submit expense\nasync def set_submit_expense(page: Page) -> None:\n\n # Click on submit expense\n await page.get_by_label("Start chat (Floating action)").click()\n await page.get_by_text("Submit expense", exact=True).click()\n\n # Select distance\n await page.get_by_label("Distance").click()\n\n # Set start and end waypoints\n await page.get_by_test_id("IOURequestStartPage").get_by_role("button", name="Start").click()\n await page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("NYC")\n await page.get_by_text("NYC", exact=True).click()\n await page.get_by_role("button", name="Stop").click()\n await page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Liberty")\n await page.get_by_text("Liberty State Park").click()\n\n # Click next\n await page.locator("text=Next").last.click()\n\n # Select workspace\n await page.get_by_label(WS_NAME).click()\n\n# Reproduce scenario\nasync def reproduce_scenario(page: Page) -> None:\n\n # Step 1: Set distance rate\n await set_distance_rate(page)\n\n # Step 2: Set submit expense\n await set_submit_expense(page)\n\n # Assert that the default rate is the new rate\n assert await page.get_by_text("mi @ R$0.50 / mi").is_visible()\n\n@pytest.mark.asyncio\nasync def test_disabled_rate_test() -> None:\n trace_path = '/app/expensify/user_tool/output_browser1.zip'\n context, page, playwright = await start_browser(slow_mo=500)\n try:\n await context.tracing.start(screenshots=True, snapshots=True, sources=True)\n # Step 1: Login user\n user_email = get_specific_derived_email(BASE_EMAIL, 42284)\n await sign_in_new_dot(page, user_email, PASSWORD)\n\n # Step 3: Reproduce scenario\n await page.wait_for_timeout(2000)\n await reproduce_scenario(page)\n except Exception as e:\n raise e\n finally:\n await context.tracing.stop(path=trace_path)\n trace_cleaner(trace_path)\n await close_browser(context, page, playwright)\n \ No newline at end of file diff --git a/issues/285/test.py b/issues/285/test.py index 39a82de7..c598d2a4 100644 --- a/issues/285/test.py +++ b/issues/285/test.py @@ -13,7 +13,7 @@ email_address = "t56826807+10@gmail.com" -password = "wxck tsaw ocna tkfd" +password = "" class EmailHandler: diff --git a/issues/285/user_tool.py b/issues/285/user_tool.py index a101a2ab..4c002c28 100644 --- a/issues/285/user_tool.py +++ b/issues/285/user_tool.py @@ -13,7 +13,7 @@ from utils.trace_cleaner import trace_cleaner email_address = "t56826807+10@gmail.com" -password = "wxck tsaw ocna tkfd" +password = "" class EmailHandler: diff --git a/issues/286/test.py b/issues/286/test.py index 8918aac8..455817fd 100644 --- a/issues/286/test.py +++ b/issues/286/test.py @@ -8,7 +8,7 @@ USER_NAME = "xecuycismfsga+42204" USER_EMAIL = f"{USER_NAME}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" def get_magic_code( diff --git a/issues/286/user_tool.py b/issues/286/user_tool.py index 9806e495..3589629f 100644 --- a/issues/286/user_tool.py +++ b/issues/286/user_tool.py @@ -9,7 +9,7 @@ USER_NAME = "xecuycismfsga+42204" USER_EMAIL = f"{USER_NAME}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" def get_magic_code( diff --git a/issues/287/test.py b/issues/287/test.py index 1c13b4e8..4775a137 100644 --- a/issues/287/test.py +++ b/issues/287/test.py @@ -14,7 +14,7 @@ TEST_URL = "https://dev.new.expensify.com:8082/" USER_NAME = "expensify31" -USER_PASSWORD = "Pass@123456" +USER_PASSWORD = "" diff --git a/issues/287/user_tool.py b/issues/287/user_tool.py index bfcef0fe..8689f1f0 100644 --- a/issues/287/user_tool.py +++ b/issues/287/user_tool.py @@ -15,7 +15,7 @@ TEST_URL = "https://dev.new.expensify.com:8082/" USER_NAME = "expensify31" -USER_PASSWORD = "Pass@123456" +USER_PASSWORD = "" diff --git a/issues/289/test.py b/issues/289/test.py index 21010091..11d3eb7b 100644 --- a/issues/289/test.py +++ b/issues/289/test.py @@ -21,7 +21,7 @@ MAX_TRIES = 2 USERNAME = "doorsqueaky@gmail.com" -PASSWORD = "eabcahqraatorpvt" +PASSWORD = "" def login_to_email(email: str=USERNAME, password: str=PASSWORD): diff --git a/issues/289/user_tool.py b/issues/289/user_tool.py index bad86144..00d6e415 100644 --- a/issues/289/user_tool.py +++ b/issues/289/user_tool.py @@ -21,7 +21,7 @@ MAX_TRIES = 2 USERNAME = "doorsqueaky@gmail.com" -PASSWORD = "eabcahqraatorpvt" +PASSWORD = "" def login_to_email(email: str=USERNAME, password: str=PASSWORD): diff --git a/issues/292/test.py b/issues/292/test.py index bbd4a2a3..68fc4e5c 100644 --- a/issues/292/test.py +++ b/issues/292/test.py @@ -18,7 +18,7 @@ NEW_DOT_URL = "https://dev.new.expensify.com:8082" EXPENSIFY_EMAIL = os.getenv("USER_EMAIL", "testingq186+41783@gmail.com") -EXPENSIFY_PASSWORD = os.getenv("PASSWORD", "kkfr hqiv yuxq rbso") +EXPENSIFY_PASSWORD = os.getenv("PASSWORD", "") FIRST_NAME = "Testing" LAST_NAME = "41783" diff --git a/issues/292/user_tool.py b/issues/292/user_tool.py index 1ae68151..031bff74 100644 --- a/issues/292/user_tool.py +++ b/issues/292/user_tool.py @@ -20,7 +20,7 @@ NEW_DOT_URL = "https://dev.new.expensify.com:8082" EXPENSIFY_EMAIL = os.getenv("USER_EMAIL", "testingq186+41783@gmail.com") -EXPENSIFY_PASSWORD = os.getenv("PASSWORD", "kkfr hqiv yuxq rbso") +EXPENSIFY_PASSWORD = os.getenv("PASSWORD", "") FIRST_NAME = "Testing" LAST_NAME = "41783" diff --git a/issues/296/test.py b/issues/296/test.py index a8349475..8562b63c 100644 --- a/issues/296/test.py +++ b/issues/296/test.py @@ -19,7 +19,7 @@ BASE_EMAIL = "testerfreelancer555@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" ISSUE_NUMBER = "41529" async def sign_in_new_dot(page: Page, email: str, password: str): diff --git a/issues/296/user_tool.py b/issues/296/user_tool.py index 453c3428..423e1ddf 100644 --- a/issues/296/user_tool.py +++ b/issues/296/user_tool.py @@ -21,7 +21,7 @@ BASE_EMAIL = "testerfreelancer555@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" ISSUE_NUMBER = "41529" async def sign_in_new_dot(page: Page, email: str, password: str): diff --git a/issues/299/test.py b/issues/299/test.py index caba5892..fed0a6ec 100644 --- a/issues/299/test.py +++ b/issues/299/test.py @@ -9,7 +9,7 @@ GMAIL_NAME = "nomandevtur+41183" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/299/user_tool.py b/issues/299/user_tool.py index 71fa03c5..5a68ab9a 100644 --- a/issues/299/user_tool.py +++ b/issues/299/user_tool.py @@ -10,7 +10,7 @@ GMAIL_NAME = "nomandevtur+41183" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/300/test.py b/issues/300/test.py index 91d3a0d8..34591257 100644 --- a/issues/300/test.py +++ b/issues/300/test.py @@ -12,7 +12,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "40464.7" diff --git a/issues/300/user_tool.py b/issues/300/user_tool.py index 51b8791a..a0f139f3 100644 --- a/issues/300/user_tool.py +++ b/issues/300/user_tool.py @@ -13,8 +13,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" - +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "40464.7" diff --git a/issues/30045_642/test.py b/issues/30045_642/test.py new file mode 100644 index 00000000..0c9fda48 --- /dev/null +++ b/issues/30045_642/test.py @@ -0,0 +1,122 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +from playwright.sync_api import sync_playwright, expect +from playwright._impl._page import Page + + +NEWDOT_URL = "https://127.0.0.1:8082/" +OLDDOT_URL = "http://localhost:9000/" +EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" + +def verify_delete_confirmation_modal_back_out(page: Page): + + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Track expense").click() + try: + + page.get_by_label("Don't show me this again").click() + page.get_by_role("button", name="Got it").click() + except: + pass + page.get_by_label("Distance").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStartPage").get_by_role("button", name="Start").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Golden Gate Bridge Vista Point") + page.wait_for_timeout(2000) + page.get_by_text("Golden Gate Bridge Vista Point", exact=True).first.click() + page.wait_for_timeout(2000) + page.get_by_role("button", name="Stop").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Telegraph Hill") + page.wait_for_timeout(2000) + page.get_by_text("Telegraph Hill", exact=True).first.click() + page.wait_for_timeout(2000) + + page.locator('button[style="cursor: pointer;"]').wait_for() + page.wait_for_timeout(2000) + for _ in range(3): + try: + + page.get_by_role("button", name="Next").nth(1).click() + page.wait_for_timeout(2000) + page.get_by_role("button", name="Track expense").wait_for(timeout=1000) + page.wait_for_timeout(2000) + break + except: + pass + page.get_by_role("button", name="Track expense").click() + page.wait_for_timeout(2000) + + try: + + page.get_by_label("Cash").locator("img").wait_for(timeout=120000) + except: + assert False, "Receipt was not able to load due to network issues" + + + page.get_by_label("Cash").locator("img").click() + page.get_by_label("View attachment").click() + page.get_by_label("More").click() + + + page.get_by_label("Download").wait_for() + + + + if page.get_by_label("Delete receipt").is_visible(): + page.get_by_label("Delete receipt").click() + + page.get_by_role("button", name="Delete").wait_for() + + + page.locator("body").press("Escape") + + + expect(page.get_by_role("dialog").get_by_text("Receipt", exact=True)).to_have_count(1) + expect(page.get_by_role("button", name="Delete")).to_have_count(0) + + +def test_delete_confirmation_modal_back_out_in_receipt_page(): + """ + Test to verify that the Delete confirmation modal in Receipt page backs out correctly + """ + with sync_playwright() as p: + + browser = p.chromium.launch(channel='chrome', headless=True, slow_mo=500, + proxy = {"server": "http://127.0.0.1:8080/"}, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + context_args = {} + context_args["geolocation"] = {"latitude": 37.7749, "longitude": 122.4194} + context_args["permissions"] = ["geolocation"] + context_args["ignore_https_errors"] = True + context = browser.new_context(**context_args) + + page = context.new_page() + page.wait_for_timeout(1000) + + + page.goto('https://127.0.0.1:8082/') + + page.locator('input[type="email"]').fill(EMAIL) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(5000) + otp = '123456' + page.get_by_test_id("validateCode").fill(otp) + + + verify_delete_confirmation_modal_back_out(page) + + + context.close() + browser.close() \ No newline at end of file diff --git a/issues/30045_642/user_tool.py b/issues/30045_642/user_tool.py new file mode 100644 index 00000000..0aca957e --- /dev/null +++ b/issues/30045_642/user_tool.py @@ -0,0 +1,143 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +from playwright.sync_api import sync_playwright, expect +from playwright._impl._page import Page + +from utils.trace_cleaner import trace_cleaner + + +NEWDOT_URL = "https://127.0.0.1:8082/" +OLDDOT_URL = "http://localhost:9000/" +EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" + +def verify_delete_confirmation_modal_back_out(page: Page): + + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Track expense").click() + try: + + page.get_by_label("Don't show me this again").click() + page.get_by_role("button", name="Got it").click() + except: + pass + page.get_by_label("Distance").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStartPage").get_by_role("button", name="Start").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Golden Gate Bridge Vista Point") + page.wait_for_timeout(2000) + page.get_by_text("Golden Gate Bridge Vista Point", exact=True).first.click() + page.wait_for_timeout(2000) + page.get_by_role("button", name="Stop").click() + page.wait_for_timeout(2000) + page.get_by_test_id("IOURequestStepWaypoint").get_by_role("textbox").fill("Telegraph Hill") + page.wait_for_timeout(2000) + page.get_by_text("Telegraph Hill", exact=True).first.click() + page.wait_for_timeout(2000) + + page.locator('button[style="cursor: pointer;"]').wait_for() + page.wait_for_timeout(2000) + for _ in range(3): + try: + + page.get_by_role("button", name="Next").nth(1).click() + page.wait_for_timeout(2000) + page.get_by_role("button", name="Track expense").wait_for(timeout=1000) + page.wait_for_timeout(2000) + break + except: + pass + page.get_by_role("button", name="Track expense").click() + page.wait_for_timeout(2000) + + try: + + page.get_by_label("Cash").locator("img").wait_for(timeout=120000) + except: + assert False, "Receipt was not able to load due to network issues" + + + page.get_by_label("Cash").locator("img").click() + page.get_by_label("View attachment").click() + page.get_by_label("More").click() + + + page.get_by_label("Download").wait_for() + + + + if page.get_by_label("Delete receipt").is_visible(): + page.get_by_label("Delete receipt").click() + + page.get_by_role("button", name="Delete").wait_for() + + + page.locator("body").press("Escape") + + + expect(page.get_by_role("dialog").get_by_text("Receipt", exact=True)).to_have_count(1) + expect(page.get_by_role("button", name="Delete")).to_have_count(0) + + +def test_delete_confirmation_modal_back_out_in_receipt_page(): + """ + Test to verify that the Delete confirmation modal in Receipt page backs out correctly + """ + with sync_playwright() as p: + browser = p.chromium.launch( + channel='chrome', + headless=True, + slow_mo=500, + proxy={"server": "http://127.0.0.1:8080/"}, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ] + ) + context_args = {} + context_args["geolocation"] = {"latitude": 37.7749, "longitude": 122.4194} + context_args["permissions"] = ["geolocation"] + context_args["ignore_https_errors"] = True + context = browser.new_context(**context_args) + + + context.tracing.start( + title="test_delete_confirmation_modal_back_out_in_receipt_page", + screenshots=True, + snapshots=True, + sources=True + ) + page = context.new_page() + page.wait_for_timeout(1000) + + try: + + page.goto('https://127.0.0.1:8082/') + + page.locator('input[type="email"]').fill(EMAIL) + page.locator('button[tabindex="0"]').click() + + page.wait_for_timeout(5000) + otp = '123456' + page.get_by_test_id("validateCode").fill(otp) + + + verify_delete_confirmation_modal_back_out(page) + + except Exception as e: + + raise e + finally: + + context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + + context.close() + browser.close() diff --git a/issues/303/test.py b/issues/303/test.py index bc2d80cd..cb0b2cf5 100644 --- a/issues/303/test.py +++ b/issues/303/test.py @@ -8,7 +8,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "randomturing@gmail.com" -PASSWORD = "ryfo zezf tmlq xybs" +PASSWORD = "" static_email = "randomturing+40121571@gmail.com" diff --git a/issues/303/user_tool.py b/issues/303/user_tool.py index 320576e2..c289661a 100644 --- a/issues/303/user_tool.py +++ b/issues/303/user_tool.py @@ -9,7 +9,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "randomturing@gmail.com" -PASSWORD = "ryfo zezf tmlq xybs" +PASSWORD = "" static_email = "randomturing+40121571@gmail.com" diff --git a/issues/304/test.py b/issues/304/test.py index 0bc5408a..02b65184 100644 --- a/issues/304/test.py +++ b/issues/304/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/304/user_tool.py b/issues/304/user_tool.py index 797d09f8..939a974e 100644 --- a/issues/304/user_tool.py +++ b/issues/304/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/306/test.py b/issues/306/test.py index 71c281c7..6dc33e13 100644 --- a/issues/306/test.py +++ b/issues/306/test.py @@ -13,7 +13,7 @@ from playwright.sync_api import TimeoutError, Playwright, Browser, Page, sync_playwright, expect EMAIL_USERNAME = "ibukunsamuel999" -EMAIL_PASSWORD = "jkgz unyn rnwl slrp" +EMAIL_PASSWORD = "" EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/306/user_tool.py b/issues/306/user_tool.py index 37dec9db..9270350a 100644 --- a/issues/306/user_tool.py +++ b/issues/306/user_tool.py @@ -14,7 +14,7 @@ from utils.trace_cleaner import trace_cleaner # Added import for trace cleaning EMAIL_USERNAME = "ibukunsamuel999" -EMAIL_PASSWORD = "jkgz unyn rnwl slrp" +EMAIL_PASSWORD = "" EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/308/test.py b/issues/308/test.py index a55c594c..70b3a3cc 100644 --- a/issues/308/test.py +++ b/issues/308/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/308/user_tool.py b/issues/308/user_tool.py index a792c633..c08a37c4 100644 --- a/issues/308/user_tool.py +++ b/issues/308/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/309/test.py b/issues/309/test.py index 4e06883e..5dfbb2f2 100644 --- a/issues/309/test.py +++ b/issues/309/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/309/user_tool.py b/issues/309/user_tool.py index dd3ab727..aed87c3f 100644 --- a/issues/309/user_tool.py +++ b/issues/309/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/31/user_tool.py b/issues/31/user_tool.py new file mode 100644 index 00000000..ecc2025a --- /dev/null +++ b/issues/31/user_tool.py @@ -0,0 +1,158 @@ +import os +import pytest +from playwright.async_api import Browser, Page, TimeoutError, async_playwright +from utils.trace_cleaner import trace_cleaner + +EMAIL_USERNAME = "xecuycismfsga" +EMAIL_ALIAS = "r5p4hfur" +USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" +PASSWORD = "" +SLOW_MO: int | None = 500 +PROXY_URL = os.getenv("PROXY_URL") + +LONG_FIRSTNAME = "XzH9tXRklkFrTjMU" +LONG_LASTNAME = "MwuCGEtROJc5CZz9" +PARTICIPANT_ALIAS = "wzec6tou" +PARTICIPANT_EMAIL = f"{EMAIL_USERNAME}+{PARTICIPANT_ALIAS}@gmail.com" + + +async def get_magic_code( + _page: Page, _user_email: str = USER_EMAIL, _password: str = PASSWORD +): + return "123456" + + +async def create_user(page: Page, firstname: str = "User", lastname: str = EMAIL_ALIAS): + await page.get_by_role("button", name="Join").click() + + # Update profile + await page.get_by_text("Track and budget expenses").click() + await page.get_by_role("textbox", name="First name").fill(firstname) + await page.get_by_role("textbox", name="Last name").fill(lastname) + await page.get_by_role("button", name="Continue").click() + + +async def login(page: Page): + # get current timestamp + magic_code = await get_magic_code(page) + + if magic_code is None: + raise ValueError("Failed to retrieve magic code") + + await page.get_by_role("textbox").fill(magic_code) + + +async def login_or_create_user( + page: Page, + firstname: str = "User", + lastname: str = EMAIL_ALIAS, + user_email: str = USER_EMAIL, +): + await page.goto("https://dev.new.expensify.com:8082/") + await page.get_by_test_id("username").fill(user_email) + await page.get_by_role("button", name="Continue").click() + + try: + await page.get_by_role("button", name="Join").wait_for( + state="visible", timeout=2000 + ) + await create_user(page, firstname=firstname, lastname=lastname) + except TimeoutError: + await login(page) + + await page.get_by_label("Inbox").wait_for(state="visible", timeout=10000) + + +async def create_participant_account(browser: Browser): + context_1 = await browser.new_context() + await context_1.tracing.start(screenshots=True, snapshots=True, sources=True) + page_1 = await context_1.new_page() + try: + await login_or_create_user( + page_1, + user_email=PARTICIPANT_EMAIL, + firstname=LONG_FIRSTNAME, + lastname=LONG_LASTNAME, + ) + finally: + await context_1.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + await page_1.close() + await context_1.close() + + +async def submit_expense(page: Page): + await page.get_by_label("Create").last.click() + await page.get_by_label("Submit expense").click() + await page.get_by_label("Manual").click() + await page.get_by_placeholder("0").fill("1000000") + await ( + page.locator("#numPadContainerView").get_by_role("button", name="Next").click() + ) + await page.get_by_role("button", name="Submit").click() + + +@pytest.mark.asyncio +async def test_search_bar_spacing(): + async with async_playwright() as p: + browser = await p.chromium.launch( + proxy={"server": PROXY_URL} if PROXY_URL else None, + headless=False, + args=[ + "--no-sandbox", + "--disable-dev-shm-usage", + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process", + ], + slow_mo=SLOW_MO, + ) + try: + await create_participant_account(browser) + + iphone = p.devices["iPhone SE"] + context = await browser.new_context(**iphone) + await context.tracing.start(screenshots=True, snapshots=True, sources=True) + page = await context.new_page() + + try: + await login_or_create_user(page) + + participant_chat = page.locator( + 'button[aria-label="Navigates to a chat"]', + has_text=f"{LONG_FIRSTNAME} {LONG_LASTNAME}", + ).first + + try: + await participant_chat.click(timeout=3000) + except TimeoutError: + await page.get_by_label("Start chat (Floating action)").click() + await page.get_by_label("Start chat", exact=True).click() + await page.get_by_test_id("selection-list-text-input").fill( + PARTICIPANT_EMAIL + ) + await page.get_by_label(PARTICIPANT_EMAIL).click() + + expense_preview = ( + page.get_by_role("button", name="View details") + .filter(has_text=f"{LONG_FIRSTNAME} owes:") + .last + ) + + try: + await expense_preview.click(timeout=3000) + except TimeoutError: + await submit_expense(page) + + right_margin = await page.locator( + "div[id='searchButton'][aria-label='Search']" + ).last.evaluate("el => getComputedStyle(el).marginRight") + + assert right_margin != "0px", "Right margin should not be zero pixels" + finally: + await context.tracing.stop(path="/app/expensify/user_tool/output_browser2.zip") + trace_cleaner("/app/expensify/user_tool/output_browser2.zip") + await page.close() + await context.close() + finally: + await browser.close() \ No newline at end of file diff --git a/issues/311/test.py b/issues/311/test.py index 84de0c4d..91d093a4 100644 --- a/issues/311/test.py +++ b/issues/311/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+111@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/311/user_tool.py b/issues/311/user_tool.py index 4ecc7a56..54b04561 100644 --- a/issues/311/user_tool.py +++ b/issues/311/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+111@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/312/test.py b/issues/312/test.py index 391b0e9e..e5670189 100644 --- a/issues/312/test.py +++ b/issues/312/test.py @@ -12,7 +12,7 @@ PROXY_URL = os.getenv("PROXY_URL") LOGIN_EMAIL = "testerfreelancer555+38130_rcrd@gmail.com" -EMAIL_PASSWORD = "snct ajbr yadx kwlq" +EMAIL_PASSWORD = "" IMAGE_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAABLUlEQVR4nO3RQREAIAzAsIF/z0NGHjQKetczO4GuDvhdA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA9gDO4gH/iDJCTQAAAABJRU5ErkJggg==" diff --git a/issues/312/user_tool.py b/issues/312/user_tool.py index fa402ce8..776f9341 100644 --- a/issues/312/user_tool.py +++ b/issues/312/user_tool.py @@ -13,7 +13,7 @@ PROXY_URL = os.getenv("PROXY_URL") LOGIN_EMAIL = "testerfreelancer555+38130_rcrd@gmail.com" -EMAIL_PASSWORD = "snct ajbr yadx kwlq" +EMAIL_PASSWORD = "" IMAGE_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAABLUlEQVR4nO3RQREAIAzAsIF/z0NGHjQKetczO4GuDvhdA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA1gCsAVgDsAZgDcAagDUAawDWAKwBWAOwBmANwBqANQBrANYArAFYA7AGYA3AGoA1AGsA9gDO4gH/iDJCTQAAAABJRU5ErkJggg==" diff --git a/issues/313/test.py b/issues/313/test.py index 143d28e9..34307b6d 100644 --- a/issues/313/test.py +++ b/issues/313/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/313/user_tool.py b/issues/313/user_tool.py index 0b165fe4..155a485f 100644 --- a/issues/313/user_tool.py +++ b/issues/313/user_tool.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/314/test.py b/issues/314/test.py index 1cc637d8..6b0338d8 100644 --- a/issues/314/test.py +++ b/issues/314/test.py @@ -16,7 +16,7 @@ EMAIL_USERNAME = "ibukunsamuel999" -EMAIL_PASSWORD = "jkgz unyn rnwl slrp" +EMAIL_PASSWORD = "" EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/314/user_tool.py b/issues/314/user_tool.py index 4d932175..182df972 100644 --- a/issues/314/user_tool.py +++ b/issues/314/user_tool.py @@ -17,7 +17,7 @@ from utils.trace_cleaner import trace_cleaner EMAIL_USERNAME = "ibukunsamuel999" -EMAIL_PASSWORD = "jkgz unyn rnwl slrp" +EMAIL_PASSWORD = "" EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" diff --git a/issues/315/test.py b/issues/315/test.py index a3ba0191..2aa7545e 100644 --- a/issues/315/test.py +++ b/issues/315/test.py @@ -16,7 +16,7 @@ BASE_EMAIL = "turingtemp+37299578@gmail.com" -PASSWORD = "rxyc esdd vdad pamq" +PASSWORD = "" class EmailHandler: def __init__(self, email_address, password): diff --git a/issues/315/user_tool.py b/issues/315/user_tool.py index 0e7fa63b..db2b6664 100644 --- a/issues/315/user_tool.py +++ b/issues/315/user_tool.py @@ -16,7 +16,7 @@ BASE_EMAIL = "turingtemp+37299578@gmail.com" -PASSWORD = "rxyc esdd vdad pamq" +PASSWORD = "" class EmailHandler: def __init__(self, email_address, password): diff --git a/issues/32/user_tool.py b/issues/32/user_tool.py new file mode 100644 index 00000000..e24682a1 --- /dev/null +++ b/issues/32/user_tool.py @@ -0,0 +1,87 @@ +from playwright._impl._page import Page +from playwright.sync_api import sync_playwright +from utils.trace_cleaner import trace_cleaner + +NEW_DOT_URL = "https://dev.new.expensify.com:8082" +ONE_SECOND = 1000 +TWO_SECONDS = 2000 +THREE_SECONDS = 3000 +FIVE_SECONDS = 5000 +email_address = "adebayovicktor0+test43726@gmail.com" +password = "" + +# Sign In to Expensify + +def sign_in_new_dot(page: Page, email: str, url: str=None): + """ + Sign in into the new Expensify dot. + """ + # Go to URL + url = url if url else NEW_DOT_URL + page.goto(url) + # Sign In + page.get_by_test_id("username").fill(email) + page.wait_for_timeout(TWO_SECONDS) + page.get_by_role("button", name="Continue").click() + page.wait_for_timeout(FIVE_SECONDS) + # OTP is hardcoded for replay + otp = '123456' + page.get_by_test_id("validateCode").fill(otp) + page.wait_for_timeout(TWO_SECONDS) + + # Wait sign in to complete + page.get_by_text("Please enter the magic code").wait_for(state="hidden") + page.wait_for_timeout(THREE_SECONDS) + + +def generate_email(): + return f"adebayovicktor0+test51336@gmail.com" + + +def test_emoji_is_deletable(): + """ + Test to verify that the send button is focused when the modal is opened + """ + with sync_playwright() as p: + browser = p.chromium.launch(headless=False, + proxy={"server": "http://127.0.0.1:8080/"}, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + slow_mo=1000 + ) + user_email = generate_email() + context = browser.new_context() + # Start tracing + context.tracing.start(screenshots=True, snapshots=True, sources=True) + page = context.new_page() + try: + sign_in_new_dot(page, user_email) + page.wait_for_timeout(2000) + page.get_by_label("Emoji").first.click() + page.get_by_role("textbox", name="Search").fill("black") + page.get_by_label("⬛", exact=True).click() + page.get_by_label("Emoji").first.click() + page.wait_for_timeout(2000) + page.get_by_role("textbox", name="Search").fill("wale") + page.get_by_label("🏴", exact=True).click() + page.wait_for_timeout(2000) + page.keyboard.press('Backspace') + page.keyboard.press('Backspace') + page.wait_for_timeout(2000) + page.keyboard.press('Backspace') + page.keyboard.press('Backspace') + inner_text = page.locator("#composer").inner_text() + assert inner_text == '', "The flag 🏴 and ⬛ is not deleted" + finally: + # Stop tracing and export the trace file + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_path) + trace_cleaner(trace_path) + browser.close() + + +if __name__ == "__main__": + test_emoji_is_deletable() \ No newline at end of file diff --git a/issues/320/test.py b/issues/320/test.py index 0f69e4a9..b6934780 100644 --- a/issues/320/test.py +++ b/issues/320/test.py @@ -11,7 +11,7 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') EMAIL = "Adebayovicktor0+test42262@gmail.com" -PASSWORD = "bruzwjfovckiesys" +PASSWORD = "" NEW_DOT_URL = "https://dev.new.expensify.com:8082" OLD_DOT_URL = "http://localhost:9000/" ONE_SECOND = 1000 diff --git a/issues/320/user_tool.py b/issues/320/user_tool.py index bc27db18..3af78403 100644 --- a/issues/320/user_tool.py +++ b/issues/320/user_tool.py @@ -11,7 +11,7 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') EMAIL = "Adebayovicktor0+test42262@gmail.com" -PASSWORD = "bruzwjfovckiesys" +PASSWORD = "" NEW_DOT_URL = "https://dev.new.expensify.com:8082" OLD_DOT_URL = "http://localhost:9000/" ONE_SECOND = 1000 diff --git a/issues/321/test.py b/issues/321/test.py index b7b6f443..34ed9ee3 100644 --- a/issues/321/test.py +++ b/issues/321/test.py @@ -11,7 +11,7 @@ import re user_email = "totherandomuser@gmail.com" -password = "umei djwi bfmp jntm" +password = "" def get_magic_code(user_email, password, retries=5, delay=10): diff --git a/issues/321/user_tool.py b/issues/321/user_tool.py index f300ebdf..c24c098d 100644 --- a/issues/321/user_tool.py +++ b/issues/321/user_tool.py @@ -13,7 +13,7 @@ from utils.trace_cleaner import trace_cleaner user_email = "totherandomuser@gmail.com" -password = "umei djwi bfmp jntm" +password = "" def get_magic_code(user_email, password, retries=5, delay=10): diff --git a/issues/32236_652/test.py b/issues/32236_652/test.py new file mode 100644 index 00000000..34ed9ee3 --- /dev/null +++ b/issues/32236_652/test.py @@ -0,0 +1,152 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +from playwright.sync_api import sync_playwright, expect +import imaplib +import email +from email.header import decode_header +import re + +user_email = "totherandomuser@gmail.com" +password = "" + + +def get_magic_code(user_email, password, retries=5, delay=10): + + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for attempt in range(retries): + + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + + time.sleep(delay) + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def login(p, if_phone=False, first_name="John", last_name="Cena"): + + permissions = ['clipboard-read', 'clipboard-write'] + browser = p.chromium.launch(headless=True, args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process' + ]) + + if if_phone: + phone = p.devices['iPhone 12 Pro'] + context = browser.new_context(**phone, permissions=permissions, reduced_motion='no-preference') + else: + context = browser.new_context() + + page = context.new_page() + + page.goto('https://dev.new.expensify.com:8082/') + + phone_or_email_input = page.locator('input[type="email"]') + expect(phone_or_email_input).to_be_visible() + phone_or_email_input.fill(user_email) + + continue_button = page.locator('button[tabindex="0"]') + expect(continue_button).to_be_visible() + continue_button.click() + + page.wait_for_timeout(1000) + + + magic_code = "123456" + validate_code_input = page.locator('input[name="validateCode"]') + expect(validate_code_input).to_be_visible() + validate_code_input.fill(magic_code) + + page.wait_for_timeout(1000) + + return browser, page + + +def test(): + with sync_playwright() as p: + + browser, page = login(p, False) + + page.wait_for_timeout(5000) + + + group_chat = page.get_by_text(f"Totherandomuser's Workspace 2").first + expect(group_chat).to_be_visible() + group_chat.click() + + page.wait_for_timeout(1000) + + page.get_by_role("textbox").fill("My Message") + page.get_by_role("textbox").press("Enter") + page.wait_for_timeout(1000) + + page.get_by_label("My settings").click() + page.get_by_label("Preferences").click() + page.get_by_label("Force offline").click() + page.locator("#overLayBottomButton").click() + page.wait_for_timeout(1000) + + message = page.locator('span', has_text="My Message").last + expect(message).to_be_visible() + message.click(button="right") + page.wait_for_timeout(1000) + + + delete_button = page.locator('[aria-label="Delete comment"]').first + delete_button.click() + page.get_by_role("button", name="Delete").click() + + page.wait_for_timeout(1000) + message = page.locator('span', has_text="My Message").last + expect(message).to_be_visible() + message.click(button="right") + page.wait_for_timeout(1000) + + is_unsubscribed = False + + + + + + unsubscribe_div = page.locator('div[data-selection-scrapper-hidden-element="false"].css-text-146c3p1', + has_text="Unsubscribe from thread") + is_unsubscribe_present = unsubscribe_div.is_visible() + + + print(is_unsubscribe_present) + + assert is_unsubscribe_present == False, "Unsubscribe from thread Button should not be visible." diff --git a/issues/32236_652/user_tool.py b/issues/32236_652/user_tool.py new file mode 100644 index 00000000..c24c098d --- /dev/null +++ b/issues/32236_652/user_tool.py @@ -0,0 +1,158 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +from playwright.sync_api import sync_playwright, expect +import imaplib +import email +from email.header import decode_header +import re + +from utils.trace_cleaner import trace_cleaner + +user_email = "totherandomuser@gmail.com" +password = "" + + +def get_magic_code(user_email, password, retries=5, delay=10): + + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for attempt in range(retries): + + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + + time.sleep(delay) + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def login(p, if_phone=False, first_name="John", last_name="Cena"): + + permissions = ['clipboard-read', 'clipboard-write'] + browser = p.chromium.launch(headless=True, args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process' + ]) + + if if_phone: + phone = p.devices['iPhone 12 Pro'] + context = browser.new_context(**phone, permissions=permissions, reduced_motion='no-preference') + else: + context = browser.new_context() + + page = context.new_page() + + page.goto('https://dev.new.expensify.com:8082/') + + phone_or_email_input = page.locator('input[type="email"]') + expect(phone_or_email_input).to_be_visible() + phone_or_email_input.fill(user_email) + + continue_button = page.locator('button[tabindex="0"]') + expect(continue_button).to_be_visible() + continue_button.click() + + page.wait_for_timeout(1000) + + + magic_code = "123456" + validate_code_input = page.locator('input[name="validateCode"]') + expect(validate_code_input).to_be_visible() + validate_code_input.fill(magic_code) + + page.wait_for_timeout(1000) + + return browser, page + + +def test(): + with sync_playwright() as p: + + browser, page = login(p, False) + context = page.context + context.tracing.start(snapshots=True, screenshots=True) + try: + page.wait_for_timeout(5000) + + + group_chat = page.get_by_text(f"Totherandomuser's Workspace 2").first + expect(group_chat).to_be_visible() + group_chat.click() + + page.wait_for_timeout(1000) + + page.get_by_role("textbox").fill("My Message") + page.get_by_role("textbox").press("Enter") + page.wait_for_timeout(1000) + + page.get_by_label("My settings").click() + page.get_by_label("Preferences").click() + page.get_by_label("Force offline").click() + page.locator("#overLayBottomButton").click() + page.wait_for_timeout(1000) + + message = page.locator('span', has_text="My Message").last + expect(message).to_be_visible() + message.click(button="right") + page.wait_for_timeout(1000) + + + delete_button = page.locator('[aria-label="Delete comment"]').first + delete_button.click() + page.get_by_role("button", name="Delete").click() + + page.wait_for_timeout(1000) + message = page.locator('span', has_text="My Message").last + expect(message).to_be_visible() + message.click(button="right") + page.wait_for_timeout(1000) + + is_unsubscribed = False + + + unsubscribe_div = page.locator('div[data-selection-scrapper-hidden-element="false"].css-text-146c3p1', + has_text="Unsubscribe from thread") + is_unsubscribe_present = unsubscribe_div.is_visible() + + print(is_unsubscribe_present) + + assert is_unsubscribe_present == False, "Unsubscribe from thread Button should not be visible." + + except Exception as e: + raise e + finally: + context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") diff --git a/issues/323/test.py b/issues/323/test.py index e5d3f0ba..f350e38b 100644 --- a/issues/323/test.py +++ b/issues/323/test.py @@ -22,7 +22,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+119@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/323/user_tool.py b/issues/323/user_tool.py index d4b2df22..84cdb3f3 100644 --- a/issues/323/user_tool.py +++ b/issues/323/user_tool.py @@ -24,7 +24,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+119@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/325/user_tool.py b/issues/325/user_tool.py index a183c456..0aca957e 100644 --- a/issues/325/user_tool.py +++ b/issues/325/user_tool.py @@ -13,7 +13,7 @@ NEWDOT_URL = "https://127.0.0.1:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "t1533148@gmail.com" # for example test+1234@gmail.com -PASSWORD = "logb hzkg pkfk kskg" # it will be something like "sdib pxop ovyl uawy" +PASSWORD = "" # it will be something like "sdib pxop ovyl uawy" def verify_delete_confirmation_modal_back_out(page: Page): diff --git a/issues/326/test.py b/issues/326/test.py index 6448402c..475300e8 100644 --- a/issues/326/test.py +++ b/issues/326/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/326/user_tool.py b/issues/326/user_tool.py index 400ca1a3..05e51f4b 100644 --- a/issues/326/user_tool.py +++ b/issues/326/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/329/test.py b/issues/329/test.py index 01d3693a..0e27c736 100644 --- a/issues/329/test.py +++ b/issues/329/test.py @@ -18,7 +18,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EXPENSIFY_EMAIL = "testingq186@gmail.com" -EXPENSIFY_PASSWORD = "kkfr hqiv yuxq rbso" +EXPENSIFY_PASSWORD = "" diff --git a/issues/329/user_tool.py b/issues/329/user_tool.py index 345b313e..7b10d1c3 100644 --- a/issues/329/user_tool.py +++ b/issues/329/user_tool.py @@ -19,7 +19,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EXPENSIFY_EMAIL = "testingq186@gmail.com" -EXPENSIFY_PASSWORD = "kkfr hqiv yuxq rbso" +EXPENSIFY_PASSWORD = "" logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") diff --git a/issues/330/test.py b/issues/330/test.py index 8689ba2f..a74a67f6 100644 --- a/issues/330/test.py +++ b/issues/330/test.py @@ -8,7 +8,7 @@ import re original_email = "nitish.expensify@gmail.com" -APP_PASSWORD = "ojhi eovp lbkz ktfb" +APP_PASSWORD = "" def get_user_email(): diff --git a/issues/330/user_tool.py b/issues/330/user_tool.py index 546291a8..97de2bd7 100644 --- a/issues/330/user_tool.py +++ b/issues/330/user_tool.py @@ -9,7 +9,7 @@ from utils.trace_cleaner import trace_cleaner # Added import original_email = "nitish.expensify@gmail.com" -APP_PASSWORD = "ojhi eovp lbkz ktfb" +APP_PASSWORD = "" def get_user_email(): diff --git a/issues/332/user_tool.py b/issues/332/user_tool.py index 8e377ac1..3d59ed6f 100644 --- a/issues/332/user_tool.py +++ b/issues/332/user_tool.py @@ -7,7 +7,7 @@ from utils.trace_cleaner import trace_cleaner GMAIL_NAME = "nomandevtur+29433" -GMAIL_APP_PASSWORD = "tpye xlsj axyq nltq" +GMAIL_APP_PASSWORD = "" def get_test_user_info(seed = None, first_name = None, last_name = None): diff --git a/issues/333/test.py b/issues/333/test.py index e20bee64..024e211c 100644 --- a/issues/333/test.py +++ b/issues/333/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/333/user_tool.py b/issues/333/user_tool.py index 7e0f0a73..df596ac1 100644 --- a/issues/333/user_tool.py +++ b/issues/333/user_tool.py @@ -22,7 +22,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+105@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/334/test.py b/issues/334/test.py index 181dbf7a..f6fb436f 100644 --- a/issues/334/test.py +++ b/issues/334/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/334/user_tool.py b/issues/334/user_tool.py index c643a029..810381e3 100644 --- a/issues/334/user_tool.py +++ b/issues/334/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/336/test.py b/issues/336/test.py index b28ea876..0b2ce757 100644 --- a/issues/336/test.py +++ b/issues/336/test.py @@ -12,7 +12,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "29178.5" diff --git a/issues/336/user_tool.py b/issues/336/user_tool.py index 2a26fe34..0cb4284f 100644 --- a/issues/336/user_tool.py +++ b/issues/336/user_tool.py @@ -13,7 +13,7 @@ EMAIL_USERNAME = "expensifytesting1@gmail.com" -EMAIL_PASSWORD = "redx tbmr hzpc rbzr" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "29178.5" diff --git a/issues/339/test.py b/issues/339/test.py index 5cee5baf..52889171 100644 --- a/issues/339/test.py +++ b/issues/339/test.py @@ -54,7 +54,7 @@ def get_magic_code(user_email, password, retries=5, delay=10): def login_user(page: Page, first_name="Yagna", last_name="Sai") -> tuple: user_email = "expensifysam@gmail.com" - password = "behw ywoc huxq yywe" + password = "" page.goto('https://dev.new.expensify.com:8082/') phone_or_email_input = page.locator('input[type="email"]') diff --git a/issues/339/user_tool.py b/issues/339/user_tool.py index 3527d8a9..0bad4bb4 100644 --- a/issues/339/user_tool.py +++ b/issues/339/user_tool.py @@ -55,7 +55,7 @@ def get_magic_code(user_email, password, retries=5, delay=10): def login_user(page: Page, first_name="Yagna", last_name="Sai") -> tuple: user_email = "expensifysam@gmail.com" - password = "behw ywoc huxq yywe" + password = "" page.goto('https://dev.new.expensify.com:8082/') phone_or_email_input = page.locator('input[type="email"]') diff --git a/issues/340/test.py b/issues/340/test.py index 4df597fa..89b2651d 100644 --- a/issues/340/test.py +++ b/issues/340/test.py @@ -14,7 +14,7 @@ BASE_EMAIL = "testerfreelancer555+28943@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" class EmailHandler: diff --git a/issues/340/user_tool.py b/issues/340/user_tool.py index ede2156f..6b87f382 100644 --- a/issues/340/user_tool.py +++ b/issues/340/user_tool.py @@ -15,7 +15,7 @@ BASE_EMAIL = "testerfreelancer555+28943@gmail.com" -PASSWORD = "snct ajbr yadx kwlq" +PASSWORD = "" class EmailHandler: diff --git a/issues/343/test.py b/issues/343/test.py index 931e9514..832c37e8 100644 --- a/issues/343/test.py +++ b/issues/343/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/343/user_tool.py b/issues/343/user_tool.py index b452a35f..c9fdfe8f 100644 --- a/issues/343/user_tool.py +++ b/issues/343/user_tool.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/346/test.py b/issues/346/test.py index e09f138f..e79a510b 100644 --- a/issues/346/test.py +++ b/issues/346/test.py @@ -16,7 +16,7 @@ EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "lmpleo" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO: int | None = 500 CACHED: bool = True PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/346/user_tool.py b/issues/346/user_tool.py index a55a945a..17e133c4 100644 --- a/issues/346/user_tool.py +++ b/issues/346/user_tool.py @@ -18,7 +18,7 @@ EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "lmpleo" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO: int | None = 500 CACHED: bool = True PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/348/test.py b/issues/348/test.py index c239e57e..c18ea595 100644 --- a/issues/348/test.py +++ b/issues/348/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/348/user_tool.py b/issues/348/user_tool.py index 959c1c28..345ce7fa 100644 --- a/issues/348/user_tool.py +++ b/issues/348/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+109@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/349/test.py b/issues/349/test.py index 781c9e7c..d98ff916 100644 --- a/issues/349/test.py +++ b/issues/349/test.py @@ -15,7 +15,7 @@ from json import tool USER_EMAIL = "playwright2user+105@gmail.com" -PASSWORD = "zehr mglm gizg gjcc" +PASSWORD = "" def fetch_verification_code_from_email(user_email, password, retries=10, delay=10): """ diff --git a/issues/353/test.py b/issues/353/test.py index e1710ee5..4fee90d8 100644 --- a/issues/353/test.py +++ b/issues/353/test.py @@ -14,7 +14,7 @@ from playwright.async_api import Page, TimeoutError, async_playwright, expect USER_EMAIL = "expensifysam@gmail.com" -PASSWORD = "behw ywoc huxq yywe" +PASSWORD = "" SLOW_MO: float | None = 500 NOW = int(time.time()) diff --git a/issues/353/user_tool.py b/issues/353/user_tool.py index ef34708f..33b927d2 100644 --- a/issues/353/user_tool.py +++ b/issues/353/user_tool.py @@ -16,7 +16,7 @@ from utils.trace_cleaner import trace_cleaner USER_EMAIL = "expensifysam@gmail.com" -PASSWORD = "behw ywoc huxq yywe" +PASSWORD = "" SLOW_MO: float | None = 500 NOW = int(time.time()) diff --git a/issues/355/test.py b/issues/355/test.py index b3ddc02b..61673de6 100644 --- a/issues/355/test.py +++ b/issues/355/test.py @@ -64,7 +64,7 @@ def get_magic_code(user_email, password, retries=5, delay=10): def login_user(p: PlaywrightContextManager, first_name="Yagna", last_name="Sai") -> tuple[Browser, Page, str]: user_email = generate_random_email() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', @@ -117,7 +117,7 @@ def check_name(page): def login_user2(p: PlaywrightContextManager, first_name="Yagna", last_name="Sai") -> tuple[Browser, Page, str]: user_email = generate_random_email() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', diff --git a/issues/355/user_tool.py b/issues/355/user_tool.py index 725214d9..07c47b69 100644 --- a/issues/355/user_tool.py +++ b/issues/355/user_tool.py @@ -63,7 +63,7 @@ def get_magic_code(user_email, password, retries=5, delay=10): def login_user(p: PlaywrightContextManager, first_name="Yagna", last_name="Sai") -> tuple[Browser, Page, str]: user_email = generate_random_email() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', @@ -110,7 +110,7 @@ def check_name(page): def login_user2(p: PlaywrightContextManager, first_name="Yagna", last_name="Sai") -> tuple[Browser, Page, str]: user_email = generate_random_email() - password = "xqxz mmcb tvkn lpgp" + password = "" browser = p.chromium.launch(headless=True, args=[ '--disable-web-security', diff --git a/issues/364/test.py b/issues/364/test.py index bba11b66..4b77e2ee 100644 --- a/issues/364/test.py +++ b/issues/364/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+114@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/364/user_tool.py b/issues/364/user_tool.py index c279c72b..8ada6c96 100644 --- a/issues/364/user_tool.py +++ b/issues/364/user_tool.py @@ -22,7 +22,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+114@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/365/test.py b/issues/365/test.py index c6ef6590..926812e4 100644 --- a/issues/365/test.py +++ b/issues/365/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+113@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/365/user_tool.py b/issues/365/user_tool.py index 9316cdd0..69ee4343 100644 --- a/issues/365/user_tool.py +++ b/issues/365/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+113@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/366/test.py b/issues/366/test.py index cda1fb60..472d24f3 100644 --- a/issues/366/test.py +++ b/issues/366/test.py @@ -21,7 +21,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+111@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/366/user_tool.py b/issues/366/user_tool.py index 743fff88..26ab955e 100644 --- a/issues/366/user_tool.py +++ b/issues/366/user_tool.py @@ -23,7 +23,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" EMAIL = "turingvidhant+111@gmail.com" -PASSWORD = "uotx fzkt kfeg dehz" +PASSWORD = "" class IMAPOTPExtractor: diff --git a/issues/368/test.py b/issues/368/test.py index 3d1986b1..4135f9c6 100644 --- a/issues/368/test.py +++ b/issues/368/test.py @@ -18,7 +18,7 @@ EMAIL_USERNAME = "naturesv057@gmail.com" -EMAIL_PASSWORD = "hyjk ilxi pnom oret" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "26235_4" diff --git a/issues/368/user_tool.py b/issues/368/user_tool.py index 74050360..43414612 100644 --- a/issues/368/user_tool.py +++ b/issues/368/user_tool.py @@ -18,7 +18,7 @@ EMAIL_USERNAME = "naturesv057@gmail.com" -EMAIL_PASSWORD = "hyjk ilxi pnom oret" +EMAIL_PASSWORD = "" EMAIL_USERNAME_POSTFIX = "26235_4" diff --git a/issues/373/test.py b/issues/373/test.py index 3a713422..b9a8ca74 100644 --- a/issues/373/test.py +++ b/issues/373/test.py @@ -10,7 +10,7 @@ from utils.login import check_if_logged_in, NEW_DOT_URL EMAIL = "testexpensifyturing+006@gmail.com" -PASSWORD = "qqdd pegp kagr emax" +PASSWORD = "" @pytest.mark.asyncio diff --git a/issues/373/user_tool.py b/issues/373/user_tool.py index d29372b1..dc11e72d 100644 --- a/issues/373/user_tool.py +++ b/issues/373/user_tool.py @@ -11,7 +11,7 @@ from utils.trace_cleaner import trace_cleaner EMAIL = "testexpensifyturing+006@gmail.com" -PASSWORD = "qqdd pegp kagr emax" +PASSWORD = "" @pytest.mark.asyncio async def test_issue_25901(): diff --git a/issues/377/test.py b/issues/377/test.py index 0e1206dd..89f398c3 100644 --- a/issues/377/test.py +++ b/issues/377/test.py @@ -16,7 +16,7 @@ NEWDOT_URL = "http://localhost:8082/" EMAIL = "f2139887@gmail.com" -PASSWORD = "sdib pdop ovyl uawy" +PASSWORD = "" def generate_random_email(): diff --git a/issues/377/user_tool.py b/issues/377/user_tool.py index 73c7d0ad..b45efc6d 100644 --- a/issues/377/user_tool.py +++ b/issues/377/user_tool.py @@ -17,7 +17,7 @@ NEWDOT_URL = "http://localhost:8082/" EMAIL = "f2139887@gmail.com" -PASSWORD = "sdib pdop ovyl uawy" +PASSWORD = "" def generate_random_email(): diff --git a/issues/379/test.py b/issues/379/test.py index f024c580..8a6d0ffd 100644 --- a/issues/379/test.py +++ b/issues/379/test.py @@ -16,7 +16,7 @@ import re USER_EMAIL = "playwright2user+1@gmail.com" -PASSWORD = "zehr mglm gizg gjcc" +PASSWORD = "" def fetch_verification_code_from_email(user_email, password, retries=10, delay=10): """ diff --git a/issues/379/user_tool.py b/issues/379/user_tool.py index cc1e785c..06f5bea5 100644 --- a/issues/379/user_tool.py +++ b/issues/379/user_tool.py @@ -19,7 +19,7 @@ from utils.trace_cleaner import trace_cleaner USER_EMAIL = "playwright2user+1@gmail.com" -PASSWORD = "zehr mglm gizg gjcc" +PASSWORD = "" def fetch_verification_code_from_email(user_email, password, retries=10, delay=10): """ @@ -175,5 +175,4 @@ def test_save_description_in_submitted_expense(): trace_cleaner("/app/expensify/user_tool/output_browser1.zip") - browser.close() -} \ No newline at end of file + browser.close() \ No newline at end of file diff --git a/issues/38087_1083/user_tool.py b/issues/38087_1083/user_tool.py new file mode 100644 index 00000000..155a485f --- /dev/null +++ b/issues/38087_1083/user_tool.py @@ -0,0 +1,167 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import os +import time +import pytest +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager +from playwright._impl._browser import Browser +from playwright._impl._page import Page +from playwright.sync_api import sync_playwright, expect +import re, time +import os +import imaplib +import email +import re +import random + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +OLDDOT_URL = "http://localhost:9000/" +EMAIL = "turingvidhant+109@gmail.com" +PASSWORD = "" + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + 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}" + + def _validate_email(self, email_address): + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + + def set_new_email(self, email): + self.new_email = email + + def check_for_otp(self): + 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": + return None + + email_ids = messages[0].split() + email_ids = email_ids[::-1] + + for email_id in email_ids: + status, msg_data = mail.fetch(email_id, '(RFC822)') + if status != "OK": + continue + + for response_part in msg_data: + if isinstance(response_part, tuple): + msg = email.message_from_bytes(response_part[1]) + + if self.new_email in msg["To"]: + otp_code = self._extract_otp_from_email(msg) + if otp_code: + mail.store(email_id, '+FLAGS', '\\Deleted') + mail.expunge() + mail.close() + mail.logout() + return otp_code + + mail.close() + mail.logout() + return None + + except imaplib.IMAP4.error: + return None + + def _extract_otp_from_email(self, msg): + 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): + match = re.search(r"\b\d{6}\b", text) + return match.group(0) if match else None + +gmail_account_helper = IMAPOTPExtractor(EMAIL, PASSWORD) + + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(3000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(3000) + gmail_account_helper.set_new_email(email) + otp = gmail_account_helper.check_for_otp() + page.locator('input[data-testid="validateCode"]').fill("123456") + try: + page.get_by_role("button", name="Sign In").click() + except: + pass + +def launch_browser(pw, headless=True, device=None, geolocation=None): + """ + Launch the browser. + """ + browser = pw.chromium.launch(headless=headless) + context_args = {} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def test_expensify(): + from utils.trace_cleaner import trace_cleaner + + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + + first_user_context = browser.new_context(ignore_https_errors=True) + + + first_user_context.tracing.start(screenshots=True, snapshots=True, sources=True) + + try: + page = first_user_context.new_page() + page.wait_for_timeout(3000) + + new_dot_login(page, EMAIL) + page.wait_for_timeout(3000) + + + dm_preview = page.locator('div[aria-label="Last chat message preview"]', has_text="This is the beginning of your chat") + expect(dm_preview).not_to_be_visible() + + page.wait_for_timeout(1500) + page.close() + browser.close() + except Exception as e: + + raise e + finally: + + first_user_context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") diff --git a/issues/381/test.py b/issues/381/test.py index fd8bcebd..f8282e75 100644 --- a/issues/381/test.py +++ b/issues/381/test.py @@ -12,7 +12,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" EMAIL = "pehlajrajput1+345@gmail.com" -PASSWORD = "vjycqezohxxrdhzr" +PASSWORD = "" def new_dot_login(page, email): diff --git a/issues/381/user_tool.py b/issues/381/user_tool.py index d124c654..43f3a209 100644 --- a/issues/381/user_tool.py +++ b/issues/381/user_tool.py @@ -13,7 +13,7 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" EMAIL = "pehlajrajput1+345@gmail.com" -PASSWORD = "vjycqezohxxrdhzr" +PASSWORD = "" def new_dot_login(page, email): diff --git a/issues/41/user_tool.py b/issues/41/user_tool.py new file mode 100644 index 00000000..d8703077 --- /dev/null +++ b/issues/41/user_tool.py @@ -0,0 +1,130 @@ +from playwright.sync_api import sync_playwright +from utils.trace_cleaner import trace_cleaner + +user_email = "testuserexpensify1@gmail.com" +password = "" +user_id = "testuserexpensify1+153@gmail.com" +didUIBlink = False + + +def login(p, if_phone=False, first_name="John", last_name="Doe"): + # step 1: Login + permissions = ['clipboard-read'] + browser = p.chromium.launch(headless=False, slow_mo=500, args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"]) + + if if_phone: + phone = p.devices['iPhone 12 Pro'] + context = browser.new_context(**phone, permissions=permissions, reduced_motion='no-preference') + else: + context = browser.new_context() + + page = context.new_page() + + page.goto('https://dev.new.expensify.com:8082/') + + phone_or_email_input = page.locator('input[type="email"]') + phone_or_email_input.fill(user_id) + + continue_button = page.locator('button[tabindex="0"]') + continue_button.click() + magic_code = "123456" + + validate_code_input = page.locator('input[name="validateCode"]') + validate_code_input.fill(magic_code) + + return browser, page + + +def test_51128(): + with sync_playwright() as p: + browser, page = login(p, False) + context = page.context + # Start tracing with screenshots, snapshots and sources + context.tracing.start(screenshots=True, snapshots=True, sources=True) + try: + chat_name = "testuser somasundar" + amount = "1" + try: + page.get_by_text("Got it").click(timeout=2000) + except: + pass + + # Navigate to the chat + page.get_by_label("Navigates to a chat").get_by_text(chat_name, exact=True).click() + + # Perform the first invoice action + page.locator('button[aria-label="Create"]').click() + page.locator('div[aria-label="Send invoice"][role="menuitem"]').click() + page.locator('input[role="presentation"]').fill(amount) + page.get_by_test_id("IOURequestStartPage").get_by_text("Next").click() + page.get_by_test_id("IOURequestStepConfirmation").get_by_text("Send ₹").click() + + # Capture initial count of chat messages + initialcount = page.get_by_test_id("report-actions-list").last.locator('div[aria-label="Chat message"]', has_text="Today at").count() + print(f"Initial message count: {initialcount}") + try: + page.get_by_text("Got it").click(timeout=2000) + except: + pass + + # Perform the second invoice action + page.locator('button[aria-label="Create"]').click() + page.locator('div[aria-label="Send invoice"][role="menuitem"]').click() + page.locator('input[role="presentation"]').fill(amount) + page.get_by_test_id("IOURequestStartPage").get_by_text("Next").click() + + noBlinks = page.evaluate(""" + (() => { + return new Promise((resolve) => { + let reportActionsLists = document.querySelectorAll('[data-testid="report-actions-list"]'); + if (reportActionsLists.length === 0) resolve(false); // Fail-safe if no elements found + + let lastReportActionsList = reportActionsLists[reportActionsLists.length - 1]; + + // Function to count messages that contain "Today at" + const getMessageCount = () => { + let messages = lastReportActionsList.querySelectorAll('div[aria-label="Chat message"]'); + return Array.from(messages).filter(msg => msg.innerText.includes("Today at")).length; + }; + + let countBefore = getMessageCount(); // Get initial count + let noBlinks = true; + + // Check message count every 10ms + let checkInterval = setInterval(() => { + let countDuring = getMessageCount(); + if (countDuring !== countBefore) { + noBlinks = false; + } + }, 10); + + setTimeout(() => { + clearInterval(checkInterval); // Stop interval after 3 seconds and return final count + resolve(noBlinks); // Return state of noBlinks variable + }, 3000); + + let container = document.querySelector('[data-testid="IOURequestStepConfirmation"]'); + if (!container) return; + + let button = Array.from(container.querySelectorAll('button')) + .find(btn => btn.innerText.includes("Send ₹")); + + if (button) { + button.click(); + } else { + noBlinks = false; //If no button found, test should fail + } + }); + })(); + """) + assert noBlinks, "The invoice preview sender appears then disappears when sending invoices consecutively." + finally: + # Stop tracing, export the trace file, run trace cleaner, and close the browser + trace_file = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_file) + trace_cleaner(trace_file) + browser.close() + + +if __name__ == "__main__": + test_51128() diff --git a/issues/41885_1134/test.py b/issues/41885_1134/test.py new file mode 100644 index 00000000..256e4b03 --- /dev/null +++ b/issues/41885_1134/test.py @@ -0,0 +1,43 @@ +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.async_api import async_playwright + +email_address = "brighturing926+49933@gmail.com" +password = "" + +@pytest.mark.asyncio +async def test_check_selfdm_isbold(): + async with async_playwright() as p: + + + browser = await p.chromium.launch(headless=True, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + context = await browser.new_context() + page = await context.new_page() + await page.goto("https://dev.new.expensify.com:8082/") + + + + await page.get_by_test_id("username").fill(email_address) + await page.get_by_role("button", name="Continue").click() + + + otp = "111111" + await page.get_by_test_id("validateCode").fill(otp) + + + selfdm_span = page.locator('span', has_text="Dimaka Brown (you)") + await selfdm_span.wait_for() + + + tag_style = await selfdm_span.get_attribute("style") + expected_tag_style = 'font-weight: 700;' + assert expected_tag_style in tag_style, f"Expected self DM name to have '{expected_tag_style}', but got '{tag_style}'" + + await browser.close() diff --git a/issues/41885_1134/user_tool.py b/issues/41885_1134/user_tool.py new file mode 100644 index 00000000..98f9fbe5 --- /dev/null +++ b/issues/41885_1134/user_tool.py @@ -0,0 +1,53 @@ +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.async_api import async_playwright +from utils.trace_cleaner import trace_cleaner + +email_address = "brighturing926+49933@gmail.com" +password = "" + +@pytest.mark.asyncio +async def test_check_selfdm_isbold(): + async with async_playwright() as p: + browser = await p.chromium.launch(headless=True, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + context = await browser.new_context() + + await context.tracing.start(screenshots=True, snapshots=True, sources=True) + page = await context.new_page() + + try: + await page.goto("https://dev.new.expensify.com:8082/") + + + + await page.get_by_test_id("username").fill(email_address) + await page.get_by_role("button", name="Continue").click() + + + otp = "111111" + await page.get_by_test_id("validateCode").fill(otp) + + + selfdm_span = page.locator('span', has_text="Dimaka Brown (you)") + await selfdm_span.wait_for() + + + tag_style = await selfdm_span.get_attribute("style") + expected_tag_style = 'font-weight: 700;' + assert expected_tag_style in tag_style, f"Expected self DM name to have '{expected_tag_style}', but got '{tag_style}'" + except Exception as e: + raise e + finally: + + await context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + + await browser.close() diff --git a/issues/42/test.py b/issues/42/test.py index 78ed98fd..da85998d 100644 --- a/issues/42/test.py +++ b/issues/42/test.py @@ -12,7 +12,7 @@ TEST_URL = "https://dev.new.expensify.com:8082" USER_NAME = "caraxxes555" -USER_PASSWORD = 'wawm wmyw omkr dpmt' +USER_PASSWORD = '' RETRIES=3 diff --git a/issues/42/user_tool.py b/issues/42/user_tool.py new file mode 100644 index 00000000..dc1c3c0e --- /dev/null +++ b/issues/42/user_tool.py @@ -0,0 +1,237 @@ +import time +import imaplib +import email +import re +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager +from playwright._impl._browser import Browser +from playwright._impl._page import Page +from enum import Enum +from utils.trace_cleaner import trace_cleaner + + +TEST_URL = "https://dev.new.expensify.com:8082" +USER_NAME = "caraxxes555" +USER_PASSWORD = '' + + +RETRIES=3 +class TodayOptions(Enum): + TRACK_AND_BUDGET_EXPENSES = 1 + SOMETHING_ELSE = 4 + + +def get_test_user_info(seed=None): + """ + Get test user info using the seed: + - If `seed` is None, this function will return a fixed email and name. + - If `seed` is the `True` boolean value, this function will generate a random number based on the current timestamp and use it as the seed to return a random email and name. + - Otherwise, this function will return a derivative of the fixed email and corresponding name. + """ + if seed is None: + return {"email": f"{USER_NAME}@gmail.com", "password": USER_PASSWORD, "first_name": f"{USER_NAME}", + "last_name": "Test"} + + if type(seed) == type(True): + seed = int(time.time()) + + return {"email": f"{USER_NAME}+{seed}@gmail.com", "password": USER_PASSWORD, "first_name": f"{USER_NAME}+{seed}", + "last_name": "Test"} + + +def wait(page, for_seconds=2): + page.wait_for_timeout(for_seconds * 1000) + + +def get_magic_code(user_email, password, page, retries=RETRIES, delay=10): + # Connect to the server + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + if status == "OK": + email_ids = messages[0].split() + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + # Search for the magic code in the subject + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + wait(page) + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def choose_what_to_do_today_if_any(page, option: TodayOptions, retries=RETRIES, **kwargs): + try: + wait(page) + for _ in range(retries): + wdyw = page.locator("text=What do you want to do today?") + if wdyw.count() == 0: + print('"What do you want to do today?" dialog is not found. Wait and retry...') + wait(page) + else: + break + if wdyw.count() == 0: + print('"What do you want to do today?" dialog is not found.') + set_full_name(page=page, first_name=kwargs['first_name'], last_name=kwargs['last_name']) + return + expect(wdyw).to_be_visible() + text = 'Track and budget expenses' + page.locator(f"text='{text}'").click() + page.get_by_role("button", name="Continue").click() + # Enter first name, last name and click continue + wait(page) + page.locator('input[name="fname"]').fill(kwargs['first_name']) + page.locator('input[name="lname"]').fill(kwargs['last_name']) + wait(page) + page.get_by_role("button", name="Continue").last.click() + if page.get_by_label("Close").count() > 0: + page.get_by_label("Close").click() + except: + pass + + +def choose_link_if_any(page, link_text, retries=RETRIES): + try: + wait(page) + for _ in range(retries): + link = page.locator(f'text={link_text}') + if link.count() == 0: + print(f'"{link_text}" link is not found. Wait and retry...') + wait(page) + else: + break + if link.count() == 0: + print(f'"{link_text}" link is not found.') + return + expect(link).to_be_visible() + link.click() + except Exception as e: + print(e) + return + + +def login(p: PlaywrightContextManager, user_info, if_phone=False) -> tuple[Browser, Page, str]: + permissions = ['clipboard-read', 'clipboard-write'] + browser = p.chromium.launch( + channel="chrome", + headless=False, + args=["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process", + "--ignore-certificate-errors"], + proxy={"server": "http://localhost:8080"}, + slow_mo=500 + ) + if if_phone: + phone = p.devices['iPhone 12 Pro'] + context = browser.new_context(**phone, permissions=permissions, reduced_motion='no-preference') + else: + context = browser.new_context() + page = context.new_page() + page.goto(TEST_URL, timeout=120000) + phone_or_email_input = page.locator('input[type="email"]') + expect(phone_or_email_input).to_be_visible() + phone_or_email_input.fill(user_info["email"]) + continue_button = page.locator('button[tabindex="0"]') + expect(continue_button).to_be_visible() + continue_button.click() + # Click Join button if the user is new. Or, use Magic Code to sign in if the user is existing. + wait(page) + join_button = page.locator('button:has-text("Join")') + if join_button.count() > 0: + print("Join button found. This is a new user.") + join_button.click() + else: + print("Join button not found. This is an existing user. Use Magic Code to sign in.") + magic_code = get_magic_code(user_info["email"], user_info["password"], page, retries=3, delay=10) or "123456" + print(f"Magic code: {magic_code}") + + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(validate_code_input).to_be_visible() + validate_code_input.fill(magic_code) + return browser, page + + +def set_full_name(page, first_name, last_name): + if page.get_by_label("Close").count() > 0: + page.get_by_label("Close").click() + page.get_by_label("My settings").click() + page.get_by_role("menuitem", name="Profile").click() + page.get_by_text("Display name").click() + page.get_by_label("First name").get_by_role("textbox").click() + page.get_by_label("First name").get_by_role("textbox").fill(first_name) + page.get_by_label("Last name").get_by_role("textbox").click() + page.get_by_label("Last name").get_by_role("textbox").fill(last_name) + page.get_by_role("button", name="Save").click() + wait(page) + if page.get_by_label("Back").count() > 0: + page.get_by_label("Back").last.click() + page.get_by_label("Inbox").click() + + +def test_51468(): + with sync_playwright() as p: + # Login user + user_info = get_test_user_info(seed=51468) + # Step 1: Login + browser, page = login(p, user_info, False) + context = page.context() + # Start tracing + context.tracing.start(screenshots=True, snapshots=True, sources=True) + try: + # Step 2: Skip onboarding/start pages if any + choose_what_to_do_today_if_any(page, TodayOptions.SOMETHING_ELSE, **user_info) + # A new user will see this Get Started link on the first logon. + choose_link_if_any(page, "Get started") + # Somehow the user can be redirected to the not-found page. This step redirects the user back to the home page. + choose_link_if_any(page, "Go back to home page") + + page.get_by_label("My settings").click() + page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").click() + page.get_by_label("row").click() + page.get_by_label("Workflows").click() + page.locator("body").press("ControlOrMeta+d") + page.get_by_label("Force offline").click() + page.get_by_label("Workflows").press("Escape") + page.get_by_label("Add approvals").click() + page.get_by_test_id("WorkspaceWorkflowsApprovalsEditPage").get_by_text("Approver", exact=True).click() + page.get_by_test_id("selection-list").get_by_label("caraxxes555+51468 Test").click() + wait(page) + page.get_by_test_id("selection-list").get_by_label("caraxxes555+51468 Test").click() + wait(page) + page.get_by_role("button", name="Save").click() + wait(page) + page.get_by_role("button", name="Save").click() + wait(page) + page.get_by_label("Add approvals").click() + page.locator("body").press("ControlOrMeta+d") + page.get_by_label("Force offline").click() + page.get_by_label("Force offline").press("Escape") + wait(page) + expect(page.get_by_label("Everyone")).to_contain_text("Expenses fromEveryone") + finally: + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_path) + trace_cleaner(trace_path) + browser.close() + + +if __name__ == "__main__": + test_51468() \ No newline at end of file diff --git a/issues/43004_724/test.py b/issues/43004_724/test.py new file mode 100644 index 00000000..32b9b367 --- /dev/null +++ b/issues/43004_724/test.py @@ -0,0 +1,50 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +from playwright._impl._page import Page + + +def sign_in_new_dot(page: Page, email: str, password: str): + page.goto("https://dev.new.expensify.com:8082/") + + page.get_by_test_id("username").fill(email) + page.get_by_role("button", name="Continue").click() + page.wait_for_timeout(2000) + + otp = "123456" + page.get_by_test_id("validateCode").fill(otp) + page.get_by_text("Please enter the magic code").wait_for(state="hidden") + return page + + +def test_invalid_currency(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + context = browser.new_context() + page = context.new_page() + + email = "bobexpensifytest+12385484515@gmail.com" + password = "" + + page = sign_in_new_dot(page, email, password) + + page.wait_for_timeout(2000) + + page.goto("https://dev.new.expensify.com:8082/r/4327846041984602") + + report_id = "4327846041984602" + statement = f'Onyx.merge("report_{report_id}",{{currency: null}});' + + page.wait_for_timeout(2000) + + page.evaluate(statement) + + error_text = page.locator('div[dir="auto"]', has_text="Uh-oh, something went wrong!") + expect(error_text).not_to_be_visible() \ No newline at end of file diff --git a/issues/43004_724/user_tool.py b/issues/43004_724/user_tool.py new file mode 100644 index 00000000..1ae59ef3 --- /dev/null +++ b/issues/43004_724/user_tool.py @@ -0,0 +1,68 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +from playwright._impl._page import Page + + +def sign_in_new_dot(page: Page, email: str, password: str): + page.goto("https://dev.new.expensify.com:8082/") + + page.get_by_test_id("username").fill(email) + page.get_by_role("button", name="Continue").click() + page.wait_for_timeout(2000) + + otp = "123456" + page.get_by_test_id("validateCode").fill(otp) + page.get_by_text("Please enter the magic code").wait_for(state="hidden") + return page + + +def test_invalid_currency(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + context = browser.new_context() + + + context.tracing.start( + title="test_invalid_currency", + screenshots=True, + snapshots=True + ) + + page = context.new_page() + + email = "bobexpensifytest+12385484515@gmail.com" + password = "" + + try: + page = sign_in_new_dot(page, email, password) + + page.wait_for_timeout(2000) + + page.goto("https://dev.new.expensify.com:8082/r/4327846041984602") + + report_id = "4327846041984602" + statement = f'Onyx.merge("report_{report_id}",{{currency: null}});' + + page.wait_for_timeout(2000) + page.evaluate(statement) + + error_text = page.locator('div[dir="auto"]', has_text="Uh-oh, something went wrong!") + expect(error_text).not_to_be_visible() + finally: + + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_path) + + + from utils.trace_cleaner import trace_cleaner + trace_cleaner(trace_path) + + browser.close() diff --git a/issues/45190_520/test.py b/issues/45190_520/test.py new file mode 100644 index 00000000..734557c4 --- /dev/null +++ b/issues/45190_520/test.py @@ -0,0 +1,158 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import email +import re +import os +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +import numpy as np +from PIL import Image +import io + +GMAIL_NAME = "testerbro7077" +GMAIL_APP_PASSWORD = "" + +def get_test_user_info(seed=None, first_name=None, last_name=None): + if first_name is None: + first_name = "Yagan" + + if last_name is None: + last_name = "Sai" + + email = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + return {"email": email, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + +def get_magic_code(user_email, password, retries=5, delay=5): + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + print(email_ids) + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + time.sleep(delay) + + imap.logout() + print("Max retries reached. Email not found.") + return None + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + page.get_by_label(activity_text).click() + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + +def login_user(page, user_info, activity_text="Track and budget expenses"): + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + expect(page.get_by_label("Inbox")).to_be_visible(timeout=3000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(join_button.or_(validate_code_input)).to_be_visible() + + if join_button.is_visible(): + join_button.click(timeout=3000) + else: + magic_code = "123456" #get_magic_code(user_info["email"], user_info["password"], retries=6, delay=5) + print(f"Magic code: {magic_code}") + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + +def chech_bg_color(page): + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_text("Preferences").click() + page.wait_for_timeout(1000) + if page.get_by_text("Dark").is_visible(): + pass + else: + page.get_by_text("Theme").click() + page.get_by_label("Dark").click() + + page.get_by_test_id("CustomBottomTabNavigator").get_by_label("Search").click() + page.get_by_role("button", name="Outstanding").click() + checkbox = page.get_by_role("checkbox").nth(3) + aria_checked = checkbox.get_attribute("aria-checked") + page.wait_for_timeout(500) + + if aria_checked == "false": + checkbox.click() + else: + checkbox.click() + page.wait_for_timeout(500) + checkbox.click() + + page.wait_for_timeout(1000) + page.mouse.click(0.5, 0.5) + + page.wait_for_timeout(1000) + view_button = page.get_by_role("button", name="View", exact=True).nth(2) + container = view_button.locator("..").locator("..").locator("..").locator("..") + background_color = container.evaluate("element => getComputedStyle(element).backgroundColor") + + expected_background_color = "rgb(26, 61, 50)" + assert background_color == expected_background_color, "Expected background UI change did not occur" + +def test_login(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process", + "--ignore-certificate-errors" + ]) + userA_info = get_test_user_info(seed=1, first_name="Yagna") + contextA = browser.new_context() + pageA = contextA.new_page() + + login_user(pageA, userA_info) + chech_bg_color(pageA) + + pageA.close() + contextA.close() + browser.close() + diff --git a/issues/45190_520/user_tool.py b/issues/45190_520/user_tool.py new file mode 100644 index 00000000..1ccfa500 --- /dev/null +++ b/issues/45190_520/user_tool.py @@ -0,0 +1,169 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import email +import re +import os +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +import numpy as np +from PIL import Image +import io + +from utils.trace_cleaner import trace_cleaner + +GMAIL_NAME = "testerbro7077" +GMAIL_APP_PASSWORD = "" + +def get_test_user_info(seed=None, first_name=None, last_name=None): + if first_name is None: + first_name = "Yagan" + + if last_name is None: + last_name = "Sai" + + email_addr = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + return {"email": email_addr, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + +def get_magic_code(user_email, password, retries=5, delay=5): + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + print(email_ids) + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + time.sleep(delay) + + imap.logout() + print("Max retries reached. Email not found.") + return None + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + page.get_by_label(activity_text).click() + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + +def login_user(page, user_info, activity_text="Track and budget expenses"): + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + expect(page.get_by_label("Inbox")).to_be_visible(timeout=3000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(join_button.or_(validate_code_input)).to_be_visible() + + if join_button.is_visible(): + join_button.click(timeout=3000) + else: + magic_code = "123456" # get_magic_code(user_info["email"], user_info["password"], retries=6, delay=5) + print(f"Magic code: {magic_code}") + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + +def chech_bg_color(page): + page.get_by_label("My settings").click() + page.wait_for_timeout(1000) + page.get_by_text("Preferences").click() + page.wait_for_timeout(1000) + if page.get_by_text("Dark").is_visible(): + pass + else: + page.get_by_text("Theme").click() + page.get_by_label("Dark").click() + + page.get_by_test_id("CustomBottomTabNavigator").get_by_label("Search").click() + page.get_by_role("button", name="Outstanding").click() + checkbox = page.get_by_role("checkbox").nth(3) + aria_checked = checkbox.get_attribute("aria-checked") + page.wait_for_timeout(500) + + if aria_checked == "false": + checkbox.click() + else: + checkbox.click() + page.wait_for_timeout(500) + checkbox.click() + + page.wait_for_timeout(1000) + page.mouse.click(0.5, 0.5) + + page.wait_for_timeout(1000) + view_button = page.get_by_role("button", name="View", exact=True).nth(2) + container = view_button.locator("..").locator("..").locator("..").locator("..").locator() + background_color = container.evaluate("element => getComputedStyle(element).backgroundColor") + + expected_background_color = "rgb(26, 61, 50)" + assert background_color == expected_background_color, "Expected background UI change did not occur" + +def test_login(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process", + "--ignore-certificate-errors" + ]) + userA_info = get_test_user_info(seed=1, first_name="Yagna") + contextA = browser.new_context() + # Start tracing after creating the context + contextA.tracing.start(screenshots=True, snapshots=True, sources=True) + pageA = contextA.new_page() + + try: + login_user(pageA, userA_info) + chech_bg_color(pageA) + finally: + trace_path = "/app/expensify/user_tool/output_browser1.zip" + contextA.tracing.stop(path=trace_path) + trace_cleaner(trace_path) + pageA.close() + contextA.close() + browser.close() + + +if __name__ == "__main__": + test_login() \ No newline at end of file diff --git a/issues/45543_1016/test.py b/issues/45543_1016/test.py new file mode 100644 index 00000000..2b9e1388 --- /dev/null +++ b/issues/45543_1016/test.py @@ -0,0 +1,121 @@ +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.async_api import expect, async_playwright, Browser, Page +from utils.login import sign_in, NEW_DOT_URL, check_if_logged_in +from utils.browser import close_browser + + +USER_EMAILA = "doorsqueaky+3182311@gmail.com" +USERNAME_A = 'John Doe' +PASSWORD_A = "" +USER_EMAILB = "windowsqueaky+3919211@gmail.com" +PASSWORD_B = "" +USERNAME_B = 'Jane Doe' + + +async def start_browser_with_proxy(): + playwright = await async_playwright().start() + browser = await playwright.chromium.launch( + slow_mo=500, + headless=True, + proxy={ + 'server': 'http://127.0.0.1:8080' + }, + args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process' + ] + ) + context = await browser.new_context(ignore_https_errors=True) + page = await context.new_page() + return context, page, playwright + + +async def send_message(page: Page, recepient_email: str, message: str): + + await page.locator('button[aria-label="Start chat (Floating action)"]').click() + await page.locator('div[aria-label="Start chat"][role="menuitem"]').click() + + + await page.locator('input[aria-label="Name, email, or phone number"]').fill(recepient_email) + await page.get_by_test_id('selection-list').locator(f'button:has-text("{recepient_email}")').click() + await page.wait_for_timeout(1000) + + + message_editor = page.locator('div[contenteditable="true"][placeholder="Write something..."]').last + await message_editor.fill(message) + await message_editor.press("Enter") + + +async def create_draft_reply_in_thread(page: Page, username: str, sender_email: str, message: str, reply: str): + + if await page.locator('button[aria-label="Navigates to a chat"]', has_text=sender_email).is_visible(): + await page.locator('button[aria-label="Navigates to a chat"]', has_text=sender_email).click() + else: + await page.locator('button[aria-label="Navigates to a chat"]', has_text=username).click() + + + await page.locator('div[aria-label="Chat message"]', has_text=message).click(button="right") + await page.locator('div[aria-label="Reply in thread"][role="menuitem"]').click() + + await page.wait_for_timeout(1000) + + + message_editor = page.locator('div[contenteditable="true"][placeholder="Write something..."]').last + await message_editor.fill(reply) + + +async def navigate_away_check_draft(page: Page, username: str, sender_email: str): + + if await page.locator('button[aria-label="Navigates to a chat"]', has_text=sender_email).is_visible(): + await page.locator('button[aria-label="Navigates to a chat"]', has_text=sender_email).click() + else: + await page.locator('button[aria-label="Navigates to a chat"]', has_text=username).click() + + + await page.wait_for_timeout(2000) + + + draft_reply_LHN_btn = page.locator('button[aria-label="Navigates to a chat"]', has_text="No activity yet") + await expect(draft_reply_LHN_btn).to_be_visible() + + +async def enter_dummy_otp_if_not_logged_in(page: Page, email: str): + if not await check_if_logged_in(page=page, url=NEW_DOT_URL): + await page.get_by_test_id("username").fill(email) + await page.get_by_role("button", name="Continue").click() + await page.get_by_test_id("validateCode").fill("123456") + + + +@pytest.mark.asyncio +async def test_workspace_switch_on_reload(): + try: + contextA, pageA, playwrightA = await start_browser_with_proxy() + + await enter_dummy_otp_if_not_logged_in(pageA, USER_EMAILA) + + + await expect(pageA.get_by_label("Inbox")).to_be_visible() + + message = "Hello How are you" + await send_message(pageA, USER_EMAILB, message) + + contextB, pageB, playwrightB = await start_browser_with_proxy() + + await enter_dummy_otp_if_not_logged_in(pageB, USER_EMAILB) + + + await expect(pageA.get_by_label("Inbox")).to_be_visible() + + reply = "Hey I am good. What about you?" + await create_draft_reply_in_thread(pageB, USERNAME_A, USER_EMAILA, message, reply) + await navigate_away_check_draft(pageB, USERNAME_A, USER_EMAILA) + + finally: + await close_browser(contextA, pageA, playwrightA) + await close_browser(contextB, pageB, playwrightB) diff --git a/issues/48694_681/test.py b/issues/48694_681/test.py new file mode 100644 index 00000000..271a8148 --- /dev/null +++ b/issues/48694_681/test.py @@ -0,0 +1,134 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +import time +import re +import random + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +EMAIL = "dev091197@gmail.com" +task_id = 48694 +EMAIL1 = f"dev091197+{task_id}@gmail.com" +PASSWORD = "" + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + 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}" + def _validate_email(self, email_address): + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + def set_new_email(self, email): + self.new_email = email + def check_for_otp(self): + default_otp_code="123456" + return default_otp_code + def _extract_otp_from_email(self, msg): + 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): + match = re.search(r"\b\d{6}\b", text) + return match.group(0) if match else None +gmail_account_helper = IMAPOTPExtractor(EMAIL, PASSWORD) + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(10000) + gmail_account_helper.set_new_email(email) + otp = gmail_account_helper.check_for_otp() + page.locator('input[data-testid="validateCode"]').fill(otp) + try: + page.get_by_role("button", name="Sign In").click() + except: + pass + +def task_check(page): + random_int_1 = 13 + random_int_2 = 21 + workspace_name = f"WS-{random_int_1}{random_int_2}" + room_name = f"r-{random_int_1}{random_int_2}" + email_1 = f"dev091197+{random_int_1}+{random_int_2}@gmail.com" + test_name = "test inzi" + page.get_by_label("My settings").click() + page.wait_for_timeout(2000) + page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").click() + page.get_by_role("button", name="New workspace").first.click() + page.wait_for_timeout(1000) + page.get_by_test_id("WorkspacePageWithSections").get_by_text("Name").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").press("ControlOrMeta+a") + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").fill(workspace_name) + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + page.get_by_label("Back").click() + page.get_by_label("Inbox").click() + page.wait_for_timeout(1000) + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Start chat", exact=True).click() + page.wait_for_timeout(1000) + page.get_by_label("Room").first.click() + page.get_by_placeholder("social").fill(room_name) + page.wait_for_timeout(1000) + page.get_by_test_id("WorkspaceNewRoomPage").get_by_label("WS-").get_by_text("Workspace").click() + page.get_by_test_id("ValueSelectorModal").get_by_label(workspace_name).click() + page.wait_for_timeout(1000) + page.get_by_role("button", name="Create room").click() + page.get_by_label(f"#{room_name}").click() + page.wait_for_timeout(1000) + page.get_by_test_id("ReportDetailsPage").get_by_label("Settings").click() + page.get_by_text("Notify me about new messages").click() + page.wait_for_timeout(1000) + page.get_by_test_id("selection-list").get_by_label("Daily").click() + page.get_by_test_id("ReportSettingsPage").get_by_label("Back").click() + page.wait_for_timeout(1000) + page.get_by_label("Leave").click() + page.wait_for_timeout(1000) + page.locator("#composer").last.click() + page.locator("#composer").last.fill(f"message-{random_int_1}{random_int_2}") + page.wait_for_timeout(1000) + page.get_by_label("Send").last.click() + page.get_by_label(f"#{room_name}").click() + page.wait_for_timeout(1000) + page.get_by_test_id("ReportDetailsPage").get_by_label("Settings").click() + page.wait_for_timeout(2000) + expect(page.get_by_text("Daily")).to_be_visible() + +def test_expensify_0000(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process', + ]) + + first_user_context = browser.new_context( + ignore_https_errors=True + ) + page = first_user_context.new_page() + page.wait_for_timeout(2000) + new_dot_login(page, EMAIL1) + page.wait_for_timeout(2000) + task_check(page) + browser.close() \ No newline at end of file diff --git a/issues/48694_681/user_tool.py b/issues/48694_681/user_tool.py new file mode 100644 index 00000000..4c75b02c --- /dev/null +++ b/issues/48694_681/user_tool.py @@ -0,0 +1,157 @@ +import sys, os +from utils.trace_cleaner import trace_cleaner + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +import time +import re +import random + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +EMAIL = "dev091197@gmail.com" +task_id = 48694 +EMAIL1 = f"dev091197+{task_id}@gmail.com" +PASSWORD = "" + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + 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}" + + def _validate_email(self, email_address): + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + + def set_new_email(self, email): + self.new_email = email + + def check_for_otp(self): + default_otp_code = "123456" + return default_otp_code + + def _extract_otp_from_email(self, msg): + 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): + match = re.search(r"\b\d{6}\b", text) + return match.group(0) if match else None + + +gmail_account_helper = IMAPOTPExtractor(EMAIL, PASSWORD) + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(10000) + gmail_account_helper.set_new_email(email) + otp = gmail_account_helper.check_for_otp() + page.locator('input[data-testid="validateCode"]').fill(otp) + try: + page.get_by_role("button", name="Sign In").click() + except: + pass + + +def task_check(page): + random_int_1 = 13 + random_int_2 = 21 + workspace_name = f"WS-{random_int_1}{random_int_2}" + room_name = f"r-{random_int_1}{random_int_2}" + email_1 = f"dev091197+{random_int_1}+{random_int_2}@gmail.com" + test_name = "test inzi" + page.get_by_label("My settings").click() + page.wait_for_timeout(2000) + page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").click() + page.get_by_role("button", name="New workspace").first.click() + page.wait_for_timeout(1000) + page.get_by_test_id("WorkspacePageWithSections").get_by_text("Name").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").press("ControlOrMeta+a") + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").fill(workspace_name) + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + page.wait_for_timeout(1000) + page.get_by_label("Back").click() + page.get_by_label("Inbox").click() + page.wait_for_timeout(1000) + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Start chat", exact=True).click() + page.wait_for_timeout(1000) + page.get_by_label("Room").first.click() + page.get_by_placeholder("social").fill(room_name) + page.wait_for_timeout(1000) + page.get_by_test_id("WorkspaceNewRoomPage").get_by_label("WS-").get_by_text("Workspace").click() + page.get_by_test_id("ValueSelectorModal").get_by_label(workspace_name).click() + page.wait_for_timeout(1000) + page.get_by_role("button", name="Create room").click() + page.get_by_label(f"#{room_name}").click() + page.wait_for_timeout(1000) + page.get_by_test_id("ReportDetailsPage").get_by_label("Settings").click() + page.get_by_text("Notify me about new messages").click() + page.wait_for_timeout(1000) + page.get_by_test_id("selection-list").get_by_label("Daily").click() + page.get_by_test_id("ReportSettingsPage").get_by_label("Back").click() + page.wait_for_timeout(1000) + page.get_by_label("Leave").click() + page.wait_for_timeout(1000) + page.locator("#composer").last.click() + page.locator("#composer").last.fill(f"message-{random_int_1}{random_int_2}") + page.wait_for_timeout(1000) + page.get_by_label("Send").last.click() + page.get_by_label(f"#{room_name}").click() + page.wait_for_timeout(1000) + page.get_by_test_id("ReportDetailsPage").get_by_label("Settings").click() + page.wait_for_timeout(2000) + expect(page.get_by_text("Daily")).to_be_visible() + + +def test_expensify_0000(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process', + ]) + + first_user_context = browser.new_context( + ignore_https_errors=True + ) + + # Start tracing with specified settings + first_user_context.tracing.start(screenshots=True, snapshots=True, sources=True) + + page = first_user_context.new_page() + page.wait_for_timeout(2000) + + try: + new_dot_login(page, EMAIL1) + page.wait_for_timeout(2000) + task_check(page) + finally: + # Stop tracing and export the trace file + first_user_context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + browser.close() + + +test_expensify_0000() \ No newline at end of file diff --git a/issues/49298_510/test.py b/issues/49298_510/test.py new file mode 100644 index 00000000..7cd5687f --- /dev/null +++ b/issues/49298_510/test.py @@ -0,0 +1,186 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import logging +import sys +import re +import email +import string, random +import pytest +from playwright.sync_api import sync_playwright, expect, Page + + + +EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" + + +EMAIL_USERNAME = "naturesv057@gmail.com" +EMAIL_PASSWORD = "" + + +EMAIL_USERNAME_POSTFIX = "49298_4" + + +logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") +LOGGER = logging.getLogger(__name__) + +def generate_user_email(user_id=None): + """ + Generate an email address for a user login. + """ + temp = EMAIL_USERNAME.rsplit("@", 1) + username = temp[0].strip() + domain = temp[1].strip() + return f"{username}+{EMAIL_USERNAME_POSTFIX}@{domain}" + + +def clear_inbox(username, password): + """ + Delete all existing messages from the Inbox. + """ + LOGGER.info("Deleting all existing messages from the email inbox") + with imaplib.IMAP4_SSL(host="imap.gmail.com") as imap: + imap.login(username, password) + imap.select("inbox") + imap.store("1:*", "+FLAGS", "\\Deleted") + imap.expunge() + imap.close() + + +def get_otp_from_email(username, password, retries=2, delay=2): + """ + Read the OTP email and return the OTP code. + """ + LOGGER.info("Reading the OTP email") + with imaplib.IMAP4_SSL(host="imap.gmail.com") as imap: + imap.login(username, password) + for i in range(1, retries + 1): + imap.select("inbox") + status, messages = imap.search(None, "ALL") + if status == "OK": + for message_id in reversed(messages[0].split()): + status, data = imap.fetch(message_id, "(RFC822)") + if status == "OK": + email_message = email.message_from_bytes(data[0][1]) + subject, encoding = email.header.decode_header(email_message["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode(encoding) + if subject.startswith("Expensify magic sign-in code:"): + otp_code = subject.split(":")[-1].strip() + LOGGER.info("Got the OTP %s", otp_code) + return otp_code + time.sleep(delay) + imap.close() + return "123456" + + +def launch_browser(pw, headless=True, device=None, geolocation=None): + """ + Launch the browser. + """ + browser = pw.chromium.launch( + headless=True, + proxy={ + 'server': 'http://127.0.0.1:8080', + }, + args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process', + ], + ) + context_args = {} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def login_user(page, email, first_name="John", last_name="Doe"): + """ + Login to the Expensify app and complete the onboarding. + """ + + clear_inbox(EMAIL_USERNAME, EMAIL_PASSWORD) + + page.goto(EXPENSIFY_URL) + + page.get_by_test_id("username").fill(email) + page.get_by_role("button", name="Continue").click() + + + otp_code = get_otp_from_email(EMAIL_USERNAME, EMAIL_PASSWORD) + page.get_by_test_id("validateCode").fill(otp_code) + + +def test(): + with sync_playwright() as p: + email = generate_user_email() + LOGGER.info("User email %s", email) + browser, context, page = launch_browser(p) + login_user(page, email) + page.wait_for_timeout(5000) + + LOGGER.info("User logged in successfully") + + page.locator( + 'button[aria-label="Start chat (Floating action)"][tabindex="0"]' + ).click() + + + page.locator('div[aria-label="Start chat"][role="menuitem"]').click() + + page.locator('input[aria-label="Name, email, or phone number"]').fill( + "t56826807+13@gmail.com" + ) + try: + page.locator('button[aria-label="Employee"]').last.click(timeout=3000) + except: + page.get_by_label("t56826807+13@gmail.com").click() + page.locator('button[aria-label="Employee"]').last.click() + + page.locator('div[aria-label="Private notes"]').last.click() + page.locator('div[aria-label="Private notes"][role="textbox"]').fill( + "new line\n" * 100 + ) + + page.locator('button[data-listener="Enter"]', has_text="Save").last.click() + + page.locator('div[aria-label="Private notes"]').last.click() + + text = page.locator('div[data-testid="PrivateNotesListPage"]').inner_text() + print(text) + + page.wait_for_selector('div[data-testid="PrivateNotesListPage"]') + parent_div = page.locator('div[data-testid="PrivateNotesListPage"]') + + + child_with_scroll_y = parent_div.evaluate_handle( + """parent => { + const children = parent.querySelectorAll("div"); + return Array.from(children).find(child => { + const style = getComputedStyle(child); + return style.overflowY === "scroll" || style.overflowY === "auto"; + }); + }""" + ) + + + if child_with_scroll_y: + text = child_with_scroll_y.evaluate("element => element.innerText") + print(text) + else: + raise Exception("No child div with overflow-y set to scroll or auto found.") + + assert ( + "Keep notes about this chat here. You're the only person who can add, edit, or view these notes." + in text + ), "The intro text on private notes list stays fixed when it should scroll with the page" + diff --git a/issues/49298_510/user_tool.py b/issues/49298_510/user_tool.py new file mode 100644 index 00000000..c975ab49 --- /dev/null +++ b/issues/49298_510/user_tool.py @@ -0,0 +1,199 @@ +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 time +import imaplib +import logging +import sys +import re +import email +import string, random +import pytest +from playwright.sync_api import sync_playwright, expect, Page + + +EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" + + +EMAIL_USERNAME = "naturesv057@gmail.com" +EMAIL_PASSWORD = "" + + +EMAIL_USERNAME_POSTFIX = "49298_4" + + +logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") +LOGGER = logging.getLogger(__name__) + + +def generate_user_email(user_id=None): + """ + Generate an email address for a user login. + """ + temp = EMAIL_USERNAME.rsplit("@", 1) + username = temp[0].strip() + domain = temp[1].strip() + return f"{username}+{EMAIL_USERNAME_POSTFIX}@{domain}" + + +def clear_inbox(username, password): + """ + Delete all existing messages from the Inbox. + """ + LOGGER.info("Deleting all existing messages from the email inbox") + with imaplib.IMAP4_SSL(host="imap.gmail.com") as imap: + imap.login(username, password) + imap.select("inbox") + imap.store("1:*", "+FLAGS", "\Deleted") + imap.expunge() + imap.close() + + +def get_otp_from_email(username, password, retries=2, delay=2): + """ + Read the OTP email and return the OTP code. + """ + LOGGER.info("Reading the OTP email") + with imaplib.IMAP4_SSL(host="imap.gmail.com") as imap: + imap.login(username, password) + for i in range(1, retries + 1): + imap.select("inbox") + status, messages = imap.search(None, "ALL") + if status == "OK": + for message_id in reversed(messages[0].split()): + status, data = imap.fetch(message_id, "(RFC822)") + if status == "OK": + email_message = email.message_from_bytes(data[0][1]) + subject, encoding = email.header.decode_header(email_message["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode(encoding) + if subject.startswith("Expensify magic sign-in code:"): + otp_code = subject.split(":")[-1].strip() + LOGGER.info("Got the OTP %s", otp_code) + return otp_code + time.sleep(delay) + imap.close() + return "123456" + + +def launch_browser(pw, headless=True, device=None, geolocation=None): + """ + Launch the browser. + """ + browser = pw.chromium.launch( + headless=True, + proxy={ + 'server': 'http://127.0.0.1:8080', + }, + args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process', + ], + ) + context_args = {} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def login_user(page, email, first_name="John", last_name="Doe"): + """ + Login to the Expensify app and complete the onboarding. + """ + + clear_inbox(EMAIL_USERNAME, EMAIL_PASSWORD) + + page.goto(EXPENSIFY_URL) + + page.get_by_test_id("username").fill(email) + page.get_by_role("button", name="Continue").click() + + + otp_code = get_otp_from_email(EMAIL_USERNAME, EMAIL_PASSWORD) + page.get_by_test_id("validateCode").fill(otp_code) + + +def test(): + with sync_playwright() as p: + email = generate_user_email() + LOGGER.info("User email %s", email) + browser, context, page = launch_browser(p) + + # Start tracing the context + context.tracing.start(screenshots=True, snapshots=True, sources=True) + + try: + login_user(page, email) + page.wait_for_timeout(5000) + + LOGGER.info("User logged in successfully") + + page.locator( + 'button[aria-label="Start chat (Floating action)"][tabindex="0"]' + ).click() + + page.locator('div[aria-label="Start chat"][role="menuitem"]').click() + + page.locator('input[aria-label="Name, email, or phone number"]').fill( + "t56826807+13@gmail.com" + ) + try: + page.locator('button[aria-label="Employee"]').last.click(timeout=3000) + except: + page.get_by_label("t56826807+13@gmail.com").click() + page.locator('button[aria-label="Employee"]').last.click() + + page.locator('div[aria-label="Private notes"]').last.click() + page.locator('div[aria-label="Private notes"][role="textbox"]').fill( + "new line\n" * 100 + ) + + page.locator('button[data-listener="Enter"]', has_text="Save").last.click() + + page.locator('div[aria-label="Private notes"]').last.click() + + text = page.locator('div[data-testid="PrivateNotesListPage"]').inner_text() + print(text) + + page.wait_for_selector('div[data-testid="PrivateNotesListPage"]') + parent_div = page.locator('div[data-testid="PrivateNotesListPage"]') + + child_with_scroll_y = parent_div.evaluate_handle( + """parent => { + const children = parent.querySelectorAll("div"); + return Array.from(children).find(child => { + const style = getComputedStyle(child); + return style.overflowY === "scroll" || style.overflowY === "auto"; + }); + }""" + ) + + if child_with_scroll_y: + text = child_with_scroll_y.evaluate("element => element.innerText") + print(text) + else: + raise Exception("No child div with overflow-y set to scroll or auto found.") + + assert ( + "Keep notes about this chat here. You're the only person who can add, edit, or view these notes." + in text + ), "The intro text on private notes list stays fixed when it should scroll with the page" + finally: + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop() + context.tracing.export_trace(trace_path) + trace_cleaner(trace_path) + browser.close() + + +if __name__ == '__main__': + test() \ No newline at end of file diff --git a/issues/49492_670/test.py b/issues/49492_670/test.py new file mode 100644 index 00000000..54f5cebc --- /dev/null +++ b/issues/49492_670/test.py @@ -0,0 +1,185 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +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) + + 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" + + browser.close() + diff --git a/issues/49492_670/user_tool.py b/issues/49492_670/user_tool.py new file mode 100644 index 00000000..2feaa728 --- /dev/null +++ b/issues/49492_670/user_tool.py @@ -0,0 +1,196 @@ +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() \ No newline at end of file diff --git a/issues/49786_515/test.py b/issues/49786_515/test.py new file mode 100644 index 00000000..96dd6125 --- /dev/null +++ b/issues/49786_515/test.py @@ -0,0 +1,134 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +from playwright.sync_api import sync_playwright, expect +import time +import re +import random + +NEWDOT_URL = "https://dev.new.expensify.com:8082/" +task_id = 49786 +EMAIL = f"dev091197+{task_id}@gmail.com" +PASSWORD = "" + + +class IMAPOTPExtractor: + def __init__(self, email_address, password): + 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}" + def _validate_email(self, email_address): + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email_address)) + def set_new_email(self, email): + self.new_email = email + def check_for_otp(self): + default_otp_code = "123456" + return default_otp_code + def _extract_otp_from_email(self, msg): + 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): + match = re.search(r"\b\d{6}\b", text) + return match.group(0) if match else None +gmail_account_helper = IMAPOTPExtractor(EMAIL, PASSWORD) + + +def new_dot_login(page, email): + page.goto(NEWDOT_URL) + page.locator('input[type="email"]').fill(email) + page.wait_for_timeout(2000) + page.get_by_role("button", name="Continue").nth(0).click() + page.wait_for_timeout(10000) + gmail_account_helper.set_new_email(email) + otp = gmail_account_helper.check_for_otp() + page.locator('input[data-testid="validateCode"]').fill(otp) + try: + page.get_by_role("button", name="Sign In").click() + except: + pass + + +def category_approvers(page): + random_int_1 = 23 + random_int_2 = 241 + workspace_name = f"WS-{random_int_1}{random_int_2}" + page.get_by_label("My settings").click() + page.wait_for_timeout(2000) + page.get_by_test_id("InitialSettingsPage").get_by_label("Workspaces").click() + page.get_by_role("button", name="New workspace").first.click() + page.wait_for_timeout(1000) + page.get_by_test_id("WorkspacePageWithSections").get_by_text("Name").click() + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").press("ControlOrMeta+a") + page.wait_for_timeout(1000) + page.get_by_role("textbox", name="Name").fill(workspace_name) + page.wait_for_timeout(1000) + page.get_by_role("button", name="Save").click() + + + page.get_by_label("More features").click() + page.get_by_label("Configure how spend is").click() + + + page.get_by_test_id("WorkspaceInitialPage").get_by_label( + "Profile" + ).click() + page.get_by_test_id("WorkspacePageWithSections").get_by_text( + "Default currency" + ).click() + page.get_by_test_id("selection-list-text-input").fill("usd") + page.get_by_label("USD - $").click() + + + routing_number = "011401533" + account_number = "1111222233334444" + page.get_by_label("Workflows").click() + page.get_by_label("Connect bank account").click() + page.get_by_label("Connect manually").click() + page.get_by_role("textbox", name="Routing number").fill(routing_number) + page.get_by_role("textbox", name="Account number").fill(account_number) + page.get_by_role("button", name="Next").click() + page.get_by_test_id("PersonalInfo").get_by_label("Back").click() + page.wait_for_timeout(2000) + + expect( + page.get_by_role("textbox", name="Routing number") + ).to_be_disabled() + expect( + page.get_by_role("textbox", name="Account number") + ).to_be_disabled() + + +def test_run(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True, args=[ + '--disable-web-security', + '--disable-features=IsolateOrigins,site-per-process', + ]) + page = browser.new_page() + + + page.goto('https://dev.new.expensify.com:8082/', timeout=60000) + + new_dot_login(page, EMAIL) + + category_approvers(page) + + browser.close() \ No newline at end of file diff --git a/issues/50065_702/test.py b/issues/50065_702/test.py new file mode 100644 index 00000000..8b55e4d6 --- /dev/null +++ b/issues/50065_702/test.py @@ -0,0 +1,259 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import pytest +import re +from playwright.async_api import async_playwright, expect, Page, TimeoutError +from utils.email_handler import get_unique_derived_email + + +async def connect_netsuite(accounting_page: Page): + await accounting_page.get_by_label("NetSuite").get_by_role( + "button", name="Connect" + ).click() + try: + await accounting_page.locator("button", has_text="Upgrade").click( + timeout=3000 + ) + await accounting_page.get_by_role( + "button", name="Got it, thanks" + ).click() + except TimeoutError: + pass + + workspace_id = re.search( + r"settings/workspaces/([^/]+)/", accounting_page.url + ).group(1) + js_code = """ + () => { + const net_suite = { + "accountID": "TSTDRV1668486", + "tokenID": "4WFxamEE2VzbjX/EN/Z9I5dFAOefKCdes1jtb1db87aATFz6T0pWt51jGFUJeYQFRdbrj6vIDbYLT/q+jW0cWXBLUcnV5CUqb2qsw4WVNlI=;kO0hlBNY1KxfPxZZTxJu/Q==;BXajerPTWHDHlPF/2NkKOHQP/cZ9zfuc3ENJN6u6K9/+KDtYxsPocN7JgZW10WDkGu5hL9YlMZSlY3tOBonSpw==", + "options": { + "data": { + "subsidiaryList": [ + { + "internalID": "1", + "country": "_unitedStates", + "isElimination": false, + "name": "Honeycomb Mfg." + }, + { + "internalID": "3", + "country": "_unitedStates", + "isElimination": false, + "name": "Honeycomb Holdings Inc." + } + ], + "items": [ + { + "name": "EST99999", + "id": "1006" + }, + { + "name": "Expensify Invoice Expense", + "id": "1171" + }, + { + "name": "Expensify Invoice Line Item", + "id": "1172" + } + ], + "payableList": [ + { + "GL Code": "0805", + "name": "0805 Expensify Card Liability Ted Test", + "id": "3050", + "type": "_otherCurrentLiability" + }, + { + "GL Code": "1000", + "name": "1000 Checking", + "id": "1", + "type": "_bank" + }, + { + "GL Code": "1002", + "name": "1002 Savings", + "id": "2", + "type": "_bank" + } + ], + "taxAccountsList": [ + { + "country": "_canada", + "name": "PST Expenses BC", + "externalID": "192" + } + ] + }, + "config": { + "invoiceItemPreference": "create", + "receivableAccount": "7", + "taxPostingAccount": "", + "exportToNextOpenPeriod": false, + "allowForeignCurrency": true, + "reimbursableExpensesExportDestination": "EXPENSE_REPORT", + "subsidiary": "Honeycomb Mfg.", + "syncOptions": { + "mapping": { + "classes": "REPORT_FIELD", + "jobs": "TAG", + "locations": "REPORT_FIELD", + "customers": "TAG", + "departments": "REPORT_FIELD" + }, + "crossSubsidiaryCustomers": false, + "syncApprovalWorkflow": true, + "syncCustomLists": false, + "exportReportsTo": "REPORTS_APPROVED_NONE", + "exportVendorBillsTo": "VENDOR_BILLS_APPROVED_NONE", + "setFinalApprover": true, + "syncReimbursedReports": true, + "customSegments": [], + "syncPeople": false, + "enableNewCategories": true, + "hasChosenAutoSyncOption": true, + "finalApprover": "yuwen@expensify.com", + "syncTax": false, + "syncCustomSegments": false, + "customLists": [], + "syncCategories": true, + "hasChosenSyncReimbursedReportsOption": true, + "exportJournalsTo": "JOURNALS_APPROVED_NONE" + }, + "autoCreateEntities": true, + "exporter": "yuwen@expensify.com", + "exportDate": "LAST_EXPENSE", + "nonreimbursableExpensesExportDestination": "VENDOR_BILL", + "reimbursablePayableAccount": "3050", + "journalPostingPreference": "JOURNALS_POSTING_TOTAL_LINE", + "invoiceItem": "1006", + "subsidiaryID": "1", + "defaultVendor": "42767", + "provincialTaxPostingAccount": " ", + "reimbursementAccountID": "1", + "approvalAccount": "2000 Accounts Payable", + "payableAcct": "3050", + "customFormIDOptions": { + "reimbursable": { + "expenseReport": null + }, + "nonReimbursable": { + "vendorBill": null + }, + "enabled": false + }, + "collectionAccount": "1" + } + }, + "verified": true, + "lastSyncDate": "2024-11-08T05:56:40+0000", + "lastErrorSyncDate": "", + "source": "EXPENSIFYWEB", + "config": { + "autoSync": { + "jobID": "5181292703454260454", + "enabled": true + } + }, + "tokenSecret": "ibhjt36G3f5dmzje63CfEtS2DxpgB7ZXzx/7mcP3U33zx00P48RxQMAwN12JpsZChWNcN+t8YqjMdZiFRFae/CIwe0B7L0cbeiv2wSzxezc=;BRBh21nq9ogfckK+dFWYiQ==;TvupLzzkSWlB4lH/rtqDUF5wvVIyp40an3sYMsCpDu4txOiNT4f51oKGfXxgqN4JxgbzvDvGlNBciy3sSTR+9Q==" + } + + Onyx.merge(`policy_WORKSPACE_ID`, {"connections":{ + "netsuite":net_suite + } + }); + } + """.replace( + "WORKSPACE_ID", workspace_id + ) + + await accounting_page.evaluate(js_code) + await accounting_page.locator("#overLayBottomButton").click() + +@pytest.mark.asyncio +async def test_send_invoice_workspace(): + async with async_playwright() as p: + base_email = "namesomerandomemail@gmail.com" + password = "" + + derived_email = get_unique_derived_email(base_email) + derived_email = 'namesomerandomemail+1733924831@gmail.com' + print(derived_email) + + browser = await 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) + + page = await browser.new_page(viewport={"width": 1280, "height": 500}) + + await page.goto('https://dev.new.expensify.com:8082/') + + + phone_or_email_input = page.locator('input[type="email"]') + await expect(phone_or_email_input).to_be_visible() + await phone_or_email_input.fill(derived_email) + + + continue_button = page.locator('button[tabindex="0"]') + await expect(continue_button).to_be_visible() + await continue_button.click() + + try: + continue_button = page.locator('button[tabindex="0"]') + await expect(continue_button).to_be_visible() + await continue_button.click() + except Exception: + pass + + + track_budget_option = page.locator("text=Track and budget expenses") + await track_budget_option.click() + + + await page.locator('input[name="fname"]').fill('Test') + await page.locator('input[name="lname"]').fill('Test') + await page.get_by_role("button", name="Continue").last.click() + + + create_button = page.locator("[aria-label='Start chat (Floating action)']") + await create_button.click() + + + new_workspace_button = page.locator("[aria-label='New workspace']") + await new_workspace_button.click() + + + more_features_button = page.locator("text=More features") + await more_features_button.click() + + + invoice_button = page.locator("[aria-label='Sync your chart of accounts and more.']") + await invoice_button.click() + + await page.locator("[aria-label='Accounting']").click() + + await connect_netsuite(page) + + await page.goto(f"{page.url}/netsuite/import/custom-segment/new") + await page.get_by_label("Custom segment").click() + await page.get_by_role("button", name="Next").click() + await page.get_by_role("textbox", name="Name").press("CapsLock") + await page.get_by_role("textbox", name="Name").fill("Posting") + await page.get_by_role("button", name="Next").click() + + + has_scroll_bar = await page.evaluate('''() => { + const element = document.querySelector(".css-view-175oi2r.r-WebkitOverflowScrolling-150rngu.r-overflowY-1rnoaur"); + return element ? element.scrollHeight > element.clientHeight : false; + }''') + + + assert has_scroll_bar, "Expected div to have a scrollbar, but it does not." + + await browser.close() diff --git a/issues/50065_702/user_tool.py b/issues/50065_702/user_tool.py new file mode 100644 index 00000000..418d63b9 --- /dev/null +++ b/issues/50065_702/user_tool.py @@ -0,0 +1,269 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import pytest +import re +from playwright.async_api import async_playwright, expect, Page, TimeoutError +from utils.email_handler import get_unique_derived_email +from utils.trace_cleaner import trace_cleaner + +async def connect_netsuite(accounting_page: Page): + await accounting_page.get_by_label("NetSuite").get_by_role( + "button", name="Connect" + ).click() + try: + await accounting_page.locator("button", has_text="Upgrade").click( + timeout=3000 + ) + await accounting_page.get_by_role( + "button", name="Got it, thanks" + ).click() + except TimeoutError: + pass + + workspace_id = re.search( + r"settings/workspaces/([^/]+)/", accounting_page.url + ).group(1) + js_code = """ + () => { + const net_suite = { + "accountID": "TSTDRV1668486", + "tokenID": "4WFxamEE2VzbjX/EN/Z9I5dFAOefKCdes1jtb1db87aATFz6T0pWt51jGFUJeYQFRdbrj6vIDbYLT/q+jW0cWXBLUcnV5CUqb2qsw4WVNlI=;kO0hlBNY1KxfPxZZTxJu/Q==;BXajerPTWHDHlPF/2NkKOHQP/cZ9zfuc3ENJN6u6K9/+KDtYxsPocN7JgZW10WDkGu5hL9YlMZSlY3tOBonSpw==", + "options": { + "data": { + "subsidiaryList": [ + { + "internalID": "1", + "country": "_unitedStates", + "isElimination": false, + "name": "Honeycomb Mfg." + }, + { + "internalID": "3", + "country": "_unitedStates", + "isElimination": false, + "name": "Honeycomb Holdings Inc." + } + ], + "items": [ + { + "name": "EST99999", + "id": "1006" + }, + { + "name": "Expensify Invoice Expense", + "id": "1171" + }, + { + "name": "Expensify Invoice Line Item", + "id": "1172" + } + ], + "payableList": [ + { + "GL Code": "0805", + "name": "0805 Expensify Card Liability Ted Test", + "id": "3050", + "type": "_otherCurrentLiability" + }, + { + "GL Code": "1000", + "name": "1000 Checking", + "id": "1", + "type": "_bank" + }, + { + "GL Code": "1002", + "name": "1002 Savings", + "id": "2", + "type": "_bank" + } + ], + "taxAccountsList": [ + { + "country": "_canada", + "name": "PST Expenses BC", + "externalID": "192" + } + ] + }, + "config": { + "invoiceItemPreference": "create", + "receivableAccount": "7", + "taxPostingAccount": "", + "exportToNextOpenPeriod": false, + "allowForeignCurrency": true, + "reimbursableExpensesExportDestination": "EXPENSE_REPORT", + "subsidiary": "Honeycomb Mfg.", + "syncOptions": { + "mapping": { + "classes": "REPORT_FIELD", + "jobs": "TAG", + "locations": "REPORT_FIELD", + "customers": "TAG", + "departments": "REPORT_FIELD" + }, + "crossSubsidiaryCustomers": false, + "syncApprovalWorkflow": true, + "syncCustomLists": false, + "exportReportsTo": "REPORTS_APPROVED_NONE", + "exportVendorBillsTo": "VENDOR_BILLS_APPROVED_NONE", + "setFinalApprover": true, + "syncReimbursedReports": true, + "customSegments": [], + "syncPeople": false, + "enableNewCategories": true, + "hasChosenAutoSyncOption": true, + "finalApprover": "yuwen@expensify.com", + "syncTax": false, + "syncCustomSegments": false, + "customLists": [], + "syncCategories": true, + "hasChosenSyncReimbursedReportsOption": true, + "exportJournalsTo": "JOURNALS_APPROVED_NONE" + }, + "autoCreateEntities": true, + "exporter": "yuwen@expensify.com", + "exportDate": "LAST_EXPENSE", + "nonreimbursableExpensesExportDestination": "VENDOR_BILL", + "reimbursablePayableAccount": "3050", + "journalPostingPreference": "JOURNALS_POSTING_TOTAL_LINE", + "invoiceItem": "1006", + "subsidiaryID": "1", + "defaultVendor": "42767", + "provincialTaxPostingAccount": " ", + "reimbursementAccountID": "1", + "approvalAccount": "2000 Accounts Payable", + "payableAcct": "3050", + "customFormIDOptions": { + "reimbursable": { + "expenseReport": null + }, + "nonReimbursable": { + "vendorBill": null + }, + "enabled": false + }, + "collectionAccount": "1" + } + }, + "verified": true, + "lastSyncDate": "2024-11-08T05:56:40+0000", + "lastErrorSyncDate": "", + "source": "EXPENSIFYWEB", + "config": { + "autoSync": { + "jobID": "5181292703454260454", + "enabled": true + } + }, + "tokenSecret": "ibhjt36G3f5dmzje63CfEtS2DxpgB7ZXzx/7mcP3U33zx00P48RxQMAwN12JpsZChWNcN+t8YqjMdZiFRFae/CIwe0B7L0cbeiv2wSzxezc=;BRBh21nq9ogfckK+dFWYiQ==;TvupLzzkSWlB4lH/rtqDUF5wvVIyp40an3sYMsCpDu4txOiNT4f51oKGfXxgqN4JxgbzvDvGlNBciy3sSTR+9Q==" + } + + Onyx.merge(`policy_WORKSPACE_ID`, {"connections":{ + "netsuite":net_suite + } + }); + } + """.replace( + "WORKSPACE_ID", workspace_id + ) + + await accounting_page.evaluate(js_code) + await accounting_page.locator("#overLayBottomButton").click() + +@pytest.mark.asyncio +async def test_send_invoice_workspace(): + async with async_playwright() as p: + base_email = "namesomerandomemail@gmail.com" + password = "" + + derived_email = get_unique_derived_email(base_email) + derived_email = 'namesomerandomemail+1733924831@gmail.com' + print(derived_email) + + browser = await 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 = await browser.new_context(viewport={"width": 1280, "height": 500}) + await context.tracing.start(title="trace", screenshots=True, snapshots=True, sources=True) + + page = await context.new_page() + + try: + await page.goto('https://dev.new.expensify.com:8082/') + + + phone_or_email_input = page.locator('input[type="email"]') + await expect(phone_or_email_input).to_be_visible() + await phone_or_email_input.fill(derived_email) + + + continue_button = page.locator('button[tabindex="0"]') + await expect(continue_button).to_be_visible() + await continue_button.click() + + try: + continue_button = page.locator('button[tabindex="0"]') + await expect(continue_button).to_be_visible() + await continue_button.click() + except Exception: + pass + + + track_budget_option = page.locator("text=Track and budget expenses") + await track_budget_option.click() + + + await page.locator('input[name="fname"]').fill('Test') + await page.locator('input[name="lname"]').fill('Test') + await page.get_by_role("button", name="Continue").last.click() + + + create_button = page.locator("[aria-label='Start chat (Floating action)']") + await create_button.click() + + + new_workspace_button = page.locator("[aria-label='New workspace']") + await new_workspace_button.click() + + + more_features_button = page.locator("text=More features") + await more_features_button.click() + + + invoice_button = page.locator("[aria-label='Sync your chart of accounts and more.']") + await invoice_button.click() + + await page.locator("[aria-label='Accounting']").click() + + await connect_netsuite(page) + + await page.goto(f"{page.url}/netsuite/import/custom-segment/new") + await page.get_by_label("Custom segment").click() + await page.get_by_role("button", name="Next").click() + await page.get_by_role("textbox", name="Name").press("CapsLock") + await page.get_by_role("textbox", name="Name").fill("Posting") + await page.get_by_role("button", name="Next").click() + + + has_scroll_bar = await page.evaluate('''() => { + const element = document.querySelector(".css-view-175oi2r.r-WebkitOverflowScrolling-150rngu.r-overflowY-1rnoaur"); + return element ? element.scrollHeight > element.clientHeight : false; + }''') + + + assert has_scroll_bar, "Expected div to have a scrollbar, but it does not." + finally: + + await context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + + await browser.close() diff --git a/issues/50163_1076/user_tool.py b/issues/50163_1076/user_tool.py new file mode 100644 index 00000000..1463783a --- /dev/null +++ b/issues/50163_1076/user_tool.py @@ -0,0 +1,190 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import email +import re +import os +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager +from utils.trace_cleaner import trace_cleaner + + +GMAIL_NAME = "nomandevtur+50163" +GMAIL_APP_PASSWORD = "" + + +def get_test_user_info(seed = None, first_name = None, last_name = None): + if first_name is None: + first_name = GMAIL_NAME + + if last_name is None: + last_name = "" + + email = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + + return {"email": email, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + + +def delete_email_inbox(user_email, password, retries=5, delay=10): + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + + + imap.select("inbox") + status, all_emails = imap.search(None, "ALL") + if status == "OK": + for email_id in all_emails[0].split(): + imap.store(email_id, "+FLAGS", "\\Deleted") + imap.expunge() + + +def get_magic_code(user_email, password, retries=5, delay=5): + code = '167554' + + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + print(email_ids) + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + + time.sleep(delay) + + + imap.logout() + print("Max retries reached. Email not found.") + return code + + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + + + page.get_by_label(activity_text).click() + + + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + + +def login_user(page, user_info, activity_text="Track and budget expenses"): + + page.context.clear_cookies() + + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + + expect(page.get_by_label("Inbox")).to_be_visible(timeout=10000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(join_button.or_(validate_code_input)).to_be_visible() + + if (join_button.is_visible()): + join_button.click(timeout=3000) + else: + magic_code = get_magic_code(user_info["email"], user_info["password"], retries=2, delay=5) + + if magic_code is None: + + page.locator(f"span:has-text('Didn't receive a magic code?')").first.click() + magic_code = get_magic_code(user_info["email"], user_info["password"], retries=6, delay=5) + print(f"Magic code: {magic_code}") + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + + +def launch_app(pw, headless=True, device=None, geolocation=None): + browser = pw.chromium.launch(headless=headless, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + ) + context_args = {"viewport": {"width": 1024, "height": 640}} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"] = ["geolocation"] + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def test_clear_btn_on_saved_search_name_field(): + with sync_playwright() as p: + user_info = get_test_user_info() + delete_email_inbox(user_info["email"], user_info["password"], retries=6, delay=5) + browser, context, page = launch_app(p) + context.tracing.start(title="test_clear_btn_on_saved_search_name_field", screenshots=True, snapshots=True, sources=True) + try: + login_user(page, user_info) + + page.get_by_test_id("CustomBottomTabNavigator").get_by_label("Search").click() + page.get_by_label("More").click() + page.get_by_label("Rename").click() + + page.wait_for_timeout(3000) + + + clear_button = page.locator("button[aria-label='Clear']") + assert clear_button.is_visible(), "The button with aria-label 'Clear' is not present on the page." + + print("The button with aria-label 'Clear' is present on the page.") + + page.wait_for_timeout(1000) + except Exception as e: + print(f"An error occurred: {e}") + raise + finally: + context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + page.close() + browser.close() diff --git a/issues/50577_1094/test.py b/issues/50577_1094/test.py new file mode 100644 index 00000000..c00d144b --- /dev/null +++ b/issues/50577_1094/test.py @@ -0,0 +1,244 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import email +import re +import os +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager + + +GMAIL_NAME = "nomandevtur+50577" +GMAIL_APP_PASSWORD = "" + + +def get_test_user_info(seed = None, first_name = None, last_name = None): + if first_name is None: + first_name = GMAIL_NAME + + if last_name is None: + last_name = "" + + email = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + + return {"email": email, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + +def delete_email_inbox(user_email, password, retries=5, delay=10): + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + + + imap.select("inbox") + status, all_emails = imap.search(None, "ALL") + if status == "OK": + for email_id in all_emails[0].split(): + imap.store(email_id, "+FLAGS", "\\Deleted") + imap.expunge() + + +def get_magic_code(user_email, password, retries=5, delay=5): + + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + print(email_ids) + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + + time.sleep(delay) + + + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + + + page.get_by_label(activity_text).click() + + + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + + +def login_user(page, user_info, activity_text="Track and budget expenses"): + + page.context.clear_cookies() + + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + + expect(page.get_by_label("Inbox")).to_be_visible(timeout=10000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(join_button.or_(validate_code_input)).to_be_visible() + + if (join_button.is_visible()): + join_button.click(timeout=3000) + else: + magic_code = "123456" + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + + +def get_context(p: PlaywrightContextManager, user_info, browser, is_phone_setup=False): + """ + Creates and returns a browser context and the initial page. + Supports mobile or desktop context setup. + """ + permissions = ['clipboard-read', 'clipboard-write'] + + + data_dir = 'mobile_context' if is_phone_setup else 'desktop_context' + data_dir += f"_{user_info['email']}" + os.makedirs(data_dir, exist_ok=True) + + + context_options = { + "permissions": permissions, + "storage_state": None + } + + if is_phone_setup: + context_options.update({ + "viewport": {"width": 390, "height": 844}, + "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1", + }) + + + context = browser.new_context(**context_options) + page = context.new_page() + return context, page + + +def test_inconsistent_button_behavior(): + with sync_playwright() as p: + + user_info = get_test_user_info(10) + + delete_email_inbox(user_info["email"], user_info["password"], retries=6, delay=5) + + browser = p.chromium.launch(channel="chrome", headless=True, slow_mo=500, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + + context, page = get_context(p, user_info, browser) + login_user(page, user_info) + + + + + + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Submit expense").nth(0).click() + page.get_by_label("Manual").click() + page.get_by_placeholder("0").fill("100") + page.locator("#numPadContainerView").get_by_role("button", name="Next").click() + + page.get_by_test_id("selection-list").get_by_label("Nomandevtur+50577's Workspace").click() + + page.get_by_role("menuitem", name="Merchant Required").click() + page.get_by_role("textbox", name="Merchant").fill("hello") + page.get_by_role("button", name="Save").click() + page1 = context.new_page() + page1.bring_to_front() + page1.goto(page.url) + page1.wait_for_load_state('load') + page.wait_for_timeout(5000) + + page.bring_to_front() + page.get_by_role("button", name="Submit PKR").click() + + page.wait_for_timeout(1000) + page1.bring_to_front() + page1.get_by_role("button", name="Submit PKR").click() + page.wait_for_timeout(1000) + + + text_locator = page1.get_by_text("Please select a participant.") + expect(text_locator).to_be_visible() + + + + page.bring_to_front() + page.get_by_label("Create").click() + page.get_by_label("Assign task").click() + page.get_by_role("textbox", name="Title").fill("877") + page.get_by_role("button", name="Next").click() + + page1.bring_to_front() + page1.goto(page.url) + page1.wait_for_load_state('load') + + + page.wait_for_timeout(5000) + + page.bring_to_front() + page.get_by_role("button", name="Confirm task").click() + + + page.wait_for_timeout(1000) + page1.bring_to_front() + page1.get_by_role("button", name="Confirm task").click() + page.wait_for_timeout(1000) + + + text_locator = page1.get_by_text("Please enter a title and select a share destination.") + expect(text_locator).to_be_visible() + + + page.close() + browser.close() \ No newline at end of file diff --git a/issues/50577_1094/user_tool.py b/issues/50577_1094/user_tool.py new file mode 100644 index 00000000..6d81ddda --- /dev/null +++ b/issues/50577_1094/user_tool.py @@ -0,0 +1,240 @@ +import sys, os + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, base_path) + +import time +import imaplib +import email +import re +import os +from email.header import decode_header +from playwright.sync_api import sync_playwright, expect +from playwright.sync_api._context_manager import PlaywrightContextManager +from utils.trace_cleaner import trace_cleaner + + +GMAIL_NAME = "nomandevtur+50577" +GMAIL_APP_PASSWORD = "" + + +def get_test_user_info(seed=None, first_name=None, last_name=None): + if first_name is None: + first_name = GMAIL_NAME + + if last_name is None: + last_name = "" + + email_addr = f"{GMAIL_NAME}+{seed}@gmail.com" if seed is not None else f"{GMAIL_NAME}@gmail.com" + + return {"email": email_addr, "password": GMAIL_APP_PASSWORD, "first_name": first_name, "last_name": last_name} + + +def delete_email_inbox(user_email, password, retries=5, delay=10): + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + imap.select("inbox") + status, all_emails = imap.search(None, "ALL") + if status == "OK": + for email_id in all_emails[0].split(): + imap.store(email_id, "+FLAGS", "\Deleted") + imap.expunge() + + +def get_magic_code(user_email, password, retries=5, delay=5): + + imap = imaplib.IMAP4_SSL("imap.gmail.com") + imap.login(user_email, password) + + for _ in range(retries): + imap.select("inbox") + status, messages = imap.search(None, '(UNSEEN SUBJECT "Expensify magic sign-in code:")') + + if status == "OK": + email_ids = messages[0].split() + print(email_ids) + + if email_ids: + latest_email_id = email_ids[-1] + status, msg_data = imap.fetch(latest_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 or "utf-8") + + + match = re.search(r"Expensify magic sign-in code: (\d+)", subject) + if match: + code = match.group(1) + imap.logout() + return code + else: + print("No unread emails found with the subject. Retrying...") + else: + print("Failed to retrieve emails. Retrying...") + + + time.sleep(delay) + + + imap.logout() + print("Max retries reached. Email not found.") + return None + + +def select_activity(page, first_name, last_name, activity_text): + expect(page.get_by_text("What do you want to do today?")).to_be_visible() + + + page.get_by_label(activity_text).click() + + + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + + +def login_user(page, user_info, activity_text="Track and budget expenses"): + + page.context.clear_cookies() + + page.goto('https://dev.new.expensify.com:8082/') + page.wait_for_load_state('load') + + try: + expect(page.get_by_label("Inbox")).to_be_visible(timeout=10000) + return + except: + pass + + page.get_by_test_id("username").fill(user_info["email"]) + page.get_by_role("button", name="Continue").click() + + join_button = page.get_by_role("button", name="Join") + validate_code_input = page.locator('input[data-testid="validateCode"]') + expect(join_button.or_(validate_code_input)).to_be_visible() + + if (join_button.is_visible()): + join_button.click(timeout=3000) + else: + magic_code = "123456" + validate_code_input.fill(magic_code) + + page.wait_for_timeout(3000) + + select_activity_dialog = page.get_by_text("What do you want to do today?") + if select_activity_dialog.count() > 0: + select_activity(page, user_info["first_name"], user_info["last_name"], activity_text) + + +def get_context(p: PlaywrightContextManager, user_info, browser, is_phone_setup=False): + """ + Creates and returns a browser context and the initial page. + Supports mobile or desktop context setup. + """ + permissions = ['clipboard-read', 'clipboard-write'] + + data_dir = 'mobile_context' if is_phone_setup else 'desktop_context' + data_dir += f"_{user_info['email']}" + os.makedirs(data_dir, exist_ok=True) + + context_options = { + "permissions": permissions, + "storage_state": None + } + + if is_phone_setup: + context_options.update({ + "viewport": {"width": 390, "height": 844}, + "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1", + }) + + context = browser.new_context(**context_options) + page = context.new_page() + return context, page + + + +def test_inconsistent_button_behavior(): + with sync_playwright() as p: + user_info = get_test_user_info(10) + + delete_email_inbox(user_info["email"], user_info["password"], retries=6, delay=5) + + browser = p.chromium.launch(channel="chrome", headless=True, slow_mo=500, args=[ + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ]) + + context, page = get_context(p, user_info, browser) + # Start tracing + context.tracing.start(screenshots=True, snapshots=True, sources=True) + + try: + login_user(page, user_info) + + page.get_by_label("Start chat (Floating action)").click() + page.get_by_label("Submit expense").nth(0).click() + page.get_by_label("Manual").click() + page.get_by_placeholder("0").fill("100") + page.locator("#numPadContainerView").get_by_role("button", name="Next").click() + + page.get_by_test_id("selection-list").get_by_label("Nomandevtur+50577's Workspace").click() + + page.get_by_role("menuitem", name="Merchant Required").click() + page.get_by_role("textbox", name="Merchant").fill("hello") + page.get_by_role("button", name="Save").click() + page1 = context.new_page() + page1.bring_to_front() + page1.goto(page.url) + page1.wait_for_load_state('load') + page.wait_for_timeout(5000) + + page.bring_to_front() + page.get_by_role("button", name="Submit PKR").click() + + page.wait_for_timeout(1000) + page1.bring_to_front() + page1.get_by_role("button", name="Submit PKR").click() + page.wait_for_timeout(1000) + + text_locator = page1.get_by_text("Please select a participant.") + expect(text_locator).to_be_visible() + + page.bring_to_front() + page.get_by_label("Create").click() + page.get_by_label("Assign task").click() + page.get_by_role("textbox", name="Title").fill("877") + page.get_by_role("button", name="Next").click() + + page1.bring_to_front() + page1.goto(page.url) + page1.wait_for_load_state('load') + + page.wait_for_timeout(5000) + + page.bring_to_front() + page.get_by_role("button", name="Confirm task").click() + + page.wait_for_timeout(1000) + page1.bring_to_front() + page1.get_by_role("button", name="Confirm task").click() + page.wait_for_timeout(1000) + + text_locator = page1.get_by_text("Please enter a title and select a share destination.") + expect(text_locator).to_be_visible() + + page.close() + finally: + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_path) + trace_cleaner(trace_path) + browser.close() + + +if __name__ == '__main__': + test_inconsistent_button_behavior() diff --git a/issues/56/user_tool.py b/issues/56/user_tool.py index 778aa51c..a7a16cf9 100644 --- a/issues/56/user_tool.py +++ b/issues/56/user_tool.py @@ -140,7 +140,7 @@ def test_28820(): # In broken state, this will show the "track expense" button email_address_2 = "rgulraiz2000+204@gmail.com" - password = "kepw uquj myoa npvj" + password = "" user_fname = "Ehsan" user_lname = "G" diff --git a/issues/60/test.py b/issues/60/test.py index 6b7abe78..4fb9844d 100644 --- a/issues/60/test.py +++ b/issues/60/test.py @@ -10,9 +10,14 @@ NEWDOT_URL = "https://dev.new.expensify.com:8082/" OLDDOT_URL = "http://localhost:9000/" +<<<<<<< HEAD:issues/38087_1083/test.py +EMAIL = "turingvidhant+109@gmail.com" +PASSWORD = "" +======= EMAIL = "turingsampleopen+53660@gmail.com" PASSWORD = "dmyi iqgn znbg kqii" +>>>>>>> main:issues/60/test.py class IMAPOTPExtractor: def __init__(self, email_address, password): diff --git a/issues/63/user_tool.py b/issues/63/user_tool.py new file mode 100644 index 00000000..d63a74f6 --- /dev/null +++ b/issues/63/user_tool.py @@ -0,0 +1,86 @@ +from playwright._impl._page import Page +from playwright.sync_api import sync_playwright +from utils.trace_cleaner import trace_cleaner + +NEW_DOT_URL = "https://dev.new.expensify.com:8082" +ONE_SECOND = 1000 +TWO_SECONDS = 2000 +THREE_SECONDS = 3000 +FIVE_SECONDS = 5000 +email_address = "adebayovicktor0+test43726@gmail.com" +password = "" + +# Sign In to Expensify +def sign_in_new_dot(page: Page, email: str, url: str = None): + """ + Sign in into the new Expensify dot. + """ + # Go to URL + url = url if url else NEW_DOT_URL + page.goto(url) + # Sign In + page.get_by_test_id("username").fill(email) + page.wait_for_timeout(TWO_SECONDS) + page.get_by_role("button", name="Continue").click() + page.wait_for_timeout(FIVE_SECONDS) + # OTP is hardcoded for replay + otp = '123456' + page.get_by_test_id("validateCode").fill(otp) + page.wait_for_timeout(TWO_SECONDS) + + # Wait sign in to complete + page.get_by_text("Please enter the magic code").wait_for(state="hidden") + page.wait_for_timeout(THREE_SECONDS) + + +def generate_email(): + return f"adebayovicktor0+test51336@gmail.com" + + +def test_emoji_is_deletable(): + """ + Test to verify that the send button is focused when the modal is opened + """ + with sync_playwright() as p: + browser = p.chromium.launch(headless=False, + proxy={"server": "http://127.0.0.1:8080/"}, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process" + ], + slow_mo=1000 + ) + user_email = generate_email() + context = browser.new_context() + # Start tracing + context.tracing.start(screenshots=True, snapshots=True, sources=True) + page = context.new_page() + try: + sign_in_new_dot(page, user_email) + # page.get_by_label("Close").click() + page.wait_for_timeout(2000) + page.get_by_label("Emoji").first.click() + page.get_by_role("textbox", name="Search").fill("black") + page.get_by_label("⬛", exact=True).click() + page.get_by_label("Emoji").first.click() + page.wait_for_timeout(2000) + page.get_by_role("textbox", name="Search").fill("wale") + page.get_by_label("🏴", exact=True).click() + page.wait_for_timeout(2000) + page.keyboard.press('Backspace') + page.keyboard.press('Backspace') + page.wait_for_timeout(2000) + page.keyboard.press('Backspace') + page.keyboard.press('Backspace') + inner_text = page.locator("#composer").inner_text() + assert inner_text == '', "The flag 🏴 and ⬛ is not deleted" + finally: + # Stop tracing, export the trace file and run trace_cleaner + context.tracing.stop(path="/app/expensify/user_tool/output_browser1.zip") + trace_cleaner("/app/expensify/user_tool/output_browser1.zip") + browser.close() + + +if __name__ == "__main__": + test_emoji_is_deletable() \ No newline at end of file diff --git a/issues/77/user_tool.py b/issues/77/user_tool.py index c55133a4..e78c44c1 100644 --- a/issues/77/user_tool.py +++ b/issues/77/user_tool.py @@ -10,7 +10,7 @@ EMAIL_USERNAME = "xecuycismfsga" EMAIL_ALIAS = "6nvqaqhy" USER_EMAIL = f"{EMAIL_USERNAME}+{EMAIL_ALIAS}@gmail.com" -PASSWORD = "uwgb zzoc cofa kaaq" +PASSWORD = "" SLOW_MO: int | None = 500 PROXY_URL = os.getenv("PROXY_URL") diff --git a/issues/94/user_tool.py b/issues/94/user_tool.py new file mode 100644 index 00000000..c7758d26 --- /dev/null +++ b/issues/94/user_tool.py @@ -0,0 +1,175 @@ +from playwright.sync_api import TimeoutError, expect, sync_playwright +from utils.trace_cleaner import trace_cleaner + +# Expensify app URL +EXPENSIFY_URL = "https://dev.new.expensify.com:8082/" + +# Email login credentials +EMAIL_USERNAME = "expensifytesting1@gmail.com" +EMAIL_PASSWORD = "" + +# Email username postfix +EMAIL_USERNAME_POSTFIX = "52678.4" + + +def generate_user_email(user_id=None): + """ + Generate an email address for user login. + """ + temp = EMAIL_USERNAME.rsplit("@", 1) + username = temp[0].strip() + domain = temp[1].strip() + return f"{username}+{EMAIL_USERNAME_POSTFIX}{user_id or ''}@{domain}" + + +def launch_browser(pw, headless=False, device=None, permissions=None, geolocation=None): + """ + Launch the browser. + """ + browser = pw.chromium.launch( + channel="chrome", + headless=False, + args=[ + "--ignore-certificate-errors", + "--disable-web-security", + "--disable-features=IsolateOrigins,site-per-process", + ], + slow_mo=1000, + ) + context_args = {"permissions": permissions or []} + if device: + context_args.update(pw.devices[device]) + if geolocation: + context_args["geolocation"] = geolocation + context_args["permissions"].append("geolocation") + context = browser.new_context(**context_args) + page = context.new_page() + return browser, context, page + + +def login_user(page, user_email, first_name="John", last_name="Doe"): + """ + Log into the Expensify app. + """ + # Open the Expensify app + page.goto(EXPENSIFY_URL) + # Login user + page.get_by_test_id("username").fill(user_email) + page.get_by_role("button", name="Continue").click() + # Check if OTP is required for the login + try: + expect(page.get_by_test_id("SignInPage").get_by_test_id("validateCode")).to_be_visible(timeout=7000) + except (AssertionError, TimeoutError): + # If not required, expect the join button to appear and click the button + page.get_by_test_id("SignInPage").get_by_role("button", name="Join").click() + else: + # Get the OTP and complete verification + otp_code = "123456" + page.get_by_test_id("SignInPage").get_by_test_id("validateCode").fill(otp_code) + try: + page.get_by_test_id("SignInPage").get_by_role("button", name="Sign in").click(timeout=2000) + except (AssertionError, TimeoutError): + pass + # Check if onboarding is required + try: + expect(page.get_by_text("What do you want to do today?")).to_be_visible(timeout=5000) + except (AssertionError, TimeoutError): + pass + else: + # Complete the onboarding + page.get_by_label("Track and budget expenses").click() + page.get_by_role("button", name="Continue").first.click() + page.get_by_role("textbox", name="First name").fill(first_name) + page.get_by_role("textbox", name="Last name").fill(last_name) + page.get_by_role("button", name="Continue").last.click() + # Dismiss get started dialog if appears + try: + page.get_by_role("button", name="Get started").click(timeout=3000) + except (AssertionError, TimeoutError): + pass + # Expect the main screen to appear + expect(page.get_by_test_id("BaseSidebarScreen")).to_be_visible(timeout=7000) + + +def test_approver_field_in_tag_editor_shows_user_name(): + """ + Verify that the approver field in the tag editor shows the user name instead of user email. + """ + with sync_playwright() as pw: + # Login user + user_email = generate_user_email() + fname, lname = "John", "Doe" + user_name = " ".join([fname, lname]).strip() + browser, context, page = launch_browser(pw) + + # Start tracing + context.tracing.start(screenshots=True, snapshots=True, sources=True) + + try: + login_user(page, user_email, first_name=fname, last_name=lname) + + # Create a new workspace, if one is not already created + page.get_by_role("button", name="My settings").click() + page.get_by_test_id("InitialSettingsPage").get_by_role("menuitem", name="Workspaces", exact=True).click() + texts = page.get_by_test_id("WorkspacesListPage").get_by_label("row").all_inner_texts() + if not texts: + page.get_by_test_id("WorkspacesListPage").get_by_role("button", name="New workspace").first.click() + else: + page.get_by_test_id("WorkspacesListPage").get_by_label("row").first.click() + + # Enable workflows, rules, and tags, if not already enabled + page.get_by_test_id("WorkspaceInitialPage").get_by_role("menuitem", name="More features").click() + ws_workflows = page.get_by_test_id("WorkspaceMoreFeaturesPage").get_by_label("Configure how spend is approved") + if not ws_workflows.is_checked(): + ws_workflows.click() + ws_rules = page.get_by_test_id("WorkspaceMoreFeaturesPage").get_by_label("Require receipts, flag high spend") + if not ws_rules.is_checked(): + ws_rules.click() + if page.get_by_test_id("workspaceUpgradePage").is_visible(): + page.get_by_test_id("workspaceUpgradePage").get_by_role("button", name="Upgrade").click() + page.get_by_test_id("workspaceUpgradePage").get_by_role("button", name="Got it").click() + ws_tags = page.get_by_test_id("WorkspaceMoreFeaturesPage").get_by_label("Classify costs and track billable") + if not ws_tags.is_checked(): + ws_tags.click() + + # Enable approvals, if not already enabled + page.get_by_test_id("WorkspaceInitialPage").get_by_role("menuitem", name="Workflows").click() + ws_approvals = page.get_by_test_id("WorkspacePageWithSections").get_by_label("Require additional approval") + if not ws_approvals.is_checked(): + ws_approvals.click() + + # Delete, if the tag already exists + tag_name = "Tag 1" + page.get_by_test_id("WorkspaceInitialPage").get_by_role("menuitem", name="Tags").click() + tag = page.get_by_test_id("WorkspaceTagsPage").get_by_role("button", name=tag_name).first + if tag.is_visible(): + tag.click() + page.get_by_test_id("TagSettingsPage").get_by_role("menuitem", name="Delete").click() + page.get_by_role("button", name="Delete").click() + + # Create tag + page.get_by_test_id("WorkspaceTagsPage").get_by_role("button", name="Add tag").click() + page.get_by_test_id("CreateTagPage").get_by_role("textbox", name="Name").fill(tag_name) + page.get_by_test_id("CreateTagPage").get_by_role("button", name="Save").click() + + # Assign approver to the tag + tag.click() + page.get_by_test_id("TagSettingsPage").get_by_text("Approver").click() + page.get_by_test_id("TagApproverPage").get_by_role("button", name=user_name).click() + + # Verify approver field in tag editor shows user name + expect( + page.get_by_test_id("TagSettingsPage").get_by_role("menuitem", name=user_name), + "User name should be visible in the approver field", + ).to_be_visible(timeout=2000) + finally: + # Stop tracing and export the trace + trace_path = "/app/expensify/user_tool/output_browser1.zip" + context.tracing.stop(path=trace_path) + trace_cleaner(trace_path) + context.close() + browser.close() + + +if __name__ == "__main__": + test_approver_field_in_tag_editor_shows_user_name()