feat: Add comprehensive Jest test suite (209 tests)
- Add Jest configuration for TypeScript testing - Add security utilities tests (44 tests) - Add Zod validation tests (34 tests) - Add cursor pagination tests (25 tests) - Add query builder tests (38 tests) - Add tools structure validation (68 tests) - All 164 tools validated for correct structure - Version bump to 1.3.4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
610
src/tools/__tests__/tools-structure.test.ts
Normal file
610
src/tools/__tests__/tools-structure.test.ts
Normal file
@@ -0,0 +1,610 @@
|
||||
/**
|
||||
* Tools Structure Tests
|
||||
* Validates that all tools have correct structure without DB connection
|
||||
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
||||
*/
|
||||
|
||||
import { documentsTools } from '../documents';
|
||||
import { collectionsTools } from '../collections';
|
||||
import { usersTools } from '../users';
|
||||
import { groupsTools } from '../groups';
|
||||
import { commentsTools } from '../comments';
|
||||
import { sharesTools } from '../shares';
|
||||
import { revisionsTools } from '../revisions';
|
||||
import { eventsTools } from '../events';
|
||||
import { attachmentsTools } from '../attachments';
|
||||
import { fileOperationsTools } from '../file-operations';
|
||||
import { oauthTools } from '../oauth';
|
||||
import { authTools } from '../auth';
|
||||
import { starsTools } from '../stars';
|
||||
import { pinsTools } from '../pins';
|
||||
import { viewsTools } from '../views';
|
||||
import { reactionsTools } from '../reactions';
|
||||
import { apiKeysTools } from '../api-keys';
|
||||
import { webhooksTools } from '../webhooks';
|
||||
import { backlinksTools } from '../backlinks';
|
||||
import { searchQueriesTools } from '../search-queries';
|
||||
import { teamsTools } from '../teams';
|
||||
import { integrationsTools } from '../integrations';
|
||||
import { notificationsTools } from '../notifications';
|
||||
import { subscriptionsTools } from '../subscriptions';
|
||||
import { templatesTools } from '../templates';
|
||||
import { importsTools } from '../imports-tools';
|
||||
import { emojisTools } from '../emojis';
|
||||
import { userPermissionsTools } from '../user-permissions';
|
||||
import { bulkOperationsTools } from '../bulk-operations';
|
||||
import { advancedSearchTools } from '../advanced-search';
|
||||
import { analyticsTools } from '../analytics';
|
||||
import { exportImportTools } from '../export-import';
|
||||
import { deskSyncTools } from '../desk-sync';
|
||||
import { BaseTool } from '../../types/tools';
|
||||
|
||||
// Helper to validate tool structure
|
||||
function validateTool(tool: BaseTool): void {
|
||||
// Name should be snake_case (tools use names like list_documents, not outline_list_documents)
|
||||
expect(tool.name).toMatch(/^[a-z][a-z0-9_]*$/);
|
||||
|
||||
// Description should exist and be non-empty
|
||||
expect(tool.description).toBeDefined();
|
||||
expect(tool.description.length).toBeGreaterThan(10);
|
||||
|
||||
// Input schema should have correct structure
|
||||
expect(tool.inputSchema).toBeDefined();
|
||||
expect(tool.inputSchema.type).toBe('object');
|
||||
expect(tool.inputSchema.properties).toBeDefined();
|
||||
expect(typeof tool.inputSchema.properties).toBe('object');
|
||||
|
||||
// Handler should be a function
|
||||
expect(typeof tool.handler).toBe('function');
|
||||
}
|
||||
|
||||
// Helper to validate required properties in schema
|
||||
function validateRequiredProps(tool: BaseTool): void {
|
||||
if (tool.inputSchema.required) {
|
||||
expect(Array.isArray(tool.inputSchema.required)).toBe(true);
|
||||
// All required fields should exist in properties
|
||||
for (const req of tool.inputSchema.required) {
|
||||
expect(tool.inputSchema.properties).toHaveProperty(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('Tools Structure Validation', () => {
|
||||
describe('Documents Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(documentsTools.length).toBeGreaterThanOrEqual(15);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of documentsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
|
||||
it('should include core document operations', () => {
|
||||
const names = documentsTools.map(t => t.name);
|
||||
expect(names).toContain('list_documents');
|
||||
expect(names).toContain('get_document');
|
||||
expect(names).toContain('create_document');
|
||||
expect(names).toContain('update_document');
|
||||
expect(names).toContain('delete_document');
|
||||
expect(names).toContain('search_documents');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Collections Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(collectionsTools.length).toBeGreaterThanOrEqual(10);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of collectionsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
|
||||
it('should include core collection operations', () => {
|
||||
const names = collectionsTools.map(t => t.name);
|
||||
expect(names).toContain('list_collections');
|
||||
expect(names).toContain('get_collection');
|
||||
expect(names).toContain('create_collection');
|
||||
expect(names).toContain('update_collection');
|
||||
expect(names).toContain('delete_collection');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Users Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(usersTools.length).toBeGreaterThanOrEqual(5);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of usersTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
|
||||
it('should include core user operations', () => {
|
||||
const names = usersTools.map(t => t.name);
|
||||
expect(names).toContain('outline_list_users');
|
||||
expect(names).toContain('outline_get_user');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Groups Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(groupsTools.length).toBeGreaterThanOrEqual(5);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of groupsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Comments Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(commentsTools.length).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of commentsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Shares Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(sharesTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of sharesTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Revisions Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(revisionsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of revisionsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Events Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(eventsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of eventsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Attachments Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(attachmentsTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of attachmentsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Operations Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(fileOperationsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of fileOperationsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('OAuth Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(oauthTools.length).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of oauthTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Auth Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(authTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of authTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Stars Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(starsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of starsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pins Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(pinsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of pinsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Views Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(viewsTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of viewsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Reactions Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(reactionsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of reactionsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('API Keys Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(apiKeysTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of apiKeysTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Webhooks Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(webhooksTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of webhooksTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Backlinks Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(backlinksTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of backlinksTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search Queries Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(searchQueriesTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of searchQueriesTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Teams Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(teamsTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of teamsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Integrations Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(integrationsTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of integrationsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Notifications Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(notificationsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of notificationsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Subscriptions Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(subscriptionsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of subscriptionsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Templates Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(templatesTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of templatesTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Imports Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(importsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of importsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Emojis Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(emojisTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of emojisTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Permissions Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(userPermissionsTools.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of userPermissionsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bulk Operations Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(bulkOperationsTools.length).toBeGreaterThanOrEqual(4);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of bulkOperationsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Advanced Search Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(advancedSearchTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of advancedSearchTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analytics Tools', () => {
|
||||
it('should export correct number of tools', () => {
|
||||
expect(analyticsTools.length).toBeGreaterThanOrEqual(3);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of analyticsTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Export/Import Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(exportImportTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of exportImportTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Desk Sync Tools', () => {
|
||||
it('should export tools', () => {
|
||||
expect(deskSyncTools.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should have valid structure for all tools', () => {
|
||||
for (const tool of deskSyncTools) {
|
||||
validateTool(tool);
|
||||
validateRequiredProps(tool);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Total Tools Count', () => {
|
||||
it('should have at least 164 tools total', () => {
|
||||
const allTools = [
|
||||
...documentsTools,
|
||||
...collectionsTools,
|
||||
...usersTools,
|
||||
...groupsTools,
|
||||
...commentsTools,
|
||||
...sharesTools,
|
||||
...revisionsTools,
|
||||
...eventsTools,
|
||||
...attachmentsTools,
|
||||
...fileOperationsTools,
|
||||
...oauthTools,
|
||||
...authTools,
|
||||
...starsTools,
|
||||
...pinsTools,
|
||||
...viewsTools,
|
||||
...reactionsTools,
|
||||
...apiKeysTools,
|
||||
...webhooksTools,
|
||||
...backlinksTools,
|
||||
...searchQueriesTools,
|
||||
...teamsTools,
|
||||
...integrationsTools,
|
||||
...notificationsTools,
|
||||
...subscriptionsTools,
|
||||
...templatesTools,
|
||||
...importsTools,
|
||||
...emojisTools,
|
||||
...userPermissionsTools,
|
||||
...bulkOperationsTools,
|
||||
...advancedSearchTools,
|
||||
...analyticsTools,
|
||||
...exportImportTools,
|
||||
...deskSyncTools
|
||||
];
|
||||
|
||||
expect(allTools.length).toBeGreaterThanOrEqual(164);
|
||||
});
|
||||
|
||||
it('should have unique tool names', () => {
|
||||
const allTools = [
|
||||
...documentsTools,
|
||||
...collectionsTools,
|
||||
...usersTools,
|
||||
...groupsTools,
|
||||
...commentsTools,
|
||||
...sharesTools,
|
||||
...revisionsTools,
|
||||
...eventsTools,
|
||||
...attachmentsTools,
|
||||
...fileOperationsTools,
|
||||
...oauthTools,
|
||||
...authTools,
|
||||
...starsTools,
|
||||
...pinsTools,
|
||||
...viewsTools,
|
||||
...reactionsTools,
|
||||
...apiKeysTools,
|
||||
...webhooksTools,
|
||||
...backlinksTools,
|
||||
...searchQueriesTools,
|
||||
...teamsTools,
|
||||
...integrationsTools,
|
||||
...notificationsTools,
|
||||
...subscriptionsTools,
|
||||
...templatesTools,
|
||||
...importsTools,
|
||||
...emojisTools,
|
||||
...userPermissionsTools,
|
||||
...bulkOperationsTools,
|
||||
...advancedSearchTools,
|
||||
...analyticsTools,
|
||||
...exportImportTools,
|
||||
...deskSyncTools
|
||||
];
|
||||
|
||||
const names = allTools.map(t => t.name);
|
||||
const uniqueNames = [...new Set(names)];
|
||||
expect(names.length).toBe(uniqueNames.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user