issues/227/user_tool.py (184 lines of code) (raw):
import sys, os
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, base_path)
import pytest_asyncio
import re
import time
import email
import pytest
import imaplib
from email.header import decode_header
from playwright.async_api import async_playwright, expect
from datetime import datetime, timezone
from utils.trace_cleaner import trace_cleaner
MAX_TRIES = 10
USERNAME = "expensify31+1943@gmail.com"
PASSWORD = ""
async def get_magic_code(user_email, password, retries=10, delay=10, since=None):
if since is None:
since = datetime.now(timezone.utc).replace(second=0, microsecond=0)
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
async def perform_first_time_user_setup(page):
login_time = datetime.now(timezone.utc).replace(second=0, microsecond=0)
phone_or_email_input = page.locator('input[type="email"]')
await expect(phone_or_email_input).to_be_visible()
await phone_or_email_input.fill(USERNAME)
continue_button = page.locator('button[tabindex="0"]')
await expect(continue_button).to_be_visible()
await continue_button.click()
join_button = page.locator('button[tabindex="0"]', has_text="Join")
if (await join_button.is_visible()):
await expect(continue_button).to_be_visible()
await continue_button.click()
await expect(page.locator("text=What do you want to do today?")).to_be_visible()
await page.locator("text='Track and budget expenses'").click()
first_name_input = page.locator('input[aria-label="First name"]')
await expect(first_name_input).to_be_visible()
await first_name_input.fill("Test")
last_name_input = page.locator('input[aria-label="Last name"]')
await expect(last_name_input).to_be_visible()
await last_name_input.fill("User")
continue_button = page.locator("text=Continue")
await expect(continue_button).to_be_visible()
await continue_button.click()
else:
await page.wait_for_timeout(3000)
otp = '123456'
await page.wait_for_timeout(5000)
validate_code_input = page.locator('input[autocomplete="one-time-code"]')
await expect(validate_code_input).to_be_visible()
await validate_code_input.fill(otp)
async def open_account_settings(page):
account_settings_button = page.locator("button[aria-label='My settings']")
await expect(account_settings_button).to_be_visible()
await account_settings_button.click()
async def open_workspaces_in_account_settings(page):
workspace = page.locator("div[role='menuitem'][aria-label='Workspaces']").get_by_text("Workspaces")
await expect(workspace).to_be_visible()
await workspace.click()
async def create_workspace(page):
create_workspace_button = await page.locator("button[aria-label='New workspace']").locator("visible=true").get_by_text("New workspace").all()
create_workspace_button = create_workspace_button[0]
await expect(create_workspace_button).to_be_visible()
await create_workspace_button.click()
async def invite_multiple_users_to_workspace(page):
more_features = page.locator("div[aria-label='Members'][role='menuitem']").locator("visible=true").get_by_text("Members")
await expect(more_features).to_be_visible()
await more_features.click()
invite_member_button = page.locator("button[data-tag='pressable']", has_text="Invite member").locator("visible=true")
await expect(invite_member_button).to_be_visible()
await invite_member_button.click()
invite_textbox = page.locator("input[aria-label='Name, email, or phone number']").locator("visible=true")
await invite_textbox.fill("abcd@gmail.com")
user_button = page.locator("button[aria-label='abcd@gmail.com']", has_text='abcd@gmail.com').locator("visible=true")
await expect(user_button).to_be_visible()
await user_button.click()
invite_textbox = page.locator("input[aria-label='Name, email, or phone number']").locator("visible=true")
await invite_textbox.fill("abcd1@gmail.com")
user_button = page.locator("button[aria-label='abcd1@gmail.com']", has_text='abcd1@gmail.com').locator("visible=true")
await expect(user_button).to_be_visible()
await user_button.click()
next_button = page.locator("button[data-tag='pressable']", has_text='Next').locator("visible=true").last
await expect(next_button).to_be_visible()
await next_button.click()
invite_button = page.locator("button[data-tag='pressable']", has_text='Invite').locator("visible=true").last
await expect(invite_button).to_be_visible()
await invite_button.click()
back_button = page.locator("button[aria-label='Back']").locator("visible=true").last
await expect(back_button).to_be_visible()
await back_button.click()
async def validate_correct_chat_name_visible(page):
inbox_page = page.locator("button[aria-label='Inbox']")
await expect(inbox_page).to_be_visible()
await inbox_page.click()
await page.wait_for_timeout(5000)
chat_button = page.locator('button[aria-label="Navigates to a chat"]', has_text="Test User's Workspace").last
await expect(chat_button).to_be_visible()
account_settings_button = page.locator("button[aria-label='My settings']")
await expect(account_settings_button).to_be_visible()
await account_settings_button.click()
troubleshoot = page.locator("div[role='menuitem'][aria-label='Troubleshoot']").get_by_text("Troubleshoot")
await expect(troubleshoot).to_be_visible()
await troubleshoot.click()
clear_cache = page.locator("div[aria-label='Clear cache and restart']")
await expect(clear_cache).to_be_visible()
await clear_cache.click()
clear_cache_confirmation = page.locator("button", has_text="Reset and refresh")
await expect(clear_cache_confirmation).to_be_visible()
await clear_cache_confirmation.click()
inbox_page = page.locator("button[aria-label='Inbox']")
await expect(inbox_page).to_be_visible()
await inbox_page.click()
await page.wait_for_timeout(2000)
chat_button = page.locator('button[aria-label="Navigates to a chat"]', has_text="Test User's Workspace").last
await expect(chat_button).to_be_visible()
chat_button = page.locator('button[aria-label="Navigates to a chat"]', has_text="Chat Report").last
await expect(chat_button).not_to_be_visible()
@pytest_asyncio.fixture
async def browser_context():
playwright = await async_playwright().start()
browser = await playwright.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=700
)
context = await browser.new_context()
page = await context.new_page()
await context.set_offline(False)
yield context, page # Provide both context and page to the test
await context.close()
await browser.close()
await playwright.stop()
@pytest.mark.asyncio
async def test_tags_disabled_button(browser_context):
context, page = browser_context # Unpack the context and page from the fixture
trace_path = "/app/expensify/user_tool/output_browser1.zip"
await context.tracing.start(screenshots=True, snapshots=True, sources=True)
try:
await page.goto("https://dev.new.expensify.com:8082/")
await perform_first_time_user_setup(page)
await open_account_settings(page)
await open_workspaces_in_account_settings(page)
await create_workspace(page)
await invite_multiple_users_to_workspace(page)
await validate_correct_chat_name_visible(page)
except Exception as e:
print("Test failed:", e)
raise e
finally:
await context.tracing.stop(path=trace_path)
trace_cleaner(trace_path)