Skip to main content
Glama
test-utils.js6.33 kB
import { render } from '@testing-library/react'; import { vi } from 'vitest'; // Mock task data generator export function createMockTask(overrides = {}) { return { id: `task-${Math.random().toString(36).substr(2, 9)}`, name: 'Mock Task', description: 'Mock task description', status: 'pending', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), notes: null, implementationGuide: null, verificationCriteria: null, summary: null, completedAt: null, dependencies: [], relatedFiles: [], ...overrides }; } // Mock profile data generator export function createMockProfile(overrides = {}) { return { id: `agent-${Math.random().toString(36).substr(2, 9)}`, name: 'Mock Agent', path: '/mock/path/tasks.json', ...overrides }; } // Generate multiple mock tasks export function createMockTasks(count, overrides = {}) { return Array.from({ length: count }, (_, i) => createMockTask({ id: `task-${i}`, name: `Task ${i}`, description: `Description for task ${i}`, ...overrides }) ); } // Custom render with common providers export function renderWithProviders(ui, options = {}) { return render(ui, { ...options }); } // Mock fetch helper export function mockFetch(responses = {}) { global.fetch = vi.fn((url) => { const response = responses[url] || responses.default || { ok: false, status: 404, json: async () => ({ error: 'Not found' }) }; return Promise.resolve({ ok: response.ok !== false, status: response.status || 200, json: async () => response.json || response.data, text: async () => response.text || JSON.stringify(response.data || response.json || ''), ...response }); }); return global.fetch; } // Wait for async operations helper export async function waitForAsync(ms = 0) { return new Promise(resolve => setTimeout(resolve, ms)); } // Mock file system helper export function mockFileSystem(files = {}) { return { readFile: vi.fn((path) => { if (files[path]) { return Promise.resolve( typeof files[path] === 'string' ? files[path] : JSON.stringify(files[path]) ); } const error = new Error('File not found'); error.code = 'ENOENT'; return Promise.reject(error); }), writeFile: vi.fn(() => Promise.resolve()), mkdir: vi.fn(() => Promise.resolve()), unlink: vi.fn(() => Promise.resolve()), access: vi.fn((path) => { if (files[path]) { return Promise.resolve(); } const error = new Error('File not found'); error.code = 'ENOENT'; return Promise.reject(error); }) }; } // Test data fixtures export const fixtures = { tasks: { authentication: createMockTask({ id: 'auth-task', name: 'Implement authentication', description: 'OAuth2 authentication system', status: 'in_progress', dependencies: [ { taskId: 'redis-setup', name: 'Setup Redis' } ], relatedFiles: [ { path: '/src/auth/index.js', type: 'CREATE' } ] }), database: createMockTask({ id: 'db-task', name: 'Setup database', description: 'PostgreSQL database configuration', status: 'completed', completedAt: new Date().toISOString() }), testing: createMockTask({ id: 'test-task', name: 'Write tests', description: 'Unit and integration tests', status: 'pending', notes: 'Use Vitest for testing framework' }) }, profiles: { development: createMockProfile({ id: 'dev-agent', name: 'Development', path: '/dev/tasks.json' }), production: createMockProfile({ id: 'prod-agent', name: 'Production', path: '/prod/tasks.json' }) } }; // Assert helpers export const assertTask = { hasStatus: (task, status) => { expect(task.status).toBe(status); }, isComplete: (task) => { expect(task.status).toBe('completed'); expect(task.completedAt).toBeTruthy(); }, hasDependencies: (task) => { expect(task.dependencies).toBeDefined(); expect(task.dependencies.length).toBeGreaterThan(0); }, hasRelatedFiles: (task) => { expect(task.relatedFiles).toBeDefined(); expect(task.relatedFiles.length).toBeGreaterThan(0); } }; // Screen query helpers export const queries = { getTaskRow: (screen, taskName) => { return screen.getByText(taskName).closest('tr'); }, getStatusBadge: (screen, status) => { return screen.getByText(status.replace('_', ' ')); }, getPaginationInfo: (screen) => { return screen.getByText(/Showing \d+ to \d+ of \d+ tasks/); } }; // Event helpers export const events = { selectProfile: (screen, profileName) => { const profileTab = screen.getByText(profileName); fireEvent.click(profileTab); }, searchTasks: async (screen, searchTerm, user) => { const searchInput = screen.getByPlaceholderText(/Search tasks/); await user.clear(searchInput); await user.type(searchInput, searchTerm); }, clickTask: (screen, taskName) => { const taskRow = queries.getTaskRow(screen, taskName); fireEvent.click(taskRow); } }; // Validation helpers export const validate = { taskInTable: (screen, task) => { expect(screen.getByText(task.name)).toBeInTheDocument(); if (task.description) { expect(screen.getByText(new RegExp(task.description.substring(0, 50)))).toBeInTheDocument(); } if (task.status) { expect(queries.getStatusBadge(screen, task.status)).toBeInTheDocument(); } }, taskNotInTable: (screen, task) => { expect(screen.queryByText(task.name)).not.toBeInTheDocument(); }, profilesLoaded: (screen, profiles) => { profiles.forEach(profile => { expect(screen.getByText(profile.name)).toBeInTheDocument(); }); } }; // Mock server response builders export const responseBuilders = { success: (data) => ({ ok: true, status: 200, json: data }), error: (message, status = 500) => ({ ok: false, status, json: { error: message } }), profiles: (profiles = []) => ({ ok: true, status: 200, json: profiles }), tasks: (tasks = []) => ({ ok: true, status: 200, json: { tasks } }) };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cjo4m06/mcp-shrimp-task-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server