Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

import-verify.test.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

import-verify.test.tsBlame91 lines · 1 contributor
14c3cc8Claude1/**
2 * Unit tests for src/lib/import-verify.ts.
3 *
4 * We stub the `../db` module with `mock.module` so we never touch Neon.
5 * The fake `db.select(...)` chain returns whatever the per-test closure
6 * decides — either undefined (repo not found) or a plausible row whose
7 * on-disk path points somewhere that doesn't exist.
5c54f77Claude8 *
9 * Bun 1.3's `bun test` shares a single module registry across every test
10 * file in a run and `mock.restore()` does NOT un-mock `mock.module(...)`
11 * registrations. To avoid leaking our stub into other test files, we use a
12 * defensive fake: `_nextRow` defaults to `undefined` (so any library code
13 * that does `select().from().where().limit(1)` sees an empty result and
14 * falls through to its DB-unavailable branch), and we reset the row back
15 * to `undefined` in `afterAll`.
14c3cc8Claude16 */
17
5c54f77Claude18import { describe, it, expect, mock, afterAll } from "bun:test";
14c3cc8Claude19
20// Per-test mutable row — each test assigns its own value before calling
21// verifyMigration. The chained Drizzle-style select builder ends in
22// `.limit(1)` which we return as an array containing (or omitting) this row.
23let _nextRow: { repoName: string; ownerName: string | null } | undefined;
24
25// Minimal Drizzle `db.select(...).from(...).leftJoin(...).where(...).limit(1)`
26// chain. Every step returns `this` except `.limit()` which resolves the
27// fake row as a 1-element (or 0-element) array.
28const _chain: any = {
29 from: () => _chain,
30 leftJoin: () => _chain,
5c54f77Claude31 innerJoin: () => _chain,
32 rightJoin: () => _chain,
14c3cc8Claude33 where: () => _chain,
5c54f77Claude34 orderBy: () => _chain,
35 groupBy: () => _chain,
14c3cc8Claude36 limit: async () => (_nextRow ? [_nextRow] : []),
37};
38
39// Mock `../db` at module scope so the dynamic import of ../lib/import-verify
40// below picks up the stub instead of the real Neon-backed proxy.
41const _fakeDb = {
5c54f77Claude42 db: { select: () => _chain, insert: () => _chain, update: () => _chain, delete: () => _chain },
43 getDb: () => ({ select: () => _chain, insert: () => _chain, update: () => _chain, delete: () => _chain }),
14c3cc8Claude44};
45mock.module("../db", () => _fakeDb);
46
5c54f77Claude47// Reset the fake row after our tests finish so any later test file whose
48// code happens to run `db.select()...limit(1)` sees an empty result (and
49// falls through to its real null/empty branch) rather than inheriting the
50// half-built row from our "git dir missing" test.
51afterAll(() => {
52 _nextRow = undefined;
53});
54
14c3cc8Claude55// Point GIT_REPOS_PATH at a directory that definitely doesn't contain
56// any of the fake repos we'll reference, so `clonable` checks fail.
57process.env.GIT_REPOS_PATH = "/tmp/gluecron-import-verify-does-not-exist";
58
59describe("verifyMigration", () => {
60 it("returns clonable:false and issue when repo not found in DB", async () => {
61 _nextRow = undefined;
62 const { verifyMigration } = await import("../lib/import-verify");
63 const r = await verifyMigration(999);
64 expect(r.repoId).toBe(999);
65 expect(r.clonable).toBe(false);
66 expect(r.hasDefaultBranch).toBe(false);
67 expect(r.commitCount).toBe(0);
68 expect(r.issues).toContain("repo not found");
69 });
70
71 it("returns clonable:false with issue when git dir is missing", async () => {
72 _nextRow = { repoName: "ghost", ownerName: "nobody" };
73 const { verifyMigration } = await import("../lib/import-verify");
74 const r = await verifyMigration(42);
75 expect(r.repoId).toBe(42);
76 expect(r.clonable).toBe(false);
77 // At least one of the sentinel-file issues should be present.
78 const hasMissing = r.issues.some(
79 (s) =>
80 s.includes("missing HEAD") ||
81 s.includes("missing config") ||
82 s.includes("missing objects")
83 );
84 expect(hasMissing).toBe(true);
85 // The git shell-outs against a non-existent path should also fail
86 // and contribute to issues, but we don't assert the exact wording
87 // (it varies across git versions).
88 expect(r.hasDefaultBranch).toBe(false);
89 expect(r.commitCount).toBe(0);
90 });
91});