Atlassian Confluence MCP Server

by aashari
Verified
import { CliTestUtil } from '../utils/cli.test.util.js'; import { getAtlassianCredentials } from '../utils/transport.util.js'; import { config } from '../utils/config.util.js'; describe('Atlassian Confluence Pages CLI Commands', () => { // Load configuration and check for credentials before all tests beforeAll(() => { // Load configuration from all sources config.load(); // Log warning if credentials aren't available const credentials = getAtlassianCredentials(); if (!credentials) { console.warn( 'Skipping Atlassian Confluence Pages CLI tests: No credentials available', ); } }); // Helper function to skip tests when credentials are missing const skipIfNoCredentials = () => { const credentials = getAtlassianCredentials(); // If we're running in CI or test environment, use mock responses instead of skipping if (!credentials && process.env.NODE_ENV === 'test') { // Return false to allow tests to run with potential mocks return false; } // Skip if no credentials are available (for integration tests) return !credentials; }; // Helper function to get a valid space key for testing async function getSpaceKey(): Promise<string | null> { // First, get a list of spaces to find a valid key const listResult = await CliTestUtil.runCommand([ 'list-spaces', '--limit', '1', ]); // Skip if no spaces are available if (listResult.stdout.includes('No spaces found')) { console.warn('Skipping test: No spaces available'); return null; } // Extract a space key from the output const keyMatch = listResult.stdout.match(/\*\*Key\*\*:\s+([^\n]+)/); if (!keyMatch || !keyMatch[1]) { console.warn('Skipping test: Could not extract space key'); return null; } // Extract the space ID since pages commands need space ID, not space key const idMatch = listResult.stdout.match(/\*\*ID\*\*:\s+([^\n]+)/); if (!idMatch || !idMatch[1]) { console.warn('Skipping test: Could not extract space ID'); return null; } // Return the space ID return idMatch[1].trim(); } // Helper function to get a valid page ID for testing async function getPageIdAndSpaceKey(): Promise<{ pageId: string; spaceId: string; } | null> { // First, get a valid space key const spaceId = await getSpaceKey(); if (!spaceId) { return null; } // List pages in the space const listResult = await CliTestUtil.runCommand([ 'list-pages', '--space-id', spaceId, '--limit', '1', ]); // Skip if no pages are available if (listResult.stdout.includes('No pages found')) { console.warn('Skipping test: No pages available'); return null; } // Extract a page ID from the output const idMatch = listResult.stdout.match(/\*\*ID\*\*:\s+(\d+)/); if (!idMatch || !idMatch[1]) { console.warn('Skipping test: Could not extract page ID'); return null; } return { pageId: idMatch[1].trim(), spaceId, }; } describe('list-pages command', () => { // Test listing pages in a space it('should list pages in a space', async () => { if (skipIfNoCredentials()) { return; } // Get a valid space key const spaceId = await getSpaceKey(); if (!spaceId) { return; // Skip if no valid space key found } // Run the CLI command const result = await CliTestUtil.runCommand([ 'list-pages', '--space-id', spaceId, ]); // Check command exit code expect(result.exitCode).toBe(0); // Verify the output format if (!result.stdout.includes('No pages found')) { // Direct testing instead of using the utility expect(result.stdout).toContain('# Confluence Pages'); expect(result.stdout).toContain('**ID**'); expect(result.stdout).toContain('**Title**'); expect(result.stdout).toMatch(/^#\s.+/m); } }, 30000); // Increased timeout for API call // Test with pagination it('should support pagination with --limit flag', async () => { if (skipIfNoCredentials()) { return; } // Get a valid space key const spaceId = await getSpaceKey(); if (!spaceId) { return; // Skip if no valid space key found } // Run the CLI command with limit const result = await CliTestUtil.runCommand([ 'list-pages', '--space-id', spaceId, '--limit', '1', ]); // Check command exit code expect(result.exitCode).toBe(0); // If there are multiple pages, pagination section should be present if ( !result.stdout.includes('No pages found') && result.stdout.includes('items remaining') ) { expect(result.stdout).toContain('Next cursor'); } }, 30000); // Increased timeout for API call // Test without space ID (which may work in authenticated environment but fail in CI) it('should handle missing space ID appropriately', async () => { if (skipIfNoCredentials()) { return; } // Run command without space ID const result = await CliTestUtil.runCommand(['list-pages']); // In authenticated environment, this works with exit code 0 // In unauthenticated environment (CI), this fails with exit code 1 // We need to handle both cases if (result.exitCode === 0) { // Should have some output if successful expect(result.stdout).toBeDefined(); expect(result.stdout.length).toBeGreaterThan(0); } else { // If it failed, there should be an error message expect(result.stderr).toBeDefined(); expect(result.stderr.length).toBeGreaterThan(0); expect(result.stderr).toContain('error'); } }, 15000); // Test with invalid space key it('should handle invalid space IDs gracefully', async () => { if (skipIfNoCredentials()) { return; } // Use a deliberately invalid space ID const invalidId = '999999999'; // A space ID that likely doesn't exist // Run command with invalid ID const result = await CliTestUtil.runCommand([ 'list-pages', '--space-id', invalidId, ]); // In CI, this might fail with exit code 1, but locally it might succeed with empty results // So we need a flexible test that works in both environments if (result.exitCode === 0) { // If it succeeded, it should show no pages found expect(result.stdout).toContain('No Confluence pages found'); } else { // If it failed, it should have an error message expect(result.stderr).toBeDefined(); } }, 30000); // Test with multiple space IDs it('should handle multiple space IDs', async () => { if (skipIfNoCredentials()) { return; } // Get a valid space ID const spaceId = await getSpaceKey(); if (!spaceId) { return; // Skip if no valid space ID found } // Use the valid space ID twice to test multiple ID support // With commander's array syntax, multiple values are passed as separate arguments const result = await CliTestUtil.runCommand([ 'list-pages', '--space-id', spaceId, '999999999', // Adding an invalid ID alongside the valid one ]); // Command should succeed regardless expect(result.exitCode).toBe(0); }, 30000); }); describe('get-page command', () => { // Test fetching a specific page it('should retrieve page details by ID', async () => { if (skipIfNoCredentials()) { return; } // Get a valid page ID const pageInfo = await getPageIdAndSpaceKey(); if (!pageInfo) { return; // Skip if no valid page ID found } // Run the get-page command const result = await CliTestUtil.runCommand([ 'get-page', '--page-id', pageInfo.pageId, ]); // Check command exit code expect(result.exitCode).toBe(0); // Verify the output structure and content expect(result.stdout).toContain('Confluence Page:'); expect(result.stdout).toContain('**ID**'); expect(result.stdout).toContain('Content'); expect(result.stdout).toMatch(/^#\s.+/m); }, 30000); // Test with missing required parameter it('should fail when page ID is not provided', async () => { if (skipIfNoCredentials()) { return; } // Run command without required parameter const result = await CliTestUtil.runCommand(['get-page']); // Should fail with non-zero exit code expect(result.exitCode).not.toBe(0); // Should indicate missing required option expect(result.stderr).toContain('required option'); }, 15000); // Test with invalid page ID it('should handle invalid page IDs gracefully', async () => { if (skipIfNoCredentials()) { return; } // Use a deliberately invalid page ID const invalidId = '999999999'; // A page ID that likely doesn't exist // Run command with invalid ID const result = await CliTestUtil.runCommand([ 'get-page', '--page-id', invalidId, ]); // Should handle API errors gracefully expect(result.exitCode).not.toBe(0); expect(result.stderr).toContain('error'); }, 30000); // Test with non-numeric page ID it('should reject non-numeric page IDs', async () => { if (skipIfNoCredentials()) { return; } // Use a page ID with invalid format (non-numeric) const invalidFormat = 'abc'; // Run command with invalid format const result = await CliTestUtil.runCommand([ 'get-page', '--page-id', invalidFormat, ]); // Should fail with non-zero exit code expect(result.exitCode).not.toBe(0); // Should contain error information about ID format expect(result.stderr).toContain('error'); }, 15000); // Test with expand options it('should support expanding additional content fields', async () => { if (skipIfNoCredentials()) { return; } // Get a valid page ID const pageInfo = await getPageIdAndSpaceKey(); if (!pageInfo) { return; // Skip if no valid page ID found } // Run the get-page command with expand options const result = await CliTestUtil.runCommand([ 'get-page', '--page-id', pageInfo.pageId, ]); // Check command exit code expect(result.exitCode).toBe(0); expect(result.stdout).toMatch(/^#\s.+/m); }, 30000); }); });