mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-03 00:27:30 -05:00
Move app to apps/web-react in pnpm workspace layout
This commit is contained in:
126
apps/web-react/app/form/utils.test.ts
Normal file
126
apps/web-react/app/form/utils.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user