import { expect, test } from "vitest" import { Variable } from "#Source/environment/index.ts" import type { Standard } from "#Source/validation/index.ts" interface TestVariables { APP_REQUIRED: string APP_OPTIONAL?: string | undefined } const createSyncSchema = (): Standard.Schema, TestVariables> => { const isRecord = (value: unknown): value is Record => { return typeof value === "object" && value !== null } return { "~standard": { version: 1 as const, vendor: "mobius-variable-spec", validate: (value: unknown): Standard.Schema.Result => { if (isRecord(value) === false) { return { issues: [{ message: "APP_REQUIRED is required" }], } } const appRequired = value["APP_REQUIRED"] const appOptional = value["APP_OPTIONAL"] if (typeof appRequired !== "string") { return { issues: [{ message: "APP_REQUIRED is required" }], } } const variable: TestVariables = { APP_REQUIRED: appRequired, } if (typeof appOptional === "string") { variable.APP_OPTIONAL = appOptional } return { value: variable, } }, }, } } const createAsyncSchema = (): Standard.Schema, TestVariables> => { return { "~standard": { version: 1 as const, vendor: "mobius-variable-spec-async", validate: async (_value: unknown): Promise> => { await Promise.resolve() return { value: { APP_REQUIRED: "ok", }, } }, }, } } test("parseVariables parses dotenv style content", () => { const result = Variable.Node.parseVariables({ variablesContent: "APP_REQUIRED=enabled\nAPP_OPTIONAL=maybe\n", }) expect(result["APP_REQUIRED"]).toBe("enabled") expect(result["APP_OPTIONAL"]).toBe("maybe") }) test("serializeVariables serializes variables into dotenv style content", () => { const result = Variable.Node.serializeVariables({ variables: { APP_REQUIRED: "enabled", APP_OPTIONAL: "maybe", }, }) expect(result).toBe("APP_REQUIRED=enabled\nAPP_OPTIONAL=maybe") }) test("getVariablesHost resolves runtime variable host", () => { const variablesHost = Variable.Node.getVariablesHost() expect(variablesHost).toBeTypeOf("object") }) test("loadVariables loads prefixed variables and keeps inline host priority", () => { const variablesHost = { APP_REQUIRED: "inline", APP_OLD: "legacy", OTHER_KEY: "ignore", } const result = Variable.Node.loadVariables({ variables: { APP_REQUIRED: "from-file", APP_OPTIONAL: "file-only", OTHER_KEY: "other", }, variablesPrefixs: ["APP_"], variablesHost, }) expect(result.variablesLoaded["APP_REQUIRED"]).toBe("from-file") expect(result.variablesLoaded["APP_OPTIONAL"]).toBe("file-only") expect(result.variablesLoaded["APP_OLD"]).toBe("legacy") expect(result.variablesLoaded["OTHER_KEY"]).toBeUndefined() }) test("validateVariables validates sync schema and throws on async or invalid results", () => { const validSchema = createSyncSchema() const validResult = Variable.Node.validateVariables({ variables: { APP_REQUIRED: "ok" }, variablesSchema: validSchema, }) expect(validResult.variablesValidated.APP_REQUIRED).toBe("ok") const invalidSchema = createSyncSchema() expect(() => Variable.Node.validateVariables({ variables: { APP_OPTIONAL: "missing-required" }, variablesSchema: invalidSchema, }), ).toThrow("Variable validation failed") const asyncSchema = createAsyncSchema() expect(() => Variable.Node.validateVariables({ variables: { APP_REQUIRED: "ok" }, variablesSchema: asyncSchema, }), ).toThrow("expected synchronous validation") }) test("getVariablesHosted returns host variables as key-value map", () => { const hosted = Variable.Node.getVariablesHosted() expect(hosted).toBeTypeOf("object") }) test("getVariables resolves from parsed content host and direct host", () => { const schema = createSyncSchema() const parsedVariables = Variable.Node.parseVariables({ variablesContent: "APP_REQUIRED=file\nAPP_OPTIONAL=extra\n", }) const fromParsedHost = Variable.Node.getVariables({ variablesHost: parsedVariables, variablesSchema: schema, }) const fromHost = Variable.Node.getVariables({ variablesHost: { APP_REQUIRED: "host" }, variablesSchema: schema, }) expect(fromParsedHost.variablesValidated.APP_REQUIRED).toBe("file") expect(fromHost.variablesValidated.APP_REQUIRED).toBe("host") }) test("VariablesManager.getFreshGetVariablesResult refreshes current variables", () => { const schema = createSyncSchema() const manager = new Variable.Node.VariablesManager({ variablesHost: { APP_REQUIRED: "fresh" }, variablesSchema: schema, }) const freshVariables = manager.getFreshGetVariablesResult() expect(freshVariables.variablesValidated.APP_REQUIRED).toBe("fresh") }) test("VariablesManager.getVariablesSchema returns schema instance", () => { const schema = createSyncSchema() const manager = new Variable.Node.VariablesManager({ variablesHost: { APP_REQUIRED: "schema" }, variablesSchema: schema, }) expect(manager.getVariablesSchema()).toBe(schema) }) test("VariablesManager.getValidatedVariables returns cached variable snapshot", () => { const schema = createSyncSchema() const manager = new Variable.Node.VariablesManager({ variablesHost: { APP_REQUIRED: "cached" }, variablesSchema: schema, }) const cachedVariables = manager.getValidatedVariables() expect(cachedVariables.APP_REQUIRED).toBe("cached") }) test("VariablesManager.getValidatedVariable returns cached variable by name", () => { const schema = createSyncSchema() const variablesHost = { APP_REQUIRED: "cached", APP_OPTIONAL: "maybe", } const manager = new Variable.Node.VariablesManager({ variablesHost, variablesSchema: schema, }) variablesHost.APP_REQUIRED = "changed" expect(manager.getValidatedVariable("APP_REQUIRED")).toBe("cached") expect(manager.getValidatedVariable("APP_OPTIONAL")).toBe("maybe") })