Skip to content

fix: make web e2e use the desktop shell contract#417

Merged
Astro-Han merged 8 commits into
devfrom
codex/i269-desktop-shell-e2e
May 4, 2026
Merged

fix: make web e2e use the desktop shell contract#417
Astro-Han merged 8 commits into
devfrom
codex/i269-desktop-shell-e2e

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 4, 2026

Copy link
Copy Markdown
Owner

Summary

Make the Web runtime keep platform: "web" while rendering through the Desktop visual shell contract. Layout, titlebar, and shell CSS now key visual appearance from platform.shell, expose data-shell / data-shell-os, and Web Playwright E2E pins the shell OS to macOS through a runtime override so the main GUI safety net exercises the shipped desktop geometry even when Playwright reuses an existing dev server.

Also updates inherited OpenCode favicon assets to PawWork branding, because the Web preview is part of the same browser-facing shell surface being validated here.

Why

#269 moved from a visual parity issue to a GUI test-confidence issue after the #412/#413 regressions. Web E2E is the broadest UI safety net, but it previously rendered the Web shell rather than the Desktop shell users run in Electron.

Related Issue

Closes #269

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence. Do not merge until desktop-smoke is fully green.

Review Focus

Please check:

  • platform.platform remains the runtime identity (web or desktop)
  • platform.shell owns visual shell appearance and OS-specific shell geometry
  • Web does not gain Electron-only native capabilities
  • Web Desktop shell keeps browser-safe fallbacks such as the project picker dialog
  • Web shell OS detection is explicit: runtime override, env override, runtime detection, then macOS fallback
  • E2E assertions cover Web runtime plus Desktop shell geometry without replacing Electron smoke

Risk Notes

Low-to-medium UI shell risk. This changes the Web visual shell path, shared shell data attributes, and Web favicon assets, but does not change route shapes, preload IPC, updater behavior, native dialogs, or packaged resource checks.

How To Verify

Red test: shell-frame contract failed before implementation on missing data-shell / Web shell contract
App unit tests: bun --cwd packages/app test -> 785 passed before review updates
App shell contract tests: bun --cwd packages/app test src/shell-frame-contract.test.ts -> 788 passed, 0 failed, 1972 expects
App typecheck: bun --cwd packages/app typecheck -> passed
Targeted Web E2E: bun --cwd packages/app test:e2e e2e/app/shell-frame.spec.ts -> 4 passed
Web smoke E2E: bun --cwd packages/app test:e2e:local:smoke -> 16 passed, 1 skipped before review updates
Desktop typecheck: bun --cwd packages/desktop-electron typecheck -> passed
Desktop tests: bun --cwd packages/desktop-electron test -> 344 passed before review updates
Diff check: git diff --check -> passed

Screenshots or Recordings

Not attached. This PR intentionally reuses the existing Desktop shell visuals and verifies the visible geometry through Playwright assertions (data-platform=web, data-shell=desktop, data-shell-os=macos, and 44px titlebar height within a 43.5-44.5px tolerance). It also verifies Web-only capability behavior by checking Electron-only update/open-directory actions are disabled and the browser-safe project picker fallback still opens.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • Tests

    • Expanded smoke and unit tests to validate shell metadata attributes, macOS titlebar height, disabled startup update controls, breadcrumb/titlebar button states, and the web "open project" dialog fallback UI.
  • Bug Fixes

    • Ensured consistent titlebar sizing and ensured startup update controls stay disabled; tightened directory-open gating so UI reflects actual capabilities.
  • Refactor

    • Standardized shell metadata/OS handling and switched styling checks to use shell attributes for consistent layout across platforms.
  • UX

    • Refined display-backend setting visibility for Linux and improved file-picker/open-directory availability handling.

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: adcc06da-1dfb-4ac5-bfcf-fd3ca71eb993

📥 Commits

Reviewing files that changed from the base of the PR and between 5667da7 and 8a5b784.

📒 Files selected for processing (7)
  • packages/app/e2e/app/shell-frame.spec.ts
  • packages/app/src/components/prompt-input.tsx
  • packages/app/src/components/session/session-header.tsx
  • packages/app/src/components/settings-general.tsx
  • packages/app/src/context/platform.tsx
  • packages/app/src/entry.tsx
  • packages/app/src/shell-frame-contract.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/app/src/context/platform.tsx
  • packages/app/src/shell-frame-contract.test.ts

