mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 05:23:08 +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",
|
"dotenv": "^16.5.0",
|
||||||
"sql.js": "^1.13.0",
|
"sql.js": "^1.13.0",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"axios": "^1.7.7"
|
"axios": "^1.7.7",
|
||||||
|
"openai": "^4.77.0",
|
||||||
|
"zod": "^3.24.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
|
|||||||
@@ -809,4 +809,85 @@ export class TemplateRepository {
|
|||||||
const results = this.db.prepare(query).all(complexity, limit, offset) as StoredTemplate[];
|
const results = this.db.prepare(query).all(complexity, limit, offset) as StoredTemplate[];
|
||||||
return results.map(t => this.decompressWorkflow(t));
|
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({
|
expect(result).toEqual({
|
||||||
items: [
|
items: [
|
||||||
{ id: 1, name: 'Template A', views: 200, nodeCount: 2 },
|
{ id: 1, name: 'Template A', description: 'Description for template 1', views: 200, nodeCount: 2 },
|
||||||
{ id: 2, name: 'Template B', views: 150, nodeCount: 1 }
|
{ id: 2, name: 'Template B', description: 'Description for template 2', views: 150, nodeCount: 1 }
|
||||||
],
|
],
|
||||||
total: 50,
|
total: 50,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
|||||||
@@ -370,13 +370,20 @@ describe('MetadataGenerator', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should handle network timeouts gracefully in generateSingle', async () => {
|
it('should handle network timeouts gracefully in generateSingle', async () => {
|
||||||
// Mock OpenAI to simulate timeout
|
// Create a new generator with mocked OpenAI client
|
||||||
const mockClient = generator['client'];
|
const mockClient = {
|
||||||
const originalCreate = mockClient.chat.completions.create;
|
chat: {
|
||||||
|
completions: {
|
||||||
|
create: vi.fn().mockRejectedValue(new Error('Request timed out'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
mockClient.chat.completions.create = vi.fn().mockRejectedValue(
|
// Override the client property using Object.defineProperty
|
||||||
new Error('Request timed out')
|
Object.defineProperty(generator, 'client', {
|
||||||
);
|
value: mockClient,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
|
||||||
const template: MetadataRequest = {
|
const template: MetadataRequest = {
|
||||||
templateId: 555,
|
templateId: 555,
|
||||||
@@ -388,9 +395,6 @@ describe('MetadataGenerator', () => {
|
|||||||
|
|
||||||
// Should return default metadata instead of throwing
|
// Should return default metadata instead of throwing
|
||||||
expect(result).toEqual(generator['getDefaultMetadata']());
|
expect(result).toEqual(generator['getDefaultMetadata']());
|
||||||
|
|
||||||
// Restore original method
|
|
||||||
mockClient.chat.completions.create = originalCreate;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user