Skip to main content
Glama
background-controls.test.ts10.9 kB
/** * Tests for Background Controls System */ import { JSDOM } from 'jsdom'; import { registerBackgroundControlHelpers, generateBackgroundControlsCSS, defaultBackgroundConfig, } from '../../src/visualization/background-controls'; import Handlebars from 'handlebars'; describe('Background Controls', () => { let dom: JSDOM; let document: Document; let window: Window; beforeEach(() => { // Set up DOM environment dom = new JSDOM( ` <!DOCTYPE html> <html> <head><title>Test</title></head> <body></body> </html> `, { url: 'http://localhost', pretendToBeVisual: true, } ); document = dom.window.document; window = dom.window as unknown as Window; // Make DOM available globally for tests global.document = document; (global as any).window = window; // Register helpers registerBackgroundControlHelpers(); }); afterEach(() => { dom.window.close(); }); describe('Handlebars Helpers', () => { test('backgroundToggle helper generates toggle button', () => { const template = Handlebars.compile('{{backgroundToggle}}'); const html = template({}); expect(html).toContain('id="background-toggle-btn"'); expect(html).toContain( 'aria-label="Toggle between light and dark backgrounds"' ); expect(html).toContain('data-keyboard-shortcut="Alt+T"'); expect(html).toContain('☀️'); // Light icon expect(html).toContain('🌙'); // Dark icon }); test('backgroundColorPicker helper generates color picker', () => { const template = Handlebars.compile('{{backgroundColorPicker}}'); const html = template({}); expect(html).toContain('id="color-picker-toggle"'); expect(html).toContain('id="color-picker-panel"'); expect(html).toContain('id="custom-color-input"'); expect(html).toContain('preset-color-btn'); expect(html).toContain('role="dialog"'); }); test('accessibilityWarning helper generates warning element', () => { const template = Handlebars.compile('{{accessibilityWarning}}'); const html = template({}); expect(html).toContain('id="accessibility-warning"'); expect(html).toContain('role="alert"'); expect(html).toContain('aria-live="polite"'); expect(html).toContain('⚠️'); // Warning icon }); test('backgroundControls helper generates complete controls', () => { const template = Handlebars.compile('{{backgroundControls}}'); const html = template({}); expect(html).toContain('class="background-controls'); expect(html).toContain('role="toolbar"'); expect(html).toContain('aria-label="Background controls"'); expect(html).toContain('background-toggle-btn'); expect(html).toContain('color-picker-toggle'); }); test('backgroundControls respects configuration', () => { const config = { enableToggle: false, enableColorPicker: true, position: 'top-left' as const, }; const template = Handlebars.compile('{{backgroundControls this}}'); const html = template(config); expect(html).not.toContain('background-toggle-btn'); expect(html).toContain('color-picker-toggle'); expect(html).toContain('controls-top-left'); }); test('shouldIncludeBackgroundControls helper works correctly', () => { const template = Handlebars.compile( '{{#if (shouldIncludeBackgroundControls options.backgroundControls)}}YES{{else}}NO{{/if}}' ); // Should include when toggle or picker is enabled let html = template({ options: { backgroundControls: { enableToggle: true, enableColorPicker: false }, }, }); expect(html).toBe('YES'); // Should not include when both are disabled html = template({ options: { backgroundControls: { enableToggle: false, enableColorPicker: false }, }, }); expect(html).toBe('NO'); }); }); describe('CSS Generation', () => { test('generateBackgroundControlsCSS returns valid CSS', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('.background-controls'); expect(css).toContain('.background-control-btn'); expect(css).toContain('.color-picker-panel'); expect(css).toContain('.accessibility-warning'); expect(css).toContain('@media (max-width: 768px)'); expect(css).toContain('@media (prefers-contrast: high)'); expect(css).toContain('@media (prefers-reduced-motion: reduce)'); }); test('CSS includes all positioning classes', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('.controls-top-right'); expect(css).toContain('.controls-top-left'); expect(css).toContain('.controls-bottom-right'); expect(css).toContain('.controls-bottom-left'); }); test('CSS includes accessibility features', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('.sr-only'); expect(css).toContain('prefers-contrast: high'); expect(css).toContain('prefers-reduced-motion: reduce'); expect(css).toContain('outline:'); expect(css).toContain('focus'); }); test('CSS includes dark mode support', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('[data-background-theme="dark"]'); expect(css).toContain('--bg-controls-default'); expect(css).toContain('--bg-controls-accent'); }); }); describe('Configuration', () => { test('defaultBackgroundConfig has expected properties', () => { expect(defaultBackgroundConfig.enableToggle).toBe(true); expect(defaultBackgroundConfig.enableColorPicker).toBe(true); expect(defaultBackgroundConfig.defaultBackground).toBe('light'); expect(defaultBackgroundConfig.position).toBe('top-right'); expect(defaultBackgroundConfig.accessibility.keyboardNavigation).toBe( true ); expect(defaultBackgroundConfig.accessibility.screenReaderSupport).toBe( true ); expect(defaultBackgroundConfig.customColors).toHaveLength(6); }); test('custom configuration merges with defaults', () => { const customConfig = { enableToggle: false, position: 'bottom-left' as const, }; const template = Handlebars.compile('{{backgroundControls this}}'); const html = template(customConfig); expect(html).toContain('controls-bottom-left'); expect(html).not.toContain('background-toggle-btn'); expect(html).toContain('color-picker-toggle'); // Should still be enabled by default }); }); describe('Accessibility Features', () => { test('controls have proper ARIA attributes', () => { const template = Handlebars.compile('{{backgroundControls}}'); const html = template({}); expect(html).toContain('role="toolbar"'); expect(html).toContain('aria-label="Background controls"'); expect(html).toContain('aria-expanded="false"'); expect(html).toContain('aria-controls="color-picker-panel"'); expect(html).toContain('aria-hidden="true"'); }); test('keyboard shortcuts are documented', () => { const template = Handlebars.compile('{{backgroundControls}}'); const html = template({}); expect(html).toContain('Alt+T'); expect(html).toContain('Alt+C'); expect(html).toContain('Escape'); expect(html).toContain('Tab'); }); test('screen reader content is properly hidden', () => { const template = Handlebars.compile('{{backgroundControls}}'); const html = template({}); expect(html).toContain('class="sr-only"'); expect(html).toContain('aria-hidden="true"'); }); test('color picker has proper dialog structure', () => { const template = Handlebars.compile('{{backgroundColorPicker}}'); const html = template({}); expect(html).toContain('role="dialog"'); expect(html).toContain('aria-label="Background color selection"'); expect(html).toContain('id="color-picker-title"'); expect(html).toContain('role="group"'); }); }); describe('Responsive Design', () => { test('CSS includes mobile responsive styles', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('@media (max-width: 768px)'); expect(css).toMatch(/width:\s*2\.25rem/); expect(css).toMatch(/height:\s*2\.25rem/); }); test('color picker adjusts for mobile', () => { const css = generateBackgroundControlsCSS(); expect(css).toContain('width: 18rem'); expect(css).toContain('right: -1rem'); }); }); describe('Color Validation', () => { test('preset colors are valid hex colors', () => { defaultBackgroundConfig.customColors.forEach(color => { expect(color).toMatch(/^#[0-9A-Fa-f]{6}$/); }); }); test('default colors provide good contrast options', () => { const colors = defaultBackgroundConfig.customColors; // Should include light colors expect(colors.some(c => c === '#ffffff' || c === '#f8f9fa')).toBe(true); // Should include dark colors expect(colors.some(c => c === '#1a1a1a' || c === '#212529')).toBe(true); }); }); describe('Integration', () => { test('controls integrate with existing HTML structure', () => { const template = Handlebars.compile(` <div class="visualization-container"> {{backgroundControls}} <main>Content</main> </div> `); const html = template({}); expect(html).toContain('visualization-container'); expect(html).toContain('background-controls'); expect(html).toContain('<main>Content</main>'); }); test('CSS custom properties are properly defined', () => { const template = Handlebars.compile('{{backgroundControlsCSS}}'); const css = template({}); expect(css).toContain('--bg-controls-position'); expect(css).toContain('--bg-controls-default'); expect(css).toContain('--bg-controls-accent'); expect(css).toContain('--bg-controls-text'); }); }); describe('Error Handling', () => { test('helpers handle missing configuration gracefully', () => { const template = Handlebars.compile('{{backgroundToggle undefined}}'); const html = template({}); // Should still generate toggle button with defaults expect(html).toContain('background-toggle-btn'); }); test('helpers handle invalid configuration gracefully', () => { const template = Handlebars.compile('{{backgroundControls this}}'); const html = template({ enableToggle: 'invalid' }); // Should still generate controls expect(html).toContain('background-controls'); }); }); });

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/keyurgolani/ColorMcp'

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