📝 Walkthrough

Walkthrough

This PR separates visual shell identity into an optional shell field with helpers, makes the Web entry report a desktop visual shell (with detected/overridable OS), updates components and CSS to use data-shell/data-shell-os, adjusts Playwright env for deterministic E2E, and updates tests to assert desktop-shell attributes and titlebar geometry.

Changes

Shell Identity Separation & Web Desktop Shell Rendering

Layer / File(s) Summary
Type & Helper Definition
packages/app/src/context/platform.tsx
Adds PlatformShell and optional shell on Platform; exports getShellKind, getShellOs, shellAttrs, and predicates isDesktopShell, isMacShell, isWindowsShell, plus capability predicates (canOpenLocalPath, canCheckUpdate, canUseDisplayBackend, canUseNativeFilePicker).
Entry Point Shell Setup
packages/app/src/entry.tsx, packages/desktop-electron/src/renderer/index.tsx
Adds runtime detection/override for shell OS (detectShellOs, global override and env precedence) and sets platform.shell = { kind: "desktop", os } for web and desktop renderer.
Component Wiring / Behavior
packages/app/src/components/titlebar.tsx, packages/app/src/pages/layout.tsx
Components spread {...shellAttrs(platform)} and use isDesktopShell/isMacShell/isWindowsShell predicates for class/height/drag-region decisions; sidebar keybind spacing made unconditional.
Styling
packages/app/src/index.css
Replaces selectors keyed on data-platform="desktop" with data-shell="desktop" so desktop-shell styling applies based on shell metadata.
Capability Checks & UI Gating
packages/app/src/components/session/session-header.tsx, packages/app/src/components/settings-general.tsx, packages/app/src/components/prompt-input.tsx
Replace direct platform.platform === "desktop" checks with capability predicates (canOpenLocalPath, canCheckUpdate, canUseDisplayBackend, canUseNativeFilePicker) to gate UI and conditional behavior.
Config / Test Environment
packages/app/playwright.config.ts
Adds VITE_PAWWORK_SHELL_OS: "macos" to Playwright webServer.env for deterministic E2E shell OS.
E2E & Contract Tests
packages/app/e2e/app/shell-frame.spec.ts, packages/app/src/shell-frame-contract.test.ts, packages/desktop-electron/src/main/window-chrome.test.ts
Updates tests to assert data-shell="desktop" / data-shell-os="macos", titlebar bounding-box ≈44px, verifies web entry uses platform: "web" with shell: { kind: "desktop", os }, adjusts CSS/favicons assertions and hashes, and adds E2E checks for specific UI disables and open-project dialog fallback.

Sequence Diagram(s)

sequenceDiagram
    participant Entry as entry.tsx
    participant Platform as context/platform
    participant Layout as pages/layout.tsx
    participant Titlebar as components/titlebar.tsx
    participant CSS as index.css

    Entry->>Platform: initialize runtime platform + shell ({kind:"desktop", os})
    Platform-->>Layout: provide platform + shell via usePlatform()
    Platform-->>Titlebar: provide platform + shell via usePlatform()
    Layout->>Layout: apply shellAttrs() -> set `data-shell` / `data-shell-os`
    Titlebar->>Titlebar: evaluate isDesktopShell()/isMacShell() -> set classes/drag-region
    CSS->>Layout: apply `[data-shell="desktop"]` styles
    CSS->>Titlebar: apply `[data-shell="desktop"][data-shell-os="macos"]` rules
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

bug

Poem

🐰 I hopped in code to name the shell,
Web dons Desktop robes and rings the bell.
Attributes steady, titlebar stands at forty‑four,
Tests now check what visuals were for.
A tiny rabbit cheer for parity and more.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: making Web E2E tests use the desktop shell contract.
Description check ✅ Passed The description comprehensively covers all required template sections including summary, rationale, related issue, review focus, risk assessment, verification steps, and completed checklist items.
Linked Issues check ✅ Passed The PR satisfies all major coding requirements from #269: Web renders desktop shell contract, titlebar geometry matches, E2E exercises desktop visuals, platform-gated UI branches work, capability fallbacks remain browser-safe, and Electron-only actions stay disabled/unavailable.
Out of Scope Changes check ✅ Passed All changes directly support the stated objective of making Web E2E use the desktop shell contract; favicon asset updates align with the shared browser-facing shell surface.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i269-desktop-shell-e2e

