Skip to main content
Glama
updateSetIntegration.test.ts14 kB
import { describe, it, expect, beforeAll } from '@jest/globals'; /** * LIVE INTEGRATION TESTS FOR UPDATE SET OPERATIONS * * These tests make real API calls to ServiceNow using actual credentials. * They will ONLY run if SERVICENOW_* environment variables are set. * * Purpose: Validate real-world update set operations and XML reassignment * Run with: npm run test:integration * * ⚠️ WARNING: These tests create and modify update sets in ServiceNow! * Only run against sandbox/dev instances with appropriate permissions. */ const skipIfNoCredentials = () => { const hasCredentials = process.env.SERVICENOW_ACE_INSTANCE && process.env.SERVICENOW_ACE_USERNAME && process.env.SERVICENOW_ACE_PASSWORD; if (!hasCredentials) { console.log('\n⚠️ Skipping live update set integration tests - ServiceNow credentials not found'); console.log(' Set SERVICENOW_ACE_INSTANCE, SERVICENOW_ACE_USERNAME, SERVICENOW_ACE_PASSWORD to run'); } return hasCredentials; }; // Only run these tests if we have credentials const testSuite = skipIfNoCredentials() ? describe : describe.skip; testSuite('Live ServiceNow Update Set Integration Tests', () => { let client: any; let createdUpdateSetId: string | null = null; beforeAll(async () => { try { // Dynamic import to avoid Jest parsing issues const { ServiceNowUpdateSetClient } = await import('../servicenow/updateSetClient.js'); client = new ServiceNowUpdateSetClient(); } catch (error) { console.error('Failed to initialize ServiceNow update set client:', error); throw error; } }); describe('Update Set Lifecycle Operations', () => { it('should create a new update set', async () => { const result = await client.executeUpdateSetOperation({ operation: 'create', name: `SkyeNet Test Update Set ${Date.now()}`, description: 'Created by SkyeNet MCP ACE integration test', scope: 'x_cls_clear_skye_i', set_as_working: true, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('update_set'); expect(result.data?.update_set?.name).toContain('SkyeNet Test Update Set'); expect(result.data?.update_set?.state).toBe('in_progress'); expect(result.data?.working_set).toBeDefined(); createdUpdateSetId = result.data?.update_set?.sys_id; }); it('should show working update set', async () => { const result = await client.executeUpdateSetOperation({ operation: 'show_working', }); expect(result.success).toBe(true); expect(result.data?.working_set).toBeDefined(); expect(result.data?.working_set?.sys_id).toBe(createdUpdateSetId); }); it('should list update sets', async () => { const result = await client.executeUpdateSetOperation({ operation: 'list', filters: { scope: 'x_cls_clear_skye_i' }, limit: 10, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('update_sets'); expect(Array.isArray(result.data?.update_sets)).toBe(true); expect(result.data?.update_sets.length).toBeGreaterThan(0); }); it('should get update set info', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for info test'); } const result = await client.executeUpdateSetOperation({ operation: 'info', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data?.update_set?.sys_id).toBe(createdUpdateSetId); expect(result.data?.update_set?.xml_count).toBeDefined(); }); }); describe('Record Operations with XML Reassignment', () => { it('should insert record with automatic XML reassignment', async () => { if (!createdUpdateSetId) { throw new Error('No working update set available for insert test'); } const result = await client.executeUpdateSetOperation({ operation: 'insert', table: 'sys_script_include', data: { name: `TestScriptInclude_${Date.now()}`, script: '// Test script include created by SkyeNet MCP ACE', active: true, }, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('record'); expect(result.data?.record?.name).toContain('TestScriptInclude_'); expect(result.data?.record?.sys_id).toBeDefined(); // Check if XML reassignment occurred if (result.data?.xml_reassignment) { expect(result.data.xml_reassignment.success).toBe(true); expect(result.data.xml_reassignment.reassigned_count).toBeGreaterThan(0); } }); it('should update record with automatic XML reassignment', async () => { if (!createdUpdateSetId) { throw new Error('No working update set available for update test'); } // First create a record to update const createResult = await client.executeUpdateSetOperation({ operation: 'insert', table: 'sys_script_include', data: { name: `TestScriptForUpdate_${Date.now()}`, script: '// Original script', active: true, }, }); expect(createResult.success).toBe(true); const recordSysId = createResult.data?.record?.sys_id; expect(recordSysId).toBeDefined(); // Now update the record const result = await client.executeUpdateSetOperation({ operation: 'update', table: 'sys_script_include', sys_id: recordSysId, data: { script: '// Updated script content', description: 'Updated by SkyeNet MCP ACE', }, }); expect(result.success).toBe(true); expect(result.data?.record?.sys_id).toBe(recordSysId); // Check if XML reassignment occurred if (result.data?.xml_reassignment) { expect(result.data.xml_reassignment.success).toBe(true); } }); }); describe('XML Management Operations', () => { it('should get update set contents', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for contents test'); } const result = await client.executeUpdateSetOperation({ operation: 'contents', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('update_set_sys_id'); expect(result.data?.update_set_sys_id).toBe(createdUpdateSetId); expect(result.data?.total_count).toBeGreaterThanOrEqual(0); expect(result.data?.by_type).toBeDefined(); expect(result.data?.by_table).toBeDefined(); }); it('should get recent XML activity', async () => { const result = await client.executeUpdateSetOperation({ operation: 'recent', limit: 20, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('total_count'); expect(result.data?.total_count).toBeGreaterThanOrEqual(0); expect(result.data?.records).toBeDefined(); expect(Array.isArray(result.data?.records)).toBe(true); }); it('should diff against default update set', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for diff test'); } const result = await client.executeUpdateSetOperation({ operation: 'diff_default', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('working_set'); expect(result.data?.working_set).toBeDefined(); expect(result.data?.default_set).toBeDefined(); expect(result.data?.stray_count).toBeGreaterThanOrEqual(0); }); }); describe('Update Set State Management', () => { it('should complete update set', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for complete test'); } const result = await client.executeUpdateSetOperation({ operation: 'complete', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data?.update_set?.state).toBe('complete'); }); it('should reopen update set', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for reopen test'); } const result = await client.executeUpdateSetOperation({ operation: 'reopen', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data?.update_set?.state).toBe('in_progress'); }); it('should delete update set', async () => { if (!createdUpdateSetId) { throw new Error('No update set created for delete test'); } const result = await client.executeUpdateSetOperation({ operation: 'delete', update_set_sys_id: createdUpdateSetId, }); expect(result.success).toBe(true); expect(result.data?.update_set?.state).toBe('deleted'); }); }); describe('Working Set Management', () => { it('should clear working set', async () => { const result = await client.executeUpdateSetOperation({ operation: 'clear_working', }); expect(result.success).toBe(true); expect(result.data?.working_set).toBeNull(); }); it('should handle operations without working set gracefully', async () => { // Clear working set first await client.executeUpdateSetOperation({ operation: 'clear_working' }); // Try an operation that requires working set await expect( client.executeUpdateSetOperation({ operation: 'insert', table: 'sys_script_include', data: { name: 'TestScript', script: '// test' }, }) ).rejects.toThrow(); }); }); describe('Error Handling', () => { it('should handle invalid update set sys_id', async () => { await expect( client.executeUpdateSetOperation({ operation: 'info', update_set_sys_id: 'invalid_sys_id_12345', }) ).rejects.toThrow(); }); it('should handle missing required parameters', async () => { await expect( client.executeUpdateSetOperation({ operation: 'create', // Missing name parameter }) ).rejects.toThrow(); }); it('should handle invalid operation', async () => { await expect( client.executeUpdateSetOperation({ operation: 'invalid_operation' as any, }) ).rejects.toThrow(); }); }); describe('Performance and Metadata', () => { it('should include execution metadata', async () => { const result = await client.executeUpdateSetOperation({ operation: 'list', limit: 5, }); expect(result.success).toBe(true); expect(result.metadata).toHaveProperty('executionTime'); expect(result.metadata).toHaveProperty('timestamp'); expect(result.metadata).toHaveProperty('operation'); expect(result.metadata.executionTime).toBeGreaterThan(0); }); it('should handle context overflow prevention', async () => { const result = await client.executeUpdateSetOperation({ operation: 'recent', limit: 1000, // Large limit to test overflow prevention }); expect(result.success).toBe(true); expect(result.metadata).toHaveProperty('responseSize'); expect(result.metadata).toHaveProperty('contextOverflowPrevention'); }); }); describe('Batch Operations', () => { it('should handle batch insert operations', async () => { // Create a new update set for batch testing const createResult = await client.executeUpdateSetOperation({ operation: 'create', name: `SkyeNet Batch Test ${Date.now()}`, description: 'Batch testing update set', set_as_working: true, }); expect(createResult.success).toBe(true); const batchUpdateSetId = createResult.data?.update_set?.sys_id; // Test batch insert const result = await client.executeUpdateSetOperation({ operation: 'insert', table: 'sys_script_include', data: [ { name: `BatchScript1_${Date.now()}`, script: '// Batch script 1', active: true, }, { name: `BatchScript2_${Date.now()}`, script: '// Batch script 2', active: true, }, ], batch: true, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('record'); expect(result.data?.record).toBeDefined(); expect(result.data?.record.sys_class_name).toBe('sys_script_include'); }); }); describe('XML Rehoming Operations', () => { it('should rehome XML records by query', async () => { if (!createdUpdateSetId) { throw new Error('No update set available for rehoming test'); } // Create a new update set for rehoming const createResult = await client.executeUpdateSetOperation({ operation: 'create', name: `SkyeNet Rehome Test ${Date.now()}`, description: 'Rehoming test update set', set_as_working: true, }); expect(createResult.success).toBe(true); const rehomeUpdateSetId = createResult.data?.update_set?.sys_id; // Try to rehome XML records (may not find any, but should not error) const result = await client.executeUpdateSetOperation({ operation: 'rehome', query: 'sys_created_on>=javascript:gs.daysAgo(1)', update_set_sys_id: rehomeUpdateSetId, force: false, }); expect(result.success).toBe(true); expect(result.data).toHaveProperty('reassigned_count'); expect(result.data?.reassigned_count).toBeGreaterThanOrEqual(0); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ClearSkye/SkyeNet-MCP-ACE'

If you have feedback or need assistance with the MCP directory API, please join our Discord server