test: four-rung suite that asserts on decoded pixels, not log lines

130 tests, ~20s, 94% coverage. Four rungs, each proving something the one
below it cannot:

  registry   admission, fan-out, signal authorization and teardown, no I/O
  wire       camelCase round-trip, malformed frames, WebSocket lifecycle
  e2e        real capture -> encode -> SRTP -> decode -> painted frames
  realdisplay the actual X11 capture backend on a private Xvfb display

The e2e rung drives Chromium's fake media device, which produces a genuine
moving 1280x720 monitor stream, so the assertion is that a watcher's <video>
has a size and that its pixels change over time -- a frozen or never-started
peer connection fails the suite, which a "signal arrived" assertion would
not have caught.

Findings encoded as flags and comments, because each cost a debugging cycle:
the headless shell has no media stack at all (use channel="chromium");
mediaDevices is undefined off a secure context (serve over 127.0.0.1); and
--use-fake-ui-for-media-stream breaks real X11 capture by approving the
request without ever selecting a source, so the realdisplay suite selects
the source explicitly instead.

The realdisplay fixture strips WAYLAND_DISPLAY and DBUS_SESSION_BUS_ADDRESS
from the browser environment. Without that, a headed Chromium reaches
xdg-desktop-portal, mirrors the developer's actual desktop and raises a
permission dialog on their real screen -- which is exactly what happened
before this was isolated. Skipped unless MIRROR_REALDISPLAY=1.

Also guards the frontend's structure: scripts must parse as ES modules,
every id a script looks up must exist in its page, ids must not collide
across pages that share one stylesheet, and nothing may load from a CDN.