Review rate limit: 6/10 reviews remaining, refill in 18 minutes and 34 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@Astro-Han Astro-Han added P1 High priority app Application behavior and product flows ui Design system and user interface platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions labels May 4, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/playwright.config.ts`:
- Around line 31-34: The test run can be flaky because VITE_PAWWORK_SHELL_OS is
force-set to "macos" even when reuseExistingServer (reuseExistingServer/reuse)
is true and the existing dev server may have been started with a different OS
value; change the config so the env.VITE_PAWWORK_SHELL_OS is only injected when
not reusing an existing server (i.e., guard the env assignment with the
reuse/reuseExistingServer flag) or alternatively detect reuseExistingServer and
skip/assertions that require macOS; update the logic around
reuseExistingServer/reuse and env to conditionally set VITE_PAWWORK_SHELL_OS or
bypass macOS-specific checks (referencing reuseExistingServer/reuse and
env.VITE_PAWWORK_SHELL_OS).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c8644c9f-e8de-4c0e-842a-39e753d0637f

📥 Commits

Reviewing files that changed from the base of the PR and between a87364b and 5f47da6.

📒 Files selected for processing (10)
  • packages/app/e2e/app/shell-frame.spec.ts
  • packages/app/playwright.config.ts
  • packages/app/src/components/titlebar.tsx
  • packages/app/src/context/platform.tsx
  • packages/app/src/entry.tsx
  • packages/app/src/index.css
  • packages/app/src/pages/layout.tsx
  • packages/app/src/shell-frame-contract.test.ts
  • packages/desktop-electron/src/main/window-chrome.test.ts
  • packages/desktop-electron/src/renderer/index.tsx

Comment thread packages/app/playwright.config.ts

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a visual shell contract to decouple the application's runtime identity from its appearance, allowing the web platform to adopt a desktop-like shell. Key changes include the addition of a shell property to the Platform context, new helper functions for shell detection, and updates to CSS and components to use data-shell attributes. Feedback focuses on further reducing logic duplication by extracting shell kind and OS resolution into shared helper functions and applying them within the Titlebar and Layout components.

Comment thread packages/app/src/context/platform.tsx
Comment thread packages/app/src/components/titlebar.tsx Outdated
Comment thread packages/app/src/components/titlebar.tsx Outdated
Comment thread packages/app/src/pages/layout.tsx Outdated
Comment thread packages/app/src/pages/layout.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/app/src/shell-frame-contract.test.ts (2)

62-64: ⚡ Quick win

Make favicon color assertions case-insensitive.

Hex casing in SVG can change during formatting/minification without changing branding. Case-insensitive matching keeps the contract semantic.

Suggested tightening
-  expect(favicon).toContain("#FF6B2B")
-  expect(favicon).toContain("#FFF8F0")
-  expect(favicon).not.toContain("#131010")
+  expect(favicon).toMatch(/#ff6b2b/i)
+  expect(favicon).toMatch(/#fff8f0/i)
+  expect(favicon).not.toMatch(/#131010/i)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/shell-frame-contract.test.ts` around lines 62 - 64, The
assertions on favicon hex colors are currently case-sensitive; update the checks
in shell-frame-contract.test (the expectations that reference favicon) to
perform case-insensitive matching—either convert favicon to a consistent case
(e.g., const normalized = favicon.toLowerCase() and assert normalized contains
'#ff6b2b' and '#fff8f0' and does not contain '#131010') or use case-insensitive
regex (e.g., expect(favicon).toMatch(/#ff6b2b/i), etc.) so
formatting/minification-driven casing changes won’t break the contract test.

48-54: ⚡ Quick win

Strengthen web-runtime contract assertion to avoid partial-match false positives.

Current checks can pass even if platform: "web" and desktop shell wiring are not in the same platform object shape. Consider asserting the object contract in one structural match (and optionally asserting no desktop runtime identity in that object).

Suggested tightening
-  expect(entry).toContain('platform: "web"')
-  expect(entry).toContain('shell: { kind: "desktop"')
-  expect(entry).toContain("getShellOs")
+  expect(entry).toMatch(
+    /const\s+platform:\s*Platform\s*=\s*\{[\s\S]*?platform:\s*"web"[\s\S]*?shell:\s*\{\s*kind:\s*"desktop",\s*os:\s*getShellOs\(\)\s*\}/,
+  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/shell-frame-contract.test.ts` around lines 48 - 54, The
current test uses separate contains checks that can match fragments in different
places; update the assertions to assert the platform object's shape in a single
structural match so the "platform: \"web\"" and absence of a desktop shell
identity appear together (e.g., parse or regex-match the exported `platform`
object string and assert it contains something like platform: "web" along with
no desktop shell wiring), and keep the other exports (`getShellOs`,
`PlatformShell`, `isDesktopShell`, `isMacShell`, `isWindowsShell`) asserted as
before; target the same symbols (`entry`, `platform`, `getShellOs`,
`PlatformShell`, `isDesktopShell`, `isMacShell`, `isWindowsShell`) when updating
the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/app/src/shell-frame-contract.test.ts`:
- Around line 62-64: The assertions on favicon hex colors are currently
case-sensitive; update the checks in shell-frame-contract.test (the expectations
that reference favicon) to perform case-insensitive matching—either convert
favicon to a consistent case (e.g., const normalized = favicon.toLowerCase() and
assert normalized contains '#ff6b2b' and '#fff8f0' and does not contain
'#131010') or use case-insensitive regex (e.g.,
expect(favicon).toMatch(/#ff6b2b/i), etc.) so formatting/minification-driven
casing changes won’t break the contract test.
- Around line 48-54: The current test uses separate contains checks that can
match fragments in different places; update the assertions to assert the
platform object's shape in a single structural match so the "platform: \"web\""
and absence of a desktop shell identity appear together (e.g., parse or
regex-match the exported `platform` object string and assert it contains
something like platform: "web" along with no desktop shell wiring), and keep the
other exports (`getShellOs`, `PlatformShell`, `isDesktopShell`, `isMacShell`,
`isWindowsShell`) asserted as before; target the same symbols (`entry`,
`platform`, `getShellOs`, `PlatformShell`, `isDesktopShell`, `isMacShell`,
`isWindowsShell`) when updating the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8aae4b36-1a25-4af4-8531-277712faad31

📥 Commits

Reviewing files that changed from the base of the PR and between 5f47da6 and 4b0cd8e.

⛔ Files ignored due to path filters (2)
  • packages/ui/src/assets/favicon/favicon-v3.svg is excluded by !**/*.svg
  • packages/ui/src/assets/favicon/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (1)
  • packages/app/src/shell-frame-contract.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/src/shell-frame-contract.test.ts`:
- Around line 53-55: The test's regex in shell-frame-contract.test.ts is too
order-sensitive (it assumes shell properties appear as kind then os); update the
expectation around the existing expect(entry).toMatch(...) to use an
order-independent pattern (e.g., use lookahead assertions or separate checks) so
it only asserts platform: "web" and that shell contains kind: "desktop" and os:
getShellOs() regardless of property order; modify the regex in the
expect(entry).toMatch call to verify the presence of those tokens rather than
their sequence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ea8c008-8000-4b55-ba7e-b76be371acd2

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb8348 and 775f7b0.

📒 Files selected for processing (4)
  • packages/app/src/components/titlebar.tsx
  • packages/app/src/context/platform.tsx
  • packages/app/src/pages/layout.tsx
  • packages/app/src/shell-frame-contract.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/app/src/context/platform.tsx
  • packages/app/src/pages/layout.tsx

Comment thread packages/app/src/shell-frame-contract.test.ts Outdated
@Astro-Han Astro-Han merged commit fdb601e into dev May 4, 2026
23 checks passed
@Astro-Han Astro-Han deleted the codex/i269-desktop-shell-e2e branch May 4, 2026 04:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows P1 High priority platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Make Web E2E match the Desktop GUI shell

1 participant