feat: protect responsive board layouts
This commit is contained in:
1 parent
4df62221c7
commit
30c00ea30d
30 files changed
+1055
-254
No files matched your search
@@ -1,9 +1,57 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { responsiveBoardLayoutsSchema } from "./board";
|
||||
import { containerSectionOptionsDefaults, sectionSchema } from "./shared";
|
||||
|
||||
const mobile = {
|
||||
id: "mobile",
|
||||
name: "Mobile",
|
||||
columnCount: 3,
|
||||
breakpoint: 0,
|
||||
role: "mobile" as const,
|
||||
};
|
||||
const base = {
|
||||
id: "base",
|
||||
name: "Base",
|
||||
columnCount: 12,
|
||||
breakpoint: 768,
|
||||
role: "base" as const,
|
||||
};
|
||||
|
||||
describe("responsiveBoardLayoutsSchema", () => {
|
||||
test("accepts protected layouts and custom layouts strictly between them", () => {
|
||||
expect(
|
||||
responsiveBoardLayoutsSchema.safeParse([
|
||||
mobile,
|
||||
{ id: "tablet", name: "Tablet", columnCount: 6, breakpoint: 480, role: "custom" },
|
||||
base,
|
||||
]).success,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ name: "missing Mobile", layouts: [{ ...mobile, role: "custom" }, base] },
|
||||
{ name: "removable Base replacement", layouts: [mobile, { ...base, role: "custom" }] },
|
||||
{ name: "non-zero Mobile breakpoint", layouts: [{ ...mobile, breakpoint: 320 }, base] },
|
||||
{
|
||||
name: "custom layout at Base breakpoint",
|
||||
layouts: [mobile, { id: "tablet", name: "Tablet", columnCount: 6, breakpoint: 768, role: "custom" }, base],
|
||||
},
|
||||
{
|
||||
name: "duplicate layout ID",
|
||||
layouts: [mobile, { ...base, id: mobile.id }],
|
||||
},
|
||||
{
|
||||
name: "mobile sidebar",
|
||||
layouts: [{ ...mobile, leftGutterColumnCount: 1 }, base],
|
||||
},
|
||||
])("rejects $name", ({ layouts }) => {
|
||||
expect(responsiveBoardLayoutsSchema.safeParse(layouts).success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("section behavior validation", () => {
|
||||
it("normalizes a container to the current behavior defaults", () => {
|
||||
test("normalizes a container to the current behavior defaults", () => {
|
||||
const result = sectionSchema.parse({
|
||||
id: "container",
|
||||
kind: "container",
|
||||
@@ -16,7 +64,7 @@ describe("section behavior validation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves configured container behavior", () => {
|
||||
test("preserves configured container behavior", () => {
|
||||
const result = sectionSchema.parse({
|
||||
id: "container",
|
||||
kind: "container",
|
||||
@@ -44,7 +92,7 @@ describe("section behavior validation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes the legacy dynamic kind to a container", () => {
|
||||
test("normalizes the legacy dynamic kind to a container", () => {
|
||||
expect(sectionSchema.parse({ id: "legacy", kind: "dynamic", layouts: [] })).toMatchObject({
|
||||
id: "legacy",
|
||||
kind: "container",
|
||||
@@ -52,11 +100,11 @@ describe("section behavior validation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects the legacy category kind", () => {
|
||||
test("rejects the legacy category kind", () => {
|
||||
expect(() => sectionSchema.parse({ id: "legacy", kind: "category", layouts: [] })).toThrow();
|
||||
});
|
||||
|
||||
it.each([
|
||||
test.each([
|
||||
{ xOffset: 0.5, yOffset: 0, width: 1, height: 1 },
|
||||
{ xOffset: -1, yOffset: 0, width: 1, height: 1 },
|
||||
{ xOffset: 0, yOffset: 0, width: 0, height: 1 },
|
||||
|
||||
Reference in new issue
Block a user