@better-openclaw/core 1.0.30 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/deployers/coolify.test.cjs +156 -0
- package/dist/deployers/coolify.test.cjs.map +1 -0
- package/dist/deployers/coolify.test.d.cts +1 -0
- package/dist/deployers/coolify.test.d.mts +1 -0
- package/dist/deployers/coolify.test.mjs +157 -0
- package/dist/deployers/coolify.test.mjs.map +1 -0
- package/dist/deployers/dokploy.test.cjs +108 -0
- package/dist/deployers/dokploy.test.cjs.map +1 -0
- package/dist/deployers/dokploy.test.d.cts +1 -0
- package/dist/deployers/dokploy.test.d.mts +1 -0
- package/dist/deployers/dokploy.test.mjs +109 -0
- package/dist/deployers/dokploy.test.mjs.map +1 -0
- package/dist/frameworks/frameworks.test.cjs +94 -0
- package/dist/frameworks/frameworks.test.cjs.map +1 -0
- package/dist/frameworks/frameworks.test.d.cts +1 -0
- package/dist/frameworks/frameworks.test.d.mts +1 -0
- package/dist/frameworks/frameworks.test.mjs +94 -0
- package/dist/frameworks/frameworks.test.mjs.map +1 -0
- package/dist/generators/cloud-init.test.cjs +58 -0
- package/dist/generators/cloud-init.test.cjs.map +1 -0
- package/dist/generators/cloud-init.test.d.cts +1 -0
- package/dist/generators/cloud-init.test.d.mts +1 -0
- package/dist/generators/cloud-init.test.mjs +59 -0
- package/dist/generators/cloud-init.test.mjs.map +1 -0
- package/dist/generators/get-shit-done.test.cjs +48 -0
- package/dist/generators/get-shit-done.test.cjs.map +1 -0
- package/dist/generators/get-shit-done.test.d.cts +1 -0
- package/dist/generators/get-shit-done.test.d.mts +1 -0
- package/dist/generators/get-shit-done.test.mjs +49 -0
- package/dist/generators/get-shit-done.test.mjs.map +1 -0
- package/dist/generators/grafana.test.cjs +74 -0
- package/dist/generators/grafana.test.cjs.map +1 -0
- package/dist/generators/grafana.test.d.cts +1 -0
- package/dist/generators/grafana.test.d.mts +1 -0
- package/dist/generators/grafana.test.mjs +74 -0
- package/dist/generators/grafana.test.mjs.map +1 -0
- package/dist/generators/n8n-workflows.test.cjs +75 -0
- package/dist/generators/n8n-workflows.test.cjs.map +1 -0
- package/dist/generators/n8n-workflows.test.d.cts +1 -0
- package/dist/generators/n8n-workflows.test.d.mts +1 -0
- package/dist/generators/n8n-workflows.test.mjs +76 -0
- package/dist/generators/n8n-workflows.test.mjs.map +1 -0
- package/dist/generators/openclaw-install-script.test.cjs +35 -0
- package/dist/generators/openclaw-install-script.test.cjs.map +1 -0
- package/dist/generators/openclaw-install-script.test.d.cts +1 -0
- package/dist/generators/openclaw-install-script.test.d.mts +1 -0
- package/dist/generators/openclaw-install-script.test.mjs +36 -0
- package/dist/generators/openclaw-install-script.test.mjs.map +1 -0
- package/dist/generators/postgres-init.test.cjs +111 -0
- package/dist/generators/postgres-init.test.cjs.map +1 -0
- package/dist/generators/postgres-init.test.d.cts +1 -0
- package/dist/generators/postgres-init.test.d.mts +1 -0
- package/dist/generators/postgres-init.test.mjs +112 -0
- package/dist/generators/postgres-init.test.mjs.map +1 -0
- package/dist/generators/prometheus.test.cjs +99 -0
- package/dist/generators/prometheus.test.cjs.map +1 -0
- package/dist/generators/prometheus.test.d.cts +1 -0
- package/dist/generators/prometheus.test.d.mts +1 -0
- package/dist/generators/prometheus.test.mjs +99 -0
- package/dist/generators/prometheus.test.mjs.map +1 -0
- package/dist/generators/stack-manifest.test.cjs +97 -0
- package/dist/generators/stack-manifest.test.cjs.map +1 -0
- package/dist/generators/stack-manifest.test.d.cts +1 -0
- package/dist/generators/stack-manifest.test.d.mts +1 -0
- package/dist/generators/stack-manifest.test.mjs +98 -0
- package/dist/generators/stack-manifest.test.mjs.map +1 -0
- package/dist/index.cjs +0 -2
- package/dist/index.d.cts +1 -2
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +1 -2
- package/dist/logger/index.cjs +0 -2
- package/dist/logger/index.d.cts +1 -2
- package/dist/logger/index.d.mts +1 -2
- package/dist/logger/index.mjs +1 -2
- package/dist/port-scanner.test.cjs +155 -0
- package/dist/port-scanner.test.cjs.map +1 -0
- package/dist/port-scanner.test.d.cts +1 -0
- package/dist/port-scanner.test.d.mts +1 -0
- package/dist/port-scanner.test.mjs +156 -0
- package/dist/port-scanner.test.mjs.map +1 -0
- package/package.json +1 -1
- package/src/deployers/coolify.test.ts +180 -0
- package/src/deployers/dokploy.test.ts +120 -0
- package/src/frameworks/frameworks.test.ts +119 -0
- package/src/generators/cloud-init.test.ts +70 -0
- package/src/generators/get-shit-done.test.ts +54 -0
- package/src/generators/grafana.test.ts +90 -0
- package/src/generators/n8n-workflows.test.ts +80 -0
- package/src/generators/openclaw-install-script.test.ts +42 -0
- package/src/generators/postgres-init.test.ts +116 -0
- package/src/generators/prometheus.test.ts +108 -0
- package/src/generators/stack-manifest.test.ts +104 -0
- package/src/index.ts +3 -2
- package/src/logger/index.ts +2 -1
- package/src/port-scanner.test.ts +167 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { a as describe, o as it, t as globalExpect } from "../test.CTcmp4Su-BRa7-bTj.mjs";
|
|
2
|
+
import { generateGrafanaConfig, generateGrafanaDashboard } from "./grafana.mjs";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
//#region src/generators/grafana.test.ts
|
|
5
|
+
describe("generateGrafanaConfig", () => {
|
|
6
|
+
it("returns multiple config files", () => {
|
|
7
|
+
const files = generateGrafanaConfig();
|
|
8
|
+
globalExpect(Object.keys(files).length).toBeGreaterThanOrEqual(3);
|
|
9
|
+
});
|
|
10
|
+
it("generates datasource provisioning YAML", () => {
|
|
11
|
+
const dsFile = generateGrafanaConfig()["config/grafana/provisioning/datasources/prometheus.yml"];
|
|
12
|
+
globalExpect(dsFile).toBeDefined();
|
|
13
|
+
const parsed = parse(dsFile);
|
|
14
|
+
globalExpect(parsed.datasources).toBeInstanceOf(Array);
|
|
15
|
+
globalExpect(parsed.datasources[0].type).toBe("prometheus");
|
|
16
|
+
globalExpect(parsed.datasources[0].isDefault).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("generates dashboard provisioning YAML", () => {
|
|
19
|
+
const dashFile = generateGrafanaConfig()["config/grafana/provisioning/dashboards/default.yml"];
|
|
20
|
+
globalExpect(dashFile).toBeDefined();
|
|
21
|
+
const parsed = parse(dashFile);
|
|
22
|
+
globalExpect(parsed.providers).toBeInstanceOf(Array);
|
|
23
|
+
globalExpect(parsed.providers[0].name).toContain("OpenClaw");
|
|
24
|
+
});
|
|
25
|
+
it("generates grafana.ini configuration", () => {
|
|
26
|
+
const iniFile = generateGrafanaConfig()["config/grafana/grafana.ini"];
|
|
27
|
+
globalExpect(iniFile).toBeDefined();
|
|
28
|
+
globalExpect(iniFile).toContain("[server]");
|
|
29
|
+
globalExpect(iniFile).toContain("[security]");
|
|
30
|
+
globalExpect(iniFile).toContain("[alerting]");
|
|
31
|
+
});
|
|
32
|
+
it("disables anonymous auth", () => {
|
|
33
|
+
const iniFile = generateGrafanaConfig()["config/grafana/grafana.ini"];
|
|
34
|
+
globalExpect(iniFile).toContain("[auth.anonymous]");
|
|
35
|
+
globalExpect(iniFile).toContain("enabled = false");
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("generateGrafanaDashboard", () => {
|
|
39
|
+
it("returns valid JSON", () => {
|
|
40
|
+
const json = generateGrafanaDashboard();
|
|
41
|
+
globalExpect(JSON.parse(json)).toBeDefined();
|
|
42
|
+
});
|
|
43
|
+
it("includes expected panels", () => {
|
|
44
|
+
const dashboard = JSON.parse(generateGrafanaDashboard());
|
|
45
|
+
globalExpect(dashboard.panels).toBeInstanceOf(Array);
|
|
46
|
+
globalExpect(dashboard.panels.length).toBe(3);
|
|
47
|
+
const titles = dashboard.panels.map((p) => p.title);
|
|
48
|
+
globalExpect(titles).toContain("Service Health");
|
|
49
|
+
globalExpect(titles).toContain("Memory Usage");
|
|
50
|
+
globalExpect(titles).toContain("Request Rate");
|
|
51
|
+
});
|
|
52
|
+
it("uses prometheus as datasource", () => {
|
|
53
|
+
const dashboard = JSON.parse(generateGrafanaDashboard());
|
|
54
|
+
for (const panel of dashboard.panels) globalExpect(panel.datasource.type).toBe("prometheus");
|
|
55
|
+
});
|
|
56
|
+
it("has openclaw tag", () => {
|
|
57
|
+
globalExpect(JSON.parse(generateGrafanaDashboard()).tags).toContain("openclaw");
|
|
58
|
+
});
|
|
59
|
+
it("has correct schema version", () => {
|
|
60
|
+
globalExpect(JSON.parse(generateGrafanaDashboard()).schemaVersion).toBe(39);
|
|
61
|
+
});
|
|
62
|
+
it("panels have proper grid positions", () => {
|
|
63
|
+
const dashboard = JSON.parse(generateGrafanaDashboard());
|
|
64
|
+
for (const panel of dashboard.panels) {
|
|
65
|
+
globalExpect(panel.gridPos).toBeDefined();
|
|
66
|
+
globalExpect(panel.gridPos.h).toBeGreaterThan(0);
|
|
67
|
+
globalExpect(panel.gridPos.w).toBeGreaterThan(0);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//#endregion
|
|
72
|
+
export {};
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=grafana.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grafana.test.mjs","names":[],"sources":["../../src/generators/grafana.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { parse } from \"yaml\";\nimport { generateGrafanaConfig, generateGrafanaDashboard } from \"./grafana.js\";\n\ndescribe(\"generateGrafanaConfig\", () => {\n\tit(\"returns multiple config files\", () => {\n\t\tconst files = generateGrafanaConfig();\n\t\texpect(Object.keys(files).length).toBeGreaterThanOrEqual(3);\n\t});\n\n\tit(\"generates datasource provisioning YAML\", () => {\n\t\tconst files = generateGrafanaConfig();\n\t\tconst dsFile = files[\"config/grafana/provisioning/datasources/prometheus.yml\"];\n\t\texpect(dsFile).toBeDefined();\n\t\tconst parsed = parse(dsFile!);\n\t\texpect(parsed.datasources).toBeInstanceOf(Array);\n\t\texpect(parsed.datasources[0].type).toBe(\"prometheus\");\n\t\texpect(parsed.datasources[0].isDefault).toBe(true);\n\t});\n\n\tit(\"generates dashboard provisioning YAML\", () => {\n\t\tconst files = generateGrafanaConfig();\n\t\tconst dashFile = files[\"config/grafana/provisioning/dashboards/default.yml\"];\n\t\texpect(dashFile).toBeDefined();\n\t\tconst parsed = parse(dashFile!);\n\t\texpect(parsed.providers).toBeInstanceOf(Array);\n\t\texpect(parsed.providers[0].name).toContain(\"OpenClaw\");\n\t});\n\n\tit(\"generates grafana.ini configuration\", () => {\n\t\tconst files = generateGrafanaConfig();\n\t\tconst iniFile = files[\"config/grafana/grafana.ini\"];\n\t\texpect(iniFile).toBeDefined();\n\t\texpect(iniFile).toContain(\"[server]\");\n\t\texpect(iniFile).toContain(\"[security]\");\n\t\texpect(iniFile).toContain(\"[alerting]\");\n\t});\n\n\tit(\"disables anonymous auth\", () => {\n\t\tconst files = generateGrafanaConfig();\n\t\tconst iniFile = files[\"config/grafana/grafana.ini\"]!;\n\t\texpect(iniFile).toContain(\"[auth.anonymous]\");\n\t\texpect(iniFile).toContain(\"enabled = false\");\n\t});\n});\n\ndescribe(\"generateGrafanaDashboard\", () => {\n\tit(\"returns valid JSON\", () => {\n\t\tconst json = generateGrafanaDashboard();\n\t\tconst dashboard = JSON.parse(json);\n\t\texpect(dashboard).toBeDefined();\n\t});\n\n\tit(\"includes expected panels\", () => {\n\t\tconst dashboard = JSON.parse(generateGrafanaDashboard());\n\t\texpect(dashboard.panels).toBeInstanceOf(Array);\n\t\texpect(dashboard.panels.length).toBe(3);\n\n\t\tconst titles = dashboard.panels.map((p: { title: string }) => p.title);\n\t\texpect(titles).toContain(\"Service Health\");\n\t\texpect(titles).toContain(\"Memory Usage\");\n\t\texpect(titles).toContain(\"Request Rate\");\n\t});\n\n\tit(\"uses prometheus as datasource\", () => {\n\t\tconst dashboard = JSON.parse(generateGrafanaDashboard());\n\t\tfor (const panel of dashboard.panels) {\n\t\t\texpect(panel.datasource.type).toBe(\"prometheus\");\n\t\t}\n\t});\n\n\tit(\"has openclaw tag\", () => {\n\t\tconst dashboard = JSON.parse(generateGrafanaDashboard());\n\t\texpect(dashboard.tags).toContain(\"openclaw\");\n\t});\n\n\tit(\"has correct schema version\", () => {\n\t\tconst dashboard = JSON.parse(generateGrafanaDashboard());\n\t\texpect(dashboard.schemaVersion).toBe(39);\n\t});\n\n\tit(\"panels have proper grid positions\", () => {\n\t\tconst dashboard = JSON.parse(generateGrafanaDashboard());\n\t\tfor (const panel of dashboard.panels) {\n\t\t\texpect(panel.gridPos).toBeDefined();\n\t\t\texpect(panel.gridPos.h).toBeGreaterThan(0);\n\t\t\texpect(panel.gridPos.w).toBeGreaterThan(0);\n\t\t}\n\t});\n});\n"],"mappings":";;;;AAIA,SAAS,+BAA+B;AACvC,IAAG,uCAAuC;EACzC,MAAM,QAAQ,uBAAuB;AACrC,eAAO,OAAO,KAAK,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE;GAC1D;AAEF,IAAG,gDAAgD;EAElD,MAAM,SADQ,uBAAuB,CAChB;AACrB,eAAO,OAAO,CAAC,aAAa;EAC5B,MAAM,SAAS,MAAM,OAAQ;AAC7B,eAAO,OAAO,YAAY,CAAC,eAAe,MAAM;AAChD,eAAO,OAAO,YAAY,GAAG,KAAK,CAAC,KAAK,aAAa;AACrD,eAAO,OAAO,YAAY,GAAG,UAAU,CAAC,KAAK,KAAK;GACjD;AAEF,IAAG,+CAA+C;EAEjD,MAAM,WADQ,uBAAuB,CACd;AACvB,eAAO,SAAS,CAAC,aAAa;EAC9B,MAAM,SAAS,MAAM,SAAU;AAC/B,eAAO,OAAO,UAAU,CAAC,eAAe,MAAM;AAC9C,eAAO,OAAO,UAAU,GAAG,KAAK,CAAC,UAAU,WAAW;GACrD;AAEF,IAAG,6CAA6C;EAE/C,MAAM,UADQ,uBAAuB,CACf;AACtB,eAAO,QAAQ,CAAC,aAAa;AAC7B,eAAO,QAAQ,CAAC,UAAU,WAAW;AACrC,eAAO,QAAQ,CAAC,UAAU,aAAa;AACvC,eAAO,QAAQ,CAAC,UAAU,aAAa;GACtC;AAEF,IAAG,iCAAiC;EAEnC,MAAM,UADQ,uBAAuB,CACf;AACtB,eAAO,QAAQ,CAAC,UAAU,mBAAmB;AAC7C,eAAO,QAAQ,CAAC,UAAU,kBAAkB;GAC3C;EACD;AAEF,SAAS,kCAAkC;AAC1C,IAAG,4BAA4B;EAC9B,MAAM,OAAO,0BAA0B;AAEvC,eADkB,KAAK,MAAM,KAAK,CACjB,CAAC,aAAa;GAC9B;AAEF,IAAG,kCAAkC;EACpC,MAAM,YAAY,KAAK,MAAM,0BAA0B,CAAC;AACxD,eAAO,UAAU,OAAO,CAAC,eAAe,MAAM;AAC9C,eAAO,UAAU,OAAO,OAAO,CAAC,KAAK,EAAE;EAEvC,MAAM,SAAS,UAAU,OAAO,KAAK,MAAyB,EAAE,MAAM;AACtE,eAAO,OAAO,CAAC,UAAU,iBAAiB;AAC1C,eAAO,OAAO,CAAC,UAAU,eAAe;AACxC,eAAO,OAAO,CAAC,UAAU,eAAe;GACvC;AAEF,IAAG,uCAAuC;EACzC,MAAM,YAAY,KAAK,MAAM,0BAA0B,CAAC;AACxD,OAAK,MAAM,SAAS,UAAU,OAC7B,cAAO,MAAM,WAAW,KAAK,CAAC,KAAK,aAAa;GAEhD;AAEF,IAAG,0BAA0B;AAE5B,eADkB,KAAK,MAAM,0BAA0B,CAAC,CACvC,KAAK,CAAC,UAAU,WAAW;GAC3C;AAEF,IAAG,oCAAoC;AAEtC,eADkB,KAAK,MAAM,0BAA0B,CAAC,CACvC,cAAc,CAAC,KAAK,GAAG;GACvC;AAEF,IAAG,2CAA2C;EAC7C,MAAM,YAAY,KAAK,MAAM,0BAA0B,CAAC;AACxD,OAAK,MAAM,SAAS,UAAU,QAAQ;AACrC,gBAAO,MAAM,QAAQ,CAAC,aAAa;AACnC,gBAAO,MAAM,QAAQ,EAAE,CAAC,gBAAgB,EAAE;AAC1C,gBAAO,MAAM,QAAQ,EAAE,CAAC,gBAAgB,EAAE;;GAE1C;EACD"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const require_test_CTcmp4Su = require("../test.CTcmp4Su-BWSPM8ZQ.cjs");
|
|
2
|
+
const require_generators_n8n_workflows = require("./n8n-workflows.cjs");
|
|
3
|
+
//#region src/generators/n8n-workflows.test.ts
|
|
4
|
+
function makeResolved(serviceIds) {
|
|
5
|
+
return {
|
|
6
|
+
services: serviceIds.map((id) => ({
|
|
7
|
+
definition: {
|
|
8
|
+
id,
|
|
9
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
10
|
+
description: "",
|
|
11
|
+
icon: "",
|
|
12
|
+
category: "test",
|
|
13
|
+
image: `${id}:latest`,
|
|
14
|
+
ports: [],
|
|
15
|
+
volumes: [],
|
|
16
|
+
environment: [],
|
|
17
|
+
dependencies: [],
|
|
18
|
+
conflicts: [],
|
|
19
|
+
skills: [],
|
|
20
|
+
memoryMB: 256,
|
|
21
|
+
docsUrl: ""
|
|
22
|
+
},
|
|
23
|
+
addedBy: "user"
|
|
24
|
+
})),
|
|
25
|
+
addedDependencies: [],
|
|
26
|
+
estimatedMemoryMB: 512
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
require_test_CTcmp4Su.describe("generateN8nWorkflows", () => {
|
|
30
|
+
require_test_CTcmp4Su.it("returns empty object when n8n is not in the stack", () => {
|
|
31
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["redis", "postgresql"]));
|
|
32
|
+
require_test_CTcmp4Su.globalExpect(Object.keys(result)).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
require_test_CTcmp4Su.it("generates workflow file when n8n is present", () => {
|
|
35
|
+
require_test_CTcmp4Su.globalExpect(require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["n8n", "redis"]))).toHaveProperty("n8n/workflows/openclaw-webhook-handler.json");
|
|
36
|
+
});
|
|
37
|
+
require_test_CTcmp4Su.it("generates valid JSON workflow", () => {
|
|
38
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["n8n"]));
|
|
39
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
40
|
+
require_test_CTcmp4Su.globalExpect(workflow).toBeDefined();
|
|
41
|
+
require_test_CTcmp4Su.globalExpect(workflow.name).toBe("OpenClaw Webhook Handler");
|
|
42
|
+
});
|
|
43
|
+
require_test_CTcmp4Su.it("workflow has three nodes (webhook, process, respond)", () => {
|
|
44
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["n8n", "redis"]));
|
|
45
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
46
|
+
require_test_CTcmp4Su.globalExpect(workflow.nodes).toHaveLength(3);
|
|
47
|
+
const types = workflow.nodes.map((n) => n.type);
|
|
48
|
+
require_test_CTcmp4Su.globalExpect(types).toContain("n8n-nodes-base.webhook");
|
|
49
|
+
require_test_CTcmp4Su.globalExpect(types).toContain("n8n-nodes-base.code");
|
|
50
|
+
require_test_CTcmp4Su.globalExpect(types).toContain("n8n-nodes-base.respondToWebhook");
|
|
51
|
+
});
|
|
52
|
+
require_test_CTcmp4Su.it("workflow has correct connections", () => {
|
|
53
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["n8n"]));
|
|
54
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
55
|
+
require_test_CTcmp4Su.globalExpect(workflow.connections).toHaveProperty("Webhook");
|
|
56
|
+
require_test_CTcmp4Su.globalExpect(workflow.connections).toHaveProperty("Process Payload");
|
|
57
|
+
});
|
|
58
|
+
require_test_CTcmp4Su.it("workflow is not active by default", () => {
|
|
59
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved(["n8n"]));
|
|
60
|
+
require_test_CTcmp4Su.globalExpect(JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]).active).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
require_test_CTcmp4Su.it("includes service names in the code node comment", () => {
|
|
63
|
+
const result = require_generators_n8n_workflows.generateN8nWorkflows(makeResolved([
|
|
64
|
+
"n8n",
|
|
65
|
+
"redis",
|
|
66
|
+
"postgresql"
|
|
67
|
+
]));
|
|
68
|
+
const codeNode = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]).nodes.find((n) => n.type === "n8n-nodes-base.code");
|
|
69
|
+
require_test_CTcmp4Su.globalExpect(codeNode.parameters.jsCode).toContain("Redis");
|
|
70
|
+
require_test_CTcmp4Su.globalExpect(codeNode.parameters.jsCode).toContain("Postgresql");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//#endregion
|
|
74
|
+
|
|
75
|
+
//# sourceMappingURL=n8n-workflows.test.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"n8n-workflows.test.cjs","names":["describe","generateN8nWorkflows"],"sources":["../../src/generators/n8n-workflows.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { ResolverOutput } from \"../types.js\";\nimport { generateN8nWorkflows } from \"./n8n-workflows.js\";\n\nfunction makeResolved(serviceIds: string[]): ResolverOutput {\n\treturn {\n\t\tservices: serviceIds.map((id) => ({\n\t\t\tdefinition: {\n\t\t\t\tid,\n\t\t\t\tname: id.charAt(0).toUpperCase() + id.slice(1),\n\t\t\t\tdescription: \"\",\n\t\t\t\ticon: \"\",\n\t\t\t\tcategory: \"test\",\n\t\t\t\timage: `${id}:latest`,\n\t\t\t\tports: [],\n\t\t\t\tvolumes: [],\n\t\t\t\tenvironment: [],\n\t\t\t\tdependencies: [],\n\t\t\t\tconflicts: [],\n\t\t\t\tskills: [],\n\t\t\t\tmemoryMB: 256,\n\t\t\t\tdocsUrl: \"\",\n\t\t\t},\n\t\t\taddedBy: \"user\" as const,\n\t\t})),\n\t\taddedDependencies: [],\n\t\testimatedMemoryMB: 512,\n\t} as unknown as ResolverOutput;\n}\n\ndescribe(\"generateN8nWorkflows\", () => {\n\tit(\"returns empty object when n8n is not in the stack\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"redis\", \"postgresql\"]));\n\t\texpect(Object.keys(result)).toHaveLength(0);\n\t});\n\n\tit(\"generates workflow file when n8n is present\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\"]));\n\t\texpect(result).toHaveProperty(\"n8n/workflows/openclaw-webhook-handler.json\");\n\t});\n\n\tit(\"generates valid JSON workflow\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow).toBeDefined();\n\t\texpect(workflow.name).toBe(\"OpenClaw Webhook Handler\");\n\t});\n\n\tit(\"workflow has three nodes (webhook, process, respond)\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.nodes).toHaveLength(3);\n\n\t\tconst types = workflow.nodes.map((n: { type: string }) => n.type);\n\t\texpect(types).toContain(\"n8n-nodes-base.webhook\");\n\t\texpect(types).toContain(\"n8n-nodes-base.code\");\n\t\texpect(types).toContain(\"n8n-nodes-base.respondToWebhook\");\n\t});\n\n\tit(\"workflow has correct connections\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.connections).toHaveProperty(\"Webhook\");\n\t\texpect(workflow.connections).toHaveProperty(\"Process Payload\");\n\t});\n\n\tit(\"workflow is not active by default\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.active).toBe(false);\n\t});\n\n\tit(\"includes service names in the code node comment\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\", \"postgresql\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\tconst codeNode = workflow.nodes.find((n: { type: string }) => n.type === \"n8n-nodes-base.code\");\n\t\texpect(codeNode.parameters.jsCode).toContain(\"Redis\");\n\t\texpect(codeNode.parameters.jsCode).toContain(\"Postgresql\");\n\t});\n});\n"],"mappings":";;;AAIA,SAAS,aAAa,YAAsC;AAC3D,QAAO;EACN,UAAU,WAAW,KAAK,QAAQ;GACjC,YAAY;IACX;IACA,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa,GAAG,GAAG,MAAM,EAAE;IAC9C,aAAa;IACb,MAAM;IACN,UAAU;IACV,OAAO,GAAG,GAAG;IACb,OAAO,EAAE;IACT,SAAS,EAAE;IACX,aAAa,EAAE;IACf,cAAc,EAAE;IAChB,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,UAAU;IACV,SAAS;IACT;GACD,SAAS;GACT,EAAE;EACH,mBAAmB,EAAE;EACrB,mBAAmB;EACnB;;AAGFA,sBAAAA,SAAS,8BAA8B;AACtC,uBAAA,GAAG,2DAA2D;EAC7D,MAAM,SAASC,iCAAAA,qBAAqB,aAAa,CAAC,SAAS,aAAa,CAAC,CAAC;AAC1E,wBAAA,aAAO,OAAO,KAAK,OAAO,CAAC,CAAC,aAAa,EAAE;GAC1C;AAEF,uBAAA,GAAG,qDAAqD;AAEvD,wBAAA,aADeA,iCAAAA,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,CAAC,CACrD,CAAC,eAAe,8CAA8C;GAC3E;AAEF,uBAAA,GAAG,uCAAuC;EACzC,MAAM,SAASA,iCAAAA,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;EAC1D,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,wBAAA,aAAO,SAAS,CAAC,aAAa;AAC9B,wBAAA,aAAO,SAAS,KAAK,CAAC,KAAK,2BAA2B;GACrD;AAEF,uBAAA,GAAG,8DAA8D;EAChE,MAAM,SAASA,iCAAAA,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,CAAC;EACnE,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,wBAAA,aAAO,SAAS,MAAM,CAAC,aAAa,EAAE;EAEtC,MAAM,QAAQ,SAAS,MAAM,KAAK,MAAwB,EAAE,KAAK;AACjE,wBAAA,aAAO,MAAM,CAAC,UAAU,yBAAyB;AACjD,wBAAA,aAAO,MAAM,CAAC,UAAU,sBAAsB;AAC9C,wBAAA,aAAO,MAAM,CAAC,UAAU,kCAAkC;GACzD;AAEF,uBAAA,GAAG,0CAA0C;EAC5C,MAAM,SAASA,iCAAAA,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;EAC1D,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,wBAAA,aAAO,SAAS,YAAY,CAAC,eAAe,UAAU;AACtD,wBAAA,aAAO,SAAS,YAAY,CAAC,eAAe,kBAAkB;GAC7D;AAEF,uBAAA,GAAG,2CAA2C;EAC7C,MAAM,SAASA,iCAAAA,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;AAE1D,wBAAA,aADiB,KAAK,MAAM,OAAO,+CAAgD,CACnE,OAAO,CAAC,KAAK,MAAM;GAClC;AAEF,uBAAA,GAAG,yDAAyD;EAC3D,MAAM,SAASA,iCAAAA,qBAAqB,aAAa;GAAC;GAAO;GAAS;GAAa,CAAC,CAAC;EAEjF,MAAM,WADW,KAAK,MAAM,OAAO,+CAAgD,CACzD,MAAM,MAAM,MAAwB,EAAE,SAAS,sBAAsB;AAC/F,wBAAA,aAAO,SAAS,WAAW,OAAO,CAAC,UAAU,QAAQ;AACrD,wBAAA,aAAO,SAAS,WAAW,OAAO,CAAC,UAAU,aAAa;GACzD;EACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { a as describe, o as it, t as globalExpect } from "../test.CTcmp4Su-BRa7-bTj.mjs";
|
|
2
|
+
import { generateN8nWorkflows } from "./n8n-workflows.mjs";
|
|
3
|
+
//#region src/generators/n8n-workflows.test.ts
|
|
4
|
+
function makeResolved(serviceIds) {
|
|
5
|
+
return {
|
|
6
|
+
services: serviceIds.map((id) => ({
|
|
7
|
+
definition: {
|
|
8
|
+
id,
|
|
9
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
10
|
+
description: "",
|
|
11
|
+
icon: "",
|
|
12
|
+
category: "test",
|
|
13
|
+
image: `${id}:latest`,
|
|
14
|
+
ports: [],
|
|
15
|
+
volumes: [],
|
|
16
|
+
environment: [],
|
|
17
|
+
dependencies: [],
|
|
18
|
+
conflicts: [],
|
|
19
|
+
skills: [],
|
|
20
|
+
memoryMB: 256,
|
|
21
|
+
docsUrl: ""
|
|
22
|
+
},
|
|
23
|
+
addedBy: "user"
|
|
24
|
+
})),
|
|
25
|
+
addedDependencies: [],
|
|
26
|
+
estimatedMemoryMB: 512
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
describe("generateN8nWorkflows", () => {
|
|
30
|
+
it("returns empty object when n8n is not in the stack", () => {
|
|
31
|
+
const result = generateN8nWorkflows(makeResolved(["redis", "postgresql"]));
|
|
32
|
+
globalExpect(Object.keys(result)).toHaveLength(0);
|
|
33
|
+
});
|
|
34
|
+
it("generates workflow file when n8n is present", () => {
|
|
35
|
+
globalExpect(generateN8nWorkflows(makeResolved(["n8n", "redis"]))).toHaveProperty("n8n/workflows/openclaw-webhook-handler.json");
|
|
36
|
+
});
|
|
37
|
+
it("generates valid JSON workflow", () => {
|
|
38
|
+
const result = generateN8nWorkflows(makeResolved(["n8n"]));
|
|
39
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
40
|
+
globalExpect(workflow).toBeDefined();
|
|
41
|
+
globalExpect(workflow.name).toBe("OpenClaw Webhook Handler");
|
|
42
|
+
});
|
|
43
|
+
it("workflow has three nodes (webhook, process, respond)", () => {
|
|
44
|
+
const result = generateN8nWorkflows(makeResolved(["n8n", "redis"]));
|
|
45
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
46
|
+
globalExpect(workflow.nodes).toHaveLength(3);
|
|
47
|
+
const types = workflow.nodes.map((n) => n.type);
|
|
48
|
+
globalExpect(types).toContain("n8n-nodes-base.webhook");
|
|
49
|
+
globalExpect(types).toContain("n8n-nodes-base.code");
|
|
50
|
+
globalExpect(types).toContain("n8n-nodes-base.respondToWebhook");
|
|
51
|
+
});
|
|
52
|
+
it("workflow has correct connections", () => {
|
|
53
|
+
const result = generateN8nWorkflows(makeResolved(["n8n"]));
|
|
54
|
+
const workflow = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]);
|
|
55
|
+
globalExpect(workflow.connections).toHaveProperty("Webhook");
|
|
56
|
+
globalExpect(workflow.connections).toHaveProperty("Process Payload");
|
|
57
|
+
});
|
|
58
|
+
it("workflow is not active by default", () => {
|
|
59
|
+
const result = generateN8nWorkflows(makeResolved(["n8n"]));
|
|
60
|
+
globalExpect(JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]).active).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it("includes service names in the code node comment", () => {
|
|
63
|
+
const result = generateN8nWorkflows(makeResolved([
|
|
64
|
+
"n8n",
|
|
65
|
+
"redis",
|
|
66
|
+
"postgresql"
|
|
67
|
+
]));
|
|
68
|
+
const codeNode = JSON.parse(result["n8n/workflows/openclaw-webhook-handler.json"]).nodes.find((n) => n.type === "n8n-nodes-base.code");
|
|
69
|
+
globalExpect(codeNode.parameters.jsCode).toContain("Redis");
|
|
70
|
+
globalExpect(codeNode.parameters.jsCode).toContain("Postgresql");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//#endregion
|
|
74
|
+
export {};
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=n8n-workflows.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"n8n-workflows.test.mjs","names":[],"sources":["../../src/generators/n8n-workflows.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { ResolverOutput } from \"../types.js\";\nimport { generateN8nWorkflows } from \"./n8n-workflows.js\";\n\nfunction makeResolved(serviceIds: string[]): ResolverOutput {\n\treturn {\n\t\tservices: serviceIds.map((id) => ({\n\t\t\tdefinition: {\n\t\t\t\tid,\n\t\t\t\tname: id.charAt(0).toUpperCase() + id.slice(1),\n\t\t\t\tdescription: \"\",\n\t\t\t\ticon: \"\",\n\t\t\t\tcategory: \"test\",\n\t\t\t\timage: `${id}:latest`,\n\t\t\t\tports: [],\n\t\t\t\tvolumes: [],\n\t\t\t\tenvironment: [],\n\t\t\t\tdependencies: [],\n\t\t\t\tconflicts: [],\n\t\t\t\tskills: [],\n\t\t\t\tmemoryMB: 256,\n\t\t\t\tdocsUrl: \"\",\n\t\t\t},\n\t\t\taddedBy: \"user\" as const,\n\t\t})),\n\t\taddedDependencies: [],\n\t\testimatedMemoryMB: 512,\n\t} as unknown as ResolverOutput;\n}\n\ndescribe(\"generateN8nWorkflows\", () => {\n\tit(\"returns empty object when n8n is not in the stack\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"redis\", \"postgresql\"]));\n\t\texpect(Object.keys(result)).toHaveLength(0);\n\t});\n\n\tit(\"generates workflow file when n8n is present\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\"]));\n\t\texpect(result).toHaveProperty(\"n8n/workflows/openclaw-webhook-handler.json\");\n\t});\n\n\tit(\"generates valid JSON workflow\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow).toBeDefined();\n\t\texpect(workflow.name).toBe(\"OpenClaw Webhook Handler\");\n\t});\n\n\tit(\"workflow has three nodes (webhook, process, respond)\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.nodes).toHaveLength(3);\n\n\t\tconst types = workflow.nodes.map((n: { type: string }) => n.type);\n\t\texpect(types).toContain(\"n8n-nodes-base.webhook\");\n\t\texpect(types).toContain(\"n8n-nodes-base.code\");\n\t\texpect(types).toContain(\"n8n-nodes-base.respondToWebhook\");\n\t});\n\n\tit(\"workflow has correct connections\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.connections).toHaveProperty(\"Webhook\");\n\t\texpect(workflow.connections).toHaveProperty(\"Process Payload\");\n\t});\n\n\tit(\"workflow is not active by default\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\texpect(workflow.active).toBe(false);\n\t});\n\n\tit(\"includes service names in the code node comment\", () => {\n\t\tconst result = generateN8nWorkflows(makeResolved([\"n8n\", \"redis\", \"postgresql\"]));\n\t\tconst workflow = JSON.parse(result[\"n8n/workflows/openclaw-webhook-handler.json\"]!);\n\t\tconst codeNode = workflow.nodes.find((n: { type: string }) => n.type === \"n8n-nodes-base.code\");\n\t\texpect(codeNode.parameters.jsCode).toContain(\"Redis\");\n\t\texpect(codeNode.parameters.jsCode).toContain(\"Postgresql\");\n\t});\n});\n"],"mappings":";;;AAIA,SAAS,aAAa,YAAsC;AAC3D,QAAO;EACN,UAAU,WAAW,KAAK,QAAQ;GACjC,YAAY;IACX;IACA,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa,GAAG,GAAG,MAAM,EAAE;IAC9C,aAAa;IACb,MAAM;IACN,UAAU;IACV,OAAO,GAAG,GAAG;IACb,OAAO,EAAE;IACT,SAAS,EAAE;IACX,aAAa,EAAE;IACf,cAAc,EAAE;IAChB,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,UAAU;IACV,SAAS;IACT;GACD,SAAS;GACT,EAAE;EACH,mBAAmB,EAAE;EACrB,mBAAmB;EACnB;;AAGF,SAAS,8BAA8B;AACtC,IAAG,2DAA2D;EAC7D,MAAM,SAAS,qBAAqB,aAAa,CAAC,SAAS,aAAa,CAAC,CAAC;AAC1E,eAAO,OAAO,KAAK,OAAO,CAAC,CAAC,aAAa,EAAE;GAC1C;AAEF,IAAG,qDAAqD;AAEvD,eADe,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,CAAC,CACrD,CAAC,eAAe,8CAA8C;GAC3E;AAEF,IAAG,uCAAuC;EACzC,MAAM,SAAS,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;EAC1D,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,eAAO,SAAS,CAAC,aAAa;AAC9B,eAAO,SAAS,KAAK,CAAC,KAAK,2BAA2B;GACrD;AAEF,IAAG,8DAA8D;EAChE,MAAM,SAAS,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,CAAC;EACnE,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,eAAO,SAAS,MAAM,CAAC,aAAa,EAAE;EAEtC,MAAM,QAAQ,SAAS,MAAM,KAAK,MAAwB,EAAE,KAAK;AACjE,eAAO,MAAM,CAAC,UAAU,yBAAyB;AACjD,eAAO,MAAM,CAAC,UAAU,sBAAsB;AAC9C,eAAO,MAAM,CAAC,UAAU,kCAAkC;GACzD;AAEF,IAAG,0CAA0C;EAC5C,MAAM,SAAS,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;EAC1D,MAAM,WAAW,KAAK,MAAM,OAAO,+CAAgD;AACnF,eAAO,SAAS,YAAY,CAAC,eAAe,UAAU;AACtD,eAAO,SAAS,YAAY,CAAC,eAAe,kBAAkB;GAC7D;AAEF,IAAG,2CAA2C;EAC7C,MAAM,SAAS,qBAAqB,aAAa,CAAC,MAAM,CAAC,CAAC;AAE1D,eADiB,KAAK,MAAM,OAAO,+CAAgD,CACnE,OAAO,CAAC,KAAK,MAAM;GAClC;AAEF,IAAG,yDAAyD;EAC3D,MAAM,SAAS,qBAAqB,aAAa;GAAC;GAAO;GAAS;GAAa,CAAC,CAAC;EAEjF,MAAM,WADW,KAAK,MAAM,OAAO,+CAAgD,CACzD,MAAM,MAAM,MAAwB,EAAE,SAAS,sBAAsB;AAC/F,eAAO,SAAS,WAAW,OAAO,CAAC,UAAU,QAAQ;AACrD,eAAO,SAAS,WAAW,OAAO,CAAC,UAAU,aAAa;GACzD;EACD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const require_test_CTcmp4Su = require("../test.CTcmp4Su-BWSPM8ZQ.cjs");
|
|
2
|
+
const require_generators_openclaw_install_script = require("./openclaw-install-script.cjs");
|
|
3
|
+
//#region src/generators/openclaw-install-script.test.ts
|
|
4
|
+
require_test_CTcmp4Su.describe("generateOpenclawInstallScript", () => {
|
|
5
|
+
require_test_CTcmp4Su.it("generates both sh and ps1 scripts", () => {
|
|
6
|
+
const files = require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test-project" });
|
|
7
|
+
require_test_CTcmp4Su.globalExpect(files).toHaveProperty("scripts/install-openclaw.sh");
|
|
8
|
+
require_test_CTcmp4Su.globalExpect(files).toHaveProperty("scripts/install-openclaw.ps1");
|
|
9
|
+
});
|
|
10
|
+
require_test_CTcmp4Su.it("sh script starts with shebang", () => {
|
|
11
|
+
require_test_CTcmp4Su.globalExpect(require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toMatch(/^#!/);
|
|
12
|
+
});
|
|
13
|
+
require_test_CTcmp4Su.it("sh script uses set -euo pipefail", () => {
|
|
14
|
+
require_test_CTcmp4Su.globalExpect(require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toContain("set -euo pipefail");
|
|
15
|
+
});
|
|
16
|
+
require_test_CTcmp4Su.it("includes project name in scripts", () => {
|
|
17
|
+
const files = require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "my-project" });
|
|
18
|
+
require_test_CTcmp4Su.globalExpect(files["scripts/install-openclaw.sh"]).toContain("my-project");
|
|
19
|
+
require_test_CTcmp4Su.globalExpect(files["scripts/install-openclaw.ps1"]).toContain("my-project");
|
|
20
|
+
});
|
|
21
|
+
require_test_CTcmp4Su.it("uses official installer URL", () => {
|
|
22
|
+
require_test_CTcmp4Su.globalExpect(require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toContain("openclaw.ai/install.sh");
|
|
23
|
+
});
|
|
24
|
+
require_test_CTcmp4Su.it("ps1 script checks for WSL", () => {
|
|
25
|
+
require_test_CTcmp4Su.globalExpect(require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.ps1"]).toContain("wsl");
|
|
26
|
+
});
|
|
27
|
+
require_test_CTcmp4Su.it("includes next steps in output", () => {
|
|
28
|
+
const files = require_generators_openclaw_install_script.generateOpenclawInstallScript({ projectName: "test" });
|
|
29
|
+
require_test_CTcmp4Su.globalExpect(files["scripts/install-openclaw.sh"]).toContain("Next steps");
|
|
30
|
+
require_test_CTcmp4Su.globalExpect(files["scripts/install-openclaw.ps1"]).toContain("Next steps");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=openclaw-install-script.test.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-install-script.test.cjs","names":["describe","generateOpenclawInstallScript"],"sources":["../../src/generators/openclaw-install-script.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { generateOpenclawInstallScript } from \"./openclaw-install-script.js\";\n\ndescribe(\"generateOpenclawInstallScript\", () => {\n\tit(\"generates both sh and ps1 scripts\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test-project\" });\n\t\texpect(files).toHaveProperty(\"scripts/install-openclaw.sh\");\n\t\texpect(files).toHaveProperty(\"scripts/install-openclaw.ps1\");\n\t});\n\n\tit(\"sh script starts with shebang\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toMatch(/^#!/);\n\t});\n\n\tit(\"sh script uses set -euo pipefail\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"set -euo pipefail\");\n\t});\n\n\tit(\"includes project name in scripts\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"my-project\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"my-project\");\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"my-project\");\n\t});\n\n\tit(\"uses official installer URL\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"openclaw.ai/install.sh\");\n\t});\n\n\tit(\"ps1 script checks for WSL\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"wsl\");\n\t});\n\n\tit(\"includes next steps in output\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"Next steps\");\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"Next steps\");\n\t});\n});\n"],"mappings":";;;AAGAA,sBAAAA,SAAS,uCAAuC;AAC/C,uBAAA,GAAG,2CAA2C;EAC7C,MAAM,QAAQC,2CAAAA,8BAA8B,EAAE,aAAa,gBAAgB,CAAC;AAC5E,wBAAA,aAAO,MAAM,CAAC,eAAe,8BAA8B;AAC3D,wBAAA,aAAO,MAAM,CAAC,eAAe,+BAA+B;GAC3D;AAEF,uBAAA,GAAG,uCAAuC;AAEzC,wBAAA,aADcA,2CAAAA,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,QAAQ,MAAM;GAC1D;AAEF,uBAAA,GAAG,0CAA0C;AAE5C,wBAAA,aADcA,2CAAAA,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,UAAU,oBAAoB;GAC1E;AAEF,uBAAA,GAAG,0CAA0C;EAC5C,MAAM,QAAQA,2CAAAA,8BAA8B,EAAE,aAAa,cAAc,CAAC;AAC1E,wBAAA,aAAO,MAAM,+BAA+B,CAAC,UAAU,aAAa;AACpE,wBAAA,aAAO,MAAM,gCAAgC,CAAC,UAAU,aAAa;GACpE;AAEF,uBAAA,GAAG,qCAAqC;AAEvC,wBAAA,aADcA,2CAAAA,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,UAAU,yBAAyB;GAC/E;AAEF,uBAAA,GAAG,mCAAmC;AAErC,wBAAA,aADcA,2CAAAA,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,gCAAgC,CAAC,UAAU,MAAM;GAC7D;AAEF,uBAAA,GAAG,uCAAuC;EACzC,MAAM,QAAQA,2CAAAA,8BAA8B,EAAE,aAAa,QAAQ,CAAC;AACpE,wBAAA,aAAO,MAAM,+BAA+B,CAAC,UAAU,aAAa;AACpE,wBAAA,aAAO,MAAM,gCAAgC,CAAC,UAAU,aAAa;GACpE;EACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { a as describe, o as it, t as globalExpect } from "../test.CTcmp4Su-BRa7-bTj.mjs";
|
|
2
|
+
import { generateOpenclawInstallScript } from "./openclaw-install-script.mjs";
|
|
3
|
+
//#region src/generators/openclaw-install-script.test.ts
|
|
4
|
+
describe("generateOpenclawInstallScript", () => {
|
|
5
|
+
it("generates both sh and ps1 scripts", () => {
|
|
6
|
+
const files = generateOpenclawInstallScript({ projectName: "test-project" });
|
|
7
|
+
globalExpect(files).toHaveProperty("scripts/install-openclaw.sh");
|
|
8
|
+
globalExpect(files).toHaveProperty("scripts/install-openclaw.ps1");
|
|
9
|
+
});
|
|
10
|
+
it("sh script starts with shebang", () => {
|
|
11
|
+
globalExpect(generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toMatch(/^#!/);
|
|
12
|
+
});
|
|
13
|
+
it("sh script uses set -euo pipefail", () => {
|
|
14
|
+
globalExpect(generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toContain("set -euo pipefail");
|
|
15
|
+
});
|
|
16
|
+
it("includes project name in scripts", () => {
|
|
17
|
+
const files = generateOpenclawInstallScript({ projectName: "my-project" });
|
|
18
|
+
globalExpect(files["scripts/install-openclaw.sh"]).toContain("my-project");
|
|
19
|
+
globalExpect(files["scripts/install-openclaw.ps1"]).toContain("my-project");
|
|
20
|
+
});
|
|
21
|
+
it("uses official installer URL", () => {
|
|
22
|
+
globalExpect(generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.sh"]).toContain("openclaw.ai/install.sh");
|
|
23
|
+
});
|
|
24
|
+
it("ps1 script checks for WSL", () => {
|
|
25
|
+
globalExpect(generateOpenclawInstallScript({ projectName: "test" })["scripts/install-openclaw.ps1"]).toContain("wsl");
|
|
26
|
+
});
|
|
27
|
+
it("includes next steps in output", () => {
|
|
28
|
+
const files = generateOpenclawInstallScript({ projectName: "test" });
|
|
29
|
+
globalExpect(files["scripts/install-openclaw.sh"]).toContain("Next steps");
|
|
30
|
+
globalExpect(files["scripts/install-openclaw.ps1"]).toContain("Next steps");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//#endregion
|
|
34
|
+
export {};
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=openclaw-install-script.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openclaw-install-script.test.mjs","names":[],"sources":["../../src/generators/openclaw-install-script.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { generateOpenclawInstallScript } from \"./openclaw-install-script.js\";\n\ndescribe(\"generateOpenclawInstallScript\", () => {\n\tit(\"generates both sh and ps1 scripts\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test-project\" });\n\t\texpect(files).toHaveProperty(\"scripts/install-openclaw.sh\");\n\t\texpect(files).toHaveProperty(\"scripts/install-openclaw.ps1\");\n\t});\n\n\tit(\"sh script starts with shebang\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toMatch(/^#!/);\n\t});\n\n\tit(\"sh script uses set -euo pipefail\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"set -euo pipefail\");\n\t});\n\n\tit(\"includes project name in scripts\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"my-project\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"my-project\");\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"my-project\");\n\t});\n\n\tit(\"uses official installer URL\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"openclaw.ai/install.sh\");\n\t});\n\n\tit(\"ps1 script checks for WSL\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"wsl\");\n\t});\n\n\tit(\"includes next steps in output\", () => {\n\t\tconst files = generateOpenclawInstallScript({ projectName: \"test\" });\n\t\texpect(files[\"scripts/install-openclaw.sh\"]).toContain(\"Next steps\");\n\t\texpect(files[\"scripts/install-openclaw.ps1\"]).toContain(\"Next steps\");\n\t});\n});\n"],"mappings":";;;AAGA,SAAS,uCAAuC;AAC/C,IAAG,2CAA2C;EAC7C,MAAM,QAAQ,8BAA8B,EAAE,aAAa,gBAAgB,CAAC;AAC5E,eAAO,MAAM,CAAC,eAAe,8BAA8B;AAC3D,eAAO,MAAM,CAAC,eAAe,+BAA+B;GAC3D;AAEF,IAAG,uCAAuC;AAEzC,eADc,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,QAAQ,MAAM;GAC1D;AAEF,IAAG,0CAA0C;AAE5C,eADc,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,UAAU,oBAAoB;GAC1E;AAEF,IAAG,0CAA0C;EAC5C,MAAM,QAAQ,8BAA8B,EAAE,aAAa,cAAc,CAAC;AAC1E,eAAO,MAAM,+BAA+B,CAAC,UAAU,aAAa;AACpE,eAAO,MAAM,gCAAgC,CAAC,UAAU,aAAa;GACpE;AAEF,IAAG,qCAAqC;AAEvC,eADc,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,+BAA+B,CAAC,UAAU,yBAAyB;GAC/E;AAEF,IAAG,mCAAmC;AAErC,eADc,8BAA8B,EAAE,aAAa,QAAQ,CAAC,CACvD,gCAAgC,CAAC,UAAU,MAAM;GAC7D;AAEF,IAAG,uCAAuC;EACzC,MAAM,QAAQ,8BAA8B,EAAE,aAAa,QAAQ,CAAC;AACpE,eAAO,MAAM,+BAA+B,CAAC,UAAU,aAAa;AACpE,eAAO,MAAM,gCAAgC,CAAC,UAAU,aAAa;GACpE;EACD"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const require_test_CTcmp4Su = require("../test.CTcmp4Su-BWSPM8ZQ.cjs");
|
|
2
|
+
const require_generators_postgres_init = require("./postgres-init.cjs");
|
|
3
|
+
//#region src/generators/postgres-init.test.ts
|
|
4
|
+
function makeResolved(serviceIds) {
|
|
5
|
+
return {
|
|
6
|
+
services: serviceIds.map((id) => ({
|
|
7
|
+
definition: {
|
|
8
|
+
id,
|
|
9
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
10
|
+
description: "",
|
|
11
|
+
icon: "",
|
|
12
|
+
category: "test",
|
|
13
|
+
image: `${id}:latest`,
|
|
14
|
+
ports: [],
|
|
15
|
+
volumes: [],
|
|
16
|
+
environment: [],
|
|
17
|
+
dependencies: [],
|
|
18
|
+
conflicts: [],
|
|
19
|
+
skills: [],
|
|
20
|
+
memoryMB: 256,
|
|
21
|
+
docsUrl: ""
|
|
22
|
+
},
|
|
23
|
+
addedBy: "user"
|
|
24
|
+
})),
|
|
25
|
+
addedDependencies: [],
|
|
26
|
+
estimatedMemoryMB: 512
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
require_test_CTcmp4Su.describe("getDbRequirements", () => {
|
|
30
|
+
require_test_CTcmp4Su.it("returns empty array when no services need a DB", () => {
|
|
31
|
+
require_test_CTcmp4Su.globalExpect(require_generators_postgres_init.getDbRequirements(makeResolved(["redis", "minio"]))).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
require_test_CTcmp4Su.it("returns requirements for n8n", () => {
|
|
34
|
+
const reqs = require_generators_postgres_init.getDbRequirements(makeResolved(["n8n", "redis"]));
|
|
35
|
+
require_test_CTcmp4Su.globalExpect(reqs).toHaveLength(1);
|
|
36
|
+
require_test_CTcmp4Su.globalExpect(reqs[0]).toEqual({
|
|
37
|
+
serviceId: "n8n",
|
|
38
|
+
serviceName: "N8n",
|
|
39
|
+
dbName: "n8n",
|
|
40
|
+
dbUser: "n8n",
|
|
41
|
+
passwordEnvVar: "N8N_DB_PASSWORD"
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
require_test_CTcmp4Su.it("returns requirements for multiple services", () => {
|
|
45
|
+
const reqs = require_generators_postgres_init.getDbRequirements(makeResolved([
|
|
46
|
+
"n8n",
|
|
47
|
+
"outline",
|
|
48
|
+
"postiz",
|
|
49
|
+
"redis"
|
|
50
|
+
]));
|
|
51
|
+
require_test_CTcmp4Su.globalExpect(reqs).toHaveLength(3);
|
|
52
|
+
const ids = reqs.map((r) => r.serviceId);
|
|
53
|
+
require_test_CTcmp4Su.globalExpect(ids).toContain("n8n");
|
|
54
|
+
require_test_CTcmp4Su.globalExpect(ids).toContain("outline");
|
|
55
|
+
require_test_CTcmp4Su.globalExpect(ids).toContain("postiz");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
require_test_CTcmp4Su.describe("generatePostgresInit", () => {
|
|
59
|
+
require_test_CTcmp4Su.it("returns null when PostgreSQL is not in the stack", () => {
|
|
60
|
+
require_test_CTcmp4Su.globalExpect(require_generators_postgres_init.generatePostgresInit(makeResolved(["n8n", "redis"]))).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
require_test_CTcmp4Su.it("returns null when PostgreSQL is present but no services need DBs", () => {
|
|
63
|
+
require_test_CTcmp4Su.globalExpect(require_generators_postgres_init.generatePostgresInit(makeResolved([
|
|
64
|
+
"postgresql",
|
|
65
|
+
"redis",
|
|
66
|
+
"minio"
|
|
67
|
+
]))).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
require_test_CTcmp4Su.it("generates init script when PostgreSQL and DB-needing services are present", () => {
|
|
70
|
+
const script = require_generators_postgres_init.generatePostgresInit(makeResolved(["postgresql", "n8n"]));
|
|
71
|
+
require_test_CTcmp4Su.globalExpect(script).not.toBeNull();
|
|
72
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("#!/bin/bash");
|
|
73
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("create_db_and_user");
|
|
74
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("\"n8n\"");
|
|
75
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("N8N_DB_PASSWORD");
|
|
76
|
+
});
|
|
77
|
+
require_test_CTcmp4Su.it("includes all services that need DBs", () => {
|
|
78
|
+
const script = require_generators_postgres_init.generatePostgresInit(makeResolved([
|
|
79
|
+
"postgresql",
|
|
80
|
+
"n8n",
|
|
81
|
+
"outline",
|
|
82
|
+
"dify"
|
|
83
|
+
]));
|
|
84
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("\"n8n\"");
|
|
85
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("\"outline\"");
|
|
86
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("\"dify\"");
|
|
87
|
+
});
|
|
88
|
+
require_test_CTcmp4Su.it("uses environment variable substitution for passwords (not literals)", () => {
|
|
89
|
+
require_test_CTcmp4Su.globalExpect(require_generators_postgres_init.generatePostgresInit(makeResolved(["postgresql", "n8n"]))).toContain("${N8N_DB_PASSWORD:-$POSTGRES_PASSWORD}");
|
|
90
|
+
});
|
|
91
|
+
require_test_CTcmp4Su.it("script uses psql with ON_ERROR_STOP", () => {
|
|
92
|
+
require_test_CTcmp4Su.globalExpect(require_generators_postgres_init.generatePostgresInit(makeResolved(["postgresql", "n8n"]))).toContain("ON_ERROR_STOP=1");
|
|
93
|
+
});
|
|
94
|
+
require_test_CTcmp4Su.it("script creates user with IF NOT EXISTS check", () => {
|
|
95
|
+
const script = require_generators_postgres_init.generatePostgresInit(makeResolved(["postgresql", "n8n"]));
|
|
96
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("IF NOT EXISTS");
|
|
97
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("CREATE ROLE");
|
|
98
|
+
});
|
|
99
|
+
require_test_CTcmp4Su.it("includes service names in summary line", () => {
|
|
100
|
+
const script = require_generators_postgres_init.generatePostgresInit(makeResolved([
|
|
101
|
+
"postgresql",
|
|
102
|
+
"n8n",
|
|
103
|
+
"outline"
|
|
104
|
+
]));
|
|
105
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("N8n");
|
|
106
|
+
require_test_CTcmp4Su.globalExpect(script).toContain("Outline");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//#endregion
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=postgres-init.test.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-init.test.cjs","names":["describe","getDbRequirements","generatePostgresInit"],"sources":["../../src/generators/postgres-init.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport type { ResolverOutput } from \"../types.js\";\nimport { generatePostgresInit, getDbRequirements } from \"./postgres-init.js\";\n\nfunction makeResolved(serviceIds: string[]): ResolverOutput {\n\treturn {\n\t\tservices: serviceIds.map((id) => ({\n\t\t\tdefinition: {\n\t\t\t\tid,\n\t\t\t\tname: id.charAt(0).toUpperCase() + id.slice(1),\n\t\t\t\tdescription: \"\",\n\t\t\t\ticon: \"\",\n\t\t\t\tcategory: \"test\",\n\t\t\t\timage: `${id}:latest`,\n\t\t\t\tports: [],\n\t\t\t\tvolumes: [],\n\t\t\t\tenvironment: [],\n\t\t\t\tdependencies: [],\n\t\t\t\tconflicts: [],\n\t\t\t\tskills: [],\n\t\t\t\tmemoryMB: 256,\n\t\t\t\tdocsUrl: \"\",\n\t\t\t},\n\t\t\taddedBy: \"user\" as const,\n\t\t})),\n\t\taddedDependencies: [],\n\t\testimatedMemoryMB: 512,\n\t} as unknown as ResolverOutput;\n}\n\ndescribe(\"getDbRequirements\", () => {\n\tit(\"returns empty array when no services need a DB\", () => {\n\t\tconst resolved = makeResolved([\"redis\", \"minio\"]);\n\t\texpect(getDbRequirements(resolved)).toEqual([]);\n\t});\n\n\tit(\"returns requirements for n8n\", () => {\n\t\tconst resolved = makeResolved([\"n8n\", \"redis\"]);\n\t\tconst reqs = getDbRequirements(resolved);\n\t\texpect(reqs).toHaveLength(1);\n\t\texpect(reqs[0]).toEqual({\n\t\t\tserviceId: \"n8n\",\n\t\t\tserviceName: \"N8n\",\n\t\t\tdbName: \"n8n\",\n\t\t\tdbUser: \"n8n\",\n\t\t\tpasswordEnvVar: \"N8N_DB_PASSWORD\",\n\t\t});\n\t});\n\n\tit(\"returns requirements for multiple services\", () => {\n\t\tconst resolved = makeResolved([\"n8n\", \"outline\", \"postiz\", \"redis\"]);\n\t\tconst reqs = getDbRequirements(resolved);\n\t\texpect(reqs).toHaveLength(3);\n\t\tconst ids = reqs.map((r) => r.serviceId);\n\t\texpect(ids).toContain(\"n8n\");\n\t\texpect(ids).toContain(\"outline\");\n\t\texpect(ids).toContain(\"postiz\");\n\t});\n});\n\ndescribe(\"generatePostgresInit\", () => {\n\tit(\"returns null when PostgreSQL is not in the stack\", () => {\n\t\tconst resolved = makeResolved([\"n8n\", \"redis\"]);\n\t\texpect(generatePostgresInit(resolved)).toBeNull();\n\t});\n\n\tit(\"returns null when PostgreSQL is present but no services need DBs\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"redis\", \"minio\"]);\n\t\texpect(generatePostgresInit(resolved)).toBeNull();\n\t});\n\n\tit(\"generates init script when PostgreSQL and DB-needing services are present\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\"]);\n\t\tconst script = generatePostgresInit(resolved);\n\t\texpect(script).not.toBeNull();\n\t\texpect(script).toContain(\"#!/bin/bash\");\n\t\texpect(script).toContain(\"create_db_and_user\");\n\t\texpect(script).toContain('\"n8n\"');\n\t\texpect(script).toContain(\"N8N_DB_PASSWORD\");\n\t});\n\n\tit(\"includes all services that need DBs\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\", \"outline\", \"dify\"]);\n\t\tconst script = generatePostgresInit(resolved)!;\n\t\texpect(script).toContain('\"n8n\"');\n\t\texpect(script).toContain('\"outline\"');\n\t\texpect(script).toContain('\"dify\"');\n\t});\n\n\tit(\"uses environment variable substitution for passwords (not literals)\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\"]);\n\t\tconst script = generatePostgresInit(resolved)!;\n\t\t// Passwords should be referenced as env vars, not hardcoded\n\t\texpect(script).toContain(\"${N8N_DB_PASSWORD:-$POSTGRES_PASSWORD}\");\n\t});\n\n\tit(\"script uses psql with ON_ERROR_STOP\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\"]);\n\t\tconst script = generatePostgresInit(resolved)!;\n\t\texpect(script).toContain(\"ON_ERROR_STOP=1\");\n\t});\n\n\tit(\"script creates user with IF NOT EXISTS check\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\"]);\n\t\tconst script = generatePostgresInit(resolved)!;\n\t\texpect(script).toContain(\"IF NOT EXISTS\");\n\t\texpect(script).toContain(\"CREATE ROLE\");\n\t});\n\n\tit(\"includes service names in summary line\", () => {\n\t\tconst resolved = makeResolved([\"postgresql\", \"n8n\", \"outline\"]);\n\t\tconst script = generatePostgresInit(resolved)!;\n\t\texpect(script).toContain(\"N8n\");\n\t\texpect(script).toContain(\"Outline\");\n\t});\n});\n"],"mappings":";;;AAIA,SAAS,aAAa,YAAsC;AAC3D,QAAO;EACN,UAAU,WAAW,KAAK,QAAQ;GACjC,YAAY;IACX;IACA,MAAM,GAAG,OAAO,EAAE,CAAC,aAAa,GAAG,GAAG,MAAM,EAAE;IAC9C,aAAa;IACb,MAAM;IACN,UAAU;IACV,OAAO,GAAG,GAAG;IACb,OAAO,EAAE;IACT,SAAS,EAAE;IACX,aAAa,EAAE;IACf,cAAc,EAAE;IAChB,WAAW,EAAE;IACb,QAAQ,EAAE;IACV,UAAU;IACV,SAAS;IACT;GACD,SAAS;GACT,EAAE;EACH,mBAAmB,EAAE;EACrB,mBAAmB;EACnB;;AAGFA,sBAAAA,SAAS,2BAA2B;AACnC,uBAAA,GAAG,wDAAwD;AAE1D,wBAAA,aAAOC,iCAAAA,kBADU,aAAa,CAAC,SAAS,QAAQ,CAAC,CACf,CAAC,CAAC,QAAQ,EAAE,CAAC;GAC9C;AAEF,uBAAA,GAAG,sCAAsC;EAExC,MAAM,OAAOA,iCAAAA,kBADI,aAAa,CAAC,OAAO,QAAQ,CAAC,CACP;AACxC,wBAAA,aAAO,KAAK,CAAC,aAAa,EAAE;AAC5B,wBAAA,aAAO,KAAK,GAAG,CAAC,QAAQ;GACvB,WAAW;GACX,aAAa;GACb,QAAQ;GACR,QAAQ;GACR,gBAAgB;GAChB,CAAC;GACD;AAEF,uBAAA,GAAG,oDAAoD;EAEtD,MAAM,OAAOA,iCAAAA,kBADI,aAAa;GAAC;GAAO;GAAW;GAAU;GAAQ,CAAC,CAC5B;AACxC,wBAAA,aAAO,KAAK,CAAC,aAAa,EAAE;EAC5B,MAAM,MAAM,KAAK,KAAK,MAAM,EAAE,UAAU;AACxC,wBAAA,aAAO,IAAI,CAAC,UAAU,MAAM;AAC5B,wBAAA,aAAO,IAAI,CAAC,UAAU,UAAU;AAChC,wBAAA,aAAO,IAAI,CAAC,UAAU,SAAS;GAC9B;EACD;AAEFD,sBAAAA,SAAS,8BAA8B;AACtC,uBAAA,GAAG,0DAA0D;AAE5D,wBAAA,aAAOE,iCAAAA,qBADU,aAAa,CAAC,OAAO,QAAQ,CAAC,CACV,CAAC,CAAC,UAAU;GAChD;AAEF,uBAAA,GAAG,0EAA0E;AAE5E,wBAAA,aAAOA,iCAAAA,qBADU,aAAa;GAAC;GAAc;GAAS;GAAQ,CAAC,CAC1B,CAAC,CAAC,UAAU;GAChD;AAEF,uBAAA,GAAG,mFAAmF;EAErF,MAAM,SAASA,iCAAAA,qBADE,aAAa,CAAC,cAAc,MAAM,CAAC,CACP;AAC7C,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU;AAC7B,wBAAA,aAAO,OAAO,CAAC,UAAU,cAAc;AACvC,wBAAA,aAAO,OAAO,CAAC,UAAU,qBAAqB;AAC9C,wBAAA,aAAO,OAAO,CAAC,UAAU,UAAQ;AACjC,wBAAA,aAAO,OAAO,CAAC,UAAU,kBAAkB;GAC1C;AAEF,uBAAA,GAAG,6CAA6C;EAE/C,MAAM,SAASA,iCAAAA,qBADE,aAAa;GAAC;GAAc;GAAO;GAAW;GAAO,CAAC,CAC1B;AAC7C,wBAAA,aAAO,OAAO,CAAC,UAAU,UAAQ;AACjC,wBAAA,aAAO,OAAO,CAAC,UAAU,cAAY;AACrC,wBAAA,aAAO,OAAO,CAAC,UAAU,WAAS;GACjC;AAEF,uBAAA,GAAG,6EAA6E;AAI/E,wBAAA,aAFeA,iCAAAA,qBADE,aAAa,CAAC,cAAc,MAAM,CAAC,CACP,CAE/B,CAAC,UAAU,yCAAyC;GACjE;AAEF,uBAAA,GAAG,6CAA6C;AAG/C,wBAAA,aADeA,iCAAAA,qBADE,aAAa,CAAC,cAAc,MAAM,CAAC,CACP,CAC/B,CAAC,UAAU,kBAAkB;GAC1C;AAEF,uBAAA,GAAG,sDAAsD;EAExD,MAAM,SAASA,iCAAAA,qBADE,aAAa,CAAC,cAAc,MAAM,CAAC,CACP;AAC7C,wBAAA,aAAO,OAAO,CAAC,UAAU,gBAAgB;AACzC,wBAAA,aAAO,OAAO,CAAC,UAAU,cAAc;GACtC;AAEF,uBAAA,GAAG,gDAAgD;EAElD,MAAM,SAASA,iCAAAA,qBADE,aAAa;GAAC;GAAc;GAAO;GAAU,CAAC,CAClB;AAC7C,wBAAA,aAAO,OAAO,CAAC,UAAU,MAAM;AAC/B,wBAAA,aAAO,OAAO,CAAC,UAAU,UAAU;GAClC;EACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { a as describe, o as it, t as globalExpect } from "../test.CTcmp4Su-BRa7-bTj.mjs";
|
|
2
|
+
import { generatePostgresInit, getDbRequirements } from "./postgres-init.mjs";
|
|
3
|
+
//#region src/generators/postgres-init.test.ts
|
|
4
|
+
function makeResolved(serviceIds) {
|
|
5
|
+
return {
|
|
6
|
+
services: serviceIds.map((id) => ({
|
|
7
|
+
definition: {
|
|
8
|
+
id,
|
|
9
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
10
|
+
description: "",
|
|
11
|
+
icon: "",
|
|
12
|
+
category: "test",
|
|
13
|
+
image: `${id}:latest`,
|
|
14
|
+
ports: [],
|
|
15
|
+
volumes: [],
|
|
16
|
+
environment: [],
|
|
17
|
+
dependencies: [],
|
|
18
|
+
conflicts: [],
|
|
19
|
+
skills: [],
|
|
20
|
+
memoryMB: 256,
|
|
21
|
+
docsUrl: ""
|
|
22
|
+
},
|
|
23
|
+
addedBy: "user"
|
|
24
|
+
})),
|
|
25
|
+
addedDependencies: [],
|
|
26
|
+
estimatedMemoryMB: 512
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
describe("getDbRequirements", () => {
|
|
30
|
+
it("returns empty array when no services need a DB", () => {
|
|
31
|
+
globalExpect(getDbRequirements(makeResolved(["redis", "minio"]))).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
it("returns requirements for n8n", () => {
|
|
34
|
+
const reqs = getDbRequirements(makeResolved(["n8n", "redis"]));
|
|
35
|
+
globalExpect(reqs).toHaveLength(1);
|
|
36
|
+
globalExpect(reqs[0]).toEqual({
|
|
37
|
+
serviceId: "n8n",
|
|
38
|
+
serviceName: "N8n",
|
|
39
|
+
dbName: "n8n",
|
|
40
|
+
dbUser: "n8n",
|
|
41
|
+
passwordEnvVar: "N8N_DB_PASSWORD"
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
it("returns requirements for multiple services", () => {
|
|
45
|
+
const reqs = getDbRequirements(makeResolved([
|
|
46
|
+
"n8n",
|
|
47
|
+
"outline",
|
|
48
|
+
"postiz",
|
|
49
|
+
"redis"
|
|
50
|
+
]));
|
|
51
|
+
globalExpect(reqs).toHaveLength(3);
|
|
52
|
+
const ids = reqs.map((r) => r.serviceId);
|
|
53
|
+
globalExpect(ids).toContain("n8n");
|
|
54
|
+
globalExpect(ids).toContain("outline");
|
|
55
|
+
globalExpect(ids).toContain("postiz");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("generatePostgresInit", () => {
|
|
59
|
+
it("returns null when PostgreSQL is not in the stack", () => {
|
|
60
|
+
globalExpect(generatePostgresInit(makeResolved(["n8n", "redis"]))).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
it("returns null when PostgreSQL is present but no services need DBs", () => {
|
|
63
|
+
globalExpect(generatePostgresInit(makeResolved([
|
|
64
|
+
"postgresql",
|
|
65
|
+
"redis",
|
|
66
|
+
"minio"
|
|
67
|
+
]))).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
it("generates init script when PostgreSQL and DB-needing services are present", () => {
|
|
70
|
+
const script = generatePostgresInit(makeResolved(["postgresql", "n8n"]));
|
|
71
|
+
globalExpect(script).not.toBeNull();
|
|
72
|
+
globalExpect(script).toContain("#!/bin/bash");
|
|
73
|
+
globalExpect(script).toContain("create_db_and_user");
|
|
74
|
+
globalExpect(script).toContain("\"n8n\"");
|
|
75
|
+
globalExpect(script).toContain("N8N_DB_PASSWORD");
|
|
76
|
+
});
|
|
77
|
+
it("includes all services that need DBs", () => {
|
|
78
|
+
const script = generatePostgresInit(makeResolved([
|
|
79
|
+
"postgresql",
|
|
80
|
+
"n8n",
|
|
81
|
+
"outline",
|
|
82
|
+
"dify"
|
|
83
|
+
]));
|
|
84
|
+
globalExpect(script).toContain("\"n8n\"");
|
|
85
|
+
globalExpect(script).toContain("\"outline\"");
|
|
86
|
+
globalExpect(script).toContain("\"dify\"");
|
|
87
|
+
});
|
|
88
|
+
it("uses environment variable substitution for passwords (not literals)", () => {
|
|
89
|
+
globalExpect(generatePostgresInit(makeResolved(["postgresql", "n8n"]))).toContain("${N8N_DB_PASSWORD:-$POSTGRES_PASSWORD}");
|
|
90
|
+
});
|
|
91
|
+
it("script uses psql with ON_ERROR_STOP", () => {
|
|
92
|
+
globalExpect(generatePostgresInit(makeResolved(["postgresql", "n8n"]))).toContain("ON_ERROR_STOP=1");
|
|
93
|
+
});
|
|
94
|
+
it("script creates user with IF NOT EXISTS check", () => {
|
|
95
|
+
const script = generatePostgresInit(makeResolved(["postgresql", "n8n"]));
|
|
96
|
+
globalExpect(script).toContain("IF NOT EXISTS");
|
|
97
|
+
globalExpect(script).toContain("CREATE ROLE");
|
|
98
|
+
});
|
|
99
|
+
it("includes service names in summary line", () => {
|
|
100
|
+
const script = generatePostgresInit(makeResolved([
|
|
101
|
+
"postgresql",
|
|
102
|
+
"n8n",
|
|
103
|
+
"outline"
|
|
104
|
+
]));
|
|
105
|
+
globalExpect(script).toContain("N8n");
|
|
106
|
+
globalExpect(script).toContain("Outline");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//#endregion
|
|
110
|
+
export {};
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=postgres-init.test.mjs.map
|