Repository navigation
JCEF doesn't expose CefExecuteJavaScriptWithUserGestureForTests, blocking real onBeforePopup test coverage #11
Description
Activity
Root-caused and fixed. Not a JCEF/CEF bug, not fundamentally a "no real user gesture" limitation -- found by reading CEF's own internal test suite (`tests/ceftests/dialog_unittest.cc`) rather than guessing further.
CEF's own maintainers don't simulate a page-side `` click at all in their automated tests. Their `DialogTest.FileOpen`/`FileOpenCancel`/etc. (which run on Linux too, not just Windows) call `CefBrowserHost::RunFileDialog()` directly -- the C++ equivalent of `CefBrowser.runFileDialog()`, which this fork's Java API already exposes and which is not actually Windows-only despite `plan/windows-todo.md`'s earlier assumption. It routes through `CefDialogHandler::OnFileDialog` the same way a real click would.
Two prior JCEF attempts both used the wrong trigger:
- A JS-synthesized `.click()` on the file input -- never fired `onFileDialog` at all (Chromium deliberately blocks script-triggered file-picker opens).
- A real synthetic AWT `MouseEvent` (same technique that fixed onBeforeContextMenu never fires for a synthetic OSR right-click (root cause not yet isolated) #17's context menu) -- fired `onFileDialog`, but then needed a hard `SIGKILL` past 45s.
Switching to `browser.runFileDialog(...)` (CEF's own test technique) fixes it cleanly: `onFileDialog` fires, `callback.Cancel()` suppresses the real dialog before it's ever shown (exactly CEF's own test's pattern), and `CefRunFileDialogCallback.onFileDialogDismissed()` fires too. Confirmed safe across 3 repeated isolated runs -- no hang, no SIGKILL. Full suite: 167/167 passing.
- added a commit that references this issue
on Aug 30, 2026 Independently re-confirmed today (2026-08-30, separate session) via a fresh
test (CefLifeSpanPopupTest,@Disabled, commit cd504b4) before finding this
issue already existed. Went a bit further diagnostically: added a
document.titlechange inside theonclickhandler (observed via
CefDisplayHandler.onTitleChange) to distinguish "click never landed" from
"click landed but window.open() got blocked" -- confirmed the click does
land and theonclickhandler does run (title change observed in the log),
so it's specifically thewindow.open()->OnBeforePopupdispatch that
never happens, exactly matching this issue's diagnosis. Also tried a real
synthetic mouse click (samecanvas.dispatchEvent(MOUSE_PRESSED/RELEASED/ CLICKED)techniqueCefContextMenuTestalready uses successfully for
right-click) rather than just a bare inline<script>call, in case a real
user-gesture-shaped input event would satisfy the popup blocker on its own --
it didn't, consistent with this issue's conclusion that
CefExecuteJavaScriptWithUserGestureForTests(or an equivalent Java binding)
is genuinely needed, not just a "trigger from a synthetic gesture" workaround.Fixed -- and the root cause turned out to be different from what this issue was originally filed against. The
CefExecuteJavaScriptWithUserGestureForTestsbinding itself (native/CefTestHelper.cpp, java/tests/junittests/CefTestHelper.java) was real, working infrastructure, but it was never actually the blocker:native/life_span_handler.cpp'sOnBeforePopupunconditionally cancels+returns before ever reaching Java whenIsWindowRenderingDisabled()(i.e. for every OSR browser), regardless of what triggers thewindow.open()call underneath it.With #3 (windowed close hang) now fixed, switched
CefLifeSpanPopupTestto a windowed browser and it passes cleanly:onBeforePopupfires with the correct target URL and frame name and cancels the popup as asserted. The user-gesture binding is kept in place as real, CEF-verified infrastructure that may still be useful for other user-activation-gated coverage (e.g.onbeforeunloaddialogs) even though it wasn't the fix here.Details:
plan/tasks/20260903-06-issue11-user-gesture-test-helper.md(archived).🤖 Generated with Claude Code
Summary
CefLifeSpanHandler.onBeforePopup(native/life_span_handler.cpp) has no testcoverage, and can't easily get any: a script-initiated
window.open()call isblocked by Chromium's own popup blocker (no user gesture) before it ever reaches
OnBeforePopupat all, so a straightforward JUnit test (create a page whose scriptcalls
window.open(), assert the handler fires) fails with the handler simply neverinvoked -- not a JCEF bug, just an untestable-as-written scenario.
CEF's own C++ API has a purpose-built helper for exactly this:
(also declared in
include/capi/test/cef_test_helpers_capi.hfor the C API). Thislets test code execute JS as if it had a real user gesture attached, which is
exactly what's needed to make a
window.open()call actually reachOnBeforePopup/onBeforePopupinstead of being silently blocked upstream.JCEF does not currently bind this anywhere (
grep -rn "UserGestureForTests" java/ native-- no results). Exposing it would need: a new native_N.cpp/.hpair (ora method added to an existing one, e.g.
CefFrame_N), the matching Java method(probably on
CefFrame, gated to test/debug use given the name), and JNI headerregeneration per root
CLAUDE.md's native-side instructions.Impact
Low urgency -- this blocks test coverage for one handler method, not any
production functionality. Filed as part of the coverage-expansion push tracked in
#5. Once available, a real
BeforePopupTest(attempted and reverted this session --see plan/roadmap.md/findings.md) becomes straightforward: call the new binding to
trigger
window.open()with a synthetic user gesture, assertonBeforePopupfiresand (when it returns
true) that the popup is actually blocked.Repro / how this was found
Wrote
BeforePopupTest.javawith a page whose script calledwindow.open()directly (no user gesture) and asserted
onBeforePopupfires. It reliably failed:onBeforePopup was never invoked ==> expected: <true> but was: <false>. Confirmedvia CEF's own header comments (
cef_life_span_handler.h'sOnBeforePopupdoc:"...whether the popup was opened via explicit user gesture...") and the existence
of the above test-helper API that this is expected/by-design Chromium behavior, not
a bug in the test or in JCEF's existing bridge code.