Skip to main content
Glama
vendor.atlassian.pages.test.ts13.4 kB
import pagesService from './vendor.atlassian.pages.service.js'; import { getAtlassianCredentials } from '../utils/transport.util.js'; import { config } from '../utils/config.util.js'; describe('Vendor Atlassian Pages Service', () => { // Load configuration before all tests beforeAll(() => { // Load configuration from all sources config.load(); // Log a warning if credentials aren't available const credentials = getAtlassianCredentials(); if (!credentials) { console.warn( 'Skipping Atlassian Pages tests: No credentials available', ); } }); // Helper function to skip tests when credentials are missing const skipIfNoCredentials = () => !getAtlassianCredentials(); // Use standard describe and skip inside test if needed describe('list', () => { it('should return a list of pages', async () => { if (skipIfNoCredentials()) return; // Get pages without filters const result = await pagesService.list({}); // Verify the response structure expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); expect(result).toHaveProperty('_links'); // Verify data types in the results if (result.results.length > 0) { const firstPage = result.results[0]; expect(firstPage).toHaveProperty('id'); expect(firstPage).toHaveProperty('title'); expect(firstPage).toHaveProperty('status'); expect(firstPage).toHaveProperty('spaceId'); } }, 15000); it('should support filtering by space ID', async () => { if (skipIfNoCredentials()) return; // Get the first space ID from the API (if available) let spaceId: string | undefined = undefined; try { const result = await pagesService.list({ limit: 1 }); if (result.results.length > 0) { spaceId = result.results[0].spaceId; } } catch (error) { console.warn('Error getting space ID for test:', error); } // If we have a space ID, test filtering by it if (spaceId) { const result = await pagesService.list({ spaceId: [spaceId] }); // Verify the response structure expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); // Verify all pages have the correct space ID for (const page of result.results) { expect(page.spaceId).toBe(spaceId); } } else { // Skip this test case if we couldn't get a space ID console.warn( 'Skipping space ID filter test: No space ID available', ); } }, 15000); it('should support filtering by status', async () => { if (skipIfNoCredentials()) return; // Get pages with status filter const result = await pagesService.list({ status: ['current'] }); // Verify the response structure expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); // Verify all pages have the correct status for (const page of result.results) { expect(page.status).toBe('current'); } }, 15000); it('should support sorting with different sort parameters', async () => { if (skipIfNoCredentials()) return; // Test sorting by title (ascending) const ascResult = await pagesService.list({ sort: 'title' }); // Verify the response structure expect(ascResult).toHaveProperty('results'); expect(Array.isArray(ascResult.results)).toBe(true); // Test sorting by title (descending) const descResult = await pagesService.list({ sort: '-title' }); // Verify the response structure expect(descResult).toHaveProperty('results'); expect(Array.isArray(descResult.results)).toBe(true); // If there are at least 2 pages, verify the order is reversed if ( ascResult.results.length >= 2 && descResult.results.length >= 2 ) { // The titles should be in reverse order expect(ascResult.results[0].title).not.toBe( descResult.results[0].title, ); } }, 15000); it('should support filtering by page title (query parameter)', async () => { if (skipIfNoCredentials()) return; // First get a list of pages const initialResult = await pagesService.list({ limit: 1 }); // If we have at least one page, use part of its title as a query let titleQuery = 'test'; if (initialResult.results.length > 0) { const firstPage = initialResult.results[0]; // Use the first word of the title as a query if it's at least 3 chars const words = firstPage.title.split(' '); for (const word of words) { if (word.length >= 3) { titleQuery = word; break; } } } // Test the title parameter const result = await pagesService.list({ title: titleQuery }); // Verify the response structure expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); }, 15000); it('should handle pagination correctly with cursor-based navigation', async () => { if (skipIfNoCredentials()) return; // Get pages with a small limit const firstResult = await pagesService.list({ limit: 2 }); // Verify the response structure expect(firstResult).toHaveProperty('results'); expect(Array.isArray(firstResult.results)).toBe(true); expect(firstResult).toHaveProperty('_links'); // Check if next page is available const result = firstResult; // Add null checks for _links property if ( result._links && result._links.next && result._links.next.includes('cursor=') ) { // Extract cursor for next page const cursorMatch = result._links.next.match(/cursor=([^&]+)/); expect(cursorMatch).toBeTruthy(); if (cursorMatch && cursorMatch[1]) { const cursor = cursorMatch[1]; expect(cursor).toBeTruthy(); } } }, 15000); it('should handle filtering by multiple space IDs', async () => { if (skipIfNoCredentials()) return; // Get some space IDs const spaceIds: string[] = []; try { const result = await pagesService.list({ limit: 10 }); for (const page of result.results) { if ( !spaceIds.includes(page.spaceId) && spaceIds.length < 2 ) { spaceIds.push(page.spaceId); } } } catch (error) { console.warn('Error getting space IDs for test:', error); } // If we have at least one space ID, test filtering if (spaceIds.length > 0) { const result = await pagesService.list({ spaceId: spaceIds }); // Verify the response structure expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); // Verify all pages have one of the correct space IDs for (const page of result.results) { expect(spaceIds).toContain(page.spaceId); } } else { // Skip this test case if we couldn't get any space IDs console.warn( 'Skipping multiple space IDs test: No space IDs available', ); } }, 15000); it('should handle empty result correctly', async () => { if (skipIfNoCredentials()) return; // Use a nonsense query that shouldn't match any pages const result = await pagesService.list({ title: `no-such-page-${Date.now()}`, }); // Verify the response structure for empty results expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); expect(result.results).toHaveLength(0); expect(result).toHaveProperty('_links'); }, 15000); it('should throw an error for invalid spaceId format if enforced by API', async () => { if (skipIfNoCredentials()) return; // Different Confluence instances may handle invalid space IDs differently // Some validate and return 400, others might allow and return empty results try { await pagesService.list({ spaceId: ['invalid-not-numeric-id'], }); // If API doesn't validate IDs, this will succeed with empty results // Specific API versions may diverge in behavior, so skip checking } catch (error) { // If API validates IDs and rejects, verify it's a proper error expect(error).toBeInstanceOf(Error); if (error instanceof Error) { // The error type might be VALIDATION_ERROR, BAD_REQUEST, API_ERROR, or NOT_FOUND // depending on API version and configuration const errorType = (error as any).type || error.name; expect([ 'VALIDATION_ERROR', 'BAD_REQUEST', 'API_ERROR', 'NOT_FOUND', 'AUTH_MISSING', 'McpError', ]).toContain(errorType); } } }, 15000); }); // Helper function to get a page ID for tests async function getFirstPageId(): Promise<string | null> { if (skipIfNoCredentials()) return null; try { // Get the first page const result = await pagesService.list({ limit: 1 }); return result.results.length > 0 ? result.results[0].id : null; } catch (error) { console.warn('Error getting page ID for tests:', error); return null; } } // Use standard describe and skip inside test if needed describe('get', () => { it('should retrieve a page by ID', async () => { if (skipIfNoCredentials()) return; const pageId = await getFirstPageId(); if (!pageId) { console.warn('Skipping get test: No page ID available'); return; } // Get the page const result = await pagesService.get(pageId); // Verify the response structure expect(result).toHaveProperty('id', pageId); expect(result).toHaveProperty('title'); expect(result).toHaveProperty('status'); expect(result).toHaveProperty('body'); }, 15000); it('should support body format parameter', async () => { if (skipIfNoCredentials()) return; const pageId = await getFirstPageId(); if (!pageId) { console.warn('Skipping body format test: No page ID available'); return; } // Get the page with specific body format const result = await pagesService.get(pageId, { bodyFormat: 'storage', }); // Verify the body format expect(result).toHaveProperty('body'); if (result.body && result.body.storage) { expect(result.body.storage).toHaveProperty('value'); expect(result.body.storage).toHaveProperty( 'representation', 'storage', ); } }, 15000); it('should retrieve page labels', async () => { if (skipIfNoCredentials()) return; const pageId = await getFirstPageId(); if (!pageId) { console.warn('Skipping labels test: No page ID available'); return; } // Get the page with labels expanded const result = await pagesService.get(pageId, { includeLabels: true, }); // Verify the labels structure expect(result).toHaveProperty('labels'); if (result.labels) { expect(result.labels).toHaveProperty('results'); expect(Array.isArray(result.labels.results)).toBe(true); } }, 15000); it('should retrieve page version information', async () => { if (skipIfNoCredentials()) return; const pageId = await getFirstPageId(); if (!pageId) { console.warn('Skipping version test: No page ID available'); return; } // Get the page with version expanded const result = await pagesService.get(pageId, { includeVersion: true, }); // Verify the version structure expect(result).toHaveProperty('version'); if (result.version) { expect(result.version).toHaveProperty('number'); expect(typeof result.version.number).toBe('number'); } }, 15000); it('should throw properly formatted error for non-existent page ID', async () => { if (skipIfNoCredentials()) return; try { // Use a page ID that shouldn't exist await pagesService.get('999999999'); // If we get here, the test has failed fail('Expected an error for non-existent page ID'); } catch (error) { expect(error).toBeInstanceOf(Error); // Error behavior may vary by API version and implementation // (NOT_FOUND or AUTH_MISSING are both valid) if (error instanceof Error) { const errorType = (error as any).type || error.name; expect(['NOT_FOUND', 'AUTH_MISSING', 'McpError']).toContain( errorType, ); // Status code test is skipped as it depends on credential state } } }, 15000); it('should throw properly formatted error for invalid page ID format', async () => { if (skipIfNoCredentials()) return; try { // Use an invalid page ID format await pagesService.get('invalid-page-id'); // If we get here, the test has failed fail('Expected an error for invalid page ID format'); } catch (error) { expect(error).toBeInstanceOf(Error); // The error type might be INVALID_REQUEST or NOT_FOUND depending on the API if (error instanceof Error) { const errorType = (error as any).type || error.name; expect([ 'INVALID_REQUEST', 'NOT_FOUND', 'API_ERROR', 'AUTH_MISSING', 'McpError', ]).toContain(errorType); // Status code test is skipped as it depends on credential state } } }, 15000); it('should support multiple include parameters', async () => { if (skipIfNoCredentials()) return; const pageId = await getFirstPageId(); if (!pageId) { console.warn( 'Skipping multiple include test: No page ID available', ); return; } // Get the page with multiple includes const result = await pagesService.get(pageId, { includeVersion: true, includeLabels: true, }); // Verify multiple expanded sections expect(result).toHaveProperty('version'); expect(result).toHaveProperty('labels'); }, 15000); }); });

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/aashari/mcp-server-atlassian-confluence'

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