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

workflow-conditionals.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.

workflow-conditionals.test.tsBlame100 lines · 1 contributor
f3e1873Claude1/**
2 * Unit tests for src/lib/workflow-conditionals.ts (Agent 4, Sprint 1).
3 *
4 * Pure evaluator — no external state, no eval(), no DB. We exercise the
5 * grammar corners: precedence, literals, context lookups, the small set of
6 * built-in helper functions (success/failure/always/contains/startsWith),
7 * and the `${{ ... }}` wrapper strip.
8 */
9
10import { describe, it, expect } from "bun:test";
11import { evaluateIf } from "../lib/workflow-conditionals";
12
13describe("workflow-conditionals — evaluateIf", () => {
14 it("undefined / null / empty expression evaluates to true", () => {
15 expect(evaluateIf(undefined, {})).toEqual({ ok: true, value: true });
16 expect(evaluateIf(null, {})).toEqual({ ok: true, value: true });
17 expect(evaluateIf("", {})).toEqual({ ok: true, value: true });
18 expect(evaluateIf(" ", {})).toEqual({ ok: true, value: true });
19 });
20
21 it("literal 'true' and 'false' evaluate correctly", () => {
22 expect(evaluateIf("true", {})).toEqual({ ok: true, value: true });
23 expect(evaluateIf("false", {})).toEqual({ ok: true, value: false });
24 });
25
26 it("context lookup with env.FOO == 'bar' returns true when matched", () => {
27 const r = evaluateIf("env.FOO == 'bar'", { env: { FOO: "bar" } });
28 expect(r).toEqual({ ok: true, value: true });
29 });
30
31 it("missing context key resolves to null and is falsy", () => {
32 const r = evaluateIf("env.DOES_NOT_EXIST", { env: {} });
33 expect(r).toEqual({ ok: true, value: false });
34 });
35
36 it("negation `!success()` is true when job status is 'failure'", () => {
37 const r = evaluateIf("!success()", { job: { status: "failure" } });
38 expect(r).toEqual({ ok: true, value: true });
39 });
40
41 it("&& binds tighter than || (precedence check)", () => {
42 // true && false || true -> (true && false) || true -> true
43 const r1 = evaluateIf("true && false || true", {});
44 expect(r1).toEqual({ ok: true, value: true });
45 // false || true && false -> false || (true && false) -> false
46 const r2 = evaluateIf("false || true && false", {});
47 expect(r2).toEqual({ ok: true, value: false });
48 // Mixed with equality: env.a == 'x' && env.b == 'y' || env.c == 'z'
49 const r3 = evaluateIf(
50 "env.a == 'x' && env.b == 'y' || env.c == 'z'",
51 { env: { a: "x", b: "y", c: "no" } }
52 );
53 expect(r3).toEqual({ ok: true, value: true });
54 });
55
56 it("contains('abcdef', 'cd') returns true", () => {
57 const r = evaluateIf("contains('abcdef', 'cd')", {});
58 expect(r).toEqual({ ok: true, value: true });
59 const miss = evaluateIf("contains('abcdef', 'zz')", {});
60 expect(miss).toEqual({ ok: true, value: false });
61 });
62
63 it("startsWith('refs/heads/main', 'refs/heads/') returns true", () => {
64 const r = evaluateIf("startsWith('refs/heads/main', 'refs/heads/')", {});
65 expect(r).toEqual({ ok: true, value: true });
66 });
67
68 it("always() returns true even when job.status == 'failure'", () => {
69 const r = evaluateIf("always()", { job: { status: "failure" } });
70 expect(r).toEqual({ ok: true, value: true });
71 });
72
73 it("success() is true when job.status is unset (default running/ok)", () => {
74 const r = evaluateIf("success()", {});
75 expect(r).toEqual({ ok: true, value: true });
76 });
77
78 it("failure() is true only when job.status == 'failure'", () => {
79 expect(evaluateIf("failure()", { job: { status: "failure" } })).toEqual({
80 ok: true,
81 value: true,
82 });
83 expect(evaluateIf("failure()", { job: { status: "success" } })).toEqual({
84 ok: true,
85 value: false,
86 });
87 expect(evaluateIf("failure()", {})).toEqual({ ok: true, value: false });
88 });
89
90 it("strips a surrounding ${{ ... }} wrapper before evaluating", () => {
91 const r = evaluateIf("${{ env.FOO == 'bar' }}", { env: { FOO: "bar" } });
92 expect(r).toEqual({ ok: true, value: true });
93 });
94
95 it("malformed expressions return {ok:false, error}", () => {
96 const r = evaluateIf("== == ==", {});
97 expect(r.ok).toBe(false);
98 if (!r.ok) expect(r.error.length).toBeGreaterThan(0);
99 });
100});