From 11d46a9cc0e43fd5fd2b952d1642077bf0b58d43 Mon Sep 17 00:00:00 2001 From: Tomas Maritano Date: Fri, 3 Jul 2026 11:08:07 -0300 Subject: [PATCH 1/4] ci: install Electron runtime in the e2e job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setup job installs with --ignore-scripts (to avoid rebuilding better-sqlite3 for Electron in the lint/test/typecheck jobs), so Electron's postinstall — which downloads the runtime binary — never runs, and the e2e job restored that binary-less cache. Every e2e test then failed with "electron.launch: Electron failed to install correctly". The e2e job now runs `pnpm install --frozen-lockfile` (with scripts) after restoring the cache, completing the skipped postinstalls (Electron binary + electron-builder install-app-deps) before launching the real app. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 325463d4..21c22f0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -175,6 +175,14 @@ jobs: working-directory: apps/desktop run: npx playwright install-deps chromium + # The `setup` job installs with --ignore-scripts, so Electron's postinstall + # (which downloads the runtime binary) and the desktop postinstall + # (electron-builder install-app-deps → better-sqlite3 rebuilt for Electron) + # never ran. e2e launches the real Electron app, so complete the install + # here — otherwise electron.launch fails with "Electron failed to install". + - name: Complete install for Electron (run postinstall scripts) + run: pnpm install --frozen-lockfile + - name: Build desktop bundle run: pnpm --filter @dripnex/desktop build From ff17fb1785aa55586d9d3c7b73f1f6839eb1f43a Mon Sep 17 00:00:00 2001 From: Tomas Maritano Date: Fri, 3 Jul 2026 14:22:57 -0300 Subject: [PATCH 2/4] ci: force Electron binary download in e2e job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prior fix ran `pnpm install --frozen-lockfile`, which re-ran the desktop postinstall (native rebuild) but not electron's own install script — the package is already "installed", so its postinstall (which downloads the runtime binary) is skipped and electron.launch still fails. Add `pnpm rebuild electron` to force-run electron's install script and fetch the binary. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 21c22f0d..4e9b0b66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -180,8 +180,14 @@ jobs: # (electron-builder install-app-deps → better-sqlite3 rebuilt for Electron) # never ran. e2e launches the real Electron app, so complete the install # here — otherwise electron.launch fails with "Electron failed to install". - - name: Complete install for Electron (run postinstall scripts) - run: pnpm install --frozen-lockfile + # `pnpm install` re-runs the desktop postinstall (native rebuild) but NOT + # electron's own install script (already "installed"), so the runtime + # binary is still missing; `pnpm rebuild electron` force-runs it to fetch + # the binary. + - name: Complete install for Electron (binary + native modules) + run: | + pnpm install --frozen-lockfile + pnpm rebuild electron - name: Build desktop bundle run: pnpm --filter @dripnex/desktop build From 8e94e19c6201a9c030ed8c5870e77ca7cfd01962 Mon Sep 17 00:00:00 2001 From: Tomas Maritano Date: Fri, 3 Jul 2026 14:28:27 -0300 Subject: [PATCH 3/4] ci: give e2e its own full install so Electron's binary is fetched Restoring the shared --ignore-scripts cache left Electron installed without its runtime binary, and a subsequent install/rebuild was a no-op (package already present), so electron.launch kept failing. The e2e job now skips the cache restore and runs its own `pnpm install --frozen-lockfile` with scripts against fresh node_modules, so electron's install.js downloads the binary and the desktop postinstall rebuilds better-sqlite3 for Electron. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e9b0b66..38bf6fb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,34 +161,21 @@ 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 run: npx playwright install-deps chromium - # The `setup` job installs with --ignore-scripts, so Electron's postinstall - # (which downloads the runtime binary) and the desktop postinstall - # (electron-builder install-app-deps → better-sqlite3 rebuilt for Electron) - # never ran. e2e launches the real Electron app, so complete the install - # here — otherwise electron.launch fails with "Electron failed to install". - # `pnpm install` re-runs the desktop postinstall (native rebuild) but NOT - # electron's own install script (already "installed"), so the runtime - # binary is still missing; `pnpm rebuild electron` force-runs it to fetch - # the binary. - - name: Complete install for Electron (binary + native modules) - run: | - pnpm install --frozen-lockfile - pnpm rebuild electron - - name: Build desktop bundle run: pnpm --filter @dripnex/desktop build From 9fd2eaaf3ee858dabe5c4aa6811791368d202714 Mon Sep 17 00:00:00 2001 From: Tomas Maritano Date: Sat, 4 Jul 2026 22:32:53 -0300 Subject: [PATCH 4/4] test(e2e): wait for layout before measuring the body in the smoke test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The smoke test measured `body` boundingBox right after launchApp, which only waits for `domcontentloaded` — that fires before the first paint/layout, so the body intermittently measured 0×0 and failed `width > 0`. Wait for the body to have non-zero size before asserting; this is a render race, not a blank-window regression. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/desktop/e2e/smoke.spec.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/desktop/e2e/smoke.spec.ts b/apps/desktop/e2e/smoke.spec.ts index 2ca924ce..1f6f9511 100644 --- a/apps/desktop/e2e/smoke.spec.ts +++ b/apps/desktop/e2e/smoke.spec.ts @@ -13,7 +13,17 @@ test.describe('app launch (smoke)', () => { // First window must render *something* — a 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);