Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,16 @@ jobs:
- uses: actions/setup-node@v5
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Restore node_modules
uses: actions/cache/restore@v5
with:
path: |
node_modules
apps/*/node_modules
packages/*/node_modules
key: modules-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
# e2e launches the REAL Electron app, so it needs Electron's runtime binary
# and better-sqlite3 rebuilt for Electron. The shared `setup` cache is
# installed with --ignore-scripts (no binary) and restoring it makes a
# later install a no-op, so this job does its own full install WITH scripts
# (fresh node_modules → electron's install.js downloads the binary,
# desktop postinstall runs electron-builder install-app-deps).
- name: Install dependencies (with postinstall scripts)
run: pnpm install --frozen-lockfile

- name: Install Playwright system deps
working-directory: apps/desktop
Expand Down
12 changes: 11 additions & 1 deletion apps/desktop/e2e/smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ test.describe('app launch (smoke)', () => {
// First window must render *something* — a <body> element with non-zero
// size is a low bar that catches the regression class from PR #266
// (editor mount crashes that produced a blank window).
const bodyBox = await window.locator('body').boundingBox();
// launchApp only waits for `domcontentloaded`, which fires before the
// first paint/layout, so the body can briefly measure 0×0. Poll until it
// actually lays out before measuring (this is a render race, not a blank
// window).
const body = window.locator('body');
await expect
.poll(async () => (await body.boundingBox())?.width ?? 0, {
message: 'body should lay out with non-zero width',
})
.toBeGreaterThan(0);
const bodyBox = await body.boundingBox();
expect(bodyBox).not.toBeNull();
expect(bodyBox!.width).toBeGreaterThan(0);
expect(bodyBox!.height).toBeGreaterThan(0);
Comment on lines +20 to 29

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Poll only guards width; reuse the polled box and also wait on height.

The poll condition only checks width > 0, but height could still be racing to lay out; the subsequent expect(bodyBox!.height).toBeGreaterThan(0) has no retry margin if height lags behind width. Also, bodyBox is re-fetched via a second boundingBox() call instead of reusing the value already obtained during polling.

♻️ Suggested fix
       const body = window.locator('body');
-      await expect
-        .poll(async () => (await body.boundingBox())?.width ?? 0, {
-          message: 'body should lay out with non-zero width',
-        })
-        .toBeGreaterThan(0);
-      const bodyBox = await body.boundingBox();
+      let bodyBox: Awaited<ReturnType<typeof body.boundingBox>> = null;
+      await expect
+        .poll(
+          async () => {
+            bodyBox = await body.boundingBox();
+            return bodyBox;
+          },
+          { message: 'body should lay out with non-zero size' },
+        )
+        .toEqual(
+          expect.objectContaining({
+            width: expect.any(Number),
+            height: expect.any(Number),
+          }),
+        );
       expect(bodyBox).not.toBeNull();
       expect(bodyBox!.width).toBeGreaterThan(0);
       expect(bodyBox!.height).toBeGreaterThan(0);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/e2e/smoke.spec.ts` around lines 20 - 29, The smoke test
currently waits only for `body.boundingBox()` width to become non-zero and then
re-reads the box, which can let height still be zero and introduces a race.
Update the polling around `body` to wait for both width and height to be greater
than zero, and reuse the bounding box value from the successful poll instead of
calling `boundingBox()` again. Keep the assertions on the `body` box aligned
with the polled result so `expect(bodyBox)` reflects the same settled layout
state.

Expand Down
Loading