import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, } from "bun:test"; import Caprover, { Application } from "./Caprover"; import { TestApp } from "../domain/testing/TestApp"; import server, { CAPROVER_TEST_DOMAIN, CAPROVER_TEST_PASSWORD, } from "./mocks/caproverServer"; import appsFixtures from "./mocks/apps.fixtures.json"; describe("Caprover", () => { describe("Application", () => { const anAppDefinition = appsFixtures[0]; it("should create an application from definition", () => { const app = Application.createFromDefinition(anAppDefinition); expect(app.name).toBe("adminer"); }); describe("docker image", () => { it("should return the docker image name of the current version", () => { const app = Application.createFromDefinition(anAppDefinition); expect(app.dockerImage).toEqual({ name: "adminer", tag: "4.8.1", hubUrl: "https://hub.docker.com/_/adminer", }); }); it("should parse names with organization namespace", () => { const app = Application.createFromDefinition({ ...anAppDefinition, deployedVersion: 0, versions: [ { ...anAppDefinition.versions[0], deployedImageName: "vaultwarden/server:1.30.0-alpine", }, ], }); expect(app.dockerImage).toEqual({ name: "vaultwarden/server", tag: "1.30.0-alpine", hubUrl: "https://hub.docker.com/r/vaultwarden/server", }); }); it("should not parse custom built images", () => { const app = Application.createFromDefinition({ ...anAppDefinition, deployedVersion: 0, versions: [ { ...anAppDefinition.versions[0], deployedImageName: "registry.example.org:996/captain/img-captain-nextcloud-cron:4", }, ], }); expect(app.dockerImage).toBeUndefined(); }); }); }); describe("Initialization", () => { it("should throw an error when no domain is provided", () => { // @ts-ignore toThrowError exists¯\_(ツ)_/¯ expect(() => new Caprover(new TestApp().eventStore, "")).toThrowError( "Missing domain or password" ); }); it("should throw an error when no password is provided", () => { expect( () => new Caprover(new TestApp().eventStore, CAPROVER_TEST_DOMAIN) // @ts-ignore toThrowError exists¯\_(ツ)_/¯ ).toThrowError("Missing domain or password"); }); }); describe("API interactions", () => { let app: TestApp, caprover: Caprover; beforeAll(() => server.listen()); beforeEach(() => { app = new TestApp(); caprover = new Caprover( app.eventStore, CAPROVER_TEST_DOMAIN, CAPROVER_TEST_PASSWORD ); }); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); describe("getApps", () => { it("should return the list of applications", async () => { const apps = await caprover.getApps(); expect(apps).toBeArrayOfSize(3); expect(apps[0]).toBeInstanceOf(Application); expect(apps[0].name).toBe("adminer"); expect(apps[1].name).toBe("mysql"); expect(apps[2].name).toBe("redis"); }); }); describe("updateApplication", () => { it("should update the application with the provided version and emit an event upon success", async () => { await caprover.updateApplication("adminer", "adminer:4.2.0"); const apps = await caprover.getApps(); expect(apps[0].imageName).toBe("adminer:4.2.0"); const events = app.eventStore.getAllEvents(); expect(events).toBeArrayOfSize(1); expect(events[0]).toMatchObject({ type: "ApplicationUpdateStarted", payload: { id: "adminer", newVersion: "adminer:4.2.0" }, }); }); it("should throw an error when the application does not exist and not emit any event", async () => { await expect( caprover.updateApplication("unknown", "adminer:4.2.0") // @ts-ignore toThrowError exists¯\_(ツ)_/¯ ).rejects.toThrowError(/Failed to update application unknown/); const events = app.eventStore.getAllEvents(); expect(events).toBeArrayOfSize(0); }); }); describe("getLogs", () => { it("should return the logs of the application when it exists", async () => { const logs = await caprover.getLogs("mysql"); expect(logs).toBe("mysql logs"); }); it("should throw an error when the application does not exist", async () => { await expect( caprover.getLogs("unknown") // @ts-ignore toThrowError exists¯\_(ツ)_/¯ ).rejects.toThrowError(/Failed to fetch logs for application unknown/); }); }); }); });