diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c5ae58..b84f4b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,6 +231,24 @@ jobs: - name: Seed database run: pnpm db:seed + - name: Run integration tests + # These talk to real Postgres. The unit-test job has no DB so + # the `*.integration.test.ts` files skip there; this job has + # the DB up + schema pushed, so flip the gate env vars to "1" + # and let them run. Each gate is read by one file — see + # `runIntegration` in each test. + # + # --no-file-parallelism: integration tests share the journal + # schema and clean up by `DELETE FROM ... WHERE email LIKE + # '%@example.test'`. Parallel files step on each other's rows + # and trip FK constraints. Running sequentially is still <3s. + run: pnpm --filter @trails-cool/journal exec vitest run --no-file-parallelism --reporter=default app/lib/explore.integration.test.ts app/lib/follow.integration.test.ts app/lib/demo-bot.integration.test.ts app/lib/notifications.integration.test.ts app/jobs/notifications-fanout.integration.test.ts + env: + EXPLORE_INTEGRATION: "1" + FOLLOW_INTEGRATION: "1" + DEMO_BOT_INTEGRATION: "1" + NOTIFICATIONS_INTEGRATION: "1" + - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v5 diff --git a/apps/journal/app/lib/demo-bot.integration.test.ts b/apps/journal/app/lib/demo-bot.integration.test.ts index 7ed763a..9556fb3 100644 --- a/apps/journal/app/lib/demo-bot.integration.test.ts +++ b/apps/journal/app/lib/demo-bot.integration.test.ts @@ -82,9 +82,26 @@ describe.skipIf(!runIntegration)("demo-bot integration", () => { }); it("generateOneWalk inserts a public synthetic route + activity", async () => { + // createPlannerSession() calls resp.json() (returns { sessionId }); + // requestBrouterGpx() then calls resp.text() (returns the GPX body). + // Stub both so the chain completes without a real Planner running. vi.stubGlobal( "fetch", - vi.fn().mockResolvedValue({ ok: true, status: 200, text: async () => STUB_GPX }), + vi.fn().mockImplementation((input: string | URL) => { + const url = typeof input === "string" ? input : input.toString(); + if (url.endsWith("/api/sessions")) { + return Promise.resolve({ + ok: true, + status: 200, + json: async () => ({ sessionId: "test-session" }), + }); + } + return Promise.resolve({ + ok: true, + status: 200, + text: async () => STUB_GPX, + }); + }), ); const ownerId = await ensureDemoUser(); diff --git a/apps/journal/app/lib/routes.server.ts b/apps/journal/app/lib/routes.server.ts index cf9ef9d..d50e54e 100644 --- a/apps/journal/app/lib/routes.server.ts +++ b/apps/journal/app/lib/routes.server.ts @@ -55,6 +55,7 @@ export async function createRoute(ownerId: string, input: RouteInput) { elevationGain, elevationLoss, dayBreaks, + ...(input.visibility ? { visibility: input.visibility } : {}), ...(input.synthetic ? { synthetic: true } : {}), });