148 lines
3.5 KiB
TypeScript
148 lines
3.5 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { parseWithSchema } from "../src/json";
|
|
import { z } from "zod";
|
|
|
|
describe("json", () => {
|
|
describe("parseWithSchema", () => {
|
|
const schema = z.object({
|
|
test: z.boolean().optional(),
|
|
name: z.string(),
|
|
nested: z.object({ foo: z.string() }).strict().optional(),
|
|
});
|
|
it("should throw with invalid json", () => {
|
|
expect(() => parseWithSchema("blah", schema)).toThrow(
|
|
new Error(
|
|
`Invalid JSON: Unexpected token 'b', "blah" is not valid JSON`,
|
|
),
|
|
);
|
|
});
|
|
it("should parse", () => {
|
|
const json = `{
|
|
"test":true,
|
|
"name":"bob",
|
|
"unknown":"unknown",
|
|
"nested":{
|
|
"foo":"bar"
|
|
}
|
|
}`;
|
|
|
|
expect(parseWithSchema(json, schema)).toStrictEqual({
|
|
test: true,
|
|
name: "bob",
|
|
nested: { foo: "bar" },
|
|
});
|
|
});
|
|
it("should throw with invalid schema", () => {
|
|
const json = `{
|
|
"test":"yes",
|
|
"nested":{
|
|
"foo":1
|
|
}
|
|
}`;
|
|
|
|
expect(() => parseWithSchema(json, schema)).toThrow(
|
|
new Error(
|
|
`JSON does not match schema: "test" expected boolean, received string, "name" required, "nested.foo" expected string, received number`,
|
|
),
|
|
);
|
|
});
|
|
it("should migrate if valid json", () => {
|
|
const json = `{
|
|
"name": 1
|
|
}`;
|
|
|
|
const result = parseWithSchema(json, schema, {
|
|
migrate: () => {
|
|
return {
|
|
name: "migrated",
|
|
test: false,
|
|
};
|
|
},
|
|
});
|
|
|
|
expect(result).toStrictEqual({
|
|
name: "migrated",
|
|
test: false,
|
|
});
|
|
});
|
|
it("should revert to fallback if invalid json", () => {
|
|
const json = `blah`;
|
|
|
|
const result = parseWithSchema(json, schema, {
|
|
fallback: {
|
|
name: "migrated",
|
|
test: false,
|
|
},
|
|
});
|
|
|
|
expect(result).toStrictEqual({
|
|
name: "migrated",
|
|
test: false,
|
|
});
|
|
});
|
|
it("should throw if migration fails", () => {
|
|
const json = `{
|
|
"name": 1
|
|
}`;
|
|
|
|
expect(() => {
|
|
parseWithSchema(json, schema, {
|
|
//@ts-expect-error need to test migration failure
|
|
migrate: () => {
|
|
return {
|
|
name: null,
|
|
test: "Hi",
|
|
};
|
|
},
|
|
});
|
|
}).toThrow(
|
|
new Error(
|
|
`Migrated value does not match schema: "test" expected boolean, received string, "name" expected string, received null`,
|
|
),
|
|
);
|
|
});
|
|
it("should revert to fallback if migration fails", () => {
|
|
const json = `{
|
|
"name": 1
|
|
}`;
|
|
|
|
const result = parseWithSchema(json, schema, {
|
|
fallback: {
|
|
name: "fallback",
|
|
test: false,
|
|
},
|
|
//@ts-expect-error need to test migration failure
|
|
migrate: () => {
|
|
return {
|
|
name: null,
|
|
test: "Hi",
|
|
};
|
|
},
|
|
});
|
|
|
|
expect(result).toStrictEqual({
|
|
name: "fallback",
|
|
test: false,
|
|
});
|
|
});
|
|
it("migrate function should receive value", () => {
|
|
const json = `{
|
|
"test":"test"
|
|
}`;
|
|
|
|
const result = parseWithSchema(json, schema, {
|
|
migrate: (value) => {
|
|
expect(value).toEqual({ test: "test" });
|
|
return {
|
|
name: "valid",
|
|
};
|
|
},
|
|
});
|
|
|
|
expect(result).toStrictEqual({
|
|
name: "valid",
|
|
});
|
|
});
|
|
});
|
|
});
|