diff --git a/moli-benchmark/README.md b/moli-benchmark/README.md
index 28d54f3df0..7d39647285 100644
--- a/moli-benchmark/README.md
+++ b/moli-benchmark/README.md
@@ -130,7 +130,7 @@ them. The runner waits for load, fonts, two animation frames, and removal of
`crashtest` with zero subtests. An outstanding wait remains a timeout, and a
renderer crash is reported even when the browser process stays alive.
-Run testdriver input cases explicitly with `--mode cdp`.
+Explicit cases that reference `testdriver.js` use CDP in `--mode auto`.
The CDP runner delivers trusted keyboard and mouse/pen input on an independent
connection, so input can finish while a harness probe awaits a JavaScript
promise. It supports `click`, ASCII and WebDriver special keys in `send_keys`,
diff --git a/moli-benchmark/moli_benchmark/wpt_cross/__main__.py b/moli-benchmark/moli_benchmark/wpt_cross/__main__.py
index 90d3e86f20..2ba4d7c55f 100644
--- a/moli-benchmark/moli_benchmark/wpt_cross/__main__.py
+++ b/moli-benchmark/moli_benchmark/wpt_cross/__main__.py
@@ -28,6 +28,7 @@ import time
from collections import Counter
from pathlib import Path
from typing import Any
+from urllib.parse import urlsplit
from .case_set import (
ANY_JS_GLOBAL_CHOICES,
@@ -57,6 +58,22 @@ from ..config import clear_current_proxy_env
REPO_CASE_LIST_DIR = Path(__file__).resolve().parents[2] / "wpt-cross-current"
WPT_CROSS_CASE_TIMEOUT_SECONDS = 120.0
WPT_CROSS_PARALLELISM = 50
+
+
+def _case_references_testdriver(wpt_root: Path, case: WptCase) -> bool:
+ path = urlsplit(case.case_path).path.lstrip("/")
+ for suffix, source_suffix in ((".any.html", ".any.js"), (".window.html", ".window.js")):
+ if path.endswith(suffix):
+ path = path.removesuffix(suffix) + source_suffix
+ break
+ source = (wpt_root / path).resolve()
+ try:
+ source.relative_to(wpt_root.resolve())
+ return b"/resources/testdriver" in source.read_bytes()
+ except (OSError, ValueError):
+ return False
+
+
WPT_CROSS_PROFILES = (
"default",
"layout-testharness",
@@ -664,7 +681,13 @@ def main(argv: list[str] | None = None) -> int:
if has_crashtests and args.mode == "cli":
print("error: crashtests require CDP mode to observe readiness and crashes", file=sys.stderr)
return 4
- requires_cdp = fixed_layout_viewport or has_crashtests
+ native_input_required = args.mode != "cdp" and any(
+ _case_references_testdriver(args.wpt_root, case) for case in cases
+ )
+ if native_input_required and args.mode == "cli":
+ print("error: testdriver cases require CDP mode for native input", file=sys.stderr)
+ return 4
+ requires_cdp = fixed_layout_viewport or has_crashtests or native_input_required
if fixed_layout_viewport and args.mode == "cli":
print(
"error: layout profiles and reftests require CDP mode for fixed viewport screenshots",
diff --git a/moli-benchmark/tests/test_wpt_native_input.py b/moli-benchmark/tests/test_wpt_native_input.py
index 10b2793827..3dbbd0c496 100644
--- a/moli-benchmark/tests/test_wpt_native_input.py
+++ b/moli-benchmark/tests/test_wpt_native_input.py
@@ -9,6 +9,7 @@ from types import SimpleNamespace
from unittest.mock import AsyncMock
from moli_benchmark.raw_cdp import RawCdpConnectionClosed
+from moli_benchmark.wpt_cross.__main__ import _case_references_testdriver
from moli_benchmark.wpt_cross.case_set import WptCase
from moli_benchmark.wpt_cross.native_input import NativeInput, Pointer, key_description
@@ -173,6 +174,17 @@ class NativeInputTests(unittest.IsolatedAsyncioTestCase):
class NativeInputSelectionTests(unittest.TestCase):
+ def test_testdriver_detection_in_html_and_generated_variants(self):
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory)
+ (root / "input.html").write_text('')
+ (root / "keys.any.js").write_text('// META: script=/resources/testdriver.js\n')
+ (root / "plain.html").write_text('')
+ self.assertTrue(_case_references_testdriver(root, WptCase("input.html?variant")))
+ self.assertTrue(_case_references_testdriver(root, WptCase("keys.any.html?variant")))
+ self.assertFalse(_case_references_testdriver(root, WptCase("plain.html")))
+ self.assertFalse(_case_references_testdriver(root, WptCase("../input.html")))
+
def test_special_keys_preserve_physical_location(self):
self.assertEqual((key_description("\ue007").code, key_description("\ue007").location), ("NumpadEnter", 3))
self.assertEqual((key_description("\ue050").code, key_description("\ue050").location), ("ShiftRight", 2))