diff --git a/src/lib/deploy-workflow-contract.test.ts b/src/lib/deploy-workflow-contract.test.ts index 07d8c0e0..051fa775 100644 --- a/src/lib/deploy-workflow-contract.test.ts +++ b/src/lib/deploy-workflow-contract.test.ts @@ -2,6 +2,16 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { describe, expect, it } from "vitest"; +const liveVar = "${" + "LIVE}"; +const stageVar = "${" + "STAGE}"; +const userVar = "${" + "DEPLOY_USER}"; +const groupVar = "${" + "DEPLOY_GROUP}"; +const appVerVar = "${" + "APP_VERSION}"; + +function toContainLiteral(workflow: string, literal: string) { + return workflow.indexOf(literal) >= 0; +} + describe("production deploy workflow", () => { const workflow = readFileSync( resolve(process.cwd(), ".gitea/workflows/deploy.yaml"), @@ -12,7 +22,7 @@ describe("production deploy workflow", () => { it("builds in a stage worktree while preserving live .env and storage", () => { expect(deployJob).toContain("worktree add --detach"); expect(deployJob).toContain("/var/tmp/atom-nexst-stage-"); - expect(deployJob).toContain('ln -sfn "${LIVE}/.env"'); + expect(toContainLiteral(deployJob, `ln -sfn "${liveVar}/.env"`)).toBe(true); expect(deployJob).toContain("-e storage"); expect(deployJob).toContain("DATABASE_POOL_SIZE="); expect(deployJob).toContain("REDIS_URL is unset"); @@ -21,13 +31,11 @@ describe("production deploy workflow", () => { }); it("reclaims ownership before git operations so www-data files can be overwritten", () => { - expect(workflow).toContain( - 'sudo chown -R "$' + "{DEPLOY_USER}:" + "$" + '{DEPLOY_GROUP}"', - ); - const reclaimAt = deployJob.indexOf( - 'sudo chown -R "$' + "{DEPLOY_USER}:" + "$" + '{DEPLOY_GROUP}"', - ); - const fetchAt = deployJob.indexOf('git -C "${LIVE}" fetch origin --prune'); + const chownCmd = `sudo chown -R "${userVar}:${groupVar}"`; + expect(toContainLiteral(workflow, chownCmd)).toBe(true); + const reclaimAt = deployJob.indexOf(chownCmd); + expect(toContainLiteral(deployJob, `git -C "${liveVar}" fetch origin --prune`)).toBe(true); + const fetchAt = deployJob.indexOf(`git -C "${liveVar}" fetch origin --prune`); expect(reclaimAt).toBeGreaterThan(-1); expect(fetchAt).toBeGreaterThan(reclaimAt); }); @@ -45,8 +53,8 @@ describe("production deploy workflow", () => { it("swaps a built .next artifact during a short service cutover", () => { expect(deployJob).toContain("mv .next .next.prev"); - expect(deployJob).toContain('mv "${STAGE}/.next" .next'); - expect(deployJob).toContain('mv "${STAGE}/node_modules" node_modules'); + expect(toContainLiteral(deployJob, `mv "${stageVar}/.next" .next`)).toBe(true); + expect(toContainLiteral(deployJob, `mv "${stageVar}/node_modules" node_modules`)).toBe(true); expect(deployJob).toContain("Rolling back .next to previous artifact"); const buildAt = deployJob.indexOf("pnpm build"); const stopAt = deployJob.indexOf("pm2 stop next"); @@ -55,7 +63,6 @@ describe("production deploy workflow", () => { const startAt = deployJob.indexOf("pm2 reload next", startLabelAt); expect(buildAt).toBeGreaterThan(-1); expect(stopAt).toBeGreaterThan(buildAt); - // Migrate runs after stop so the live pool frees DB slots. expect(migrateAt).toBeGreaterThan(stopAt); expect(startLabelAt).toBeGreaterThan(migrateAt); expect(startAt).toBeGreaterThan(startLabelAt); @@ -75,12 +82,9 @@ describe("production deploy workflow", () => { }); it("exports APP_VERSION from git for Sentry releases", () => { - expect(workflow).toContain( - 'export APP_VERSION="$(git -C "${LIVE}" rev-parse --short origin/main)"', - ); - expect(workflow).toContain( - 'export NEXT_PUBLIC_APP_VERSION="$' + '{APP_VERSION}"', - ); + const exportCmd = `export APP_VERSION="$(git -C "${liveVar}" rev-parse --short origin/main)"`; + expect(toContainLiteral(workflow, exportCmd)).toBe(true); + expect(toContainLiteral(workflow, `export NEXT_PUBLIC_APP_VERSION="${appVerVar}"`)).toBe(true); }); it("runs an HTTP health check before declaring deploy success", () => { diff --git a/src/lib/services/send-currency.test.ts b/src/lib/services/send-currency.test.ts index 605f8c78..63b11315 100644 --- a/src/lib/services/send-currency.test.ts +++ b/src/lib/services/send-currency.test.ts @@ -1,15 +1,18 @@ import { describe, expect, it, vi } from "vitest"; +import type { CurrencyDb } from "./send-currency"; vi.mock("@/lib/services/rcon", () => ({})); import { sendCurrency } from "./send-currency"; +const mockDb = {} as CurrencyDb; + describe("sendCurrency", () => { it("returns false for non-positive amount", async () => { - expect(await sendCurrency({} as any, 1, "credits", 0)).toBe(false); - expect(await sendCurrency({} as any, 1, "credits", -5)).toBe(false); - expect(await sendCurrency({} as any, 1, "credits", null)).toBe(false); - expect(await sendCurrency({} as any, 1, "credits", undefined)).toBe(false); + expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", 0)).toBe(false); + expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", -5)).toBe(false); + expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", null)).toBe(false); + expect(await sendCurrency({ rcon: {} as never, db: mockDb }, 1, "credits", undefined)).toBe(false); }); it("delivers credits via RCON", async () => { @@ -20,7 +23,7 @@ describe("sendCurrency", () => { givePointsGotw: vi.fn(), }; const result = await sendCurrency( - { rcon, db: {} as any }, + { rcon, db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } } }, 1, "credits", 100, @@ -40,7 +43,7 @@ describe("sendCurrency", () => { const result = await sendCurrency( { rcon, - db: { user: { update: userUpdate } } as any, + db: { user: { update: userUpdate }, usersCurrency: { upsert: vi.fn() } }, }, 1, "credits", @@ -61,7 +64,7 @@ describe("sendCurrency", () => { givePointsGotw: vi.fn(), }; const result = await sendCurrency( - { rcon, db: {} as any }, + { rcon, db: { user: { update: vi.fn() }, usersCurrency: { upsert: vi.fn() } } }, 1, "duckets", 50, @@ -81,7 +84,7 @@ describe("sendCurrency", () => { await sendCurrency( { rcon, - db: { usersCurrency: { upsert } } as any, + db: { user: { update: vi.fn() }, usersCurrency: { upsert } }, }, 1, "duckets", @@ -107,7 +110,7 @@ describe("sendCurrency", () => { await sendCurrency( { rcon, - db: { usersCurrency: { upsert } } as any, + db: { user: { update: vi.fn() }, usersCurrency: { upsert } }, }, 1, "diamonds", @@ -133,7 +136,7 @@ describe("sendCurrency", () => { await sendCurrency( { rcon, - db: { usersCurrency: { upsert } } as any, + db: { user: { update: vi.fn() }, usersCurrency: { upsert } }, }, 1, "points",