quickbooks-api
Version:
A modular TypeScript SDK for seamless integration with Intuit QuickBooks APIs. Provides robust authentication handling and future-ready foundation for accounting, payments, and commerce operations.
252 lines (204 loc) • 8.32 kB
text/typescript
import { ApiClient } from '../src/app';
import { AuthProvider, Environment, AuthScopes, type CreditMemoQueryResponse } from '../src/app';
import { describe, expect, it, beforeEach, afterEach } from 'bun:test';
import { mockFetch, mockCreditMemoData, mockTokenData } from './helpers';
// Mock configuration
const TEST_CONFIG = {
clientId: 'test_client_id',
clientSecret: 'test_client_secret',
redirectUri: 'http://localhost:3000/auth-code',
scopes: [AuthScopes.Accounting],
};
// Describe the CreditMemo API
describe('CreditMemo API', () => {
// Declare the API Client
let apiClient: ApiClient;
// Declare the Global Fetch
let globalFetch: typeof fetch;
// Before Each
beforeEach(async () => {
// Set the Global Fetch
globalFetch = global.fetch;
// Create the Auth Provider
const authProvider = new AuthProvider(TEST_CONFIG.clientId, TEST_CONFIG.clientSecret, TEST_CONFIG.redirectUri, TEST_CONFIG.scopes);
// Set the Token for the Auth Provider
await authProvider.setToken(mockTokenData);
// Create the API Client
apiClient = new ApiClient(authProvider, Environment.Sandbox);
});
// After Each
afterEach(() => {
// Set the Global Fetch
global.fetch = globalFetch;
});
// Describe the getAllCreditMemos Method
describe('getAllCreditMemos', () => {
// Describe the getAllCreditMemos Method
it('should fetch all credit memos', async () => {
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: CreditMemoQueryResponse } = {
QueryResponse: {
CreditMemo: mockCreditMemoData,
maxResults: mockCreditMemoData.length,
startPosition: 1,
totalCount: mockCreditMemoData.length,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemos
const searchResponse = await apiClient.creditMemos.getAllCreditMemos();
// Assert the CreditMemos
expect(searchResponse.results).toBeArray();
// Assert the CreditMemos Length
expect(searchResponse.results.length).toBe(mockCreditMemoData.length);
// Assert the CreditMemos
expect(searchResponse.results[0].Id).toBe(mockCreditMemoData[0].Id);
});
});
// Describe the hasNextPage Method
describe('hasNextPage', () => {
// Describe the hasNextPage Method
it('should return true if there is a next page', async () => {
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: CreditMemoQueryResponse } = {
QueryResponse: {
CreditMemo: mockCreditMemoData,
maxResults: mockCreditMemoData.length,
startPosition: 1,
totalCount: mockCreditMemoData.length,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemos
const searchResponse = await apiClient.creditMemos.getAllCreditMemos();
// Assert the CreditMemos
expect(searchResponse.hasNextPage).toBe(true);
});
});
// Describe the getCreditMemoById Method
describe('getCreditMemoById', () => {
// Describe the getCreditMemoById Method
it('should fetch single credit memo by ID', async () => {
// Get the Test CreditMemo
const testCreditMemo = mockCreditMemoData[0];
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: CreditMemoQueryResponse } = {
QueryResponse: {
CreditMemo: [testCreditMemo],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
// Mock single credit memo response structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemo
const creditMemo = await apiClient.creditMemos.getCreditMemoById(testCreditMemo.Id);
// Assert the CreditMemo
expect(creditMemo.Id).toBe(testCreditMemo.Id);
});
// Describe the getCreditMemoById Method
it('should throw error for invalid credit memo ID', async () => {
// Mock empty response with 400 status
global.fetch = mockFetch(
JSON.stringify({
QueryResponse: {},
fault: { error: [{ message: 'CreditMemo not found' }] },
}),
400,
);
// Assert the CreditMemo
expect(apiClient.creditMemos.getCreditMemoById('invalid')).rejects.toThrow('CreditMemo not found');
});
});
// Describe the getCreditMemosForDateRange Method
describe('getCreditMemosForDateRange', () => {
// Describe the getCreditMemosForDateRange Method
it('should fetch credit memos within date range', async () => {
// Set the start Date
const startDate = new Date('2020-01-09');
// Set the end Date
const endDate = new Date('2022-01-12');
// Get the List of CreditMemos in that date range for the mock data
const creditMemosInDateRange = mockCreditMemoData.filter((creditMemo) => {
// Get the CreditMemo Date
const creditMemoDate = new Date(creditMemo.MetaData!.LastUpdatedTime!);
// Return the CreditMemo if it is in the date range
return creditMemoDate >= startDate && creditMemoDate <= endDate;
});
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: CreditMemoQueryResponse } = {
QueryResponse: {
CreditMemo: creditMemosInDateRange,
maxResults: creditMemosInDateRange.length,
startPosition: 1,
totalCount: creditMemosInDateRange.length,
},
};
// Mock response with proper structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemos
const searchResponse = await apiClient.creditMemos.getCreditMemosForDateRange(startDate, endDate);
// Assert the CreditMemos
expect(searchResponse.results).toBeArray();
// Assert the CreditMemos Length
expect(searchResponse.results.length).toBe(creditMemosInDateRange.length);
// Assert the CreditMemos
expect(searchResponse.results[0].Id).toBe(creditMemosInDateRange[0].Id);
});
});
// Describe the getUpdatedCreditMemos Method
describe('getUpdatedCreditMemos', () => {
// Describe the getUpdatedCreditMemos Method
it('should fetch updated credit memos', async () => {
// Get the Last Updated Time
const lastUpdatedTime = new Date('2025-01-09');
// Get the List of CreditMemos in that date range for the mock data
const creditMemosInDateRange = mockCreditMemoData.filter((creditMemo) => {
// Check if the last updated date is invalid
if (!creditMemo.MetaData?.LastUpdatedTime) return false;
// Get the CreditMemo Date
const creditMemoDate = new Date(creditMemo.MetaData.LastUpdatedTime);
// Return the CreditMemo if it is in the date range
return creditMemoDate >= lastUpdatedTime;
});
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: CreditMemoQueryResponse } = {
QueryResponse: {
CreditMemo: creditMemosInDateRange,
maxResults: creditMemosInDateRange.length,
startPosition: 1,
totalCount: creditMemosInDateRange.length,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemos
const searchResponse = await apiClient.creditMemos.getUpdatedCreditMemos(lastUpdatedTime);
// Assert the CreditMemos
expect(searchResponse.results).toBeArray();
// Assert the CreditMemos Length
expect(searchResponse.results.length).toBe(creditMemosInDateRange.length);
// Assert the CreditMemos
expect(searchResponse.results[0].Id).toBe(creditMemosInDateRange[0].Id);
});
// Describe the getUpdatedCreditMemos Method
it('should return an empty array if no credit memos are updated', async () => {
// Setup the CreditMemo Query Response
const creditMemoQueryResponse: { QueryResponse: {}; time: string } = {
QueryResponse: {},
time: '2025-03-04T05:46:36.933-08:00',
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(creditMemoQueryResponse));
// Get the CreditMemos
const searchResponse = await apiClient.creditMemos.getUpdatedCreditMemos(new Date(new Date().getTime() + 68400000));
// Assert the CreditMemos
expect(searchResponse.results).toBeArray();
// Assert the CreditMemos Length
expect(searchResponse.results.length).toBe(0);
});
});
});