|
1 | | -import { describe, expect, expectTypeOf, it, vi } from "vitest" |
| 1 | +import { type } from "arktype" |
2 | 2 | import mitt from "mitt" |
| 3 | +import { describe, expect, expectTypeOf, it, vi } from "vitest" |
3 | 4 | import { z } from "zod" |
4 | 5 | import { SchemaValidationError, createCollection } from "../src/collection" |
5 | 6 | import { createTransaction } from "../src/transactions" |
@@ -956,6 +957,99 @@ describe(`Collection`, () => { |
956 | 957 | }) |
957 | 958 |
|
958 | 959 | describe(`Collection with schema validation`, () => { |
| 960 | + it(`should validate data against arktype schema on insert`, () => { |
| 961 | + // Create a Zod schema for a user |
| 962 | + const userSchema = type({ |
| 963 | + name: `string > 0`, |
| 964 | + age: `number.integer > 0`, |
| 965 | + "email?": `string.email`, |
| 966 | + }) |
| 967 | + |
| 968 | + // Create a collection with the schema |
| 969 | + const collection = createCollection<typeof userSchema.infer>({ |
| 970 | + id: `test`, |
| 971 | + getKey: (item) => item.name, |
| 972 | + startSync: true, |
| 973 | + sync: { |
| 974 | + sync: ({ begin, commit }) => { |
| 975 | + begin() |
| 976 | + commit() |
| 977 | + }, |
| 978 | + }, |
| 979 | + schema: userSchema, |
| 980 | + }) |
| 981 | + const mutationFn = async () => {} |
| 982 | + |
| 983 | + // Valid data should work |
| 984 | + const validUser = { |
| 985 | + name: `Alice`, |
| 986 | + age: 30, |
| 987 | + email: `alice@example.com`, |
| 988 | + } |
| 989 | + |
| 990 | + const tx1 = createTransaction({ mutationFn }) |
| 991 | + tx1.mutate(() => collection.insert(validUser)) |
| 992 | + |
| 993 | + // Invalid data should throw SchemaValidationError |
| 994 | + const invalidUser = { |
| 995 | + name: ``, // Empty name (fails min length) |
| 996 | + age: -5, // Negative age (fails positive) |
| 997 | + email: `not-an-email`, // Invalid email |
| 998 | + } |
| 999 | + |
| 1000 | + try { |
| 1001 | + const tx2 = createTransaction({ mutationFn }) |
| 1002 | + tx2.mutate(() => collection.insert(invalidUser)) |
| 1003 | + // Should not reach here |
| 1004 | + expect(true).toBe(false) |
| 1005 | + } catch (error) { |
| 1006 | + expect(error).toBeInstanceOf(SchemaValidationError) |
| 1007 | + if (error instanceof SchemaValidationError) { |
| 1008 | + expect(error.type).toBe(`insert`) |
| 1009 | + expect(error.issues.length).toBeGreaterThan(0) |
| 1010 | + // Check that we have validation errors for each invalid field |
| 1011 | + expect(error.issues.some((issue) => issue.path?.includes(`name`))).toBe( |
| 1012 | + true |
| 1013 | + ) |
| 1014 | + expect(error.issues.some((issue) => issue.path?.includes(`age`))).toBe( |
| 1015 | + true |
| 1016 | + ) |
| 1017 | + expect( |
| 1018 | + error.issues.some((issue) => issue.path?.includes(`email`)) |
| 1019 | + ).toBe(true) |
| 1020 | + } |
| 1021 | + } |
| 1022 | + |
| 1023 | + // Partial updates should work with valid data |
| 1024 | + const tx3 = createTransaction({ mutationFn }) |
| 1025 | + tx3.mutate(() => |
| 1026 | + collection.update(`Alice`, (draft) => { |
| 1027 | + draft.age = 31 |
| 1028 | + }) |
| 1029 | + ) |
| 1030 | + |
| 1031 | + // Partial updates should fail with invalid data |
| 1032 | + try { |
| 1033 | + const tx4 = createTransaction({ mutationFn }) |
| 1034 | + tx4.mutate(() => |
| 1035 | + collection.update(`Alice`, (draft) => { |
| 1036 | + draft.age = -1 |
| 1037 | + }) |
| 1038 | + ) |
| 1039 | + // Should not reach here |
| 1040 | + expect(true).toBe(false) |
| 1041 | + } catch (error) { |
| 1042 | + expect(error).toBeInstanceOf(SchemaValidationError) |
| 1043 | + if (error instanceof SchemaValidationError) { |
| 1044 | + expect(error.type).toBe(`update`) |
| 1045 | + expect(error.issues.length).toBeGreaterThan(0) |
| 1046 | + expect(error.issues.some((issue) => issue.path?.includes(`age`))).toBe( |
| 1047 | + true |
| 1048 | + ) |
| 1049 | + } |
| 1050 | + } |
| 1051 | + }) |
| 1052 | + |
959 | 1053 | it(`should validate data against schema on insert`, () => { |
960 | 1054 | // Create a Zod schema for a user |
961 | 1055 | const userSchema = z.object({ |
|
0 commit comments