Skip to content

fix(desktop): keep e2e windows visible without stealing focus - #4579

Draft
Astro-Han wants to merge 1 commit into
apache:mainfrom
Astro-Han:fix/e2e-show-window-inactive
Draft

fix(desktop): keep e2e windows visible without stealing focus#4579
Astro-Han wants to merge 1 commit into
apache:mainfrom
Astro-Han:fix/e2e-show-window-inactive

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

MAKA_E2E_SHOW_WINDOW conflated two things: whether the Desktop window appears, and whether the app takes the foreground. Eight fixtures in apps/desktop/e2e/fixtures.ts set it, and every run on a CI Linux display sets it too — so a local suite run gave the Electron app a dock tile, activated it, and threw its window in front of whatever the developer was doing, over and over for the length of the run. None of those fixtures wants focus. They want the compositor (a hidden window is throttled to ~1fps under xvfb) and a real layout for geometry assertions.

The flag now lifts the window's visibility and stops there. The single startHidden boolean becomes the run's reveal mode — hidden, inactive, active — resolved once in window-reveal.ts and consumed by both the reveal gate and the dock rule:

  • hidden: unchanged. E2E captures paint the hidden window via paintWhenInitiallyHidden.
  • inactive: reveal with showInactive(), stay an accessory app, and answer a focus request with a reveal and nothing more. maximize() reveals a hidden window and that reveal activates the app, so an inactive reveal runs first and leaves the maximize nothing to show.
  • active: the product. Unchanged — a normal launch still gets its dock icon, its reveal, and its focus.

The E2E harness carried the same conflation: the prompt-rail worker window is re-revealed before every test in the file with window.show(), which activates the app regardless of what the main process decided. It reveals inactively now.

The Linux CI path is untouched: those runs are inactive rather than hidden, so the window is on screen and the compositor runs at full rate exactly as before; only the macOS foreground behavior changes, and nobody is watching a headless X display.

This deletes the startHidden concept rather than adding a flag next to it — one authority for how far a run may go when it reveals its window.

Verification

  • apps/desktop/src/main/__tests__/window-reveal-mode.test.ts (new, 14 cases): the mode rule, the dock rule, and the reveal gate. Every "inactive" case fails against the old code, which called show()/focus() and resolved the dock to icon.
  • npm run build, npm run format, npm run lint, npm exec -w @maka/desktop -- tsc typecheck (all four projects): pass.
  • npm exec -w @maka/desktop -- playwright test e2e/prompt-rail.spec.ts: 9 passed.
  • Focus evidence on macOS — sampled the frontmost application (lsappinfo front) 130 times during that same spec run, before and after:
BEFORE  116 /Applications/Google Chrome.app
         14 .../e2e-focus/node_modules/electron/dist/Electron.app   <- steals foreground

AFTER   130 /Applications/WeChat.app
          0 Electron

And a single fixture window launched directly, before and after, reporting from inside the main process:

BEFORE  { dockVisible: true,  visible: true, focused: false }  frontmost in 5/25 samples
AFTER   { dockVisible: false, visible: true, focused: false }  frontmost in 0/25 samples
  • Not run: the full repo suite, and the Linux CI display path (no Linux host here) — that path is covered by CI on this PR.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code drafted the change and this description; verified by the author.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

`MAKA_E2E_SHOW_WINDOW` conflated two things: whether the window appears
and whether the app takes the foreground. Every fixture that sets it —
and `e2e/fixtures.ts` sets it for eight of them, plus every run on a CI
Linux display — got a dock tile, an activated app, and a window that
jumped in front of whatever the developer was doing, repeatedly, for the
length of the suite. Nothing in those fixtures wants focus: they want the
compositor (a hidden window is throttled to ~1fps under xvfb) and a real
layout for geometry assertions.

So the flag now lifts the window's visibility and stops there. The single
`startHidden` boolean becomes the run's reveal mode — `hidden`,
`inactive`, `active` — resolved once in `window-reveal.ts` and consumed
by both the reveal gate and the dock rule:

  - `hidden`: unchanged. E2E captures paint the hidden window.
  - `inactive`: reveal with `showInactive()`, stay an accessory app, and
    answer a focus request with a reveal and nothing more. `maximize()`
    reveals a hidden window and that reveal activates, so an inactive
    reveal comes first and leaves it nothing to show.
  - `active`: the product, unchanged.

The E2E harness had the same conflation of its own: the prompt-rail
worker window is re-revealed before every test in the file with
`window.show()`, which activates the app each time no matter what the
main process decided. It reveals inactively now.

Verified on macOS by sampling the frontmost application while running
`playwright test e2e/prompt-rail.spec.ts`: before, the Electron app held
the foreground in 14 of 130 samples; after, in 0 of 130, with all nine
tests still passing.

Generated-by: Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/M Under 500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant