Skip to main content
Glama
by calebl
GetUnapprovedTransactionsTool.test.ts8.11 kB
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; import * as ynab from 'ynab'; import * as GetUnapprovedTransactionsTool from '../tools/GetUnapprovedTransactionsTool'; vi.mock('ynab'); describe('GetUnapprovedTransactionsTool', () => { let mockApi: { transactions: { getTransactions: Mock; }; }; beforeEach(() => { vi.clearAllMocks(); mockApi = { transactions: { getTransactions: vi.fn(), }, }; (ynab.API as any).mockImplementation(() => mockApi); process.env.YNAB_API_TOKEN = 'test-token'; process.env.YNAB_BUDGET_ID = 'test-budget-id'; }); describe('execute', () => { const mockTransactionsData = [ { id: 'transaction-1', date: '2023-01-01', amount: -50000, // -$50.00 in milliunits memo: 'Test transaction 1', approved: false, account_name: 'Checking', payee_name: 'Test Payee 1', category_name: 'Groceries', deleted: false, transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, { id: 'transaction-2', date: '2023-01-02', amount: -25500, // -$25.50 in milliunits memo: 'Test transaction 2', approved: false, account_name: 'Credit Card', payee_name: 'Test Payee 2', category_name: 'Dining Out', deleted: false, transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, { id: 'transaction-3', date: '2023-01-03', amount: -10000, // -$10.00 in milliunits memo: 'Test transaction 3', approved: false, account_name: 'Checking', payee_name: 'Test Payee 3', category_name: 'Gas', deleted: true, // This should be filtered out transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, ]; it('should successfully get unapproved transactions using budget ID from environment', async () => { mockApi.transactions.getTransactions.mockResolvedValue({ data: { transactions: mockTransactionsData }, }); const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); expect(mockApi.transactions.getTransactions).toHaveBeenCalledWith( 'test-budget-id', undefined, ynab.GetTransactionsTypeEnum.Unapproved ); const expectedTransactions = [ { id: 'transaction-1', date: '2023-01-01', amount: '-50.00', memo: 'Test transaction 1', approved: false, account_name: 'Checking', payee_name: 'Test Payee 1', category_name: 'Groceries', transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, { id: 'transaction-2', date: '2023-01-02', amount: '-25.50', memo: 'Test transaction 2', approved: false, account_name: 'Credit Card', payee_name: 'Test Payee 2', category_name: 'Dining Out', transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, ]; const expectedResult = { content: [{ type: "text", text: JSON.stringify({ transactions: expectedTransactions, transaction_count: 2, }, null, 2) }] }; expect(result).toEqual(expectedResult); }); it('should successfully get unapproved transactions using provided budget ID', async () => { mockApi.transactions.getTransactions.mockResolvedValue({ data: { transactions: mockTransactionsData }, }); const result = await GetUnapprovedTransactionsTool.execute( { budgetId: 'custom-budget-id' }, mockApi as any ); expect(mockApi.transactions.getTransactions).toHaveBeenCalledWith( 'custom-budget-id', undefined, ynab.GetTransactionsTypeEnum.Unapproved ); }); it('should handle empty transactions list', async () => { mockApi.transactions.getTransactions.mockResolvedValue({ data: { transactions: [] }, }); const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); const expectedResult = { content: [{ type: "text", text: JSON.stringify({ transactions: [], transaction_count: 0, }, null, 2) }] }; expect(result).toEqual(expectedResult); }); it('should filter out deleted transactions', async () => { const transactionsWithDeleted = [ ...mockTransactionsData, { id: 'transaction-4', date: '2023-01-04', amount: -5000, memo: 'Deleted transaction', approved: false, account_name: 'Checking', payee_name: 'Deleted Payee', category_name: 'Test', deleted: true, transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, ]; mockApi.transactions.getTransactions.mockResolvedValue({ data: { transactions: transactionsWithDeleted }, }); const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); const parsedResult = JSON.parse(result.content[0].text); expect(parsedResult.transaction_count).toBe(2); // Should not include deleted transactions expect(parsedResult.transactions).toHaveLength(2); }); it('should handle API error', async () => { const apiError = new Error('API Error: Unauthorized'); mockApi.transactions.getTransactions.mockRejectedValue(apiError); const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); expect(result.content[0].text).toContain('Error getting unapproved transactions:'); expect(result.content[0].text).toContain('API Error: Unauthorized'); }); it('should throw error when no budget ID is provided', async () => { delete process.env.YNAB_BUDGET_ID; const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); expect(result.content[0].text).toContain('Error getting unapproved transactions:'); expect(result.content[0].text).toContain('No budget ID provided'); }); it('should convert milliunits to dollars correctly', async () => { const testTransactions = [ { id: 'test-1', date: '2023-01-01', amount: 123456, // $123.456 -> should round to $123.46 memo: 'Test', approved: false, account_name: 'Test', payee_name: 'Test', category_name: 'Test', deleted: false, transfer_account_id: null, transfer_transaction_id: null, matched_transaction_id: null, import_id: null, }, ]; mockApi.transactions.getTransactions.mockResolvedValue({ data: { transactions: testTransactions }, }); const result = await GetUnapprovedTransactionsTool.execute({}, mockApi as any); const parsedResult = JSON.parse(result.content[0].text); expect(parsedResult.transactions[0].amount).toBe('123.46'); }); }); describe('tool configuration', () => { it('should have correct name and description', () => { expect(GetUnapprovedTransactionsTool.name).toBe('get_unapproved_transactions'); expect(GetUnapprovedTransactionsTool.description).toContain('Gets unapproved transactions from a budget'); }); it('should have correct input schema', () => { expect(GetUnapprovedTransactionsTool.inputSchema).toHaveProperty('budgetId'); }); }); });

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/calebl/ynab-mcp-server'

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