Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,153 @@
|
||||
import { ApiConfigError, type ApiConfig } from "@toolctrl/config";
|
||||
import { afterEach, describe, expect, test } from "vitest";
|
||||
import { getApiRuntimeConfig, resetApiRuntimeConfigForTests, setApiRuntimeConfigForTests } from "./config.js";
|
||||
|
||||
const originalEnv = { ...process.env };
|
||||
|
||||
const REQUIRED_PRODUCTION_ENV = {
|
||||
APP_NAME: "Production API",
|
||||
DATABASE_URL: "postgres://example.invalid/app",
|
||||
APP_BASE_DOMAIN: "example.com",
|
||||
WEB_APP_HOST: "app.example.com",
|
||||
ADMIN_APP_HOST: "admin.example.com",
|
||||
API_HOST: "api.example.com",
|
||||
SESSION_SECRET: "session-secret-value",
|
||||
CRYPTO_SECRET: "crypto-secret-value",
|
||||
API_ACCESS_TOKEN: "api-access-token-value",
|
||||
JWT_SECRET: "jwt-secret-value",
|
||||
ANALYTICS_TOKEN: "analytics-token-value",
|
||||
API_PORT: "8081",
|
||||
APP_PROTOCOL: "https",
|
||||
};
|
||||
|
||||
const SECRET_VALUES = [
|
||||
"api-access-token-value",
|
||||
"jwt-secret-value",
|
||||
"secret-like-invalid-port-value",
|
||||
"session-secret-value",
|
||||
"crypto-secret-value",
|
||||
"analytics-token-value",
|
||||
];
|
||||
|
||||
afterEach(() => {
|
||||
resetApiRuntimeConfigForTests();
|
||||
process.env = { ...originalEnv };
|
||||
});
|
||||
|
||||
describe("getApiRuntimeConfig", () => {
|
||||
test("loads required API runtime config from a complete production-like environment", () => {
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
...REQUIRED_PRODUCTION_ENV,
|
||||
NODE_ENV: "production",
|
||||
};
|
||||
|
||||
expect(getApiRuntimeConfig()).toMatchObject({
|
||||
appName: "Production API",
|
||||
nodeEnv: "production",
|
||||
listen: { port: 8081 },
|
||||
routing: {
|
||||
appBaseDomain: "example.com",
|
||||
webAppHost: "app.example.com",
|
||||
adminAppHost: "admin.example.com",
|
||||
apiHost: "api.example.com",
|
||||
protocol: "https",
|
||||
},
|
||||
apiAccessToken: "api-access-token-value",
|
||||
jwtSecret: "jwt-secret-value",
|
||||
analytics: {
|
||||
token: "analytics-token-value",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("throws redacted ApiConfigError when API_ACCESS_TOKEN is missing", () => {
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
...REQUIRED_PRODUCTION_ENV,
|
||||
NODE_ENV: "production",
|
||||
API_ACCESS_TOKEN: undefined,
|
||||
};
|
||||
|
||||
expect(() => getApiRuntimeConfig()).toThrow(ApiConfigError);
|
||||
|
||||
try {
|
||||
getApiRuntimeConfig();
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(ApiConfigError);
|
||||
const apiConfigError = error as ApiConfigError;
|
||||
expect(apiConfigError.message).toBe("Invalid API configuration (API_ACCESS_TOKEN:missing-required).");
|
||||
expect(apiConfigError.details.diagnostics).toEqual([
|
||||
expect.objectContaining({
|
||||
code: "missing-required",
|
||||
name: "API_ACCESS_TOKEN",
|
||||
classification: "required-per-app",
|
||||
}),
|
||||
]);
|
||||
const errorText = JSON.stringify({ message: apiConfigError.message, details: apiConfigError.details });
|
||||
for (const secretValue of SECRET_VALUES) {
|
||||
expect(errorText).not.toContain(secretValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("throws redacted ApiConfigError when API_PORT is invalid", () => {
|
||||
process.env = {
|
||||
...originalEnv,
|
||||
...REQUIRED_PRODUCTION_ENV,
|
||||
NODE_ENV: "production",
|
||||
API_PORT: "secret-like-invalid-port-value",
|
||||
};
|
||||
|
||||
try {
|
||||
getApiRuntimeConfig();
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(ApiConfigError);
|
||||
const apiConfigError = error as ApiConfigError;
|
||||
expect(apiConfigError.message).toBe("Invalid API configuration (API_PORT:invalid-port).");
|
||||
expect(apiConfigError.details.diagnostics).toEqual([
|
||||
expect.objectContaining({
|
||||
code: "invalid-port",
|
||||
name: "API_PORT",
|
||||
}),
|
||||
]);
|
||||
const errorText = JSON.stringify({ message: apiConfigError.message, details: apiConfigError.details });
|
||||
for (const secretValue of SECRET_VALUES) {
|
||||
expect(errorText).not.toContain(secretValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("uses setApiRuntimeConfigForTests override without reading required environment", () => {
|
||||
process.env = { NODE_ENV: "production" };
|
||||
const overrideConfig: ApiConfig = {
|
||||
appName: "Override API",
|
||||
nodeEnv: "test",
|
||||
revision: "unknown",
|
||||
listen: { port: 9999 },
|
||||
routing: {
|
||||
appBaseDomain: "override.localhost",
|
||||
webAppHost: "app.override.localhost",
|
||||
adminAppHost: "admin.override.localhost",
|
||||
apiHost: "api.override.localhost",
|
||||
protocol: "http",
|
||||
},
|
||||
origins: {},
|
||||
apiAccessToken: "override-token",
|
||||
jwtSecret: "override-jwt-secret",
|
||||
analytics: {},
|
||||
mailjet: {},
|
||||
stripe: {},
|
||||
apiKeys: {
|
||||
allowLegacyPlaintextFallback: true,
|
||||
},
|
||||
storage: {},
|
||||
};
|
||||
|
||||
setApiRuntimeConfigForTests(overrideConfig);
|
||||
|
||||
expect(getApiRuntimeConfig()).toBe(overrideConfig);
|
||||
resetApiRuntimeConfigForTests();
|
||||
expect(() => getApiRuntimeConfig()).toThrow(ApiConfigError);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user