Skip to main content
Glama
template-manager.test.ts11.8 kB
import { TemplateManager } from '../template-manager'; describe('TemplateManager', () => { let templateManager: TemplateManager; beforeEach(() => { templateManager = new TemplateManager(); }); describe('getAllTemplates', () => { it('should return all available templates', () => { const templates = templateManager.getAllTemplates(); expect(templates.length).toBeGreaterThanOrEqual(11); expect(templates).toEqual( expect.arrayContaining([ expect.objectContaining({ name: 'nodejs-typescript' }), expect.objectContaining({ name: 'python' }), expect.objectContaining({ name: 'go' }), expect.objectContaining({ name: 'rust' }), expect.objectContaining({ name: 'java' }), expect.objectContaining({ name: 'php' }), expect.objectContaining({ name: 'ruby' }), expect.objectContaining({ name: 'react' }), expect.objectContaining({ name: 'mean-stack' }), expect.objectContaining({ name: 'docker-compose' }), expect.objectContaining({ name: 'universal' }) ]) ); }); it('should return templates with all required properties', () => { const templates = templateManager.getAllTemplates(); for (const template of templates) { expect(template).toHaveProperty('name'); expect(template).toHaveProperty('description'); expect(template).toHaveProperty('languages'); expect(template).toHaveProperty('frameworks'); expect(template).toHaveProperty('features'); expect(template).toHaveProperty('category'); expect(template).toHaveProperty('config'); expect(typeof template.name).toBe('string'); expect(typeof template.description).toBe('string'); expect(Array.isArray(template.languages)).toBe(true); expect(Array.isArray(template.frameworks)).toBe(true); expect(Array.isArray(template.features)).toBe(true); expect(typeof template.category).toBe('string'); expect(typeof template.config).toBe('object'); } }); }); describe('getTemplates with filters', () => { it('should filter templates by category', () => { const backendTemplates = templateManager.getTemplates({ category: 'backend' }); expect(backendTemplates.length).toBeGreaterThan(0); for (const template of backendTemplates) { expect(template.category).toBe('backend'); } }); it('should filter templates by language', () => { const jsTemplates = templateManager.getTemplates({ language: 'javascript' }); expect(jsTemplates.length).toBeGreaterThan(0); for (const template of jsTemplates) { expect(template.languages).toContain('javascript'); } }); it('should filter templates by framework', () => { const reactTemplates = templateManager.getTemplates({ framework: 'react' }); expect(reactTemplates.length).toBeGreaterThan(0); for (const template of reactTemplates) { expect(template.frameworks).toContain('react'); } }); it('should return empty array for non-existent category', () => { const templates = templateManager.getTemplates({ category: 'non-existent' }); expect(templates).toEqual([]); }); it('should handle multiple filters', () => { const templates = templateManager.getTemplates({ category: 'backend', language: 'python' }); for (const template of templates) { expect(template.category).toBe('backend'); expect(template.languages).toContain('python'); } }); }); describe('findBestMatch', () => { it('should find best match for React TypeScript', () => { const match = templateManager.findBestMatch( ['javascript', 'typescript'], ['react'] ); expect(match).not.toBeNull(); expect(match?.name).toBe('react'); }); it('should find best match for Python Django', () => { const match = templateManager.findBestMatch( ['python'], ['django'] ); expect(match).not.toBeNull(); expect(match?.name).toBe('python'); }); it('should find best match for Go', () => { const match = templateManager.findBestMatch( ['go'], [] ); expect(match).not.toBeNull(); expect(match?.name).toBe('go'); }); it('should prefer specific templates over universal', () => { const match = templateManager.findBestMatch( ['rust'], ['actix'] ); expect(match).not.toBeNull(); expect(match?.name).toBe('rust'); expect(match?.name).not.toBe('universal'); }); it('should return universal template when no specific match found', () => { const match = templateManager.findBestMatch( ['unknown-language'], ['unknown-framework'] ); expect(match).not.toBeNull(); expect(match?.name).toBe('universal'); }); it('should handle empty arrays', () => { const match = templateManager.findBestMatch([], []); expect(match).not.toBeNull(); expect(match?.name).toBe('universal'); }); it('should score language matches higher than framework matches', () => { // This test ensures that language detection is prioritized const jsMatch = templateManager.findBestMatch(['javascript'], []); const reactMatch = templateManager.findBestMatch(['javascript'], ['react']); expect(jsMatch).not.toBeNull(); expect(reactMatch).not.toBeNull(); expect(reactMatch?.name).toBe('react'); // Should pick React for JS + React }); }); describe('getTemplate', () => { it('should return template by name', () => { const template = templateManager.getTemplate('nodejs-typescript'); expect(template).not.toBeNull(); expect(template?.name).toBe('nodejs-typescript'); expect(template?.languages).toContain('javascript'); expect(template?.languages).toContain('typescript'); }); it('should return null for non-existent template', () => { const template = templateManager.getTemplate('non-existent'); expect(template).toBeNull(); }); it('should return template with valid config', () => { const template = templateManager.getTemplate('python'); expect(template).not.toBeNull(); expect(template?.config).toHaveProperty('name'); expect(template?.config).toHaveProperty('image'); const config = template?.config as Record<string, unknown>; expect(typeof config.name).toBe('string'); expect(typeof config.image).toBe('string'); }); }); describe('getCategories', () => { it('should return all available categories', () => { const categories = templateManager.getCategories(); expect(categories).toContain('backend'); expect(categories).toContain('frontend'); expect(categories).toContain('fullstack'); expect(categories).toContain('universal'); expect(categories.length).toBeGreaterThan(0); }); it('should return sorted categories', () => { const categories = templateManager.getCategories(); const sortedCategories = [...categories].sort(); expect(categories).toEqual(sortedCategories); }); it('should not have duplicate categories', () => { const categories = templateManager.getCategories(); const uniqueCategories = [...new Set(categories)]; expect(categories).toEqual(uniqueCategories); }); }); describe('getTemplateSummary', () => { it('should return template summary with required fields', () => { const template = templateManager.getTemplate('react'); expect(template).not.toBeNull(); const summary = templateManager.getTemplateSummary(template!); expect(summary).toHaveProperty('name'); expect(summary).toHaveProperty('description'); expect(summary).toHaveProperty('languages'); expect(summary).toHaveProperty('frameworks'); expect(summary).toHaveProperty('features'); expect(summary).toHaveProperty('category'); expect(summary.name).toBe('react'); expect(Array.isArray(summary.languages)).toBe(true); expect(Array.isArray(summary.frameworks)).toBe(true); expect(Array.isArray(summary.features)).toBe(true); }); it('should not include config in summary', () => { const template = templateManager.getTemplate('nodejs-typescript'); expect(template).not.toBeNull(); const summary = templateManager.getTemplateSummary(template!); expect(summary).not.toHaveProperty('config'); }); }); describe('template configurations', () => { it('should have valid Node.js TypeScript configuration', () => { const template = templateManager.getTemplate('nodejs-typescript'); expect(template).not.toBeNull(); const config = template?.config as Record<string, unknown>; expect(config.image).toContain('typescript-node'); expect(config.forwardPorts).toContain(3000); const customizations = config.customizations as Record<string, unknown>; const vscode = customizations.vscode as Record<string, unknown>; const extensions = vscode.extensions as string[]; expect(extensions).toContain('ms-vscode.vscode-typescript-next'); }); it('should have valid Python configuration', () => { const template = templateManager.getTemplate('python'); expect(template).not.toBeNull(); const config = template?.config as Record<string, unknown>; expect(config.image).toContain('python'); expect(config.forwardPorts).toContain(8000); const customizations = config.customizations as Record<string, unknown>; const vscode = customizations.vscode as Record<string, unknown>; const extensions = vscode.extensions as string[]; expect(extensions).toContain('ms-python.python'); }); it('should have valid React configuration', () => { const template = templateManager.getTemplate('react'); expect(template).not.toBeNull(); const config = template?.config as Record<string, unknown>; expect(config.image).toContain('typescript-node'); const ports = config.forwardPorts as number[]; expect(ports).toContain(3000); expect(ports).toContain(5173); // Vite dev server const customizations = config.customizations as Record<string, unknown>; const vscode = customizations.vscode as Record<string, unknown>; const extensions = vscode.extensions as string[]; expect(extensions).toContain('bradlc.vscode-tailwindcss'); }); it('should have valid Go configuration', () => { const template = templateManager.getTemplate('go'); expect(template).not.toBeNull(); const config = template?.config as Record<string, unknown>; expect(config.image).toContain('go'); expect(config.forwardPorts).toContain(8080); expect(config.postCreateCommand).toBe('go mod download'); }); it('should have valid universal configuration', () => { const template = templateManager.getTemplate('universal'); expect(template).not.toBeNull(); const config = template?.config as Record<string, unknown>; expect(config.image).toContain('universal'); const features = config.features as Record<string, unknown>; expect(Object.keys(features)).toContain('ghcr.io/devcontainers/features/docker-in-docker:2'); expect(Object.keys(features)).toContain('ghcr.io/devcontainers/features/git:1'); }); }); });

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/Siddhant-K-code/mcp-devcontainer'

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