@memberjunction/actions-bizapps-crm
Version:
CRM system integration actions for MemberJunction
203 lines (168 loc) • 7.33 kB
text/typescript
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock dependencies
vi.mock('@memberjunction/actions', () => ({
BaseAction: class BaseAction {
protected async InternalRunAction(): Promise<unknown> { return {}; }
}
}));
vi.mock('@memberjunction/global', () => ({
RegisterClass: () => (target: unknown) => target
}));
vi.mock('@memberjunction/core', () => ({
UserInfo: class UserInfo {},
Metadata: vi.fn(),
RunView: vi.fn().mockImplementation(() => ({
RunView: vi.fn().mockResolvedValue({ Success: true, Results: [] })
}))
}));
vi.mock('@memberjunction/core-entities', () => ({
MJCompanyIntegrationEntity: class MJCompanyIntegrationEntity {
CompanyID: string = '';
APIKey: string | null = null;
AccessToken: string | null = null;
RefreshToken: string | null = null;
CustomAttribute1: string | null = null;
}
}));
vi.mock('@memberjunction/actions-base', () => ({
ActionParam: class ActionParam {
Name: string = '';
Value: unknown = null;
Type: string = 'Input';
},
ActionResultSimple: class ActionResultSimple {},
RunActionParams: class RunActionParams {
Params: unknown[] = [];
ContextUser: unknown = null;
}
}));
import { BaseCRMAction } from '../base/base-crm.action';
// Concrete subclass for testing
class TestCRMAction extends BaseCRMAction {
protected crmProvider = 'TestCRM';
protected integrationName = 'TestCRM';
protected async InternalRunAction(): Promise<{ Success: boolean; ResultCode: string }> {
return { Success: true, ResultCode: 'SUCCESS' };
}
}
describe('BaseCRMAction', () => {
let action: TestCRMAction;
beforeEach(() => {
action = new TestCRMAction();
});
describe('formatPhoneNumber', () => {
it('should format 10-digit US numbers to E.164', () => {
expect(action['formatPhoneNumber']('5551234567')).toBe('+15551234567');
});
it('should format numbers with existing country code', () => {
expect(action['formatPhoneNumber']('15551234567')).toBe('+15551234567');
});
it('should strip non-numeric characters', () => {
expect(action['formatPhoneNumber']('(555) 123-4567')).toBe('+15551234567');
});
it('should return empty string for empty input', () => {
expect(action['formatPhoneNumber']('')).toBe('');
});
it('should return cleaned string for non-US numbers', () => {
expect(action['formatPhoneNumber']('+44 20 7123 4567')).toBe('442071234567');
});
});
describe('isValidEmail', () => {
it('should return true for valid emails', () => {
expect(action['isValidEmail']('test@example.com')).toBe(true);
expect(action['isValidEmail']('user.name@domain.org')).toBe(true);
});
it('should return false for invalid emails', () => {
expect(action['isValidEmail']('invalid')).toBe(false);
expect(action['isValidEmail']('no@')).toBe(false);
expect(action['isValidEmail']('@domain.com')).toBe(false);
expect(action['isValidEmail']('has spaces@domain.com')).toBe(false);
});
});
describe('mapDealStatus', () => {
it('should map won statuses', () => {
expect(action['mapDealStatus']('closed-won')).toBe('won');
expect(action['mapDealStatus']('Won')).toBe('won');
expect(action['mapDealStatus']('Success')).toBe('won');
});
it('should map lost statuses', () => {
expect(action['mapDealStatus']('closed-lost')).toBe('lost');
expect(action['mapDealStatus']('Lost')).toBe('lost');
expect(action['mapDealStatus']('Failed')).toBe('lost');
});
it('should map open statuses', () => {
expect(action['mapDealStatus']('open')).toBe('open');
expect(action['mapDealStatus']('Active')).toBe('open');
expect(action['mapDealStatus']('Qualified')).toBe('open');
});
it('should return unknown for unrecognized statuses', () => {
expect(action['mapDealStatus']('pending')).toBe('unknown');
expect(action['mapDealStatus']('review')).toBe('unknown');
});
});
describe('mapActivityType', () => {
it('should map call types', () => {
expect(action['mapActivityType']('call')).toBe('call');
expect(action['mapActivityType']('Phone')).toBe('call');
});
it('should map email types', () => {
expect(action['mapActivityType']('email')).toBe('email');
});
it('should map meeting types', () => {
expect(action['mapActivityType']('meeting')).toBe('meeting');
expect(action['mapActivityType']('Appointment')).toBe('meeting');
});
it('should map task types', () => {
expect(action['mapActivityType']('task')).toBe('task');
expect(action['mapActivityType']('Todo')).toBe('task');
});
it('should return other for unknown types', () => {
expect(action['mapActivityType']('unknown')).toBe('other');
});
});
describe('formatCRMDate', () => {
it('should format date as ISO string', () => {
const date = new Date('2024-06-15T10:30:00Z');
expect(action['formatCRMDate'](date)).toBe('2024-06-15T10:30:00.000Z');
});
});
describe('parseCRMDate', () => {
it('should parse ISO date string', () => {
const result = action['parseCRMDate']('2024-06-15T10:30:00Z');
expect(result.toISOString()).toBe('2024-06-15T10:30:00.000Z');
});
});
describe('buildCRMErrorMessage', () => {
it('should build error without system error', () => {
expect(action['buildCRMErrorMessage']('GetContact', 'Not found'))
.toBe('CRM operation failed: GetContact. Not found');
});
it('should include system error', () => {
const result = action['buildCRMErrorMessage']('GetContact', 'Failed', new Error('API timeout'));
expect(result).toContain('System error: API timeout');
});
});
describe('getCommonCRMParams', () => {
it('should return CompanyID param', () => {
const params = action['getCommonCRMParams']();
expect(params).toHaveLength(1);
expect(params[0].Name).toBe('CompanyID');
});
});
describe('getCredentialFromEnv', () => {
it('should build correct env key', () => {
process.env['BIZAPPS_TESTCRM_COMP1_API_KEY'] = 'key123';
expect(action['getCredentialFromEnv']('COMP1', 'API_KEY')).toBe('key123');
delete process.env['BIZAPPS_TESTCRM_COMP1_API_KEY'];
});
});
describe('getParamValue', () => {
it('should find param by name', () => {
const params = [{ Name: 'ContactId', Value: '42', Type: 'Input' as const }];
expect(action['getParamValue'](params, 'ContactId')).toBe('42');
});
it('should return undefined for missing param', () => {
expect(action['getParamValue']([], 'Missing')).toBeUndefined();
});
});
});