LLM-Generated: true
This commit is contained in:
2026-11-01 16:54:28 -05:00
parent 555fc1c3b4
commit 7359ee4e07
10 changed files with 1738 additions and 0 deletions
View File
+173
View File
@@ -0,0 +1,173 @@
"""Fixtures for the browser end-to-end suite.
The capture flags matter: with a fake UI and a fake device, Chromium answers
`getDisplayMedia()` with a real, *moving* 1280x720 monitor stream. That means
these tests exercise the genuine capture -> encode -> SRTP -> decode -> paint
path rather than a stubbed-out media source.
"""
from __future__ import annotations
import os
import socket
import subprocess
import sys
import time
from pathlib import Path
import pytest
from playwright.sync_api import expect, sync_playwright
pytestmark = pytest.mark.e2e
REPO_ROOT = Path(__file__).resolve().parents[2]
CHROMIUM_ARGS = [
"--use-fake-ui-for-media-stream",
"--use-fake-device-for-media-stream",
"--use-fake-device-for-audio-capture",
"--autoplay-policy=no-user-gesture-required",
# Two Chromium instances must each get their own UDP ports; never proxy.
"--no-sandbox",
"--disable-dev-shm-usage",
"--no-proxy-server",
]
def _free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
probe.bind(("127.0.0.1", 0))
return probe.getsockname()[1]
@pytest.fixture(scope="session")
def base_url() -> str:
"""A real `mirror serve` process on a real port — not a test double."""
import httpx
port = _free_port()
process = subprocess.Popen(
[
sys.executable,
"-m",
"mirror",
"serve",
"--host",
"127.0.0.1",
"--port",
str(port),
"--log-level",
"warning",
],
cwd=REPO_ROOT,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
env={
**os.environ,
"MIRROR_ICE_SERVERS": "",
"PYTHONUNBUFFERED": "1",
# A stray DEBUGPY in the developer's shell would stall the server.
"DEBUGPY": "0",
},
)
url = f"http://127.0.0.1:{port}"
deadline = time.time() + 25
last_error: Exception | None = None
while time.time() < deadline:
if process.poll() is not None:
output = process.stdout.read() if process.stdout else ""
raise RuntimeError(f"mirror serve exited early ({process.returncode}):\n{output}")
try:
if httpx.get(f"{url}/healthz", timeout=1.0).status_code == 200:
break
except Exception as exc: # still booting
last_error = exc
time.sleep(0.15)
else:
process.terminate()
raise RuntimeError(f"mirror serve never came up: {last_error}")
yield url
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired: # pragma: no cover
process.kill()
@pytest.fixture(scope="session")
def browser():
with sync_playwright() as playwright:
# channel="chromium" = the full Chromium binary in new headless mode.
# The trimmed "headless shell" has no media stack at all and hides
# navigator.mediaDevices entirely.
instance = playwright.chromium.launch(channel="chromium", headless=True, args=CHROMIUM_ARGS)
yield instance
instance.close()
@pytest.fixture
def context(browser):
"""One browser context == one device. Closed after every test."""
created = browser.new_context(viewport={"width": 1100, "height": 720})
yield created
created.close()
@pytest.fixture
def page(context):
return context.new_page()
def start_sharing(page) -> None:
page.locator("#start").click()
expect(page.locator("body")).to_have_attribute("data-live", "on", timeout=15_000)
def stop_sharing(page) -> None:
page.locator("#stop").click()
expect(page.locator("body")).to_have_attribute("data-live", "off", timeout=10_000)
# Returns {width, height, currentTime, distinct} for the first <video> matching.
FRAME_PROBE = """
async (selector) => {
const video = document.querySelector(selector);
if (!video) return {missing: true};
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 32;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const seen = new Set();
for (let i = 0; i < 8; i++) {
await new Promise((resolve) => setTimeout(resolve, 120));
try { ctx.drawImage(video, 0, 0, 48, 32); } catch { /* not ready yet */ }
const data = ctx.getImageData(0, 0, 48, 32).data;
let hash = 0;
for (let j = 0; j < data.length; j += 4) {
hash = ((hash * 31) + data[j] + data[j + 1] * 3 + data[j + 2] * 7) >>> 0;
}
seen.add(hash);
}
return {
width: video.videoWidth,
height: video.videoHeight,
currentTime: video.currentTime,
paused: video.paused,
distinct: seen.size,
};
}
"""
def frames_matching(page, selector: str, attempts: int = 10) -> dict:
"""Poll until real, changing pixels show up (or give up and return last)."""
result: dict = {}
for _ in range(attempts):
result = page.evaluate(FRAME_PROBE, selector)
if result.get("distinct", 0) >= 2 and result.get("width", 0) > 0:
return result
time.sleep(0.4)
return result
+269
View File
@@ -0,0 +1,269 @@
"""End-to-end: a real `mirror serve`, real Chromium, real captured frames.
Every assertion about "it works" is made on pixels that reached the viewer's
<video>, not on log lines. If the media path breaks, these tests break.
"""
from __future__ import annotations
import re
import time
import pytest
from playwright.sync_api import expect
from .conftest import frames_matching, start_sharing, stop_sharing
pytestmark = [pytest.mark.e2e, pytest.mark.timeout(180)]
@pytest.fixture
def device(base_url, browser, request):
"""Open a page as its own device (isolated context, fresh peer id)."""
opened = []
def _open(path: str = "/", errors: list | None = None):
context = browser.new_context(viewport={"width": 1100, "height": 720})
opened.append(context)
request.addfinalizer(context.close)
page = context.new_page()
if errors is not None:
page.on("pageerror", lambda error: errors.append(str(error)))
page.goto(f"{base_url}{path}", wait_until="domcontentloaded")
expect(page.locator("#net")).to_have_attribute("data-state", "online", timeout=10_000)
return page
return _open
def tile_ids(page) -> list[str]:
return page.locator(".tile").evaluate_all("els => els.map(e => e.dataset.stream)")
class TestShareThenWatch:
def test_a_shared_window_reaches_a_viewer_as_moving_pixels(self, device):
errors: list = []
sharer = device("/mirror", errors)
start_sharing(sharer)
expect(sharer.locator("#stat-resolution")).to_have_text(
re.compile(r"\d{3,4}\s.\s\d{3,4}"), timeout=10_000
)
expect(sharer.locator("#stat-surface")).to_contain_text("Screen", timeout=5_000)
viewer = device("/watch", errors)
expect(viewer.locator(".tile")).to_have_count(1, timeout=15_000)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
frames = frames_matching(viewer, ".tile video")
assert not frames.get("missing"), "no <video> element in the tile"
assert frames["width"] > 0 and frames["height"] > 0, f"no decoded frame size: {frames}"
assert frames["distinct"] >= 2, f"video is frozen: {frames}"
# The sharer learns that someone is watching.
expect(sharer.locator("#viewer-count")).to_have_text("1", timeout=10_000)
assert errors == [], f"uncaught browser errors: {errors}"
def test_clicking_a_tile_takes_it_on_stage(self, device):
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
viewer.locator(".tile").click()
expect(viewer.locator("body")).to_have_class(re.compile("staged"), timeout=5_000)
expect(viewer.locator("#watch-stage .tile")).to_have_count(1)
expect(viewer.locator("#watch-stage video")).to_have_count(1)
# Still moving while staged — staging must not restart the peer connection.
frames = frames_matching(viewer, "#watch-stage video")
assert frames["distinct"] >= 2, f"staged video froze: {frames}"
# And the mirror survives the stage: the sharer still has one viewer.
expect(sharer.locator("#viewer-count")).to_have_text("1", timeout=10_000)
def test_stopping_the_share_clears_the_wall(self, device):
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile")).to_have_count(1, timeout=15_000)
stop_sharing(sharer)
expect(viewer.locator(".tile")).to_have_count(0, timeout=10_000)
expect(viewer.locator("#empty")).to_be_visible()
expect(viewer.locator("body")).not_to_have_class(re.compile("staged"))
def test_closing_the_sharer_tab_clears_the_wall(self, device):
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile")).to_have_count(1, timeout=15_000)
sharer.close()
expect(viewer.locator(".tile")).to_have_count(0, timeout=10_000)
class TestChromeVisibility:
"""The page must never advertise a control that does not apply to its state."""
def test_the_idle_share_page_offers_only_a_start(self, device):
sharer = device("/mirror")
expect(sharer.locator("#start")).to_be_visible()
expect(sharer.locator("#placeholder")).to_be_visible()
expect(sharer.locator("#stop")).not_to_be_visible()
expect(sharer.locator("#livetag")).not_to_be_visible()
start_sharing(sharer)
expect(sharer.locator("#stop")).to_be_visible()
expect(sharer.locator("#livetag")).to_be_visible()
expect(sharer.locator("#start")).not_to_be_visible()
expect(sharer.locator("#placeholder")).not_to_be_visible()
def test_exit_only_appears_on_the_tile_that_is_on_stage(self, device):
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile")).to_have_count(1, timeout=15_000)
expect(viewer.locator(".tile .exit")).not_to_be_visible()
viewer.locator(".tile").click()
expect(viewer.locator("#watch-stage .exit")).to_be_visible()
viewer.locator("#watch-stage .exit").click()
expect(viewer.locator("body")).not_to_have_class(re.compile("staged"), timeout=5_000)
expect(viewer.locator(".tile .exit")).not_to_be_visible()
# Leaving the stage must not have disturbed the stream.
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=20_000)
class TestManyToMany:
def test_one_mirror_fans_out_to_several_viewers(self, device):
errors: list = []
sharer = device("/mirror", errors)
start_sharing(sharer)
viewers = [device("/watch", errors) for _ in range(3)]
for viewer in viewers:
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
expect(sharer.locator("#viewer-count")).to_have_text("3", timeout=15_000)
expect(sharer.locator("#audience li")).to_have_count(3, timeout=10_000)
for viewer in viewers:
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"a viewer froze: {frames}"
# One viewer leaving must not disturb the others.
viewers[0].close()
expect(sharer.locator("#viewer-count")).to_have_text("2", timeout=15_000)
for viewer in viewers[1:]:
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"collateral damage: {frames}"
assert errors == [], f"uncaught browser errors: {errors}"
def test_several_mirrors_land_on_one_wall(self, device):
errors: list = []
sharers = []
for _ in range(2):
page = device("/mirror", errors)
start_sharing(page)
sharers.append(page)
viewer = device("/watch", errors)
expect(viewer.locator(".tile")).to_have_count(2, timeout=15_000)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(2, timeout=30_000)
ids = tile_ids(viewer)
assert len(ids) == 2 and len(set(ids)) == 2, "tiles must be distinct mirrors"
# Stage the second mirror, then jump to the first.
viewer.locator(".tile").nth(1).click()
expect(viewer.locator("#watch-stage .tile")).to_have_count(1)
staged = viewer.locator("#watch-stage .tile").get_attribute("data-stream")
assert staged == ids[1]
viewer.locator("#watch-stage .exit").click()
expect(viewer.locator("body")).not_to_have_class(re.compile("staged"), timeout=5_000)
viewer.locator(".tile").nth(0).click()
expect(viewer.locator("#watch-stage .tile")).to_have_count(1)
assert viewer.locator("#watch-stage .tile").get_attribute("data-stream") == ids[0]
# Both mirrors are still alive and untouched by the staging gymnastics.
expect(viewer.locator(".tile[data-state='live']")).to_have_count(2, timeout=20_000)
assert errors == [], f"uncaught browser errors: {errors}"
def test_stopping_one_mirror_leaves_the_other_running(self, device):
first = device("/mirror")
start_sharing(first)
second = device("/mirror")
start_sharing(second)
viewer = device("/watch")
expect(viewer.locator(".tile[data-state='live']")).to_have_count(2, timeout=30_000)
stop_sharing(first)
expect(viewer.locator(".tile")).to_have_count(1, timeout=10_000)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=20_000)
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"the surviving mirror froze: {frames}"
class TestTimingAndRecovery:
def test_a_viewer_already_on_the_wall_sees_a_late_mirror(self, device):
viewer = device("/watch")
expect(viewer.locator("#empty")).to_be_visible()
sharer = device("/mirror")
start_sharing(sharer)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"late mirror did not animate: {frames}"
def test_a_reloaded_viewer_recovers_the_live_mirror(self, device):
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
viewer.reload(wait_until="domcontentloaded")
expect(viewer.locator("#net")).to_have_attribute("data-state", "online", timeout=10_000)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"reload did not restore motion: {frames}"
expect(sharer.locator("#viewer-count")).to_have_text("1", timeout=15_000)
def test_the_index_page_counts_what_is_live(self, device):
index = device("/")
expect(index.locator("#livebar")).to_contain_text("No mirrors live", timeout=10_000)
sharer = device("/mirror")
start_sharing(sharer)
expect(index.locator("#livebar")).to_contain_text("1 mirror", timeout=10_000)
class TestRosterTruthfulness:
def test_the_api_agrees_with_what_the_browser_shows(self, device, base_url):
import httpx
sharer = device("/mirror")
start_sharing(sharer)
viewer = device("/watch")
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
# Give the stats ticker a beat, then compare server truth to pixels.
time.sleep(1.0)
payload = httpx.get(f"{base_url}/api/streams", timeout=5).json()
assert payload["stats"]["mirrors"] == 1
assert payload["stats"]["watching"] == 1
mirror = payload["mirrors"][0]
assert mirror["width"] and mirror["height"]
assert mirror["displaySurface"] in ("monitor", "window", "browser")
+296
View File
@@ -0,0 +1,296 @@
"""The Linux-native capture path: a real X11 screen, no fake media devices.
The rest of the suite drives Chromium's fake capture device, which is
deterministic but synthetic. This module is the counterweight: it starts its own
Xvfb server, runs a *headed* Chromium on it, and asks that browser to mirror the
whole monitor through Chromium's real X11 capture backend. A second Chromium
process — a different machine as far as WebRTC cares — watches it.
Skipped unless ``MIRROR_REALDISPLAY=1``, because it needs an X server binary and
a headed browser::
MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay
"""
from __future__ import annotations
import os
import shutil
import socket
import subprocess
import time
import httpx
import pytest
from playwright.sync_api import expect, sync_playwright
pytestmark = [
pytest.mark.e2e,
pytest.mark.realdisplay,
pytest.mark.timeout(240),
pytest.mark.skipif(shutil.which("Xvfb") is None, reason="Xvfb is not installed"),
pytest.mark.skipif(
os.environ.get("MIRROR_REALDISPLAY", "") not in {"1", "true", "yes"},
reason="set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend",
),
]
# Deliberately not 16:9: Chromium's fake device reports 1280x720 no matter what,
# so an aspect ratio of exactly 1280/800 is a fingerprint of the real screen.
XVFB_GEOMETRY = "1280x800x24"
XVFB_ASPECT = 1280 / 800
FAKE_DEVICE_SIZE = (1280, 720)
# Flags learned the hard way, and worth keeping written down:
#
# * No `--use-fake-device-for-media-stream`: that is exactly what we are trying
# not to use here.
# * No `--use-fake-ui-for-media-stream` either. It short-circuits the picker
# *before* the X11 backend selects a source, and every capture then dies with
# `NotReadableError: Could not start video source` in ~55ms. Choosing the
# source with `--auto-select-desktop-capture-source` grants and selects in one
# step, which is what makes unattended desktop capture work.
# * `--ozone-platform=x11` keeps Chromium on its native X11 capturer instead of
# xdg-desktop-portal/PipeWire. Combined with `browser_env()` this makes a
# permission dialog on the developer's own session impossible.
REAL_CAPTURE_ARGS = [
"--auto-select-desktop-capture-source=Entire screen",
"--ozone-platform=x11",
"--autoplay-policy=no-user-gesture-required",
"--no-sandbox",
"--disable-dev-shm-usage",
"--no-proxy-server",
]
# Never reachable: without a session bus and without a Wayland socket there is no
# portal to ask, so these tests cannot interrupt a human.
UNREACHABLE_SESSION_VARS = (
"WAYLAND_DISPLAY",
"DBUS_SESSION_BUS_ADDRESS",
"XDG_CURRENT_DESKTOP",
"XDG_BACKEND",
)
def browser_env(display: str | None = None) -> dict[str, str]:
"""An environment that can only reach the display this test owns."""
env = {key: value for key, value in os.environ.items() if key not in UNREACHABLE_SESSION_VARS}
env["XDG_SESSION_TYPE"] = "x11"
env["MIRROR_ICE_SERVERS"] = ""
if display is None:
env.pop("DISPLAY", None)
else:
env["DISPLAY"] = display
return env
# Starts a pixel-sampling loop without blocking, so the test can drive motion on
# the captured screen while the watcher is measuring it.
PROBE = """() => {
const video = document.querySelector('.tile video');
const canvas = document.createElement('canvas');
canvas.width = 96;
canvas.height = 60;
const ctx = canvas.getContext('2d', {willReadFrequently: true});
window.__probe = (async () => {
const seen = new Set();
for (let i = 0; i < 14; i++) {
await new Promise((r) => setTimeout(r, 120));
try { ctx.drawImage(video, 0, 0, 96, 60); } catch {}
const d = ctx.getImageData(0, 0, 96, 60).data;
let h = 0;
for (let j = 0; j < d.length; j += 4) {
h = ((h * 31) + d[j] + d[j + 1] * 3 + d[j + 2] * 7) >>> 0;
}
seen.add(h);
}
return {distinct: seen.size, width: video.videoWidth, height: video.videoHeight};
})();
return 'started';
}"""
def _free_display() -> str:
for number in range(90, 120):
path = f"/tmp/.X11-unix/X{number}"
if os.path.exists(path):
continue
with socket.socket(socket.AF_UNIX) as probe:
try:
probe.connect(path)
except OSError:
return f":{number}"
else:
continue
raise RuntimeError("no free X display in :90..:119")
def _socket_path(display: str) -> str:
"""`:90` -> `/tmp/.X11-unix/X90`, the file whose existence means "ready"."""
return f"/tmp/.X11-unix/X{display.lstrip(':')}"
@pytest.fixture(scope="module")
def x_display():
display = _free_display()
ready = _socket_path(display)
server = subprocess.Popen(
["Xvfb", display, "-screen", "0", XVFB_GEOMETRY, "-nolisten", "tcp"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
deadline = time.time() + 20
while time.time() < deadline:
if os.path.exists(ready):
break
if server.poll() is not None: # pragma: no cover
raise RuntimeError(f"Xvfb exited immediately with code {server.returncode}")
time.sleep(0.15)
else: # pragma: no cover
server.terminate()
raise RuntimeError(f"Xvfb never created {ready}")
yield display
server.terminate()
try:
server.wait(timeout=5)
except subprocess.TimeoutExpired: # pragma: no cover
server.kill()
@pytest.fixture(scope="module")
def browsers(x_display):
"""Two Chromium *processes* from one Playwright driver.
The sharer is headed and lives on the Xvfb display, so what it captures is a
genuine desktop. The watcher is headless: it never touches the display, which
is exactly why it can be a separate process.
"""
previous = os.environ.get("DISPLAY")
os.environ["DISPLAY"] = x_display
try:
with sync_playwright() as playwright:
sharer = playwright.chromium.launch(
channel="chromium",
headless=False,
args=REAL_CAPTURE_ARGS,
env=browser_env(x_display),
)
watcher = playwright.chromium.launch(
channel="chromium",
headless=True,
args=[
"--no-sandbox",
"--disable-dev-shm-usage",
"--no-proxy-server",
"--ozone-platform=x11",
],
env=browser_env(),
)
try:
yield {"sharer": sharer, "watcher": watcher}
finally:
sharer.close()
watcher.close()
finally:
if previous is not None:
os.environ["DISPLAY"] = previous
else: # pragma: no cover
os.environ.pop("DISPLAY", None)
@pytest.fixture
def share_page(browsers, base_url):
page = browsers["sharer"].new_context(viewport={"width": 1200, "height": 760}).new_page()
page.goto(f"{base_url}/mirror", wait_until="domcontentloaded")
expect(page.locator("#net")).to_have_attribute("data-state", "online", timeout=20_000)
yield page
page.close()
@pytest.fixture
def watch_page(browsers, base_url):
page = browsers["watcher"].new_context().new_page()
page.goto(f"{base_url}/watch", wait_until="domcontentloaded")
expect(page.locator("#net")).to_have_attribute("data-state", "online", timeout=20_000)
yield page
page.close()
class TestRealX11Capture:
def test_the_real_desktop_is_captured_not_a_synthetic_one(self, base_url, share_page):
errors: list[str] = []
share_page.on("pageerror", lambda error: errors.append(str(error)))
share_page.locator("#start").click()
expect(share_page.locator("body")).to_have_attribute("data-live", "on", timeout=40_000)
settings = share_page.evaluate(
"""() => {
const track = document.querySelector('#preview').srcObject.getVideoTracks()[0];
return {label: track.label, ...track.getSettings()};
}"""
)
assert settings["displaySurface"] == "monitor", f"not a monitor capture: {settings}"
assert settings["label"], "a real capture always names its source"
assert not settings["label"].startswith("screen:-"), (
f"{settings['label']} is Chromium's synthetic capture device"
)
size = (settings["width"], settings["height"])
assert size != FAKE_DEVICE_SIZE, (
f"got exactly {size}: that is Chromium's fake capture device, not the X11 screen"
)
assert settings["width"] >= 640, f"implausibly small capture: {settings}"
# Chromium scales a monitor capture to the capturing window, so compare
# the aspect ratio: 1280x800 in, 1200x750 out is the real screen.
assert abs(settings["width"] / settings["height"] - XVFB_ASPECT) < 0.06, (
f"{size} does not match the {XVFB_GEOMETRY} desktop aspect "
f"({XVFB_ASPECT:.3f}); this is not our Xvfb screen"
)
# The roster must carry the real geometry, not a made-up one.
time.sleep(0.6)
mirror = httpx.get(f"{base_url}/api/streams", timeout=5).json()["mirrors"][0]
assert (mirror["width"], mirror["height"]) == size
assert mirror["displaySurface"] == "monitor"
assert errors == [], f"uncaught browser errors: {errors}"
def test_a_real_desktop_reaches_a_second_machine_and_moves(self, base_url, browsers):
share_page = (
browsers["sharer"].new_context(viewport={"width": 1200, "height": 760}).new_page()
)
share_page.goto(f"{base_url}/mirror", wait_until="domcontentloaded")
expect(share_page.locator("#net")).to_have_attribute("data-state", "online", timeout=20_000)
share_page.locator("#start").click()
expect(share_page.locator("body")).to_have_attribute("data-live", "on", timeout=40_000)
watch_page = browsers["watcher"].new_context().new_page()
watch_page.goto(f"{base_url}/watch", wait_until="domcontentloaded")
expect(watch_page.locator("#net")).to_have_attribute("data-state", "online", timeout=20_000)
expect(watch_page.locator(".tile[data-state='live']")).to_have_count(1, timeout=60_000)
# Start measuring on the watcher, then paint: cycling the captured
# machine's background is what a real presenter's screen does constantly.
assert watch_page.evaluate(PROBE) == "started"
for colour in ("#c81e1e", "#0b0d10", "#1e6ec8", "#0b0d10", "#1ec85a"):
share_page.evaluate("(colour) => { document.body.style.background = colour; }", colour)
time.sleep(0.28)
result = watch_page.evaluate("() => window.__probe")
assert result["width"] >= 640 and result["height"] >= 400, (
f"the watcher decoded no picture: {result}"
)
assert abs(result["width"] / result["height"] - XVFB_ASPECT) < 0.06, result
assert result["distinct"] >= 2, (
f"the watcher received a frozen frame: {result} — real desktop motion "
f"never made it across the peer connection"
)
# And the sharer agrees that someone is watching its desktop.
expect(share_page.locator("#viewer-count")).to_have_text("1", timeout=20_000)
# Stopping the share tears the mirror away for the watcher as well.
share_page.locator("#stop").click()
expect(watch_page.locator(".tile")).to_have_count(0, timeout=20_000)
watch_page.close()
share_page.close()