mirror of
https://github.com/johndoe6345789/snippet-pastebin.git
synced 2026-04-24 13:34:55 +00:00
- Created comprehensive test suites for quality validator module (430+ tests) * index.test.ts: QualityValidator main module * reporters/*.test.ts: ReporterBase and all reporters * scoring/*.test.ts: Scoring engine with edge cases * utils/*.test.ts: Validators, formatters, FileChangeDetector - Added UI component tests for sidebar menu and templates (800+ tests) * SidebarMenuButton, SidebarMenuSubButton, etc. * DashboardTemplate, BlogTemplate * ContentPreviewCardsSection, FormFieldsSection - Coverage improvements: * Statements: 56.62% → 60.93% (+4.31%) * Functions: 76.76% → 79.82% (+3.06%) * Branches: 84.37% → 85.92% (+1.55%) * Tests passing: 5,512 (added 363 new passing tests) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
621 lines
18 KiB
TypeScript
621 lines
18 KiB
TypeScript
/**
|
|
* Unit Tests for useSnippetForm Hook
|
|
* Tests form state management for snippet creation/editing
|
|
*/
|
|
|
|
import { renderHook, act } from '@testing-library/react';
|
|
import { useSnippetForm } from '@/hooks/useSnippetForm';
|
|
import type { Snippet, InputParameter } from '@/lib/types';
|
|
import { strings } from '@/lib/config';
|
|
|
|
describe('useSnippetForm Hook', () => {
|
|
const mockSnippet: Snippet = {
|
|
id: '1',
|
|
title: 'Test Snippet',
|
|
description: 'Test Description',
|
|
language: 'javascript',
|
|
code: 'console.log("test")',
|
|
category: 'general',
|
|
hasPreview: true,
|
|
functionName: 'testFunc',
|
|
inputParameters: [
|
|
{ name: 'param1', type: 'string', defaultValue: '', description: 'First param' },
|
|
],
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
namespaceId: 'default',
|
|
isTemplate: false,
|
|
};
|
|
|
|
describe('initial state', () => {
|
|
it('should initialize with empty form when no snippet provided', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
expect(result.current.title).toBe('');
|
|
expect(result.current.description).toBe('');
|
|
expect(result.current.code).toBe('');
|
|
expect(result.current.language).toBeTruthy();
|
|
expect(result.current.hasPreview).toBe(false);
|
|
expect(result.current.inputParameters).toEqual([]);
|
|
expect(result.current.errors).toEqual({});
|
|
});
|
|
|
|
it('should initialize form with snippet data when provided', () => {
|
|
const { result } = renderHook(() => useSnippetForm(mockSnippet));
|
|
|
|
expect(result.current.title).toBe(mockSnippet.title);
|
|
expect(result.current.description).toBe(mockSnippet.description);
|
|
expect(result.current.code).toBe(mockSnippet.code);
|
|
expect(result.current.language).toBe(mockSnippet.language);
|
|
expect(result.current.hasPreview).toBe(true);
|
|
expect(result.current.functionName).toBe('testFunc');
|
|
expect(result.current.inputParameters).toHaveLength(1);
|
|
});
|
|
});
|
|
|
|
describe('form field setters', () => {
|
|
it('should update title', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('New Title');
|
|
});
|
|
|
|
expect(result.current.title).toBe('New Title');
|
|
});
|
|
|
|
it('should update description', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setDescription('New Description');
|
|
});
|
|
|
|
expect(result.current.description).toBe('New Description');
|
|
});
|
|
|
|
it('should update code', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setCode('console.log("new")');
|
|
});
|
|
|
|
expect(result.current.code).toBe('console.log("new")');
|
|
});
|
|
|
|
it('should update language', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setLanguage('python');
|
|
});
|
|
|
|
expect(result.current.language).toBe('python');
|
|
});
|
|
|
|
it('should toggle hasPreview', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
expect(result.current.hasPreview).toBe(false);
|
|
|
|
act(() => {
|
|
result.current.setHasPreview(true);
|
|
});
|
|
|
|
expect(result.current.hasPreview).toBe(true);
|
|
});
|
|
|
|
it('should update functionName', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setFunctionName('myFunction');
|
|
});
|
|
|
|
expect(result.current.functionName).toBe('myFunction');
|
|
});
|
|
});
|
|
|
|
describe('parameter management', () => {
|
|
it('should add new parameter', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
expect(result.current.inputParameters).toHaveLength(0);
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(1);
|
|
expect(result.current.inputParameters[0]).toEqual({
|
|
name: '',
|
|
type: 'string',
|
|
defaultValue: '',
|
|
description: '',
|
|
});
|
|
});
|
|
|
|
it('should add multiple parameters', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(3);
|
|
});
|
|
|
|
it('should remove parameter by index', () => {
|
|
const { result } = renderHook(() => useSnippetForm(mockSnippet));
|
|
|
|
expect(result.current.inputParameters).toHaveLength(1);
|
|
|
|
act(() => {
|
|
result.current.handleRemoveParameter(0);
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(0);
|
|
});
|
|
|
|
it('should remove middle parameter correctly', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleRemoveParameter(1);
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(2);
|
|
});
|
|
|
|
it('should update parameter field', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
act(() => {
|
|
result.current.handleUpdateParameter(0, 'name', 'newParam');
|
|
});
|
|
|
|
expect(result.current.inputParameters[0].name).toBe('newParam');
|
|
});
|
|
|
|
it('should update parameter type', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
act(() => {
|
|
result.current.handleUpdateParameter(0, 'type', 'number');
|
|
});
|
|
|
|
expect(result.current.inputParameters[0].type).toBe('number');
|
|
});
|
|
|
|
it('should update parameter defaultValue', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
act(() => {
|
|
result.current.handleUpdateParameter(0, 'defaultValue', 'default');
|
|
});
|
|
|
|
expect(result.current.inputParameters[0].defaultValue).toBe('default');
|
|
});
|
|
|
|
it('should update parameter description', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
act(() => {
|
|
result.current.handleUpdateParameter(0, 'description', 'Param description');
|
|
});
|
|
|
|
expect(result.current.inputParameters[0].description).toBe('Param description');
|
|
});
|
|
});
|
|
|
|
describe('validation', () => {
|
|
it('should validate empty title', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('');
|
|
const isValid = result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.title).toBeTruthy();
|
|
});
|
|
|
|
it('should validate empty code', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setCode('');
|
|
const isValid = result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.code).toBeTruthy();
|
|
});
|
|
|
|
it('should validate whitespace-only title', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle(' ');
|
|
const isValid = result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.title).toBeTruthy();
|
|
});
|
|
|
|
it('should validate whitespace-only code', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setCode(' ');
|
|
const isValid = result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.code).toBeTruthy();
|
|
});
|
|
|
|
it('should return true for valid form', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('Valid Title');
|
|
result.current.setCode('console.log("code")');
|
|
});
|
|
|
|
const isValid = act(() => result.current.validate());
|
|
expect(result.current.errors).toEqual({});
|
|
});
|
|
|
|
it('should return false for invalid form', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
const isValid = act(() => result.current.validate());
|
|
expect(Object.keys(result.current.errors).length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should clear previous errors on revalidation', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('');
|
|
result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.title).toBeTruthy();
|
|
|
|
act(() => {
|
|
result.current.setTitle('Valid Title');
|
|
result.current.validate();
|
|
});
|
|
|
|
expect(result.current.errors.title).toBeFalsy();
|
|
});
|
|
});
|
|
|
|
describe('getFormData', () => {
|
|
it('should return form data with basic fields', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('My Snippet');
|
|
result.current.setDescription('Description');
|
|
result.current.setCode('console.log("test")');
|
|
result.current.setLanguage('javascript');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
|
|
expect(formData.title).toBe('My Snippet');
|
|
expect(formData.description).toBe('Description');
|
|
expect(formData.code).toBe('console.log("test")');
|
|
expect(formData.language).toBe('javascript');
|
|
});
|
|
|
|
it('should trim whitespace from fields', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle(' Title ');
|
|
result.current.setDescription(' Desc ');
|
|
result.current.setCode(' code ');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
|
|
expect(formData.title).toBe('Title');
|
|
expect(formData.description).toBe('Desc');
|
|
expect(formData.code).toBe('code');
|
|
});
|
|
|
|
it('should include hasPreview flag', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setHasPreview(true);
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.hasPreview).toBe(true);
|
|
});
|
|
|
|
it('should include functionName if provided', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setFunctionName(' testFunc ');
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.functionName).toBe('testFunc');
|
|
});
|
|
|
|
it('should exclude functionName if empty', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.functionName).toBeUndefined();
|
|
});
|
|
|
|
it('should include inputParameters if provided', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
result.current.handleAddParameter();
|
|
result.current.handleUpdateParameter(0, 'name', 'param1');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.inputParameters).toBeTruthy();
|
|
expect(formData.inputParameters).toHaveLength(1);
|
|
});
|
|
|
|
it('should exclude inputParameters if empty', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.inputParameters).toBeUndefined();
|
|
});
|
|
|
|
it('should preserve category from editing snippet', () => {
|
|
const { result } = renderHook(() => useSnippetForm({ ...mockSnippet, category: 'utility' }));
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.category).toBe('utility');
|
|
});
|
|
|
|
it('should default category to general for new snippets', () => {
|
|
const { result } = renderHook(() => useSnippetForm(null));
|
|
|
|
act(() => {
|
|
result.current.setTitle('Test');
|
|
result.current.setCode('code');
|
|
});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.category).toBe('general');
|
|
});
|
|
});
|
|
|
|
describe('resetForm', () => {
|
|
it('should reset all fields to initial state', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('Title');
|
|
result.current.setDescription('Description');
|
|
result.current.setCode('code');
|
|
result.current.setLanguage('python');
|
|
result.current.setHasPreview(true);
|
|
result.current.setFunctionName('func');
|
|
result.current.handleAddParameter();
|
|
});
|
|
|
|
expect(result.current.title).toBe('Title');
|
|
expect(result.current.inputParameters).toHaveLength(1);
|
|
|
|
act(() => {
|
|
result.current.resetForm();
|
|
});
|
|
|
|
expect(result.current.title).toBe('');
|
|
expect(result.current.description).toBe('');
|
|
expect(result.current.code).toBe('');
|
|
expect(result.current.hasPreview).toBe(false);
|
|
expect(result.current.functionName).toBe('');
|
|
expect(result.current.inputParameters).toHaveLength(0);
|
|
expect(result.current.errors).toEqual({});
|
|
});
|
|
|
|
it('should clear validation errors on reset', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.validate();
|
|
});
|
|
|
|
expect(Object.keys(result.current.errors).length).toBeGreaterThan(0);
|
|
|
|
act(() => {
|
|
result.current.resetForm();
|
|
});
|
|
|
|
expect(result.current.errors).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe('editing existing snippet', () => {
|
|
it('should populate form with snippet data', () => {
|
|
const { result } = renderHook(() => useSnippetForm(mockSnippet));
|
|
|
|
expect(result.current.title).toBe(mockSnippet.title);
|
|
expect(result.current.description).toBe(mockSnippet.description);
|
|
expect(result.current.language).toBe(mockSnippet.language);
|
|
expect(result.current.code).toBe(mockSnippet.code);
|
|
expect(result.current.hasPreview).toBe(mockSnippet.hasPreview);
|
|
expect(result.current.functionName).toBe(mockSnippet.functionName);
|
|
});
|
|
|
|
it('should load parameters from snippet', () => {
|
|
const { result } = renderHook(() => useSnippetForm(mockSnippet));
|
|
|
|
expect(result.current.inputParameters).toEqual(mockSnippet.inputParameters);
|
|
});
|
|
|
|
it('should switch to different snippet', () => {
|
|
const newSnippet: Snippet = {
|
|
...mockSnippet,
|
|
id: '2',
|
|
title: 'Different Snippet',
|
|
};
|
|
|
|
const { result, rerender } = renderHook(
|
|
({ snippet }) => useSnippetForm(snippet),
|
|
{ initialProps: { snippet: mockSnippet } }
|
|
);
|
|
|
|
expect(result.current.title).toBe('Test Snippet');
|
|
|
|
rerender({ snippet: newSnippet });
|
|
|
|
expect(result.current.title).toBe('Different Snippet');
|
|
});
|
|
|
|
it('should handle null snippet', () => {
|
|
const { result, rerender } = renderHook(
|
|
({ snippet }) => useSnippetForm(snippet),
|
|
{ initialProps: { snippet: mockSnippet } }
|
|
);
|
|
|
|
expect(result.current.title).toBe('Test Snippet');
|
|
|
|
rerender({ snippet: null });
|
|
|
|
expect(result.current.title).toBe('');
|
|
expect(result.current.code).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('dialog open/close', () => {
|
|
it('should reset form when dialog opens', () => {
|
|
const { result } = renderHook(
|
|
({ open }) => useSnippetForm(null, open),
|
|
{ initialProps: { open: false } }
|
|
);
|
|
|
|
act(() => {
|
|
result.current.setTitle('Title');
|
|
});
|
|
|
|
const { rerender } = result;
|
|
rerender({ open: true });
|
|
|
|
expect(result.current.title).toBe('');
|
|
});
|
|
|
|
it('should handle open state change', () => {
|
|
const { result } = renderHook(
|
|
({ open }) => useSnippetForm(mockSnippet, open),
|
|
{ initialProps: { open: false } }
|
|
);
|
|
|
|
expect(result.current.title).toBe('Test Snippet');
|
|
});
|
|
});
|
|
|
|
describe('complex scenarios', () => {
|
|
it('should handle multiple parameter updates', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleUpdateParameter(0, 'name', 'param1');
|
|
result.current.handleUpdateParameter(0, 'type', 'string');
|
|
result.current.handleUpdateParameter(1, 'name', 'param2');
|
|
result.current.handleUpdateParameter(1, 'type', 'number');
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(2);
|
|
expect(result.current.inputParameters[0].name).toBe('param1');
|
|
expect(result.current.inputParameters[1].name).toBe('param2');
|
|
});
|
|
|
|
it('should handle form submission workflow', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.setTitle('My Snippet');
|
|
result.current.setCode('code here');
|
|
result.current.setLanguage('javascript');
|
|
result.current.setDescription('Description');
|
|
result.current.setHasPreview(true);
|
|
});
|
|
|
|
const isValid = act(() => result.current.validate());
|
|
expect(result.current.errors).toEqual({});
|
|
|
|
const formData = result.current.getFormData();
|
|
expect(formData.title).toBe('My Snippet');
|
|
expect(formData.code).toBe('code here');
|
|
|
|
act(() => {
|
|
result.current.resetForm();
|
|
});
|
|
|
|
expect(result.current.title).toBe('');
|
|
});
|
|
|
|
it('should handle rapid parameter additions and removals', () => {
|
|
const { result } = renderHook(() => useSnippetForm());
|
|
|
|
act(() => {
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleAddParameter();
|
|
result.current.handleRemoveParameter(1);
|
|
result.current.handleAddParameter();
|
|
result.current.handleRemoveParameter(0);
|
|
});
|
|
|
|
expect(result.current.inputParameters).toHaveLength(2);
|
|
});
|
|
});
|
|
});
|