Fix Forgejo CI test mocks and Bun path handling
Tightened the CI-facing web tests and Bun resolution path so Forgejo can install dependencies, run the typecheck helper, and execute the web test suite without shell PATH surprises.
Summary
Forgejo was failing in two places: first because the CI shell could not reliably find bun when a helper script spawned it, and then because two web tests depended on Next.js navigation module shapes that did not hold up in the CI runtime. The fix makes the typecheck helper invoke the current Bun executable directly and adjusts the affected mocks to match the module forms used during test execution.
Changes Made
- Changed
scripts/typecheck.tsto spawn the current Bun executable instead of assumingbunxis reachable on PATH. - Added
$HOME/.bun/binto$GITHUB_PATHin.forgejo/workflows/ci.ymlso shell-invoked package scripts can find Bun during the workflow. - Expanded the
next/navigationmock inapps/web/app/routes.test.tsto cover both module entry points and exposeredirectin the shape the app expects. - Updated
apps/web/app/terminal.test.tsto mocknext/navigationbefore importing the terminal module, including a pathname stub and redirect helper for the CI runtime.
Context
The repo uses Bun-first tooling and Forgejo as the canonical remote. The CI workflow installs Bun by absolute path, but some helper scripts and package-level commands still assume a PATH-visible Bun binary. On the web side, the terminal and route tests were sensitive to how Bun resolved Next.js module mocks, so the failures only showed up in the CI-shaped run.
Important Implementation Details
scripts/typecheck.tsnow usesprocess.execPathso it stays anchored to the Bun runtime that launched the script.- The CI workflow change is defensive, it keeps any later shell step from depending on a hidden PATH assumption.
- The route test mock covers both
next/navigationandnext/navigation.js, which avoids the module-shape mismatch that appeared in the full suite. terminal.test.tsnow installs the mock first and then dynamically imports the terminal module, which matches the order Bun needs for module interception.
Relevant Diff Snippets
Rendered with @pierre/diffs/ssr. The first fragment is the full rendered output for the routes test change. The second fragment reuses the same rendered markup shape for the terminal test change after stripping the duplicate style prelude so the page stays readable.
3 unmodified lines456789103 unmodified linesthrow new Error(`NEXT_REDIRECT:${path}`);});mock.module("next/navigation", () => ({ redirect }));describe("legacy page redirects", () => {beforeEach(() => {3 unmodified lines45678910113 unmodified linesthrow new Error(`NEXT_REDIRECT:${path}`);});mock.module("next/navigation", () => ({ default: { redirect }, redirect }));mock.module("next/navigation.js", () => ({ default: { redirect }, redirect }));describe("legacy page redirects", () => {beforeEach(() => {
12345642 unmodified lines49505152535455import { describe, expect, it } from "bun:test";import { getSubscriptionKey as getLiveSubscriptionKey } from "@islandflow/types";import {NAV_ITEMS,appendHistoryTail,buildAlertContextPath,42 unmodified linesresolveAlertFlowPacket,statusLabel,toggleFilterValue} from "./terminal";const makeItem = (traceId: string, seq: number, ts: number) => ({trace_id: traceId,1234567891011121314151642 unmodified lines59606162636465import { describe, expect, it, mock } from "bun:test";import { getSubscriptionKey as getLiveSubscriptionKey } from "@islandflow/types";const redirect = mock((path: string) => {throw new Error(`NEXT_REDIRECT:${path}`);});mock.module("next/navigation", () => ({redirect,usePathname: () => "/options"}));const {NAV_ITEMS,appendHistoryTail,buildAlertContextPath,42 unmodified linesresolveAlertFlowPacket,statusLabel,toggleFilterValue} = await import("./terminal");const makeItem = (traceId: string, seq: number, ts: number) => ({trace_id: traceId,
Expected Impact for End-Users
Contributors should see Forgejo fail less often on environment-specific Bun lookup issues, and the web test suite should stay stable under the same runtime shape the CI runner uses. That means fewer false negatives and a clearer path from local validation to a green pipeline.
Validation
env PATH="$HOME/.bun/bin:/usr/bin:/bin" bun run typecheckpassed.env PATH="$HOME/.bun/bin:/usr/bin:/bin" bun testpassed: 250 tests, 0 failures.env PATH="$HOME/.bun/bin:/usr/bin:/bin" bun run check:docker-workspacepassed in the earlier CI recovery pass.
Issues, Limitations, and Mitigations
The current fix addresses the CI failure path that was blocking the workflow. It does not change the wider Next.js testing strategy, so if more module-shape drift appears later, the same pattern may need to be applied to adjacent tests. The workflow path fix is intentionally narrow and should not affect local development outside the CI shell.
Follow-up Work
- Watch the next Forgejo run on this branch to confirm the CI path stays clean under the exact runner environment.
- Fold any other CI-only Next.js mock quirks into shared helpers if more tests start to depend on the same module shape.
- Close out the Beads issue once the Forgejo result is confirmed.