Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

pr-workflow-sync.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.

pr-workflow-sync.test.tsBlame128 lines · 1 contributor
91b054eccanty labs1/**
2 * Tests for src/lib/pr-workflow-sync.ts — the fix for `on: pull_request`
3 * workflow triggers being silently dead. Before this, `enqueueRun()` was
4 * never called with `event: "pull_request"` anywhere in the codebase, so a
5 * workflow declaring `on: pull_request` was parsed, stored in the
6 * `workflows` table (by push-workflow-sync.ts), and never actually run.
7 *
8 * Both the workflow lookup and enqueueRun are passed in via the injectable
9 * `deps` param (same DI rationale as codeowners.test.ts's
10 * requiredOwnersApproved tests) — no mock.module() on ../db or
11 * ../lib/workflow-runner, both of which are imported by dozens of unrelated
12 * test files and would leak a global mock across the whole `bun test` run.
13 */
14
15import { beforeEach, describe, expect, it } from "bun:test";
16import { enqueuePullRequestWorkflows } from "../lib/pr-workflow-sync";
17
18let _workflowRows: Array<{ id: string; onEvents: string }> = [];
19let _selectShouldThrow = false;
20
21let _enqueueCalls: any[] = [];
22let _enqueueShouldThrow = false;
23
24const fakeDeps = {
25 loadWorkflows: async (_repositoryId: string) => {
26 if (_selectShouldThrow) throw new Error("db boom");
27 return _workflowRows;
28 },
29 enqueueRun: async (opts: any) => {
30 if (_enqueueShouldThrow) throw new Error("enqueue boom");
31 _enqueueCalls.push(opts);
32 return "run-id-1";
33 },
34} as any;
35
36beforeEach(() => {
37 _workflowRows = [];
38 _selectShouldThrow = false;
39 _enqueueCalls = [];
40 _enqueueShouldThrow = false;
41});
42
43function baseOpts(overrides: Partial<Parameters<typeof enqueuePullRequestWorkflows>[0]> = {}) {
44 return {
45 repositoryId: "repo-1",
46 headBranch: "feature/foo",
47 headSha: "b".repeat(40),
48 triggeredBy: "user-1",
49 ...overrides,
50 };
51}
52
53describe("enqueuePullRequestWorkflows", () => {
54 it("returns zero enqueued when the repo has no workflows", async () => {
55 _workflowRows = [];
56 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
57 expect(result).toEqual({ enqueued: 0, errors: [] });
58 expect(_enqueueCalls).toHaveLength(0);
59 });
60
61 it("enqueues a workflow whose on: includes pull_request", async () => {
62 _workflowRows = [{ id: "wf-1", onEvents: JSON.stringify(["pull_request"]) }];
63 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
64
65 expect(result.enqueued).toBe(1);
66 expect(result.errors).toEqual([]);
67 expect(_enqueueCalls[0]).toMatchObject({
68 workflowId: "wf-1",
69 repositoryId: "repo-1",
70 event: "pull_request",
71 ref: "feature/foo",
72 commitSha: "b".repeat(40),
73 triggeredBy: "user-1",
74 });
75 });
76
77 it("does NOT enqueue a workflow with only an on:push trigger", async () => {
78 _workflowRows = [{ id: "wf-2", onEvents: JSON.stringify(["push"]) }];
79 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
80
81 expect(result.enqueued).toBe(0);
82 expect(_enqueueCalls).toHaveLength(0);
83 });
84
85 it("enqueues only the matching workflow out of several", async () => {
86 _workflowRows = [
87 { id: "wf-push", onEvents: JSON.stringify(["push"]) },
88 { id: "wf-pr", onEvents: JSON.stringify(["push", "pull_request"]) },
89 { id: "wf-dispatch", onEvents: JSON.stringify(["workflow_dispatch"]) },
90 ];
91 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
92
93 expect(result.enqueued).toBe(1);
94 expect(_enqueueCalls[0].workflowId).toBe("wf-pr");
95 });
96
97 it("records a per-row error but keeps going when onEvents is malformed JSON", async () => {
98 _workflowRows = [
99 { id: "wf-broken", onEvents: "not json" },
100 { id: "wf-good", onEvents: JSON.stringify(["pull_request"]) },
101 ];
102 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
103
104 expect(result.enqueued).toBe(1);
105 expect(_enqueueCalls[0].workflowId).toBe("wf-good");
106 expect(result.errors.some((e) => e.includes("wf-broken"))).toBe(true);
107 });
108
109 it("records an error but does not throw when enqueueRun fails", async () => {
110 _workflowRows = [{ id: "wf-1", onEvents: JSON.stringify(["pull_request"]) }];
111 _enqueueShouldThrow = true;
112
113 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
114
115 expect(result.enqueued).toBe(0);
116 expect(result.errors.length).toBe(1);
117 expect(result.errors[0]).toContain("enqueue");
118 });
119
120 it("returns a query error but does not throw when the DB select fails", async () => {
121 _selectShouldThrow = true;
122 const result = await enqueuePullRequestWorkflows(baseOpts(), fakeDeps);
123
124 expect(result.enqueued).toBe(0);
125 expect(result.errors.length).toBe(1);
126 expect(result.errors[0]).toContain("query");
127 });
128});