Files
movim-rs/tests/e2e/browser_muji.py
T
2026-10-24 14:03:52 +07:00

104 lines
4.5 KiB
Python

"""Muji (XEP-0272) group call between three browsers in a group chat."""
import asyncio, time
from playwright.async_api import async_playwright
import sys
from browser import login, BASE, OUT
VIDEO = 'true' if '--video' in sys.argv else 'false'
async def open_room(page, room):
await page.evaluate(f"Chat_ajaxGetRoom('{room}')")
await page.wait_for_selector("#chat_textarea", timeout=15000)
await page.wait_for_timeout(1500)
async def join_from_lobby(page):
await page.wait_for_selector("#lobby_start:not(.disabled)", timeout=15000)
await page.click("#lobby_start")
async def sessions(page):
return await page.evaluate(
"Object.fromEntries(Object.entries(MovimJingles.sessions || {}).map(([j, s]) => [j, s.pc && s.pc.connectionState]))"
)
async def main():
room = f"call{int(time.time())}@conference.localhost"
async with async_playwright() as p:
browser = await p.chromium.launch(args=["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream"])
users = [("alice", "alicepass"), ("bob", "bobpass"), ("carol", "carolpass")]
pages, errors = {}, []
for name, password in users:
ctx, page, err = await login(browser, f"{name}@localhost", password, f"muji{name}")
await ctx.grant_permissions(["microphone", "camera"], origin=BASE)
pages[name] = page
await page.evaluate("""
window.addEventListener('unhandledrejection', e => console.error('REJECTION', e.reason && e.reason.stack));
window.addEventListener('error', e => console.error('ERROR', e.error && e.error.stack));
""")
errors.append(err)
alice, bob, carol = pages["alice"], pages["bob"], pages["carol"]
# Alice creates a group chat and invites the others, who join it
await alice.evaluate(f"""RoomsUtils_ajaxAddCreate({{
jid: {{value: '{room}'}}, name: {{value: 'Call room'}}, nick: {{value: 'alice'}},
type: {{value: 'groupchat'}}, autojoin: {{value: true}}, pinned: {{value: false}},
notify: {{value: 'always'}}
}})""")
await alice.wait_for_timeout(3000)
for name in ("bob", "carol"):
await alice.evaluate(f"RoomsUtils_ajaxInvite({{to: {{value: '{room}'}}, invite: {{value: '{name}@localhost'}}}})")
await alice.wait_for_timeout(1500)
for name in ("bob", "carol"):
await pages[name].evaluate(f"""RoomsUtils_ajaxAddConfirm({{
jid: {{value: '{room}'}}, name: {{value: 'Call room'}}, nick: {{value: '{name}'}},
autojoin: {{value: true}}, pinned: {{value: false}}, notify: {{value: 'on-mention'}}
}})""")
await alice.wait_for_timeout(3000)
for page in pages.values():
await open_room(page, room)
await alice.screenshot(path=f"{OUT}/muji_0_header.png")
# Alice starts the call
await alice.evaluate(f"Visio_ajaxGetMujiLobby('{room}', true, {VIDEO})")
await join_from_lobby(alice)
await alice.wait_for_timeout(3000)
await alice.screenshot(path=f"{OUT}/muji_1_alice_waiting.png")
await bob.screenshot(path=f"{OUT}/muji_1_bob_header.png")
print("bob sees a call to join:", await bob.locator("button.oppose.color.blue").count() > 0)
# Bob then Carol join
for name, page in (("bob", bob), ("carol", carol)):
button = page.locator("button.oppose.color.blue").first
try:
await button.click(timeout=10000)
except Exception:
await page.screenshot(path=f"{OUT}/muji_fail_{name}.png")
print(name, "header:", await page.content())
raise
await join_from_lobby(page)
await page.wait_for_timeout(6000)
print(f"after {name} joined:", {n: await sessions(pg) for n, pg in pages.items()})
for name, page in pages.items():
await page.screenshot(path=f"{OUT}/muji_2_{name}.png")
print(name, "sessions:", await sessions(page))
print("JS errors before leaving:", sum(len(e) for e in errors))
# Carol leaves, the others keep talking
await carol.evaluate(f"Visio_ajaxLeaveMuji('{room}')")
await alice.wait_for_timeout(3000)
print("after carol left, alice sessions:", await sessions(alice))
print("carol sessions:", await sessions(carol))
await alice.screenshot(path=f"{OUT}/muji_3_alice.png")
for err in errors:
for e in err:
print(e)
await browser.close()
asyncio.run(main())