regression-prevention-relationships-workflows.e2e.test.ts•6.91 kB
/**
* Split: Regression Prevention E2E – Relationships & Workflows slice
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import {
callUniversalTool,
callTasksTool,
callNotesTool,
validateTestEnvironment,
} from '../utils/enhanced-tool-caller.js';
import { E2EAssertions } from '../utils/assertions.js';
import type { McpToolResponse } from '../utils/assertions.js';
import { testDataGenerator } from '../fixtures/index.js';
import {
extractRecordId,
createTestRecord,
cleanupTestRecords,
} from '../utils/error-handling-utils.js';
import { startTestSuite, endTestSuite } from '../utils/logger.js';
describe.skipIf(
!process.env.ATTIO_API_KEY || process.env.SKIP_E2E_TESTS === 'true'
)('Regression Prevention – Relationships & Workflows', () => {
const testRecordIds: string[] = [];
const T45 = 45000,
T60 = 60000;
let prevForceRealApi: string | undefined;
beforeAll(async () => {
startTestSuite('regression-prevention-relationships-workflows');
const validation = await validateTestEnvironment();
if (!validation.valid)
console.warn(
'⚠️ Regression prevention test warnings:',
validation.warnings
);
// Ensure create + read operate against the same backend.
// In E2E mode the system prefers mocks for create, while reads hit real API.
// Force real API for this suite when an API key is available to keep CRUD consistent.
prevForceRealApi = process.env.FORCE_REAL_API;
if (process.env.ATTIO_API_KEY) {
process.env.FORCE_REAL_API = 'true';
}
});
afterAll(async () => {
if (testRecordIds.length > 0) await cleanupTestRecords(testRecordIds);
// Restore environment
if (prevForceRealApi === undefined) delete process.env.FORCE_REAL_API;
else process.env.FORCE_REAL_API = prevForceRealApi;
endTestSuite();
});
it(
'preserves core CRUD workflow integrity',
async () => {
let recordId: string | undefined;
const companyData = testDataGenerator.companies.basicCompany();
const createResponse = (await callUniversalTool('create-record', {
resource_type: 'companies',
record_data: companyData,
} as any)) as McpToolResponse;
E2EAssertions.expectMcpSuccess(createResponse);
recordId = extractRecordId(createResponse as McpToolResponse);
expect(recordId).toBeDefined();
if (!recordId) return;
testRecordIds.push(recordId);
const readResponse = (await callUniversalTool('get-record-details', {
resource_type: 'companies',
record_id: recordId,
} as any)) as McpToolResponse;
E2EAssertions.expectMcpSuccess(readResponse);
// get-record-details returns data in content array, just verify success
expect(readResponse.content).toBeDefined();
expect(
Array.isArray(readResponse.content)
? readResponse.content.length > 0
: readResponse.content
).toBeTruthy();
const updateResponse = (await callUniversalTool('update-record', {
resource_type: 'companies',
record_id: recordId,
record_data: { description: 'Updated for CRUD workflow test' },
} as any)) as McpToolResponse;
E2EAssertions.expectMcpSuccess(updateResponse);
const verifyResponse = (await callUniversalTool('get-record-details', {
resource_type: 'companies',
record_id: recordId,
} as any)) as McpToolResponse;
E2EAssertions.expectMcpSuccess(verifyResponse);
// Verify the response is valid (updated description verification would require parsing)
expect(verifyResponse.content).toBeDefined();
expect(
Array.isArray(verifyResponse.content)
? verifyResponse.content.length > 0
: verifyResponse.content
).toBeTruthy();
console.error('✅ Core CRUD workflow integrity preserved');
},
T45
);
it(
'preserves cross-resource relationship integrity',
async () => {
const companyData = testDataGenerator.companies.basicCompany();
const companyId = await createTestRecord(
(resourceType, data) =>
callUniversalTool('create-record', {
resource_type: resourceType as any,
record_data: data,
}),
'companies',
companyData
);
if (!companyId) {
console.error(
'⏭️ Skipping relationship test - could not create company'
);
return;
}
testRecordIds.push(companyId);
const taskResponse = await callTasksTool('create-record', {
resource_type: 'tasks',
record_data: {
content: 'Relationship integrity test task',
recordId: companyId,
targetObject: 'companies',
},
} as any);
expect(taskResponse).toBeDefined();
const noteResponse = await callNotesTool('create-note', {
resource_type: 'companies',
record_id: companyId,
title: 'Relationship integrity test note',
content: 'Testing cross-resource relationships',
format: 'markdown',
} as any);
expect(noteResponse).toBeDefined();
const companyCheck = (await callUniversalTool('get-record-details', {
resource_type: 'companies',
record_id: companyId,
} as any)) as McpToolResponse;
E2EAssertions.expectMcpSuccess(companyCheck);
// Verify company details are returned successfully
expect(companyCheck.content).toBeDefined();
expect(
Array.isArray(companyCheck.content)
? companyCheck.content.length > 0
: companyCheck.content
).toBeTruthy();
console.error('✅ Cross-resource relationship integrity preserved');
},
T60
);
it(
'preserves data validation rules',
async () => {
const validationTests = [
{
name: 'Required field validation',
test: async () => {
const response = await callUniversalTool('create-record', {
resource_type: 'companies',
record_data: {
/* intentionally missing required fields to assert validation */
},
} as any);
return response;
},
},
{
name: 'Data type validation',
test: async () => {
const response = await callUniversalTool('search-records', {
resource_type: 'companies',
query: 'validation-test',
limit: 5,
} as any);
return response;
},
},
];
for (const validationTest of validationTests) {
const result = await validationTest.test();
expect(result).toBeDefined();
console.error(`✅ ${validationTest.name} preserved`);
}
console.error('✅ Data validation rules preservation validated');
},
T45
);
});