Skip to content

ci: install Electron runtime in the e2e job - #447

Open
tomymaritano wants to merge 5 commits into
developfrom
fix/ci-e2e-electron-install
Open

ci: install Electron runtime in the e2e job#447
tomymaritano wants to merge 5 commits into
developfrom
fix/ci-e2e-electron-install

Conversation

@tomymaritano

@tomymaritano tomymaritano commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Problem

e2e has been failing on every PR (verified on an unrelated one-line PR) with:

electron.launch: Electron failed to install correctly, please delete node_modules/electron and try installing again

Root cause: the setup job installs deps with --ignore-scripts (intentional — it avoids rebuilding better-sqlite3 for Electron in the lint/test/typecheck jobs). But that also skips Electron's postinstall, which downloads the Electron runtime binary. The e2e job restores that binary-less node_modules cache and then tries to launch the real Electron app → fails.

Fix

The e2e job now runs pnpm install --frozen-lockfile (with scripts) after restoring the cache, which completes the skipped postinstalls — Electron's binary download and electron-builder install-app-deps (better-sqlite3 rebuilt for the Electron ABI) — before building and launching the app.

Scoped to the e2e job only; the other jobs keep the fast --ignore-scripts path.

Note

e2e is continue-on-error: true and not a required check, so this was silently red rather than blocking merges — but it means e2e has been providing no signal. This restores it.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Improved end-to-end test reliability by using a fresh pnpm install --frozen-lockfile during the desktop E2E flow to ensure required native post-install rebuilds complete successfully.
    • Reduced intermittent smoke test failures by polling for initial page layout (non-zero body dimensions) before asserting window sizing.

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) <noreply@anthropic.com>
@github-actions github-actions Bot added the ci label Jul 3, 2026
@github-actions
github-actions Bot enabled auto-merge (squash) July 3, 2026 14:08
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The CI e2e job now runs a fresh pnpm install --frozen-lockfile before the desktop build and Playwright run, and the desktop smoke test waits for the page body to finish layout before measuring it.

Changes

E2E stability

Layer / File(s) Summary
Run install scripts in e2e job
.github/workflows/ci.yml
Removes the cached node_modules restore step and adds a fresh pnpm install --frozen-lockfile before the Electron E2E launch.
Wait for body layout in smoke test
apps/desktop/e2e/smoke.spec.ts
Polls the <body> width until it becomes non-zero before checking the body bounding box and its dimensions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main CI change: enabling Electron runtime installation in the e2e job.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 fix/ci-e2e-electron-install

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 178-185: The Electron postinstall completion step in the CI
workflow is using a second pnpm install, which can still skip pending scripts on
the restored node_modules tree. Replace that step with pnpm rebuild --pending so
the Electron and better-sqlite3 hooks rerun after the setup job’s ignore-scripts
install; keep the change in the workflow job that follows setup and targets the
existing “Complete install for Electron” step.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 7e1a7f18-67a6-4d38-9ea9-f2b5acd09d26

📥 Commits

Reviewing files that changed from the base of the PR and between 6781e71 and 11d46a9.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +178 to +185
# 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for pnpm build-script allowlist config and pnpm version pin.
fd -H -a 'pnpm-workspace.yaml' -x cat -n {}
rg -n 'onlyBuiltDependencies|allowBuilds|ignoredBuiltDependencies|neverBuiltDependencies|strictDepBuilds' -g '*.json' -g '*.yaml' -g '*.yml'
rg -n '"packageManager"' package.json
rg -n 'pnpm/action-setup@' .github/workflows/ci.yml

Repository: dripnex/readide

Length of output: 214


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## workflow excerpt\n'
sed -n '1,240p' .github/workflows/ci.yml | nl -ba | sed -n '150,210p'

printf '\n## root package.json\n'
if [ -f package.json ]; then
  cat -n package.json | sed -n '1,220p'
fi

printf '\n## desktop package.json\n'
if [ -f apps/desktop/package.json ]; then
  cat -n apps/desktop/package.json | sed -n '1,220p'
fi

printf '\n## pnpm metadata\n'
if [ -f pnpm-workspace.yaml ]; then
  cat -n pnpm-workspace.yaml
fi
if [ -f pnpm-lock.yaml ]; then
  rg -n 'packageManager|pnpm|postinstall|better-sqlite3|electron-builder' pnpm-lock.yaml
fi

Repository: dripnex/readide

Length of output: 214


🏁 Script executed:

#!/bin/bash
set -euo pipefail

num() { awk '{printf "%6d  %s\n", NR, $0}'; }

printf '\n## workflow excerpt\n'
sed -n '150,210p' .github/workflows/ci.yml | num

printf '\n## root package.json\n'
if [ -f package.json ]; then
  sed -n '1,220p' package.json | num
fi

printf '\n## desktop package.json\n'
if [ -f apps/desktop/package.json ]; then
  sed -n '1,220p' apps/desktop/package.json | num
fi

printf '\n## pnpm-workspace.yaml\n'
if [ -f pnpm-workspace.yaml ]; then
  sed -n '1,120p' pnpm-workspace.yaml | num
fi

printf '\n## pnpm-lock.yaml matches\n'
if [ -f pnpm-lock.yaml ]; then
  rg -n 'packageManager|pnpm|postinstall|better-sqlite3|electron-builder' pnpm-lock.yaml
fi

Repository: dripnex/readide

Length of output: 15091


🌐 Web query:

pnpm 9 ignore-scripts rebuild --pending install rerun postinstall official docs

💡 Result:

