diff --git a/src/__tests__/pages/api/validate.test.js b/src/__tests__/pages/api/validate.test.js index 86c40e2e0..8a1eec21b 100644 --- a/src/__tests__/pages/api/validate.test.js +++ b/src/__tests__/pages/api/validate.test.js @@ -2,12 +2,15 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import createMockRes from "test-utils/create-mock-res"; -const { checkAndCopyConfig } = vi.hoisted(() => ({ +const { checkAndCopyConfig, getSettings } = vi.hoisted(() => ({ checkAndCopyConfig: vi.fn(), + getSettings: vi.fn(() => ({})), })); vi.mock("utils/config/config", () => ({ default: checkAndCopyConfig, + getSettings, + CONF_DIR: "/tmp", })); import handler from "pages/api/validate"; @@ -18,13 +21,28 @@ describe("pages/api/validate", () => { }); it("returns errors for any configs that don't validate", async () => { - checkAndCopyConfig.mockReturnValueOnce(true).mockReturnValueOnce("settings bad").mockReturnValue(true); + checkAndCopyConfig + .mockReturnValueOnce(true) + .mockReturnValueOnce({ + name: "YAMLException", + config: "settings.yaml", + reason: "settings bad", + mark: { line: 1 }, + }) + .mockReturnValue(true); const req = {}; const res = createMockRes(); await handler(req, res); - expect(res.body).toEqual(["settings bad"]); + expect(res.body).toEqual([ + { + name: "YAMLException", + config: "settings.yaml", + reason: "settings bad", + mark: { line: 1 }, + }, + ]); }); }); diff --git a/src/__tests__/pages/index.test.jsx b/src/__tests__/pages/index.test.jsx index 114689d94..1d8c03240 100644 --- a/src/__tests__/pages/index.test.jsx +++ b/src/__tests__/pages/index.test.jsx @@ -324,13 +324,12 @@ describe("pages/index Index routing + SWR branches", () => { }); it("renders config errors when /api/validate returns a list of errors", async () => { - state.validateData = [{ config: "services.yaml", reason: "broken", mark: { snippet: "x: y" } }]; + state.validateData = [{ config: "services.yaml", name: "Service 1", reason: "broken", mark: { line: 4 } }]; await renderIndex({ initialSettings: { title: "Homepage", layout: {} }, settings: { layout: {} } }); - expect(screen.getByText("services.yaml")).toBeInTheDocument(); - expect(screen.getByText("broken")).toBeInTheDocument(); - expect(screen.getByText("x: y")).toBeInTheDocument(); + expect(screen.getByText(/services.yaml/)).toBeInTheDocument(); + expect(screen.getByText(/line 4/)).toBeInTheDocument(); }); it("marks the UI stale when the hash changes and triggers a revalidate reload", async () => { diff --git a/src/pages/api/validate.js b/src/pages/api/validate.js index 803d22827..aa892072f 100644 --- a/src/pages/api/validate.js +++ b/src/pages/api/validate.js @@ -1,9 +1,19 @@ import checkAndCopyConfig from "utils/config/config"; +import createLogger from "utils/logger"; const configs = ["docker.yaml", "settings.yaml", "services.yaml", "bookmarks.yaml", "kubernetes.yaml", "proxmox.yaml"]; +const logger = createLogger("configValidationHandler"); export default async function handler(req, res) { - const errors = configs.map((config) => checkAndCopyConfig(config)).filter((status) => status !== true); - + let errors = configs.map((config) => checkAndCopyConfig(config)).filter((status) => status !== true); + if (errors.length > 0) { + logger.error("Configuration validation errors", errors); + errors = errors.map((error) => ({ + name: error.name, + config: error.config, + reason: error.reason, + mark: { line: error.mark?.line }, + })); + } res.send(errors); } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index f0e8afae6..a51313e07 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -167,11 +167,13 @@ function Index({ initialSettings, fallback }) { >
{error.reason}
- {error.mark.snippet}
+
+ Reason: "{error.reason}" at line {error.mark?.line}
+
+ Check logs for details.