/**
* Unit tests for Validators
*/
import { describe, expect, it } from 'vitest';
import {
commentSchema,
itemResponseSchema,
searchParamsSchema,
searchResultSchema,
storySchema,
userSchema,
} from '../../src/lib/validators.js';
describe('Validators', () => {
describe('searchParamsSchema', () => {
it('should validate basic search params', () => {
const params = { query: 'test query' };
const result = searchParamsSchema.parse(params);
expect(result).toEqual({
query: 'test query',
page: 0,
hitsPerPage: 20,
});
});
it('should validate complete search params', () => {
const params = {
query: 'machine learning',
tags: 'story,author_pg',
numericFilters: 'points>=100,created_at_i>1640995200',
page: 2,
hitsPerPage: 50,
restrictSearchableAttributes: 'title,url',
};
const result = searchParamsSchema.parse(params);
expect(result).toEqual(params);
});
it('should reject invalid page number', () => {
const params = { query: 'test', page: -1 };
expect(() => searchParamsSchema.parse(params)).toThrow();
});
it('should reject invalid hitsPerPage', () => {
const params = { query: 'test', hitsPerPage: 150 };
expect(() => searchParamsSchema.parse(params)).toThrow();
});
it('should reject missing query', () => {
const params = { tags: 'story' };
expect(() => searchParamsSchema.parse(params)).toThrow();
});
});
describe('storySchema', () => {
it('should validate complete story object', () => {
const story = {
id: 123,
title: 'Test Story',
url: 'https://example.com',
author: 'testuser',
points: 42,
story_text: 'Story content',
comment_text: null,
created_at: '2023-01-01T00:00:00.000Z',
created_at_i: 1672531200,
num_comments: 10,
objectID: '123',
_tags: ['story', 'author_testuser'],
_highlightResult: { title: { value: 'Test Story' } },
};
const result = storySchema.parse(story);
expect(result).toEqual(story);
});
it('should validate story with null url', () => {
const story = {
id: 123,
title: 'Ask HN: Test Question',
url: null,
author: 'testuser',
points: 42,
story_text: null,
comment_text: null,
created_at: '2023-01-01T00:00:00.000Z',
created_at_i: 1672531200,
num_comments: 10,
objectID: '123',
_tags: ['story', 'ask_hn'],
};
const result = storySchema.parse(story);
expect(result.url).toBeNull();
});
it('should reject invalid story', () => {
const invalidStory = {
id: 'not-a-number', // Should be number
title: 'Test Story',
author: 'testuser',
points: 42,
created_at: '2023-01-01T00:00:00.000Z',
created_at_i: 1672531200,
num_comments: 10,
objectID: '123',
_tags: ['story'],
};
expect(() => storySchema.parse(invalidStory)).toThrow();
});
});
describe('commentSchema', () => {
it('should validate complete comment object', () => {
const comment = {
id: 456,
author: 'commenter',
text: 'This is a comment',
comment_text: 'This is a comment',
story_text: null,
points: 5,
parent_id: 123,
story_id: 123,
created_at: '2023-01-01T01:00:00.000Z',
created_at_i: 1672534800,
objectID: '456',
_tags: ['comment', 'author_commenter'],
children: [],
};
const result = commentSchema.parse(comment);
expect(result).toEqual(comment);
});
it('should validate comment with null points', () => {
const comment = {
id: 456,
author: 'commenter',
text: 'This is a comment',
comment_text: 'This is a comment',
story_text: null,
points: null,
parent_id: 123,
story_id: 123,
created_at: '2023-01-01T01:00:00.000Z',
created_at_i: 1672534800,
objectID: '456',
_tags: ['comment'],
};
const result = commentSchema.parse(comment);
expect(result.points).toBeNull();
});
});
describe('userSchema', () => {
it('should validate complete user object', () => {
const user = {
username: 'testuser',
about: 'About me text',
karma: 1234,
created_at: '2020-01-01T00:00:00.000Z',
created_at_i: 1577836800,
};
const result = userSchema.parse(user);
expect(result).toEqual(user);
});
it('should validate user with null about', () => {
const user = {
username: 'testuser',
about: null,
karma: 1234,
};
const result = userSchema.parse(user);
expect(result.about).toBeNull();
});
it('should validate minimal user object', () => {
const user = {
username: 'testuser',
about: null,
karma: 1234,
};
const result = userSchema.parse(user);
expect(result).toEqual({
username: 'testuser',
about: null,
karma: 1234,
created_at: undefined,
created_at_i: undefined,
});
});
});
describe('searchResultSchema', () => {
const resultSchema = searchResultSchema(storySchema);
it('should validate search result with stories', () => {
const searchResult = {
hits: [
{
id: 123,
title: 'Test Story',
url: 'https://example.com',
author: 'testuser',
points: 42,
story_text: 'Story content',
comment_text: null,
created_at: '2023-01-01T00:00:00.000Z',
created_at_i: 1672531200,
num_comments: 10,
objectID: '123',
_tags: ['story'],
},
],
nbHits: 1,
nbPages: 1,
page: 0,
hitsPerPage: 20,
processingTimeMS: 15,
query: 'test',
params: 'query=test',
};
const result = resultSchema.parse(searchResult);
expect(result).toEqual(searchResult);
});
it('should validate empty search result', () => {
const searchResult = {
hits: [],
nbHits: 0,
nbPages: 0,
page: 0,
hitsPerPage: 20,
processingTimeMS: 5,
query: 'nonexistent',
params: 'query=nonexistent',
};
const result = resultSchema.parse(searchResult);
expect(result.hits).toEqual([]);
expect(result.nbHits).toBe(0);
});
});
describe('itemResponseSchema', () => {
it('should validate complete item response', () => {
const item = {
id: 123,
created_at: '2023-01-01T00:00:00.000Z',
created_at_i: 1672531200,
author: 'testuser',
title: 'Test Story',
url: 'https://example.com',
text: 'Story text',
points: 42,
parent_id: null,
children: [
{
id: 456,
author: 'commenter',
text: 'Comment text',
created_at: '2023-01-01T01:00:00.000Z',
points: 5,
},
],
type: 'story',
};
const result = itemResponseSchema.parse(item);
expect(result).toEqual(item);
});
it('should validate minimal item response', () => {
const item = {
id: 123,
created_at: '2023-01-01T00:00:00.000Z',
author: 'testuser',
points: 42,
parent_id: null,
};
const result = itemResponseSchema.parse(item);
expect(result.id).toBe(123);
expect(result.author).toBe('testuser');
expect(result.points).toBe(42);
});
});
});