mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import { z } from "zod";
|
|
import { getNestedSchema, getNestedValue, setNestedValue } from "./utils";
|
|
|
|
describe("getNestedValue", () => {
|
|
test("returns value at simple path", () => {
|
|
expect(getNestedValue({ name: "test" }, "name")).toBe("test");
|
|
});
|
|
|
|
test("returns value at nested path", () => {
|
|
expect(getNestedValue({ config: { name: "test" } }, "config.name")).toBe(
|
|
"test",
|
|
);
|
|
});
|
|
|
|
test("returns undefined for missing path", () => {
|
|
expect(getNestedValue({ config: {} }, "config.name")).toBe(undefined);
|
|
});
|
|
|
|
test("returns undefined when parent is null", () => {
|
|
expect(getNestedValue({ config: null }, "config.name")).toBe(undefined);
|
|
});
|
|
|
|
test("handles deeply nested paths", () => {
|
|
const obj = { a: { b: { c: { d: "deep" } } } };
|
|
expect(getNestedValue(obj, "a.b.c.d")).toBe("deep");
|
|
});
|
|
});
|
|
|
|
describe("setNestedValue", () => {
|
|
test("sets value at simple path", () => {
|
|
expect(setNestedValue({}, "name", "test")).toEqual({ name: "test" });
|
|
});
|
|
|
|
test("sets value at nested path", () => {
|
|
expect(setNestedValue({}, "config.name", "test")).toEqual({
|
|
config: { name: "test" },
|
|
});
|
|
});
|
|
|
|
test("preserves existing sibling values", () => {
|
|
const obj = { config: { existing: "keep" } };
|
|
expect(setNestedValue(obj, "config.name", "test")).toEqual({
|
|
config: { existing: "keep", name: "test" },
|
|
});
|
|
});
|
|
|
|
test("is immutable - does not modify original", () => {
|
|
const obj = { config: { name: "old" } };
|
|
setNestedValue(obj, "config.name", "new");
|
|
expect(obj.config.name).toBe("old");
|
|
});
|
|
|
|
test("handles deeply nested paths", () => {
|
|
expect(setNestedValue({}, "a.b.c.d", "deep")).toEqual({
|
|
a: { b: { c: { d: "deep" } } },
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("getNestedSchema", () => {
|
|
test("returns schema for simple path", () => {
|
|
const schema = z.object({ name: z.string() });
|
|
const result = getNestedSchema(schema, "name");
|
|
expect(result).toBeInstanceOf(z.ZodString);
|
|
});
|
|
|
|
test("returns schema for nested path", () => {
|
|
const schema = z.object({ config: z.object({ name: z.string() }) });
|
|
const result = getNestedSchema(schema, "config.name");
|
|
expect(result).toBeInstanceOf(z.ZodString);
|
|
});
|
|
|
|
test("unwraps nullable wrapper", () => {
|
|
const schema = z.object({
|
|
config: z.object({ name: z.string() }).nullable(),
|
|
});
|
|
const result = getNestedSchema(schema, "config.name");
|
|
const def = result?._def ?? (result as unknown as { def?: unknown })?.def;
|
|
const typeName =
|
|
(def as { typeName?: string })?.typeName ??
|
|
(def as { type?: string })?.type;
|
|
expect(typeName).toBe("string");
|
|
});
|
|
|
|
test("unwraps optional wrapper", () => {
|
|
const schema = z.object({
|
|
config: z.object({ name: z.string() }).optional(),
|
|
});
|
|
const result = getNestedSchema(schema, "config.name");
|
|
const def = result?._def ?? (result as unknown as { def?: unknown })?.def;
|
|
const typeName =
|
|
(def as { typeName?: string })?.typeName ??
|
|
(def as { type?: string })?.type;
|
|
expect(typeName).toBe("string");
|
|
});
|
|
|
|
test("returns undefined for invalid path", () => {
|
|
const schema = z.object({ name: z.string() });
|
|
expect(getNestedSchema(schema, "missing.path")).toBe(undefined);
|
|
});
|
|
|
|
test("returns undefined when path goes through non-object", () => {
|
|
const schema = z.object({ name: z.string() });
|
|
expect(getNestedSchema(schema, "name.invalid")).toBe(undefined);
|
|
});
|
|
|
|
test("returns schema for array element path", () => {
|
|
const schema = z.object({
|
|
items: z.array(z.object({ name: z.string() })),
|
|
});
|
|
const result = getNestedSchema(schema, "items[0].name");
|
|
expect(result).toBeInstanceOf(z.ZodString);
|
|
});
|
|
|
|
test("returns schema for array element path with min/max", () => {
|
|
const schema = z.object({
|
|
items: z
|
|
.array(z.object({ name: z.string() }))
|
|
.min(1)
|
|
.max(10),
|
|
});
|
|
const result = getNestedSchema(schema, "items[0].name");
|
|
expect(result).toBeInstanceOf(z.ZodString);
|
|
});
|
|
});
|