spawn/packages/cli/src/__tests__/parse.test.ts
A 65f6f1be32
feat: Bun workspace monorepo — packages/cli + packages/shared (#1853)
Restructure the repo as a Bun workspace monorepo:

- Move cli/ → packages/cli/
- Create packages/shared/ (@openrouter/spawn-shared) with type-guards and parse utilities
- Add root package.json with workspace configuration
- Update all CLI imports to use @openrouter/spawn-shared
- Deduplicate toRecord/toObjectArray helpers from 4 cloud modules
- Update SPA (slack-bot) to use shared package instead of local toObj()
- Update 48 agent shell scripts for new packages/cli/ path
- Update install.sh, install.ps1, e2e, and test scripts
- Update all GitHub workflows, .gitignore, pre-commit hooks
- Update CLAUDE.md, README.md, and skill prompt references
- Pin all dependency versions (no ^ ranges)
- Bump CLI version 0.9.1 → 0.10.0

All 1908 tests pass. Lint clean. All 8 cloud bundles build.

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-23 22:07:05 -08:00

107 lines
2.8 KiB
TypeScript

import { describe, it, expect } from "bun:test";
import * as v from "valibot";
import { parseJsonWith, parseJsonRaw } from "@openrouter/spawn-shared";
describe("parseJsonWith", () => {
const NumberSchema = v.object({
count: v.number(),
});
it("should return validated data for valid JSON matching the schema", () => {
const result = parseJsonWith('{"count": 42}', NumberSchema);
expect(result).toEqual({
count: 42,
});
});
it("should return null for valid JSON that doesn't match the schema", () => {
const result = parseJsonWith('{"count": "not a number"}', NumberSchema);
expect(result).toBeNull();
});
it("should return null for invalid JSON", () => {
const result = parseJsonWith("not json at all", NumberSchema);
expect(result).toBeNull();
});
it("should return null for empty string", () => {
const result = parseJsonWith("", NumberSchema);
expect(result).toBeNull();
});
it("should handle nested schemas", () => {
const NestedSchema = v.object({
user: v.object({
name: v.string(),
age: v.number(),
}),
});
const result = parseJsonWith('{"user": {"name": "Alice", "age": 30}}', NestedSchema);
expect(result).toEqual({
user: {
name: "Alice",
age: 30,
},
});
});
it("should handle optional fields", () => {
const OptSchema = v.object({
name: v.string(),
email: v.optional(v.string()),
});
const result = parseJsonWith('{"name": "Bob"}', OptSchema);
expect(result).toEqual({
name: "Bob",
});
});
it("should handle record schemas", () => {
const RecordSchema = v.record(v.string(), v.unknown());
const result = parseJsonWith('{"key": "value", "num": 1}', RecordSchema);
expect(result).toEqual({
key: "value",
num: 1,
});
});
it("should reject array when object schema expected", () => {
const result = parseJsonWith("[1, 2, 3]", NumberSchema);
expect(result).toBeNull();
});
});
describe("parseJsonRaw", () => {
it("should parse valid JSON to unknown", () => {
const result = parseJsonRaw('{"key": "value"}');
expect(result).toEqual({
key: "value",
});
});
it("should parse JSON arrays", () => {
const result = parseJsonRaw("[1, 2, 3]");
expect(result).toEqual([
1,
2,
3,
]);
});
it("should return null for invalid JSON", () => {
const result = parseJsonRaw("not json");
expect(result).toBeNull();
});
it("should return null for empty string", () => {
const result = parseJsonRaw("");
expect(result).toBeNull();
});
it("should parse primitive JSON values", () => {
expect(parseJsonRaw("42")).toBe(42);
expect(parseJsonRaw('"hello"')).toBe("hello");
expect(parseJsonRaw("true")).toBe(true);
expect(parseJsonRaw("null")).toBeNull();
});
});