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.
274 lines (229 loc) • 9.13 kB
text/typescript
import { ApiClient } from '../src/app';
import { AuthProvider, Environment, AuthScopes, type CompanyInfoQueryResponse, CompanyInfo } from '../src/app';
import { describe, expect, it, beforeEach, afterEach } from 'bun:test';
import { mockFetch, mockTokenData } from './helpers';
import { mockCompanyInfoData } from './__mocks__/company-info-data';
// Mock configuration
const TEST_CONFIG = {
clientId: 'test_client_id',
clientSecret: 'test_client_secret',
redirectUri: 'http://localhost:3000/auth-code',
scopes: [AuthScopes.Accounting],
};
// Describe the Company Info API
describe('Company Info 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 getCompanyInfo Method
describe('getCompanyInfo', () => {
// After Each
afterEach(() => {
// Set the Global Fetch
global.fetch = globalFetch;
});
// Test fetching company info
it('should fetch company info', async () => {
// Setup the Company Info Query Response
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [mockCompanyInfoData],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
// Get the Company Info
const companyInfoResponse = await apiClient.companyInfo.getCompanyInfo();
// Assert the Company Info Response Structure
expect(companyInfoResponse).toBeObject();
expect(companyInfoResponse).toHaveProperty('companyInfo');
expect(companyInfoResponse).toHaveProperty('intuitTID');
expect(typeof companyInfoResponse.intuitTID).toBe('string');
expect(companyInfoResponse.intuitTID).toBe('test-tid-12345-67890');
// Assert the Company Info
expect(companyInfoResponse.companyInfo.Id).toBe(mockCompanyInfoData.Id);
expect(companyInfoResponse.companyInfo.CompanyName).toBe(mockCompanyInfoData.CompanyName);
expect(companyInfoResponse.companyInfo.LegalName).toBe(mockCompanyInfoData.LegalName);
expect(companyInfoResponse.companyInfo.Email.Address).toBe(mockCompanyInfoData.Email.Address);
expect(companyInfoResponse.companyInfo.PrimaryPhone.FreeFormNumber).toBe(mockCompanyInfoData.PrimaryPhone.FreeFormNumber);
});
// Test handling search options
it('should handle search options', async () => {
// Setup the Company Info Query Response
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [mockCompanyInfoData],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
// Get the Company Info with search options
const companyInfoResponse = await apiClient.companyInfo.getCompanyInfo({
maxResults: 1,
page: 1,
});
// Assert the Company Info Response Structure
expect(companyInfoResponse).toBeObject();
expect(companyInfoResponse).toHaveProperty('companyInfo');
expect(companyInfoResponse).toHaveProperty('intuitTID');
expect(typeof companyInfoResponse.intuitTID).toBe('string');
expect(companyInfoResponse.intuitTID).toBe('test-tid-12345-67890');
// Assert the Company Info
expect(companyInfoResponse.companyInfo.Id).toBe(mockCompanyInfoData.Id);
// Assert the CompanyInfo is a class instance
if (companyInfoResponse.companyInfo) {
expect(companyInfoResponse.companyInfo).toBeInstanceOf(CompanyInfo);
expect(typeof companyInfoResponse.companyInfo.setApiClient).toBe('function');
expect(typeof companyInfoResponse.companyInfo.reload).toBe('function');
}
});
// Test error handling when no company info is found
it('should return undefined when no company info is found', async () => {
// Setup the Company Info Query Response with empty CompanyInfo array
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [],
maxResults: 0,
startPosition: 1,
totalCount: 0,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
// Get the Company Info
const companyInfoResponse = await apiClient.companyInfo.getCompanyInfo();
// Assert that it returns a response with null companyInfo when no company info is found
expect(companyInfoResponse).toBeObject();
expect(companyInfoResponse).toHaveProperty('companyInfo');
expect(companyInfoResponse).toHaveProperty('intuitTID');
expect(companyInfoResponse.companyInfo).toBeUndefined();
});
// Test error handling for invalid response
it('should throw error for invalid response', async () => {
// Mock empty response with 400 status
global.fetch = mockFetch(
JSON.stringify({
fault: { error: [{ message: 'Invalid Response' }] },
}),
400,
);
// Assert the Error
await expect(apiClient.companyInfo.getCompanyInfo()).rejects.toThrow('Failed to run request');
});
});
// Describe the rawCompanyInfoQuery Method
describe('rawCompanyInfoQuery', () => {
it('should execute raw company info query', async () => {
// Setup the Company Info Query Response
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [mockCompanyInfoData],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
// Mock the Fetch with proper QueryResponse structure
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
// Execute Raw Query
const companyInfoResponse = await apiClient.companyInfo.rawCompanyInfoQuery('select * from companyinfo');
// Assert the Company Info Response Structure
expect(companyInfoResponse).toBeObject();
expect(companyInfoResponse).toHaveProperty('companyInfo');
expect(companyInfoResponse).toHaveProperty('intuitTID');
expect(typeof companyInfoResponse.intuitTID).toBe('string');
expect(companyInfoResponse.intuitTID).toBe('test-tid-12345-67890');
// Assert the Company Info
expect(companyInfoResponse.companyInfo.Id).toBe(mockCompanyInfoData.Id);
expect(companyInfoResponse.companyInfo.CompanyName).toBe(mockCompanyInfoData.CompanyName);
});
// Test error handling for raw query
it('should throw error for invalid raw query', async () => {
// Mock empty response with 400 status
global.fetch = mockFetch(
JSON.stringify({
fault: { error: [{ message: 'Invalid Query' }] },
}),
400,
);
// Assert the Error
await expect(apiClient.companyInfo.rawCompanyInfoQuery('invalid query')).rejects.toThrow('Failed to run request');
});
});
// Describe the CompanyInfo Class Methods
describe('CompanyInfo Class', () => {
afterEach(() => {
global.fetch = globalFetch;
});
it('should return CompanyInfo class instance', async () => {
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [mockCompanyInfoData],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
const companyInfoResponse = await apiClient.companyInfo.getCompanyInfo();
expect(companyInfoResponse.companyInfo).toBeInstanceOf(CompanyInfo);
expect(typeof companyInfoResponse.companyInfo?.setApiClient).toBe('function');
expect(typeof companyInfoResponse.companyInfo?.reload).toBe('function');
});
it('should reload company info data', async () => {
const initialCompanyInfo = mockCompanyInfoData;
const updatedCompanyInfo = { ...initialCompanyInfo, CompanyName: 'Updated Company Name' };
// Setup initial fetch
const companyInfoQueryResponse = {
QueryResponse: {
CompanyInfo: [initialCompanyInfo],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
global.fetch = mockFetch(JSON.stringify(companyInfoQueryResponse));
const companyInfoResponse = await apiClient.companyInfo.getCompanyInfo();
const companyInfo = companyInfoResponse.companyInfo!;
// Modify locally (if possible)
(companyInfo as any).CompanyName = 'Local-Change';
// Setup reload response
const reloadQueryResponse = {
QueryResponse: {
CompanyInfo: [updatedCompanyInfo],
maxResults: 1,
startPosition: 1,
totalCount: 1,
},
};
global.fetch = mockFetch(JSON.stringify(reloadQueryResponse));
// Reload the company info
await companyInfo.reload();
// Assert the company info was reloaded
expect(companyInfo.CompanyName).toBe(updatedCompanyInfo.CompanyName);
});
});
});