godcrm/backend/services/labs/__tests__/labs-service.test.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

188 lines
No EOL
5.7 KiB
JavaScript

/**
* Tests for Labs Service
* @see ADR-043: Laboratories Feature
*/
import { describe, it, expect } from 'vitest';
import { LabsService } from '../index.js';
describe('LabsService', () => {
describe('getNodeTypes', () => {
it('should return all node types', () => {
const types = LabsService.getNodeTypes();
expect(types).toHaveLength(8);
const typeKeys = types.map(t => t.typeKey);
expect(typeKeys).toContain('text');
expect(typeKeys).toContain('ai_agent');
expect(typeKeys).toContain('image');
expect(typeKeys).toContain('file');
expect(typeKeys).toContain('input');
expect(typeKeys).toContain('output');
expect(typeKeys).toContain('code');
expect(typeKeys).toContain('note');
});
});
describe('getNodeType', () => {
it('should return specific node type', () => {
const textNode = LabsService.getNodeType('text');
expect(textNode).toBeDefined();
expect(textNode.typeKey).toBe('text');
expect(textNode.name).toBe('Text');
});
it('should return null for unknown type', () => {
const unknownNode = LabsService.getNodeType('unknown');
expect(unknownNode).toBeNull();
});
});
describe('validateNodeConfig', () => {
it('should validate text node config', () => {
const result = LabsService.validateNodeConfig('text', {
fontSize: 16,
fontWeight: 'bold'
});
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should reject invalid config', () => {
const result = LabsService.validateNodeConfig('text', {
fontSize: 100 // Too large
});
expect(result.valid).toBe(false);
expect(result.errors).toContain('fontSize must be a number between 8 and 72');
});
});
describe('createNodeWithDefaults', () => {
it('should create text node with defaults', () => {
const nodeData = LabsService.createNodeWithDefaults('text', {
title: 'My Text Node',
content: 'Hello world'
});
expect(nodeData.type_key).toBe('text');
expect(nodeData.title).toBe('My Text Node');
expect(nodeData.content).toBe('Hello world');
expect(nodeData.width).toBe(250); // Default from TextNode
expect(nodeData.height).toBe(150); // Default from TextNode
expect(nodeData.node_id).toBeDefined();
expect(nodeData.config).toEqual({
content: '',
fontSize: 14,
fontWeight: 'normal',
textAlign: 'left'
});
});
it('should merge custom config with defaults', () => {
const nodeData = LabsService.createNodeWithDefaults('text', {
title: 'Custom Node',
config: {
fontSize: 18,
customField: 'value'
}
});
expect(nodeData.config.fontSize).toBe(18); // Custom value
expect(nodeData.config.fontWeight).toBe('normal'); // Default value
expect(nodeData.config.customField).toBe('value'); // Custom field preserved
});
it('should throw error for unknown node type', () => {
expect(() => {
LabsService.createNodeWithDefaults('unknown_type', {});
}).toThrow('Unknown node type: unknown_type');
});
});
describe('validateNode', () => {
it('should validate complete node data', () => {
const nodeData = {
type_key: 'text',
title: 'Valid Node',
content: 'Content',
position_x: 100,
position_y: 200,
width: 300,
height: 150,
config: {
fontSize: 16
}
};
const result = LabsService.validateNode(nodeData);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should reject node without type_key', () => {
const nodeData = {
title: 'Invalid Node'
};
const result = LabsService.validateNode(nodeData);
expect(result.valid).toBe(false);
expect(result.errors).toContain('type_key is required');
});
it('should reject node with invalid dimensions', () => {
const nodeData = {
type_key: 'text',
title: 'Invalid Node',
width: -100,
height: 0
};
const result = LabsService.validateNode(nodeData);
expect(result.valid).toBe(false);
expect(result.errors).toContain('width must be a positive number');
expect(result.errors).toContain('height must be a positive number');
});
});
describe('executeNode', () => {
it('should execute text node', async () => {
const node = {
type_key: 'text',
content: 'Test content',
config: {}
};
const result = await LabsService.executeNode(node);
expect(result.success).toBe(true);
expect(result.output).toBe('Test content');
expect(result.type).toBe('text');
});
it('should execute AI agent node (returns error in test environment)', async () => {
const node = {
type_key: 'ai_agent',
config: {
ai_agent_id: 123
}
};
const result = await LabsService.executeNode(node);
// In test environment, either agent doesn't exist or DB query fails
expect(result.success).toBe(false);
expect(result.type).toBe('ai_agent');
// Error can be "AI agent 123 not found" or "AI agent execution failed"
expect(result.error).toMatch(/AI agent/);
});
it('should handle execution errors gracefully', async () => {
const node = {
type_key: 'unknown_type'
};
const result = await LabsService.executeNode(node);
expect(result.success).toBe(false);
expect(result.error).toBe('Unknown node type: unknown_type');
});
});
});