Skip to content

test: add X11/Preedit browser E2E foundation with Playwright and xdotool - #479

Draft
naoNao89 wants to merge 6 commits into
LotusInputMethod:devfrom
naoNao89:test/browser-e2e-x11
Draft

test: add X11/Preedit browser E2E foundation with Playwright and xdotool#479
naoNao89 wants to merge 6 commits into
LotusInputMethod:devfrom
naoNao89:test/browser-e2e-x11

Conversation

@naoNao89

@naoNao89 naoNao89 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Adds browser E2E foundation tests for Lotus on X11/Xvfb using Playwright and xdotool.

Keystrokes are injected through X11 XTEST and the resulting text is asserted in the browser DOM. Lotus is built from the PR checkout and runs through a real Fcitx5 session.

Tests

  • Control: Positive & negative control verifying input goes through Lotus:
    • Active Lotus: ddđ
    • Deactivated Lotus (keyboard-us): dddd
    • Reactivated Lotus: ddđ
  • Smoke: Telex input, tone placement, <input>, <textarea>, <div contenteditable>, committed-text continuity across blur & refocus
  • Rapid input: Fast sequential key injection, rapid backspace deletion followed by new composition, repeated composition cycles
  • Browsers: Sequential Chromium and Firefox suites
  • Reliability: 3/3 consecutive green runs on the final SHA with retries disabled (retries: 0); no flakes observed

CI & Isolation Architecture

  • Separate workflow (.github/workflows/browser-e2e.yml) to preserve core CTest build graph optimization from ci: reduce CI time and redundant test compilation #475
  • Owned X11 display: the harness never inherits the host DISPLAY; it uses BROWSER_E2E_DISPLAY (default :99), fails closed when the display is occupied by a live server or a stale socket, and always starts its own Xvfb
  • Xvfb readiness: requires the Xvfb process to stay alive AND xdpyinfo to succeed; socket existence alone is not accepted
  • Fully isolated temporary runtime directory (TEST_HOME / XDG_CONFIG_HOME / private dbus-daemon session); setup-fcitx.sh requires TEST_HOME and scripts/run-browser-e2e.sh is the local lifecycle entrypoint (creates it, traps EXIT for cleanup)
  • Process lifecycle strictly managed via explicit PID file tracking: every managed process is terminated exactly once via the PID file; dbus.pid/dbus.addr are removed on stop so stale PIDs are never re-killed
  • No global process termination (pkill or fcitx5-remote -e), keeping developer desktop sessions safe
  • Private dbus-session.conf omitting standard service directories to prevent D-Bus auto-activation without mutating system files under /usr/share
  • Fcitx5 launched with -r (--replace) and --disable=wayland,waylandim to eliminate unconfigured Wayland socket delays
  • Deterministic waits: fixed settle sleeps replaced by fcitx5-remote state polling; ensureActive polls the fixture event log for a genuine focus event (blur + click guarantees a fresh focus transition)
  • Diagnostic logs and Playwright trace artifacts collected and uploaded on failure

Scope Boundaries

  • Covers the current Mode=Preedit browser path on standard HTML editable elements under X11/Xvfb.
  • Kernel-level uinput, Wayland/Weston compositors, and SurroundingText regressions are explicitly reserved for Phase 2.

@github-project-automation github-project-automation Bot moved this to Backlog in Kanban Sep 9, 2026
@naoNao89
naoNao89 marked this pull request as draft September 9, 2026 09:08
@nhktmdzhg

Copy link
Copy Markdown
Collaborator

hay

@naoNao89
naoNao89 force-pushed the test/browser-e2e-x11 branch from 56e44b4 to ca186f9 Compare September 9, 2026 14:57
@naoNao89
naoNao89 marked this pull request as ready for review September 10, 2026 19:09
@naoNao89
naoNao89 marked this pull request as draft September 10, 2026 21:32
@naoNao89
naoNao89 force-pushed the test/browser-e2e-x11 branch from b7adc54 to c92ef91 Compare September 11, 2026 00:48
…ction

- Local HTTP server fixture with input, textarea, and contenteditable
- Event instrumentation recording keydown, keyup, beforeinput, input, compositionstart/update/end
- OS-level input injection via xdotool XTEST to exercise X11 -> Fcitx5 -> Lotus -> Browser DOM
- Positive and negative Telex control tests (dd -> đ vs dd -> dd)
- Sequential Chromium and Firefox smoke and rapid input typing test suites
- Fully isolated temporary runtime environment with private D-Bus busconfig and explicit PID tracking
- Dedicated workflow triggered on PR and workflow_dispatch
- Separate job from GCC/Clang core CTest matrix to preserve build optimization
- Runs on ubuntu-24.04 with Xvfb, Openbox, private D-Bus, Fcitx5, Chromium, and Firefox
- Exercises sequential E2E tests across both browsers
- Uploads complete diagnostics, Playwright reports, and server logs on failure
@naoNao89
naoNao89 force-pushed the test/browser-e2e-x11 branch from af91cbf to 105d23c Compare September 11, 2026 05:04
- Display selection moved to BROWSER_E2E_DISPLAY (default :99); the harness
  never inherits the host DISPLAY and fails closed when the display is
  occupied by a live server or stale socket instead of reusing it
