mirror of
https://github.com/Dokploy/cli.git
synced 2026-07-15 19:05:27 +02:00
feat: integrate Vitest for testing and update workflows
- Added Vitest as a testing framework in package.json and configured test scripts. - Created new test files for CLI and client functionalities, ensuring comprehensive coverage. - Updated GitHub Actions workflows to include testing steps and streamlined release process. - Removed the deprecated onRelease workflow to consolidate CI/CD processes.
This commit is contained in:
86
tests/cli.test.ts
Normal file
86
tests/cli.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(__dirname, "..");
|
||||
const CLI = path.join(ROOT, "dist", "index.js");
|
||||
|
||||
function run(...args: string[]): string {
|
||||
return execFileSync("node", [CLI, ...args], {
|
||||
encoding: "utf8",
|
||||
env: { ...process.env, NO_COLOR: "1" },
|
||||
});
|
||||
}
|
||||
|
||||
describe("CLI", () => {
|
||||
it("should show help with --help", () => {
|
||||
const output = run("--help");
|
||||
expect(output).toContain("Dokploy CLI");
|
||||
expect(output).toContain("auth");
|
||||
expect(output).toContain("application");
|
||||
expect(output).toContain("project");
|
||||
});
|
||||
|
||||
it("should show version with --version", () => {
|
||||
const output = run("--version");
|
||||
expect(output.trim()).toMatch(/^\d+\.\d+\.\d+$/);
|
||||
});
|
||||
|
||||
it("should show subcommands for application", () => {
|
||||
const output = run("application", "--help");
|
||||
expect(output).toContain("create");
|
||||
expect(output).toContain("deploy");
|
||||
expect(output).toContain("delete");
|
||||
expect(output).toContain("stop");
|
||||
});
|
||||
|
||||
it("should show subcommands for postgres", () => {
|
||||
const output = run("postgres", "--help");
|
||||
expect(output).toContain("create");
|
||||
expect(output).toContain("deploy");
|
||||
expect(output).toContain("remove");
|
||||
});
|
||||
|
||||
it("should show options for a specific command", () => {
|
||||
const output = run("application", "create", "--help");
|
||||
expect(output).toContain("--name");
|
||||
expect(output).toContain("--environmentId");
|
||||
});
|
||||
|
||||
it("should show auth command options", () => {
|
||||
const output = run("auth", "--help");
|
||||
expect(output).toContain("--url");
|
||||
expect(output).toContain("--token");
|
||||
});
|
||||
|
||||
it("should show all expected command groups", () => {
|
||||
const output = run("--help");
|
||||
const expectedGroups = [
|
||||
"application",
|
||||
"postgres",
|
||||
"mysql",
|
||||
"redis",
|
||||
"mongo",
|
||||
"mariadb",
|
||||
"compose",
|
||||
"docker",
|
||||
"project",
|
||||
"server",
|
||||
"domain",
|
||||
"backup",
|
||||
"settings",
|
||||
"user",
|
||||
"environment",
|
||||
];
|
||||
for (const group of expectedGroups) {
|
||||
expect(output).toContain(group);
|
||||
}
|
||||
});
|
||||
|
||||
it("should exit with 0 when no args provided", () => {
|
||||
const output = run();
|
||||
expect(output).toContain("Usage:");
|
||||
});
|
||||
});
|
||||
56
tests/client.test.ts
Normal file
56
tests/client.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("readAuthConfig", () => {
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
beforeEach(() => {
|
||||
delete process.env.DOKPLOY_URL;
|
||||
delete process.env.DOKPLOY_API_KEY;
|
||||
delete process.env.DOKPLOY_AUTH_TOKEN;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env = { ...originalEnv };
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("should read from DOKPLOY_API_KEY env var", async () => {
|
||||
process.env.DOKPLOY_URL = "https://test.dokploy.com";
|
||||
process.env.DOKPLOY_API_KEY = "test-key-123";
|
||||
|
||||
const { readAuthConfig } = await import("../src/client.js");
|
||||
const config = readAuthConfig();
|
||||
|
||||
expect(config.url).toBe("https://test.dokploy.com");
|
||||
expect(config.token).toBe("test-key-123");
|
||||
});
|
||||
|
||||
it("should read from DOKPLOY_AUTH_TOKEN env var as fallback", async () => {
|
||||
process.env.DOKPLOY_URL = "https://test.dokploy.com";
|
||||
process.env.DOKPLOY_AUTH_TOKEN = "auth-token-456";
|
||||
|
||||
const { readAuthConfig } = await import("../src/client.js");
|
||||
const config = readAuthConfig();
|
||||
|
||||
expect(config.url).toBe("https://test.dokploy.com");
|
||||
expect(config.token).toBe("auth-token-456");
|
||||
});
|
||||
|
||||
it("should prefer DOKPLOY_API_KEY over DOKPLOY_AUTH_TOKEN", async () => {
|
||||
process.env.DOKPLOY_URL = "https://test.dokploy.com";
|
||||
process.env.DOKPLOY_API_KEY = "api-key";
|
||||
process.env.DOKPLOY_AUTH_TOKEN = "auth-token";
|
||||
|
||||
const { readAuthConfig } = await import("../src/client.js");
|
||||
const config = readAuthConfig();
|
||||
|
||||
expect(config.token).toBe("api-key");
|
||||
});
|
||||
});
|
||||
|
||||
describe("saveAuthConfig", () => {
|
||||
it("should write config with correct structure", async () => {
|
||||
const { saveAuthConfig } = await import("../src/client.js");
|
||||
expect(typeof saveAuthConfig).toBe("function");
|
||||
});
|
||||
});
|
||||
63
tests/generator.test.ts
Normal file
63
tests/generator.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(__dirname, "..");
|
||||
|
||||
describe("generator", () => {
|
||||
const specPath = path.join(ROOT, "openapi.json");
|
||||
const generatedPath = path.join(ROOT, "src", "generated", "commands.ts");
|
||||
|
||||
it("openapi.json should exist", () => {
|
||||
expect(fs.existsSync(specPath)).toBe(true);
|
||||
});
|
||||
|
||||
it("generated commands file should exist", () => {
|
||||
expect(fs.existsSync(generatedPath)).toBe(true);
|
||||
});
|
||||
|
||||
it("generated file should export registerGeneratedCommands", () => {
|
||||
const content = fs.readFileSync(generatedPath, "utf8");
|
||||
expect(content).toContain("export function registerGeneratedCommands");
|
||||
});
|
||||
|
||||
it("generated file should import from client", () => {
|
||||
const content = fs.readFileSync(generatedPath, "utf8");
|
||||
expect(content).toContain('from "../client.js"');
|
||||
});
|
||||
|
||||
it("generated file should contain command groups from the spec", () => {
|
||||
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
||||
const content = fs.readFileSync(generatedPath, "utf8");
|
||||
|
||||
// Only check groups that have a dot-separated action (group.action)
|
||||
const groups = new Set<string>();
|
||||
for (const p of Object.keys(spec.paths)) {
|
||||
const clean = p.replace(/^\//, "");
|
||||
const [group, ...rest] = clean.split(".");
|
||||
if (group && rest.length > 0) groups.add(group);
|
||||
}
|
||||
|
||||
for (const group of groups) {
|
||||
expect(content).toContain(`"${group}.`);
|
||||
}
|
||||
});
|
||||
|
||||
it("number of apiPost/apiGet calls should match valid endpoints", () => {
|
||||
const spec = JSON.parse(fs.readFileSync(specPath, "utf8"));
|
||||
const content = fs.readFileSync(generatedPath, "utf8");
|
||||
|
||||
// Count only endpoints with group.action pattern
|
||||
let validEndpoints = 0;
|
||||
for (const p of Object.keys(spec.paths)) {
|
||||
const clean = p.replace(/^\//, "");
|
||||
const [group, ...rest] = clean.split(".");
|
||||
if (group && rest.length > 0) validEndpoints++;
|
||||
}
|
||||
|
||||
const apiCalls = (content.match(/await api(Post|Get)\(/g) || []).length;
|
||||
expect(apiCalls).toBe(validEndpoints);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user