refactor(web): move website into turbo app workspace
This commit is contained in:
parent
2664804e91
commit
b4e626a868
66 changed files with 318 additions and 298 deletions
204
apps/web/src/lib/model/schema.test.ts
Normal file
204
apps/web/src/lib/model/schema.test.ts
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
DASHBOARD_SCHEMA_VERSION,
|
||||
dashboardDocumentJsonSchema,
|
||||
validateDashboardDocument,
|
||||
} from ".";
|
||||
import {
|
||||
dimensionLabDashboardFixture,
|
||||
genericDashboardFixture,
|
||||
} from "./fixtures";
|
||||
|
||||
describe("dashboard model validation", () => {
|
||||
it("accepts the generic dashboard fixture", () => {
|
||||
const result = validateDashboardDocument(genericDashboardFixture);
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
if (result.valid) {
|
||||
expect(result.data.schemaVersion).toBe(DASHBOARD_SCHEMA_VERSION);
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts the Dimension Lab dashboard fixture", () => {
|
||||
const result = validateDashboardDocument(dimensionLabDashboardFixture);
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects documents with an unsupported schema version", () => {
|
||||
const invalid = {
|
||||
...genericDashboardFixture,
|
||||
schemaVersion: "dashboard.v0",
|
||||
};
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("must be equal to constant");
|
||||
expect(result.details.length).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("returns actionable field paths for invalid documents", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
delete invalid.metadata.title;
|
||||
invalid.telemetry[0].severity = "fine";
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.some((error) => error.includes("/metadata"))).toBe(true);
|
||||
expect(result.errors.some((error) => error.includes("/telemetry/0/severity"))).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("includes offending additional property names in errors", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.metadata.unexpected = true;
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("unexpected");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects non-finite numbers that cannot roundtrip through JSON", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].value.value = Number.NaN;
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("finite JSON number");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects dangling layout references", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.layout.telemetry.push("missing-card");
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("missing-card");
|
||||
expect(result.errors.join(" ")).toContain("must reference an existing item");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects duplicate IDs within collections", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[1].id = invalid.telemetry[0].id;
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("must be unique");
|
||||
expect(result.errors.join(" ")).toContain(invalid.telemetry[0].id);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects duplicate status strip item IDs", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.statusStrips[0].items.push({
|
||||
...invalid.statusStrips[0].items[0],
|
||||
});
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("must be unique");
|
||||
expect(result.errors.join(" ")).toContain(invalid.statusStrips[0].items[0].id);
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects string values for numeric metric kinds", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].value.value = "not a percent";
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects percent values outside 0 to 100", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].value.value = 150;
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects negative values for nonnegative metric kinds", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].value = { kind: "latency", value: -20 };
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects contradictory warning and danger thresholds", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].thresholds = { warning: 90, danger: 80 };
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("warning threshold");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects percent thresholds above 100", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].thresholds = { warning: 99, danger: 999 };
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("percent thresholds");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects thresholds on text metric values", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.telemetry[0].value = { kind: "text", value: "available" };
|
||||
invalid.telemetry[0].thresholds = { warning: 10 };
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("text metric values");
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects undefined properties because they are not JSON values", () => {
|
||||
const invalid = JSON.parse(JSON.stringify(genericDashboardFixture));
|
||||
invalid.serviceGroups[0].services[0].link = undefined;
|
||||
|
||||
const result = validateDashboardDocument(invalid);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
if (!result.valid) {
|
||||
expect(result.errors.join(" ")).toContain("must be omitted instead of undefined");
|
||||
}
|
||||
});
|
||||
|
||||
it("exports JSON Schema for external tool contracts", () => {
|
||||
expect(dashboardDocumentJsonSchema.$id).toContain("dashboard-document.v1");
|
||||
expect(dashboardDocumentJsonSchema.properties).toHaveProperty("schemaVersion");
|
||||
expect(dashboardDocumentJsonSchema.properties).toHaveProperty("telemetry");
|
||||
expect(dashboardDocumentJsonSchema.properties).toHaveProperty("serviceGroups");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue