@memberjunction/actions-bizapps-accounting
Version:
Accounting system integration actions for MemberJunction
230 lines • 9.17 kB
JavaScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock external dependencies
vi.mock('@memberjunction/actions', () => ({
BaseAction: class BaseAction {
async InternalRunAction() { return {}; }
}
}));
vi.mock('@memberjunction/global', () => ({
RegisterClass: () => (target) => target
}));
vi.mock('@memberjunction/core', () => ({
UserInfo: class UserInfo {
},
Metadata: vi.fn().mockImplementation(() => ({
GetEntityObject: vi.fn()
})),
RunView: vi.fn().mockImplementation(() => ({
RunView: vi.fn().mockResolvedValue({ Success: true, Results: [] })
}))
}));
vi.mock('@memberjunction/core-entities', () => ({
MJCompanyIntegrationEntity: class MJCompanyIntegrationEntity {
constructor() {
this.CompanyID = '';
this.AccessToken = null;
this.RefreshToken = null;
this.TokenExpirationDate = null;
this.APIKey = null;
this.ExternalSystemID = null;
this.CustomAttribute1 = null;
this.NavigationBaseURL = null;
}
},
MJIntegrationEntity: class MJIntegrationEntity {
constructor() {
this.NavigationBaseURL = null;
}
}
}));
vi.mock('@memberjunction/actions-base', () => ({
ActionParam: class ActionParam {
constructor() {
this.Name = '';
this.Value = null;
this.Type = 'Input';
}
},
ActionResultSimple: class ActionResultSimple {
},
RunActionParams: class RunActionParams {
constructor() {
this.Params = [];
this.ContextUser = null;
}
}
}));
import { BaseAccountingAction } from '../base/base-accounting-action.js';
import { QuickBooksBaseAction } from '../providers/quickbooks/quickbooks-base.action.js';
// Create a concrete subclass for testing abstract BaseAccountingAction
class TestAccountingAction extends BaseAccountingAction {
constructor() {
super(...arguments);
this.accountingProvider = 'TestProvider';
this.integrationName = 'Test Integration';
}
async InternalRunAction() {
return { Success: true, ResultCode: 'SUCCESS' };
}
}
describe('BaseAccountingAction', () => {
let action;
beforeEach(() => {
action = new TestAccountingAction();
});
describe('validateAccountNumber', () => {
it('should return true for valid account numbers', () => {
expect(action['validateAccountNumber']('1234')).toBe(true);
expect(action['validateAccountNumber']('100-200')).toBe(true);
expect(action['validateAccountNumber']('100.200')).toBe(true);
});
it('should return false for invalid account numbers', () => {
expect(action['validateAccountNumber']('abc')).toBe(false);
expect(action['validateAccountNumber']('12 34')).toBe(false);
expect(action['validateAccountNumber']('12@34')).toBe(false);
});
});
describe('validateJournalEntryBalance', () => {
it('should return true when debits equal credits', () => {
const lines = [
{ debit: 100, credit: 0 },
{ debit: 0, credit: 100 }
];
expect(action['validateJournalEntryBalance'](lines)).toBe(true);
});
it('should return true for small rounding differences', () => {
const lines = [
{ debit: 100.005, credit: 0 },
{ debit: 0, credit: 100.001 }
];
expect(action['validateJournalEntryBalance'](lines)).toBe(true);
});
it('should return false when debits do not equal credits', () => {
const lines = [
{ debit: 100, credit: 0 },
{ debit: 0, credit: 50 }
];
expect(action['validateJournalEntryBalance'](lines)).toBe(false);
});
it('should handle missing debit/credit values', () => {
const lines = [
{ debit: 100 },
{ credit: 100 }
];
expect(action['validateJournalEntryBalance'](lines)).toBe(true);
});
});
describe('formatCurrency', () => {
it('should format USD by default', () => {
const result = action['formatCurrency'](1234.56);
expect(result).toBe('$1,234.56');
});
it('should handle zero', () => {
const result = action['formatCurrency'](0);
expect(result).toBe('$0.00');
});
});
describe('formatAccountingDate', () => {
it('should format date as YYYY-MM-DD', () => {
const date = new Date('2024-06-15T10:30:00Z');
const result = action['formatAccountingDate'](date);
expect(result).toBe('2024-06-15');
});
});
describe('buildAccountingErrorMessage', () => {
it('should build error message without system error', () => {
const result = action['buildAccountingErrorMessage']('CreateJournal', 'Invalid data');
expect(result).toBe('Accounting operation failed: CreateJournal. Invalid data');
});
it('should include system error when provided', () => {
const result = action['buildAccountingErrorMessage']('CreateJournal', 'Invalid data', new Error('DB error'));
expect(result).toContain('System error: DB error');
});
});
describe('getParamValue', () => {
it('should return param value by name', () => {
const params = [{ Name: 'CompanyID', Value: '123', Type: 'Input' }];
expect(action['getParamValue'](params, 'CompanyID')).toBe('123');
});
it('should return undefined for missing param', () => {
const params = [{ Name: 'CompanyID', Value: '123', Type: 'Input' }];
expect(action['getParamValue'](params, 'NonExistent')).toBeUndefined();
});
});
describe('getCommonAccountingParams', () => {
it('should return three common params', () => {
const params = action['getCommonAccountingParams']();
expect(params).toHaveLength(3);
expect(params.map((p) => p.Name)).toEqual(['CompanyID', 'FiscalYear', 'AccountingPeriod']);
});
});
describe('getCredentialFromEnv', () => {
it('should construct correct env key', () => {
process.env['BIZAPPS_TESTPROVIDER_COMP1_ACCESS_TOKEN'] = 'token123';
const result = action['getCredentialFromEnv']('COMP1', 'ACCESS_TOKEN');
expect(result).toBe('token123');
delete process.env['BIZAPPS_TESTPROVIDER_COMP1_ACCESS_TOKEN'];
});
it('should return undefined for missing env var', () => {
const result = action['getCredentialFromEnv']('COMP1', 'MISSING_KEY');
expect(result).toBeUndefined();
});
});
});
describe('QuickBooksBaseAction', () => {
describe('mapAccountType', () => {
// Create test instance
class TestQBAction extends QuickBooksBaseAction {
async InternalRunAction() {
return { Success: true, ResultCode: 'SUCCESS' };
}
}
let action;
beforeEach(() => {
action = new TestQBAction();
});
it('should map Bank to Asset', () => {
expect(action['mapAccountType']('Bank')).toBe('Asset');
});
it('should map Accounts Payable to Liability', () => {
expect(action['mapAccountType']('Accounts Payable')).toBe('Liability');
});
it('should map Equity to Equity', () => {
expect(action['mapAccountType']('Equity')).toBe('Equity');
});
it('should map Income to Revenue', () => {
expect(action['mapAccountType']('Income')).toBe('Revenue');
});
it('should map Expense to Expense', () => {
expect(action['mapAccountType']('Expense')).toBe('Expense');
});
it('should return Other for unknown types', () => {
expect(action['mapAccountType']('Unknown')).toBe('Other');
});
});
describe('parseQBODate', () => {
class TestQBAction extends QuickBooksBaseAction {
async InternalRunAction() {
return { Success: true, ResultCode: 'SUCCESS' };
}
}
it('should parse QBO date format', () => {
const action = new TestQBAction();
const date = action['parseQBODate']('2024-06-15');
expect(date.toISOString()).toBe('2024-06-15T00:00:00.000Z');
});
});
describe('formatQBODate', () => {
class TestQBAction extends QuickBooksBaseAction {
async InternalRunAction() {
return { Success: true, ResultCode: 'SUCCESS' };
}
}
it('should format date for QBO API', () => {
const action = new TestQBAction();
const date = new Date('2024-06-15T10:30:00Z');
expect(action['formatQBODate'](date)).toBe('2024-06-15');
});
});
});
//# sourceMappingURL=accounting.test.js.map