- Xvfb is always started unconditionally; readiness requires the process to
  stay alive AND xdpyinfo to succeed, so stale sockets cannot pass
- D-Bus PID terminated exactly once via the PID file; dbus.pid and dbus.addr
  are removed on --stop so stale PIDs can never be re-killed
- x11-env.sh now lives under the isolated TEST_HOME instead of global /tmp
- setup-fcitx.sh requires TEST_HOME; new scripts/run-browser-e2e.sh is the
  local lifecycle entrypoint that creates it and traps EXIT for cleanup
- fcitx5.ts: fixed 100ms settle sleeps replaced by fcitx5-remote state
  polling (active IM name, active/inactive state codes)
- x11-input.ts: ensureActive settle sleep replaced by polling the fixture
  event log until the browser records the focus event for the target
The hardened Xvfb readiness check requires xdpyinfo to succeed (process
alive AND display responsive); xvfb alone does not ship xdpyinfo, so the
previously socket-only readiness silently passed without it.
Clicking an already-focused element fires no focus event, and clearInput
resets the fixture event log beforehand, so the focus-event readiness poll
could never observe a new event for the target. Blur first, then click, so
a fresh genuine focus event is always recorded and the IM-context readiness
poll is meaningful.
@naoNao89

Copy link
Copy Markdown
Contributor Author

All round-2 review items are addressed in 766c6ec..f6a2a8e (CI green, 3/3 consecutive runs on the final SHA, retries disabled).

Blocker — owned X11 display

  • run-xvfb.sh no longer reads DISPLAY at all: display selection is BROWSER_E2E_DISPLAY (default :99), so a host desktop display is never inherited.
  • The harness never reuses an existing X server: it fails closed with error: display ... is already in use; set BROWSER_E2E_DISPLAY to a free display and retry if the display is occupied by a live server (xdpyinfo) or even a stale socket (/tmp/.X11-unix/X<n>).
  • Xvfb startup is now unconditional; readiness requires the Xvfb process to stay alive AND xdpyinfo to succeed (x11-utils added to CI deps, since the hardened check exposed that xvfb alone doesn't ship xdpyinfo).

High — D-Bus PID killed twice / stale dbus.pid

  • Chose option A: the D-Bus PID lives only in run-xvfb.pids and is terminated exactly once via the PID-file loop; the separate dbus.pid kill block is gone. --stop now also removes dbus.pid and dbus.addr, so stale PID files can never cause a later re-kill of a recycled PID.

Medium — /tmp/x11-env.sh

  • Removed from /tmp; it is now written to ${TEST_HOME}/x11-env.sh (the workflow never consumed it).

Medium — TEST_HOME propagation

  • setup-fcitx.sh no longer auto-creates a TEST_HOME it can't export back; it hard-fails with guidance. New scripts/run-browser-e2e.sh is the local lifecycle entrypoint: creates + exports TEST_HOME when unset, runs setup + Xvfb/Fcitx + both browser suites, and traps EXIT to run-xvfb.sh --stop (covers errors and Ctrl-C).

Low — fixed sleeps

  • fcitx5.ts: all setTimeout(100) settle sleeps replaced by polling fcitx5-remote state (-n for active-IM name, state codes 1/2 for inactive/active), 50 ms interval, 3 s deadline.
  • x11-input.ts: ensureActive no longer uses waitForTimeout(100); it polls the fixture event log until the browser records a genuine focus event for the target. This surfaced a real sequencing bug: clearInput resets the event log, and clicking an already-focused element fires no focus event, so ensureActive now blurs before clicking to guarantee a fresh, real focus transition (no synthetic events).

Low — Xvfb readiness false positive

  • Fixed as part of the blocker: readiness is kill -0 $XVFB_PID AND xdpyinfo; a stale socket alone can never satisfy it.

Validation: Browser E2E green on Chromium + Firefox, 3/3 consecutive runs (initial + 2 reruns) on f6a2a8e, all 19 PR checks passing.

Failed startup attempts were appended to run-xvfb.pids before readiness
and killed during retry, leaving stale PIDs that cleanup would re-kill.
Record ownership only for a daemon that is alive and responsive; also
correct the wrapper comment: --stop tears down processes and keeps
TEST_HOME for post-mortem logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants