#798 left RDM on for isMobile, as Playwright's Juggler does. RDM matches no real browser: Firefox for Android never runs it, and under touch emulation it drops a mouse click's pointer events, which no device does. Camoufox only has desktop identities, so an is_mobile context was a desktop UA, platform, fonts and GPU with devtools' mobile mode on top. Juggler now keeps inRDMPane off for every page, is_mobile included, and the isMobile plumbing #798 added is gone again. viewport-no-rdm requires is_mobile=True to keep the platform's scrollbars too. Both launchers warn instead (warnings.yml is_mobile): on new_page() / new_context(is_mobile=True) of a Camoufox browser, and on is_mobile passed to launch_options() for a persistent context. has_touch, device_scale_factor and viewport keep working without RDM. Upstream playwright-python skips its isMobile tests on Firefox in 1.61-1.63, so no skiplist entries are needed. On beta.31 with this Juggler in omni.ja, viewport-no-rdm passes: 12/12 px of scrollbar with no viewport, with a viewport, and with is_mobile, and a has_touch click fires pointerdown and pointerup. pythonlib 411 passed; typescript 584 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests
Two things live here, and neither is a copy of anyone else's suite.
patches/ — patch guards
One standalone script per shipped spoofing behaviour: isolated evaluate, trusted events, font spoofing, mouse trajectories, the touchscreen digitizer, and so on. Each exits 0 or 1 and drives the browser through the Python package.
These are the most direct evidence that a Firefox bump did not quietly neuter a patch that still applies cleanly — the failure a compile check cannot catch.
python3 -m ci.run_patch_guards --binary /path/to/camoufox-bin
python3 -m ci.run_patch_guards --binary /path/to/camoufox-bin --only isolated-evaluate
camoufox/ — Camoufox's own Playwright tests
Tests for behaviour upstream Playwright has no equivalent for, or asserts the
opposite of on purpose. ci/suite.py overlays them onto the upstream checkout
so they run against its harness. See camoufox/README.md for when to add one.
Where the Playwright suite went
This directory used to hold a fork of a ~v1.55-era playwright-python suite. It was deleted, because measuring it showed it was strictly weaker than running upstream's own suite:
- 73 of the 74 tests it skipped as "Not supported by Camoufox" pass when the same binary runs upstream's copy. The skips predated main-world execution and were never revisited; the suite was asserting that Camoufox was worse than it is.
- Of its passing tests, eight had no upstream counterpart. Six of those were
Camoufox-specific and are now the three modules in
camoufox/; the other two were tests upstream had since renamed. - Everything else was upstream code, one generation stale.
ci/run_playwright.py fetches playwright-python at the tag ci/versions.py
resolves for the browser under test, applies ci/skiplist.yml, and overlays
camoufox/. A suite that is re-fetched every run cannot go stale, and a
deliberate difference from upstream now has to be written down in the skiplist
with a reason instead of being encoded as a silent fork.
make tests # the whole suite
make tests headful=true # ... headed
python3 -m ci.run_playwright --binary /path/to/camoufox-bin --shard 3/6