Skip to main content
Glama
mock-freshbooks-client.ts6.99 kB
import { vi } from "vitest"; /** * Mock FreshBooks SDK client for testing * Provides vi.fn() mocks for all entity operations */ export function createMockFreshBooksClient() { return { // Time Entries timeEntries: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Projects projects: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Services services: { list: vi.fn(), single: vi.fn(), create: vi.fn(), rate: { single: vi.fn(), create: vi.fn(), update: vi.fn(), }, }, // Tasks tasks: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Clients clients: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Invoices invoices: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), shareLink: vi.fn(), }, // Expenses expenses: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Expense Categories expenseCategories: { list: vi.fn(), single: vi.fn(), }, // Payments payments: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Items items: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), }, // Bills bills: { list: vi.fn(), single: vi.fn(), create: vi.fn(), delete: vi.fn(), archive: vi.fn(), }, // Bill Payments billPayments: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Bill Vendors billVendors: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Credit Notes creditNotes: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Other Income otherIncomes: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), }, // Journal Entries journalEntries: { create: vi.fn(), }, // Journal Entry Accounts journalEntryAccounts: { list: vi.fn(), }, // Callbacks (Webhooks) callbacks: { list: vi.fn(), single: vi.fn(), create: vi.fn(), update: vi.fn(), delete: vi.fn(), verify: vi.fn(), resendVerification: vi.fn(), }, // Users users: { me: vi.fn(), }, // Payment Options paymentOptions: { single: vi.fn(), create: vi.fn(), default: vi.fn(), }, // Reports reports: { paymentsCollected: vi.fn(), profitLoss: vi.fn(), taxSummary: vi.fn(), }, }; } /** * Type for the mock client */ export type MockFreshBooksClient = ReturnType<typeof createMockFreshBooksClient>; /** * Setup a mock response for a specific entity and method * * @example * setupMockResponse(mockClient, 'timeEntries', 'list', mockTimeEntryListResponse()) */ export function setupMockResponse( mockClient: MockFreshBooksClient, entity: string, method: string, response: any ): void { const entityClient = (mockClient as any)[entity]; if (!entityClient) { throw new Error(`Entity '${entity}' not found in mock client`); } const methodFn = entityClient[method]; if (!methodFn || typeof methodFn !== 'function') { throw new Error(`Method '${method}' not found on entity '${entity}'`); } methodFn.mockResolvedValueOnce(response); } /** * Setup a mock error for a specific entity and method * * @example * setupMockError(mockClient, 'timeEntries', 'single', mockNotFoundError('TimeEntry', 123)) */ export function setupMockError( mockClient: MockFreshBooksClient, entity: string, method: string, error: any ): void { const entityClient = (mockClient as any)[entity]; if (!entityClient) { throw new Error(`Entity '${entity}' not found in mock client`); } const methodFn = entityClient[method]; if (!methodFn || typeof methodFn !== 'function') { throw new Error(`Method '${method}' not found on entity '${entity}'`); } methodFn.mockRejectedValueOnce(error); } /** * Setup multiple mock responses in sequence * Useful for testing pagination or retry logic * * @example * setupMockSequence(mockClient, 'timeEntries', 'list', [ * mockTimeEntryFirstPage(), * mockTimeEntryMiddlePage(), * mockTimeEntryLastPage() * ]) */ export function setupMockSequence( mockClient: MockFreshBooksClient, entity: string, method: string, responses: any[] ): void { const entityClient = (mockClient as any)[entity]; if (!entityClient) { throw new Error(`Entity '${entity}' not found in mock client`); } const methodFn = entityClient[method]; if (!methodFn || typeof methodFn !== 'function') { throw new Error(`Method '${method}' not found on entity '${entity}'`); } for (const response of responses) { methodFn.mockResolvedValueOnce(response); } } /** * Reset all mocks on a client */ export function resetMockClient(mockClient: MockFreshBooksClient): void { Object.values(mockClient).forEach((entity: any) => { if (typeof entity === 'object' && entity !== null) { Object.values(entity).forEach((method: any) => { if (typeof method === 'function' && method.mockReset) { method.mockReset(); } else if (typeof method === 'object' && method !== null) { // Handle nested objects like services.rate Object.values(method).forEach((nestedMethod: any) => { if (typeof nestedMethod === 'function' && nestedMethod.mockReset) { nestedMethod.mockReset(); } }); } }); } }); } /** * Clear all mock calls on a client (keeps implementations) */ export function clearMockClient(mockClient: MockFreshBooksClient): void { Object.values(mockClient).forEach((entity: any) => { if (typeof entity === 'object' && entity !== null) { Object.values(entity).forEach((method: any) => { if (typeof method === 'function' && method.mockClear) { method.mockClear(); } else if (typeof method === 'object' && method !== null) { // Handle nested objects like services.rate Object.values(method).forEach((nestedMethod: any) => { if (typeof nestedMethod === 'function' && nestedMethod.mockClear) { nestedMethod.mockClear(); } }); } }); } }); }

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/Good-Samaritan-Software-LLC/freshbooks-mcp'

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