In pnpm 9 and later, when you run an installation with the --ignore-scripts flag, lifecycle scripts (such as postinstall) are not executed for your project or its dependencies [1][2]. To rerun or execute these pending scripts after an installation with --ignore-scripts, you can use the pnpm rebuild command [3][4]. Key details regarding this process: 1. Executing Rebuild: Running pnpm rebuild will attempt to execute lifecycle scripts for packages present in node_modules [4]. If scripts were skipped during the initial install, they are considered pending and should be processed by the rebuild command [4]. 2. Pending Builds and Approvals: If you are using pnpm's security features to control script execution, you may need to approve builds for specific dependencies before they can run [5]. You can use the pnpm approve-builds command to interactively manage these permissions [5]. 3. Limitations and Troubleshooting: - If pnpm rebuild does not trigger the scripts as expected, ensure that the dependencies are not being excluded by your configuration (e.g., in.npmrc) [6]. - Be aware of the side-effects-cache setting [6][7]. If enabled, pnpm may skip running scripts for packages it believes have already been built and cached [6][7]. Setting side-effects-cache=false in your.npmrc can force pnpm to re-run build scripts [6][7]. - There are known edge cases, such as in certain monorepo configurations or when installing only development dependencies, where pnpm rebuild may behave inconsistently [3]. For further details on managing scripts, refer to the official pnpm documentation on scripts [8] and supply chain security [9].

Citations:


Use pnpm rebuild --pending here instead of a second install.
setup restores node_modules from an --ignore-scripts install, and pnpm install --frozen-lockfile can leave electron/better-sqlite3 postinstall hooks skipped on the restored tree. pnpm rebuild --pending is the step that reruns those scripts.

🤖 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 @.github/workflows/ci.yml around lines 178 - 185, The Electron postinstall
completion step in the CI workflow is using a second pnpm install, which can
still skip pending scripts on the restored node_modules tree. Replace that step
with pnpm rebuild --pending so the Electron and better-sqlite3 hooks rerun after
the setup job’s ignore-scripts install; keep the change in the workflow job that
follows setup and targets the existing “Complete install for Electron” step.

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) <noreply@anthropic.com>
@github-actions github-actions Bot added size/S and removed size/XS labels Jul 3, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 187-190: The Electron install step in the CI workflow is doing a
full-tree pnpm install just to trigger apps/desktop postinstall and Electron’s
native rebuild. Update the step to use a scoped install or pending rebuild
approach tied to the `@dripnex/desktop` workspace, and keep the electron rebuild
call so the needed binary/native modules are still installed without
reprocessing the entire dependency tree.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 4a818b4f-dcb3-45d1-a209-201d170cc68c

📥 Commits

Reviewing files that changed from the base of the PR and between 11d46a9 and ff17fb1.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +187 to +190
- name: Complete install for Electron (binary + native modules)
run: |
pnpm install --frozen-lockfile
pnpm rebuild electron

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider scoping the install to avoid full-tree reinstall overhead.

Running a full pnpm install --frozen-lockfile after cache restore re-verifies/re-links the entire dependency tree just to trigger one workspace package's postinstall. Since the goal is specifically to run apps/desktop's postinstall and Electron's install script, a scoped approach (e.g., pnpm --filter @dripnex/desktop install or pnpm rebuild --pending combined with pnpm rebuild electron) could achieve the same effect with less overhead in the e2e job's critical path.

Not blocking given the job is continue-on-error: true, but worth considering since this step runs on every e2e execution.

🤖 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 @.github/workflows/ci.yml around lines 187 - 190, The Electron install step
in the CI workflow is doing a full-tree pnpm install just to trigger
apps/desktop postinstall and Electron’s native rebuild. Update the step to use a
scoped install or pending rebuild approach tied to the `@dripnex/desktop`
workspace, and keep the electron rebuild call so the needed binary/native
modules are still installed without reprocessing the entire dependency tree.

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) <noreply@anthropic.com>

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

154-173: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Drop needs: setup from e2e
setup only seeds the pnpm cache; e2e does its own fresh install and doesn’t consume any artifact or output from that job. Removing the dependency would let e2e start sooner in CI.

🤖 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 @.github/workflows/ci.yml around lines 154 - 173, The e2e job is
unnecessarily blocked by the setup job even though it only relies on its own
fresh install and does not consume any outputs or artifacts from setup. Update
the e2e job in the CI workflow to remove the needs: setup dependency, keeping
the existing checkout, pnpm setup, node setup, and Install dependencies (with
postinstall scripts) steps unchanged.
🤖 Prompt for all review comments with 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.

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 154-173: The e2e job is unnecessarily blocked by the setup job
even though it only relies on its own fresh install and does not consume any
outputs or artifacts from setup. Update the e2e job in the CI workflow to remove
the needs: setup dependency, keeping the existing checkout, pnpm setup, node
setup, and Install dependencies (with postinstall scripts) steps unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 307cfe12-2e81-46c8-818d-2b3fcdddb889

📥 Commits

Reviewing files that changed from the base of the PR and between ff17fb1 and 8e94e19.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

tomymaritano and others added 2 commits July 3, 2026 15:44
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) <noreply@anthropic.com>

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@apps/desktop/e2e/smoke.spec.ts`:
- Around line 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.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 2fea920e-195f-4e88-af54-2e85f8920aaf

📥 Commits

Reviewing files that changed from the base of the PR and between 8e94e19 and 9fd2eaa.

📒 Files selected for processing (1)
  • apps/desktop/e2e/smoke.spec.ts

Comment on lines +20 to 29
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);

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant