mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 13:33:11 +00:00
fix: resolve CI test failures and Docker build issues
- Fix template service tests to include description field - Add missing repository methods for metadata queries - Fix metadata generator test mocking issues - Add missing runtime dependencies (openai, zod) to package.runtime.json - Update test expectations for new template format Fixes CI failures in PR #194 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,9 @@
|
||||
"dotenv": "^16.5.0",
|
||||
"sql.js": "^1.13.0",
|
||||
"uuid": "^10.0.0",
|
||||
"axios": "^1.7.7"
|
||||
"axios": "^1.7.7",
|
||||
"openai": "^4.77.0",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
|
||||
@@ -809,4 +809,85 @@ export class TemplateRepository {
|
||||
const results = this.db.prepare(query).all(complexity, limit, offset) as StoredTemplate[];
|
||||
return results.map(t => this.decompressWorkflow(t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of templates matching metadata search
|
||||
*/
|
||||
getSearchTemplatesByMetadataCount(filters: {
|
||||
category?: string;
|
||||
complexity?: 'simple' | 'medium' | 'complex';
|
||||
maxSetupMinutes?: number;
|
||||
minSetupMinutes?: number;
|
||||
requiredService?: string;
|
||||
targetAudience?: string;
|
||||
}): number {
|
||||
let sql = `
|
||||
SELECT COUNT(*) as count FROM templates
|
||||
WHERE metadata_json IS NOT NULL
|
||||
`;
|
||||
const params: any[] = [];
|
||||
|
||||
if (filters.category) {
|
||||
sql += ` AND json_extract(metadata_json, '$.categories') LIKE ?`;
|
||||
params.push(`%"${filters.category}"%`);
|
||||
}
|
||||
|
||||
if (filters.complexity) {
|
||||
sql += ` AND json_extract(metadata_json, '$.complexity') = ?`;
|
||||
params.push(filters.complexity);
|
||||
}
|
||||
|
||||
if (filters.maxSetupMinutes !== undefined) {
|
||||
sql += ` AND CAST(json_extract(metadata_json, '$.estimated_setup_minutes') AS INTEGER) <= ?`;
|
||||
params.push(filters.maxSetupMinutes);
|
||||
}
|
||||
|
||||
if (filters.minSetupMinutes !== undefined) {
|
||||
sql += ` AND CAST(json_extract(metadata_json, '$.estimated_setup_minutes') AS INTEGER) >= ?`;
|
||||
params.push(filters.minSetupMinutes);
|
||||
}
|
||||
|
||||
if (filters.requiredService) {
|
||||
sql += ` AND json_extract(metadata_json, '$.required_services') LIKE ?`;
|
||||
params.push(`%"${filters.requiredService}"%`);
|
||||
}
|
||||
|
||||
if (filters.targetAudience) {
|
||||
sql += ` AND json_extract(metadata_json, '$.target_audience') LIKE ?`;
|
||||
params.push(`%"${filters.targetAudience}"%`);
|
||||
}
|
||||
|
||||
const result = this.db.prepare(sql).get(...params) as { count: number };
|
||||
return result?.count || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique categories from metadata
|
||||
*/
|
||||
getUniqueCategories(): string[] {
|
||||
const sql = `
|
||||
SELECT DISTINCT value as category
|
||||
FROM templates, json_each(metadata_json, '$.categories')
|
||||
WHERE metadata_json IS NOT NULL
|
||||
ORDER BY category
|
||||
`;
|
||||
|
||||
const results = this.db.prepare(sql).all() as { category: string }[];
|
||||
return results.map(r => r.category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique target audiences from metadata
|
||||
*/
|
||||
getUniqueTargetAudiences(): string[] {
|
||||
const sql = `
|
||||
SELECT DISTINCT value as audience
|
||||
FROM templates, json_each(metadata_json, '$.target_audience')
|
||||
WHERE metadata_json IS NOT NULL
|
||||
ORDER BY audience
|
||||
`;
|
||||
|
||||
const results = this.db.prepare(sql).all() as { audience: string }[];
|
||||
return results.map(r => r.audience);
|
||||
}
|
||||
}
|
||||
@@ -350,8 +350,8 @@ describe('TemplateService', () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
items: [
|
||||
{ id: 1, name: 'Template A', views: 200, nodeCount: 2 },
|
||||
{ id: 2, name: 'Template B', views: 150, nodeCount: 1 }
|
||||
{ id: 1, name: 'Template A', description: 'Description for template 1', views: 200, nodeCount: 2 },
|
||||
{ id: 2, name: 'Template B', description: 'Description for template 2', views: 150, nodeCount: 1 }
|
||||
],
|
||||
total: 50,
|
||||
limit: 10,
|
||||
|
||||
@@ -370,13 +370,20 @@ describe('MetadataGenerator', () => {
|
||||
});
|
||||
|
||||
it('should handle network timeouts gracefully in generateSingle', async () => {
|
||||
// Mock OpenAI to simulate timeout
|
||||
const mockClient = generator['client'];
|
||||
const originalCreate = mockClient.chat.completions.create;
|
||||
// Create a new generator with mocked OpenAI client
|
||||
const mockClient = {
|
||||
chat: {
|
||||
completions: {
|
||||
create: vi.fn().mockRejectedValue(new Error('Request timed out'))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
mockClient.chat.completions.create = vi.fn().mockRejectedValue(
|
||||
new Error('Request timed out')
|
||||
);
|
||||
// Override the client property using Object.defineProperty
|
||||
Object.defineProperty(generator, 'client', {
|
||||
value: mockClient,
|
||||
writable: true
|
||||
});
|
||||
|
||||
const template: MetadataRequest = {
|
||||
templateId: 555,
|
||||
@@ -388,9 +395,6 @@ describe('MetadataGenerator', () => {
|
||||
|
||||
// Should return default metadata instead of throwing
|
||||
expect(result).toEqual(generator['getDefaultMetadata']());
|
||||
|
||||
// Restore original method
|
||||
mockClient.chat.completions.create = originalCreate;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user