test: add vitest unit tests across packages

Cover shared zod schemas, extract traversal/refs/downloads, and tts filename/error handling. Document the test setup in the README and docs.
This commit is contained in:
2026-08-08 11:13:14 +08:00
parent 1de559c321
commit 92f11db415
15 changed files with 1185 additions and 3 deletions
+1
View File
@@ -14,6 +14,7 @@
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run",
"lint": "echo \"no lint configured\""
},
"dependencies": {
+135
View File
@@ -0,0 +1,135 @@
import { describe, expect, it } from 'vitest';
import {
assetRefSchema,
extractedObjectSchema,
itemIdSchema,
searchQuerySchema,
searchResultSchema,
workshopItemSchema,
} from './schemas.js';
describe('itemIdSchema', () => {
it('accepts a run of digits', () => {
expect(itemIdSchema.parse('123456')).toBe('123456');
});
it('rejects empty strings', () => {
expect(itemIdSchema.safeParse('').success).toBe(false);
});
it('rejects non-numeric input', () => {
expect(itemIdSchema.safeParse('abc').success).toBe(false);
expect(itemIdSchema.safeParse('12a34').success).toBe(false);
});
});
describe('searchQuerySchema', () => {
it('coerces page to a number and defaults it', () => {
expect(searchQuerySchema.parse({ q: 'cards' })).toEqual({
q: 'cards',
page: 1,
});
expect(searchQuerySchema.parse({ q: 'cards', page: '3' })).toEqual({
q: 'cards',
page: 3,
});
});
it('rejects a missing or blank query', () => {
expect(searchQuerySchema.safeParse({}).success).toBe(false);
expect(searchQuerySchema.safeParse({ q: ' ' }).success).toBe(false);
});
it('rejects a non-positive page', () => {
expect(searchQuerySchema.safeParse({ q: 'cards', page: 0 }).success).toBe(
false,
);
});
});
describe('assetRefSchema', () => {
it('accepts a valid ref', () => {
const ref = {
kind: 'pdf',
url: 'https://example.com/doc.pdf',
ownerGuid: 'abc',
};
expect(assetRefSchema.parse(ref)).toEqual(ref);
});
it('rejects an invalid URL', () => {
expect(
assetRefSchema.safeParse({
kind: 'pdf',
url: 'not-a-url',
ownerGuid: 'abc',
}).success,
).toBe(false);
});
it('rejects an unknown kind', () => {
expect(
assetRefSchema.safeParse({
kind: 'video',
url: 'https://example.com/a.mp4',
ownerGuid: 'abc',
}).success,
).toBe(false);
});
});
describe('extractedObjectSchema', () => {
it('accepts a minimal object', () => {
const obj = {
guid: 'g1',
name: 'Card',
type: 'Card',
childrenGuids: [],
refs: [],
};
expect(extractedObjectSchema.parse(obj)).toEqual(obj);
});
it('accepts optional parentGuid', () => {
const obj = {
guid: 'g1',
name: 'Card',
type: 'Card',
parentGuid: 'g0',
childrenGuids: ['g2'],
refs: [],
};
expect(extractedObjectSchema.parse(obj).parentGuid).toBe('g0');
});
});
describe('workshopItemSchema', () => {
it('accepts a full item', () => {
const item = {
id: '1',
title: 'Deck',
author: 'someone',
previewImageUrl: 'https://example.com/p.png',
tags: ['card'],
timeCreated: 123,
};
expect(workshopItemSchema.parse(item)).toEqual(item);
});
it('accepts a minimal item', () => {
const item = {
id: '1',
title: 'Deck',
author: 'someone',
previewImageUrl: 'https://example.com/p.png',
};
expect(workshopItemSchema.parse(item)).toEqual(item);
});
});
describe('searchResultSchema', () => {
it('accepts an empty result set', () => {
const result = { items: [], page: 1, hasMore: false };
expect(searchResultSchema.parse(result)).toEqual(result);
});
});