Skip to main content
Glama
pagination-fixes.test.tsโ€ข7.06 kB
import { describe, it } from 'node:test'; import { strict as assert } from 'node:assert'; /** * Unit tests for pagination fixes in MCP tools * * Tests the fixes applied to: * - list_test_suites (added pagination parameters) * - get_tcm_test_suites_by_project (fixed token-based pagination) * - get_root_suites (fixed pagination logic) * - get_all_tcm_test_cases_by_project (fixed to use token-based pagination) * - get_root_id_by_suite_id (fixed pagination) * - get_tcm_suite_by_id (fixed pagination) */ describe('Pagination Fixes Unit Tests', () => { describe('Pagination Parameter Validation', () => { it('should validate page parameter is non-negative', () => { const validPage = 0; const invalidPage = -1; assert.ok(validPage >= 0, 'Page 0 should be valid'); assert.ok(invalidPage < 0, 'Negative page should be invalid'); }); it('should validate size parameter is positive and within limits', () => { const validSize = 50; const invalidSizeZero = 0; const invalidSizeNegative = -1; const maxSize = 1000; const oversizeValue = 1001; assert.ok(validSize > 0 && validSize <= maxSize, 'Size 50 should be valid'); assert.ok(invalidSizeZero <= 0, 'Size 0 should be invalid'); assert.ok(invalidSizeNegative <= 0, 'Negative size should be invalid'); assert.ok(oversizeValue > maxSize, 'Oversize value should exceed max'); }); it('should handle page token as optional string', () => { const validToken = 'abc123token'; const emptyToken = ''; const undefinedToken = undefined; assert.equal(typeof validToken, 'string', 'Valid token should be string'); assert.equal(typeof emptyToken, 'string', 'Empty token should be string'); assert.equal(undefinedToken, undefined, 'Undefined token should be undefined'); }); }); describe('Pagination Response Structure', () => { it('should structure pagination response correctly', () => { const mockResponse = { items: [{ id: 1, title: 'Test Suite 1' }], _meta: { nextPageToken: 'next123' }, pagination: { currentPage: 0, pageSize: 50, hasNextPage: true, nextPageToken: 'next123' } }; assert.ok(Array.isArray(mockResponse.items), 'Items should be an array'); assert.ok(mockResponse._meta, 'Meta should be present'); assert.ok(mockResponse.pagination, 'Pagination info should be present'); assert.equal(mockResponse.pagination.hasNextPage, !!mockResponse._meta.nextPageToken, 'hasNextPage should match token presence'); }); it('should handle pagination metadata correctly', () => { const withNextPage = { nextPageToken: 'token123' }; const withoutNextPage = { nextPageToken: undefined }; assert.equal(!!withNextPage.nextPageToken, true, 'Should have next page when token exists'); assert.equal(!!withoutNextPage.nextPageToken, false, 'Should not have next page when token is undefined'); }); }); describe('Token-based vs Page-based Pagination', () => { it('should prefer token-based pagination over page-based', () => { // Token-based pagination (correct approach) const tokenBasedParams = { size: 50, pageToken: 'abc123' }; // Page-based pagination (old, incorrect approach) const pageBasedParams = { size: 50, page: 1 }; assert.ok('pageToken' in tokenBasedParams, 'Token-based should use pageToken'); assert.ok('page' in pageBasedParams, 'Page-based uses page number'); // Verify we're using the correct approach assert.ok(tokenBasedParams.pageToken, 'pageToken should be preferred'); }); it('should handle pagination loop termination correctly', () => { // Simulate pagination loop conditions let pageCount = 0; const maxPages = 50; let pageToken: string | undefined = 'initial-token'; const shouldContinue = () => !!(pageToken && pageCount < maxPages); // Test normal termination (no more pages) pageToken = undefined; assert.equal(shouldContinue(), false, 'Should stop when no more pages'); // Test safety limit termination pageToken = 'still-has-token'; pageCount = 50; assert.equal(shouldContinue(), false, 'Should stop at safety limit'); // Test normal continuation pageToken = 'has-token'; pageCount = 10; assert.equal(shouldContinue(), true, 'Should continue when conditions are met'); }); }); describe('Error Handling in Pagination', () => { it('should handle MAX_PAGE_SIZE validation', () => { const MAX_PAGE_SIZE = 100; // Simulated config value const requestedSize = 150; const isValidSize = requestedSize <= MAX_PAGE_SIZE; assert.equal(isValidSize, false, 'Should reject size exceeding MAX_PAGE_SIZE'); const validSize = 50; const isValidSizeOk = validSize <= MAX_PAGE_SIZE; assert.equal(isValidSizeOk, true, 'Should accept size within MAX_PAGE_SIZE'); }); it('should provide helpful error messages for pagination issues', () => { const MAX_PAGE_SIZE = 100; const requestedSize = 200; const errorMessage = `โŒ Error: Requested page size (${requestedSize}) exceeds configured maximum (${MAX_PAGE_SIZE}). Set MAX_PAGE_SIZE environment variable to increase the limit.`; assert.ok(errorMessage.includes('exceeds configured maximum'), 'Error should explain the limit'); assert.ok(errorMessage.includes('MAX_PAGE_SIZE environment variable'), 'Error should mention configuration'); }); }); describe('Hierarchy Processing with Pagination', () => { it('should maintain hierarchy information across paginated results', () => { // Simulate paginated suite data const page1Suites = [ { id: 1, title: 'Root Suite', parentSuiteId: null }, { id: 2, title: 'Child Suite', parentSuiteId: 1 } ]; const page2Suites = [ { id: 3, title: 'Grandchild Suite', parentSuiteId: 2 } ]; const allSuites = [...page1Suites, ...page2Suites]; // Verify hierarchy can be built from combined results const rootSuites = allSuites.filter(suite => suite.parentSuiteId === null); const childSuites = allSuites.filter(suite => suite.parentSuiteId !== null); assert.equal(rootSuites.length, 1, 'Should find one root suite'); assert.equal(childSuites.length, 2, 'Should find two child suites'); // Verify parent-child relationships const childOfRoot = allSuites.find(s => s.parentSuiteId === 1); const grandchild = allSuites.find(s => s.parentSuiteId === 2); assert.ok(childOfRoot, 'Should find child of root'); assert.ok(grandchild, 'Should find grandchild'); }); }); });

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/maksimsarychau/mcp-zebrunner'

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