109 lines
4.9 KiB
TypeScript
109 lines
4.9 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { resolve } from "node:path";
|
|
import { readProviderAppsConfig } from "../../src/components/provider-apps/config";
|
|
import { readProviderRelease, releaseResponse } from "../../src/components/provider-apps/release";
|
|
import { providerAppsHelp } from "./provider-apps";
|
|
|
|
const repositoryRoot = resolve(import.meta.dir, "../..");
|
|
|
|
describe("Provider Apps L1 release", () => {
|
|
const config = readProviderAppsConfig(repositoryRoot);
|
|
const release = readProviderRelease(repositoryRoot, config);
|
|
|
|
test("owning YAML declares a fixed native HTTPS origin", () => {
|
|
expect(config.target.id).toBe("NC01");
|
|
expect(config.runtime.port).toBe(18121);
|
|
expect(config.publicExposure.publicBaseUrl).toBe("https://apps.hwpod.com");
|
|
});
|
|
|
|
test("serves release files and rejects unknown or mutating requests", async () => {
|
|
expect((await releaseResponse("GET", config.release.routes.health, config, release).json()).ok).toBe(true);
|
|
expect(releaseResponse("GET", config.release.routes.manifest, config, release).status).toBe(200);
|
|
expect(releaseResponse("HEAD", config.release.routes.provider, config, release).status).toBe(200);
|
|
expect(releaseResponse("GET", "/private", config, release).status).toBe(404);
|
|
expect(releaseResponse("POST", config.release.routes.provider, config, release).status).toBe(405);
|
|
});
|
|
|
|
test("serves human and agent installer surfaces from one L1 service", async () => {
|
|
const index = releaseResponse(
|
|
"GET",
|
|
config.install.routes.index,
|
|
config,
|
|
release,
|
|
"https://apps.hwpod.com",
|
|
);
|
|
expect(index.status).toBe(200);
|
|
expect(index.headers.get("content-security-policy")).toContain("default-src 'self'");
|
|
const indexHtml = await index.text();
|
|
expect(indexHtml).toContain("32 条 TCP warm channel");
|
|
expect(indexHtml).toContain('<link rel="icon" href="/assets/provider-icon.svg"');
|
|
const appScript = await releaseResponse(
|
|
"GET",
|
|
config.install.routes.script,
|
|
config,
|
|
release,
|
|
).text();
|
|
const referencedIds = [...appScript.matchAll(/querySelector\("#([^"]+)"\)/gu)]
|
|
.map((match) => match[1]);
|
|
expect(referencedIds.length).toBeGreaterThan(0);
|
|
for (const id of referencedIds) {
|
|
expect(indexHtml).toContain(`id="${id}"`);
|
|
}
|
|
const contract = await releaseResponse(
|
|
"GET",
|
|
config.install.routes.contract,
|
|
config,
|
|
release,
|
|
"https://apps.hwpod.com",
|
|
).json() as Record<string, any>;
|
|
expect(contract.schemaVersion).toBe(2);
|
|
expect(contract.humanUrl).toBe("https://apps.hwpod.com/");
|
|
expect(contract.sensitiveInputs.acceptedByWeb).toBe(false);
|
|
expect(contract.installer.acceptsArguments).toBe(false);
|
|
expect(contract.config.mustExistBeforeInstall).toBe(true);
|
|
expect(contract.oneLineTemplate).toBe(
|
|
"irm 'https://apps.hwpod.com/v1/unideskcprovider/install.ps1' | iex",
|
|
);
|
|
const fallbackContract = await releaseResponse(
|
|
"GET",
|
|
config.install.routes.contract,
|
|
config,
|
|
release,
|
|
"http://127.0.0.1:18121",
|
|
).json() as Record<string, any>;
|
|
expect(fallbackContract.humanUrl).toBe("https://apps.hwpod.com/");
|
|
});
|
|
|
|
test("PowerShell installer has release URLs resolved and accepts no arguments", async () => {
|
|
const installer = await releaseResponse(
|
|
"GET",
|
|
config.install.routes.installer,
|
|
config,
|
|
release,
|
|
).text();
|
|
expect(installer).toContain("https://apps.hwpod.com/v1/unideskcprovider/update.json");
|
|
expect(installer).toContain("https://apps.hwpod.com/v1/unideskcprovider/unideskcprovider.py");
|
|
expect(installer).toContain("$ErrorActionPreference = \"Continue\"");
|
|
expect(installer).toContain("sys.modules[spec.name] = module");
|
|
expect(installer).toContain("\"config-probe-$PID.py\"");
|
|
expect(installer).not.toContain("\"-c\",\n $configProbeCode");
|
|
expect(installer).toContain("\"$providerPath.install.bak\"");
|
|
expect(installer).not.toContain("$providerPath, $null");
|
|
expect(installer).toContain("param()");
|
|
expect(installer).not.toContain("__MANIFEST_URL__");
|
|
expect(installer).not.toContain("__PROVIDER_URL__");
|
|
expect(installer).not.toContain("[Parameter(Mandatory");
|
|
expect(installer).not.toContain("nodeRequired");
|
|
expect(releaseResponse("HEAD", config.install.routes.style, config, release).status).toBe(200);
|
|
expect(releaseResponse("HEAD", config.install.routes.script, config, release).status).toBe(200);
|
|
expect(releaseResponse("HEAD", config.install.routes.favicon, config, release).status).toBe(200);
|
|
expect(releaseResponse("HEAD", config.install.routes.panelImage, config, release).status).toBe(200);
|
|
});
|
|
|
|
test("CLI help keeps one YAML-owned native lifecycle", () => {
|
|
const help = providerAppsHelp();
|
|
expect(help.config).toBe("config/platform-infra/apps.yaml");
|
|
expect(help.usage).toContain("bun scripts/cli.ts provider-apps server status");
|
|
});
|
|
});
|