|
1 | 1 | import { describe, expect, it } from "vitest"; |
2 | 2 | import { ValidationError } from "./error"; |
3 | 3 | import { v } from "./index"; |
4 | | -import { attrsOf, validate, withAttrs } from "./schema"; |
| 4 | +import { |
| 5 | + asType, |
| 6 | + attrsOf, |
| 7 | + omitFields, |
| 8 | + parseFields, |
| 9 | + rejectFields, |
| 10 | + validate, |
| 11 | + withAttrs, |
| 12 | +} from "./schema"; |
5 | 13 |
|
6 | 14 | describe("schema $attrs", () => { |
7 | 15 | it("withAttrs merges within a namespace and isolates namespaces", () => { |
@@ -61,3 +69,69 @@ describe("schema $attrs", () => { |
61 | 69 | ).toBeDefined(); |
62 | 70 | }); |
63 | 71 | }); |
| 72 | + |
| 73 | +describe("omitFields / rejectFields / parseFields", () => { |
| 74 | + const dropMarked = (schema: unknown) => |
| 75 | + attrsOf(schema, "http")?.readonly === true; |
| 76 | + const shape = v.object({ |
| 77 | + id: v.string(), |
| 78 | + role: withAttrs(v.string(), "http", { readonly: true }), |
| 79 | + meta: v.object({ |
| 80 | + note: v.string(), |
| 81 | + secret: withAttrs(v.string(), "http", { readonly: true }), |
| 82 | + }), |
| 83 | + }); |
| 84 | + |
| 85 | + it("omitFields projects nested objects", () => { |
| 86 | + const projected = asType(omitFields(shape, dropMarked)); |
| 87 | + expect(Object.keys(projected.shape as object).sort()).toEqual([ |
| 88 | + "id", |
| 89 | + "meta", |
| 90 | + ]); |
| 91 | + const meta = asType((projected.shape as Record<string, unknown>).meta); |
| 92 | + expect(Object.keys(meta.shape as object)).toEqual(["note"]); |
| 93 | + }); |
| 94 | + |
| 95 | + it("rejectFields throws on smuggled keys", () => { |
| 96 | + expect(() => |
| 97 | + rejectFields(shape, { id: "1", role: "admin" }, dropMarked), |
| 98 | + ).toThrow(ValidationError); |
| 99 | + expect(() => |
| 100 | + rejectFields( |
| 101 | + shape, |
| 102 | + { id: "1", meta: { note: "n", secret: "s" } }, |
| 103 | + dropMarked, |
| 104 | + ), |
| 105 | + ).toThrow(/field is not allowed/); |
| 106 | + }); |
| 107 | + |
| 108 | + it("parseFields rejects then validates the projection", () => { |
| 109 | + expect( |
| 110 | + parseFields( |
| 111 | + shape, |
| 112 | + { id: "1", meta: { note: "hi" } }, |
| 113 | + { reject: dropMarked, omit: dropMarked }, |
| 114 | + ), |
| 115 | + ).toEqual({ id: "1", meta: { note: "hi" } }); |
| 116 | + expect(() => |
| 117 | + parseFields( |
| 118 | + shape, |
| 119 | + { id: "1", role: "admin" }, |
| 120 | + { reject: dropMarked, omit: dropMarked }, |
| 121 | + ), |
| 122 | + ).toThrow(ValidationError); |
| 123 | + }); |
| 124 | + |
| 125 | + it("omitFields projects through a var schema", () => { |
| 126 | + const user = v.var("parse_user", { |
| 127 | + schema: shape, |
| 128 | + }); |
| 129 | + const projected = omitFields(user, dropMarked); |
| 130 | + expect(projected.$var).toBe(true); |
| 131 | + expect( |
| 132 | + Object.keys( |
| 133 | + asType((projected as { schema: unknown }).schema).shape as object, |
| 134 | + ).sort(), |
| 135 | + ).toEqual(["id", "meta"]); |
| 136 | + }); |
| 137 | +}); |
0 commit comments