- Updated n8n from 1.100.1 to 1.101.1 - Updated n8n-core from 1.99.0 to 1.100.0 - Updated n8n-workflow from 1.97.0 to 1.98.0 - Updated @n8n/n8n-nodes-langchain from 1.99.0 to 1.100.1 - Rebuilt node database with 528 nodes - All validation tests passing - Bumped version to 2.7.12 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
162 lines
4.7 KiB
JavaScript
162 lines
4.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { N8NDocumentationMCPServer } from '../src/mcp/server';
|
|
|
|
interface SearchTest {
|
|
query: string;
|
|
mode?: 'OR' | 'AND' | 'FUZZY';
|
|
description: string;
|
|
expectedTop?: string[];
|
|
}
|
|
|
|
async function testFTS5Search() {
|
|
console.log('Testing FTS5 Search Implementation\n');
|
|
console.log('='.repeat(50));
|
|
|
|
const server = new N8NDocumentationMCPServer();
|
|
|
|
// Wait for initialization
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
const tests: SearchTest[] = [
|
|
{
|
|
query: 'webhook',
|
|
description: 'Basic search - should return Webhook node first',
|
|
expectedTop: ['nodes-base.webhook']
|
|
},
|
|
{
|
|
query: 'http call',
|
|
description: 'Multi-word OR search - should return HTTP Request node first',
|
|
expectedTop: ['nodes-base.httpRequest']
|
|
},
|
|
{
|
|
query: 'send message',
|
|
mode: 'AND',
|
|
description: 'AND mode - only nodes with both "send" AND "message"',
|
|
},
|
|
{
|
|
query: 'slak',
|
|
mode: 'FUZZY',
|
|
description: 'FUZZY mode - should find Slack despite typo',
|
|
expectedTop: ['nodes-base.slack']
|
|
},
|
|
{
|
|
query: '"email trigger"',
|
|
description: 'Exact phrase search with quotes',
|
|
},
|
|
{
|
|
query: 'http',
|
|
mode: 'FUZZY',
|
|
description: 'FUZZY mode with common term',
|
|
expectedTop: ['nodes-base.httpRequest']
|
|
},
|
|
{
|
|
query: 'google sheets',
|
|
mode: 'AND',
|
|
description: 'AND mode - find Google Sheets node',
|
|
expectedTop: ['nodes-base.googleSheets']
|
|
},
|
|
{
|
|
query: 'webhook trigger',
|
|
mode: 'OR',
|
|
description: 'OR mode - should return nodes with either word',
|
|
}
|
|
];
|
|
|
|
let passedTests = 0;
|
|
let failedTests = 0;
|
|
|
|
for (const test of tests) {
|
|
console.log(`\n${test.description}`);
|
|
console.log(`Query: "${test.query}" (Mode: ${test.mode || 'OR'})`);
|
|
console.log('-'.repeat(40));
|
|
|
|
try {
|
|
const results = await server.executeTool('search_nodes', {
|
|
query: test.query,
|
|
mode: test.mode,
|
|
limit: 5
|
|
});
|
|
|
|
if (!results.results || results.results.length === 0) {
|
|
console.log('❌ No results found');
|
|
if (test.expectedTop) {
|
|
failedTests++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
console.log(`Found ${results.results.length} results:`);
|
|
results.results.forEach((node: any, index: number) => {
|
|
const marker = test.expectedTop && index === 0 && test.expectedTop.includes(node.nodeType) ? ' ✅' : '';
|
|
console.log(` ${index + 1}. ${node.nodeType} - ${node.displayName}${marker}`);
|
|
});
|
|
|
|
// Verify search mode is returned
|
|
if (results.mode) {
|
|
console.log(`\nSearch mode used: ${results.mode}`);
|
|
}
|
|
|
|
// Check expected results
|
|
if (test.expectedTop) {
|
|
const firstResult = results.results[0];
|
|
if (test.expectedTop.includes(firstResult.nodeType)) {
|
|
console.log('✅ Test passed: Expected node found at top');
|
|
passedTests++;
|
|
} else {
|
|
console.log('❌ Test failed: Expected node not at top');
|
|
console.log(` Expected: ${test.expectedTop.join(' or ')}`);
|
|
console.log(` Got: ${firstResult.nodeType}`);
|
|
failedTests++;
|
|
}
|
|
} else {
|
|
// Test without specific expectations
|
|
console.log('✅ Search completed successfully');
|
|
passedTests++;
|
|
}
|
|
|
|
} catch (error) {
|
|
console.log(`❌ Error: ${error}`);
|
|
failedTests++;
|
|
}
|
|
}
|
|
|
|
console.log('\n' + '='.repeat(50));
|
|
console.log('FTS5 Feature Tests');
|
|
console.log('='.repeat(50));
|
|
|
|
// Test FTS5-specific features
|
|
console.log('\n1. Testing relevance ranking...');
|
|
const webhookResult = await server.executeTool('search_nodes', {
|
|
query: 'webhook',
|
|
limit: 10
|
|
});
|
|
console.log(` Primary "Webhook" node position: #${webhookResult.results.findIndex((r: any) => r.nodeType === 'nodes-base.webhook') + 1}`);
|
|
|
|
console.log('\n2. Testing fuzzy matching with various typos...');
|
|
const typoTests = ['webook', 'htpp', 'slck', 'googl sheet'];
|
|
for (const typo of typoTests) {
|
|
const result = await server.executeTool('search_nodes', {
|
|
query: typo,
|
|
mode: 'FUZZY',
|
|
limit: 1
|
|
});
|
|
if (result.results.length > 0) {
|
|
console.log(` "${typo}" → ${result.results[0].displayName} ✅`);
|
|
} else {
|
|
console.log(` "${typo}" → No results ❌`);
|
|
}
|
|
}
|
|
|
|
console.log('\n' + '='.repeat(50));
|
|
console.log(`Test Summary: ${passedTests} passed, ${failedTests} failed`);
|
|
console.log('='.repeat(50));
|
|
|
|
process.exit(failedTests > 0 ? 1 : 0);
|
|
}
|
|
|
|
// Run tests
|
|
testFTS5Search().catch(error => {
|
|
console.error('Test execution failed:', error);
|
|
process.exit(1);
|
|
}); |