godcrm/backend/routes/v3/__tests__/labs-routes.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

249 lines
No EOL
7.8 KiB
JavaScript

/**
* Labs Routes Tests
* ADR-043: MindWorkflow Integration
*/
// Set env vars BEFORE imports
process.env.SKIP_DEV_USER = 'true';
const JWT_SECRET = 'test-secret-key';
process.env.JWT_SECRET = JWT_SECRET;
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import jwt from 'jsonwebtoken';
import express from 'express';
import labsRouter from '../labs.js';
import { dbRun, dbGet, dbAll } from '../../../database/connection.js';
import { setupTestDatabase, cleanupTestDatabase } from '../../../tests/helpers/test-db.js';
// Create test app
const app = express();
app.use(express.json());
// Mock auth middleware that handles JWT tokens
app.use((req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (token) {
try {
req.user = jwt.verify(token, JWT_SECRET);
} catch (e) {
// Invalid token
}
}
next();
});
app.use('/api/v3/labs', labsRouter);
let authToken;
let testUserId;
describe('Labs Routes', () => {
beforeAll(async () => {
// Set up test database with all necessary tables
await setupTestDatabase();
// Create test user
const ts = Date.now();
try {
const userResult = await dbRun(`
INSERT INTO users (email, password_hash, name, role, encryption_key_encrypted, created_at)
VALUES (?, ?, ?, ?, ?, NOW())
`, [`labs-test-${ts}@test.com`, 'hash123', 'Labs Test User', 'admin', 'enc123']);
testUserId = userResult.lastInsertRowid;
authToken = jwt.sign({
id: testUserId,
userId: testUserId,
email: `labs-test-${ts}@test.com`,
role: 'admin'
}, JWT_SECRET);
} catch (err) {
// User table might not exist, create a simple token
authToken = jwt.sign({
id: 1,
userId: 1,
email: 'test@test.com',
role: 'admin'
}, JWT_SECRET);
}
// Add test AI templates (delete first to avoid unique constraint violations)
await dbRun(`DELETE FROM labs_ai_templates WHERE mindworkflow_id IN ('test_planner', 'test_assistant')`);
await dbRun(`
INSERT INTO labs_ai_templates
(mindworkflow_id, name, category, description, system_prompt, user_prompt_example, settings, routing_config, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
`, [
'test_planner',
'Test Strategic Planner',
'text_to_text',
'Test template for planning',
'You are a test planner.',
'Create a test plan.',
JSON.stringify({ model: 'gpt-4o-mini', temperature: 0.4 }),
JSON.stringify({ outputs: [{ id: 'text', type: 'text', enabled: true }] })
]);
await dbRun(`
INSERT INTO labs_ai_templates
(mindworkflow_id, name, category, description, system_prompt, user_prompt_example, settings, routing_config, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
`, [
'test_assistant',
'Test Assistant',
'text_to_text',
'Test template for assistance',
'You are a test assistant.',
'Help with testing.',
JSON.stringify({ model: 'gpt-4o-mini', temperature: 0.3 }),
JSON.stringify({ outputs: [{ id: 'text', type: 'text', enabled: true }] })
]);
});
afterAll(async () => {
await cleanupTestDatabase();
});
beforeEach(async () => {
// Clean up test data - use correct table and column names
try {
await dbRun('DELETE FROM labs_edges WHERE lab_id LIKE ?', ['labs-test-%']);
await dbRun('DELETE FROM labs_nodes WHERE lab_id LIKE ?', ['labs-test-%']);
await dbRun('DELETE FROM labs WHERE lab_id LIKE ?', ['labs-test-%']);
} catch (err) {
// Tables might not exist yet, ignore errors
}
});
afterEach(async () => {
// Clean up test data - use correct table and column names
try {
await dbRun('DELETE FROM labs_edges WHERE lab_id LIKE ?', ['labs-test-%']);
await dbRun('DELETE FROM labs_nodes WHERE lab_id LIKE ?', ['labs-test-%']);
await dbRun('DELETE FROM labs WHERE lab_id LIKE ?', ['labs-test-%']);
} catch (err) {
// Tables might not exist, ignore errors
}
});
describe('Projects CRUD', () => {
it.todo('should list all projects');
it.todo('should create a new project');
it.todo('should get project with nodes and edges');
it.todo('should update project');
it.todo('should delete project and cascade delete nodes/edges');
it.todo('should return 404 for non-existent project');
it.todo('should require title when creating project');
});
describe('Nodes CRUD', () => {
it.todo('should list nodes for a project');
it.todo('should create a new node');
it.todo('should update node');
it.todo('should delete node and related edges');
it.todo('should return 404 for non-existent node');
it.todo('should require type and title when creating node');
});
describe('Edges CRUD', () => {
it.todo('should list edges for a project');
it.todo('should create a new edge');
it.todo('should delete edge');
it.todo('should return 404 for non-existent edge');
it.todo('should require source_node_id and target_node_id when creating edge');
});
describe('AI Integration', () => {
it.todo('should get available AI agents');
it.todo('should get AI providers');
it('should get AI templates', async () => {
const response = await request(app)
.get('/api/v3/labs/ai/templates')
.set('Authorization', `Bearer ${authToken}`)
.expect(200);
expect(response.body.success).toBe(true);
expect(Array.isArray(response.body.data)).toBe(true);
// Templates may be empty in test environment (no seeding)
// If templates exist, verify structure
if (response.body.data.length > 0) {
const template = response.body.data[0];
expect(template).toHaveProperty('id');
expect(template).toHaveProperty('name');
expect(template).toHaveProperty('mindworkflow_id');
expect(template).toHaveProperty('category');
expect(template).toHaveProperty('description');
expect(template).toHaveProperty('system_prompt');
}
});
it.todo('should execute AI node');
it.todo('should return 404 when executing non-existent node');
it.todo('should return error when executing non-AI node');
});
describe('Error Handling', () => {
it.todo('should handle database errors gracefully');
it.todo('should validate input parameters');
it.todo('should return proper error responses');
});
describe('Authentication', () => {
it.todo('should require authentication for all endpoints');
it.todo('should return 401 for unauthenticated requests');
});
});
// Helper functions for tests
export const createTestProject = async (overrides = {}) => {
const projectData = {
space_id: null,
title: 'Test Project',
description: 'Test Description',
settings: {},
...overrides
};
const response = await request(app)
.post('/api/v3/labs/projects')
.send(projectData);
return response.body.data;
};
export const createTestNode = async (projectId, overrides = {}) => {
const nodeData = {
type: 'text',
title: 'Test Node',
content: 'Test content',
meta: {},
ai_config: {},
ui_config: {},
...overrides
};
const response = await request(app)
.post(`/api/v3/labs/projects/${projectId}/nodes`)
.send(nodeData);
return response.body.data;
};
export const createTestEdge = async (projectId, sourceNodeId, targetNodeId, overrides = {}) => {
const edgeData = {
source_node_id: sourceNodeId,
target_node_id: targetNodeId,
source_handle: null,
target_handle: null,
...overrides
};
const response = await request(app)
.post(`/api/v3/labs/projects/${projectId}/edges`)
.send(edgeData);
return response.body.data;
};