UNPKG

@tiberriver256/mcp-server-azure-devops

Version:

Azure DevOps reference server for the Model Context Protocol (MCP)

413 lines 19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const feature_1 = require("./feature"); const feature_2 = require("../get-wikis/feature"); const test_helpers_1 = require("@/shared/test/test-helpers"); const environment_1 = require("@/utils/environment"); const azure_devops_errors_1 = require("@/shared/errors/azure-devops-errors"); // Ensure environment variables are set for testing process.env.AZURE_DEVOPS_DEFAULT_PROJECT = process.env.AZURE_DEVOPS_DEFAULT_PROJECT || 'default-project'; describe('listWikiPages integration', () => { let projectName; let orgUrl; let organizationId; beforeAll(async () => { // Mock the required environment variable for testing process.env.AZURE_DEVOPS_ORG_URL = process.env.AZURE_DEVOPS_ORG_URL || 'https://example.visualstudio.com'; // Get and validate required environment variables const envProjectName = process.env.AZURE_DEVOPS_DEFAULT_PROJECT; if (!envProjectName) { throw new Error('AZURE_DEVOPS_DEFAULT_PROJECT environment variable is required'); } projectName = envProjectName; const envOrgUrl = process.env.AZURE_DEVOPS_ORG_URL; if (!envOrgUrl) { throw new Error('AZURE_DEVOPS_ORG_URL environment variable is required'); } orgUrl = envOrgUrl; organizationId = (0, environment_1.getOrgNameFromUrl)(orgUrl); }); describe('Happy Path Tests', () => { test('should list pages in real test wiki', async () => { // Skip if no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // List wiki pages const result = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, }); // Verify the result structure expect(result).toBeDefined(); expect(Array.isArray(result)).toBe(true); // If pages exist, verify their structure matches WikiPageSummary interface if (result.length > 0) { const page = result[0]; expect(page).toHaveProperty('id'); expect(page).toHaveProperty('path'); expect(page).toHaveProperty('url'); expect(typeof page.id).toBe('number'); expect(typeof page.path).toBe('string'); // url and order are optional if (page.url !== undefined) { expect(typeof page.url).toBe('string'); } if (page.order !== undefined) { expect(typeof page.order).toBe('number'); } } }); test('should handle path filtering with real wiki structure', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // First get all pages to find a valid path const allPages = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, }); // If we have pages, test filtering by path if (allPages.length > 0) { // Try to find a page with a nested path const nestedPage = allPages.find((page) => page.path.includes('/')); if (nestedPage) { // Extract parent path const pathParts = nestedPage.path.split('/'); const parentPath = pathParts.slice(0, -1).join('/'); if (parentPath) { // Test filtering by parent path const filteredResult = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, path: parentPath, }); expect(Array.isArray(filteredResult)).toBe(true); // All returned pages should be under the specified path filteredResult.forEach((page) => { expect(page.path.startsWith(parentPath)).toBe(true); }); } } } }); test('should handle recursionLevel parameter with various values', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // Test with recursionLevel 1 (shallow) const shallowResult = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 1, }); expect(Array.isArray(shallowResult)).toBe(true); // Test with recursionLevel 5 (deeper) const deeperResult = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 5, }); expect(Array.isArray(deeperResult)).toBe(true); // Deeper recursion should return same or more pages expect(deeperResult.length).toBeGreaterThanOrEqual(shallowResult.length); }); }); describe('Error Scenarios', () => { test('should handle invalid wikiId (expect 404 error)', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } const invalidWikiId = 'non-existent-wiki-id-12345'; await expect((0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: invalidWikiId, })).rejects.toThrow(azure_devops_errors_1.AzureDevOpsError); }); test('should handle invalid projectId', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } const invalidProjectId = 'non-existent-project-12345'; await expect((0, feature_1.listWikiPages)({ organizationId, projectId: invalidProjectId, wikiId: 'any-wiki', })).rejects.toThrow(azure_devops_errors_1.AzureDevOpsError); }); test('should handle invalid organizationId', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } const invalidOrgId = 'non-existent-org-12345'; await expect((0, feature_1.listWikiPages)({ organizationId: invalidOrgId, projectId: projectName, wikiId: 'any-wiki', })).rejects.toThrow(azure_devops_errors_1.AzureDevOpsError); }); }); describe('Edge Cases', () => { test('should handle empty wikis gracefully', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // Test with a path that likely doesn't exist const result = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, path: '/non-existent-path-12345', }); // Should return an array (may be empty or contain all pages depending on API behavior) expect(Array.isArray(result)).toBe(true); // Note: Azure DevOps API may return all pages when path doesn't match console.log(`Path filter test returned ${result.length} pages`); }); test('should handle deeply nested paths', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // Test with maximum recursion level const result = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 50, // Maximum allowed }); expect(Array.isArray(result)).toBe(true); // Should not throw error even with max recursion }); test('should handle boundary recursionLevel values', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } // Test minimum recursion level const minResult = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 1, }); expect(Array.isArray(minResult)).toBe(true); // Test maximum recursion level const maxResult = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 50, }); expect(Array.isArray(maxResult)).toBe(true); }); }); describe('Data Structure Validation', () => { test('should verify returned data structure matches WikiPageSummary interface', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } const result = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, }); expect(Array.isArray(result)).toBe(true); // Validate each page in the result result.forEach((page) => { // Required fields expect(page).toHaveProperty('id'); expect(page).toHaveProperty('path'); expect(page).toHaveProperty('url'); expect(typeof page.id).toBe('number'); expect(typeof page.path).toBe('string'); // Optional fields if (page.url !== undefined) { expect(typeof page.url).toBe('string'); } if (page.order !== undefined) { expect(typeof page.order).toBe('number'); } // Validate URL format (if present) if (page.url !== undefined) { expect(page.url).toMatch(/^https?:\/\//); } // Validate path format (should start with /) expect(page.path).toMatch(/^\//); }); }); }); describe('Performance and Pagination', () => { test('should handle large wiki structures efficiently', async () => { // Skip if integration tests are disabled or no connection available if ((0, test_helpers_1.shouldSkipIntegrationTest)()) { return; } // Get a real connection using environment variables const connection = await (0, test_helpers_1.getTestConnection)(); if (!connection) { throw new Error('Connection should be available when test is not skipped'); } // First get available wikis const wikis = await (0, feature_2.getWikis)(connection, { projectId: projectName }); // Skip if no wikis are available if (wikis.length === 0) { console.log('Skipping test: No wikis available in the project'); return; } // Use the first available wiki const wiki = wikis[0]; if (!wiki.name) { throw new Error('Wiki name is undefined'); } const startTime = Date.now(); const result = await (0, feature_1.listWikiPages)({ organizationId, projectId: projectName, wikiId: wiki.name, recursionLevel: 50, // Maximum depth to test performance }); const endTime = Date.now(); const duration = endTime - startTime; expect(Array.isArray(result)).toBe(true); // Performance check - should complete within reasonable time (30 seconds) expect(duration).toBeLessThan(30000); console.log(`Retrieved ${result.length} pages in ${duration}ms`); }); }); }); //# sourceMappingURL=feature.spec.int.js.map