Files
michaelschiemer/tests/JavaScript/PopoverManager.test.js
2025-11-24 21:28:25 +01:00

265 lines
8.5 KiB
JavaScript

/**
* Tests for PopoverManager
*/
import { PopoverManager } from '../../resources/js/modules/livecomponent/PopoverManager.js';
describe('PopoverManager', () => {
let manager;
let anchor;
beforeEach(() => {
// Create anchor element for testing
anchor = document.createElement('button');
anchor.id = 'test-anchor';
anchor.textContent = 'Anchor';
document.body.appendChild(anchor);
manager = new PopoverManager();
});
afterEach(() => {
if (manager) {
manager.destroy();
}
if (anchor && anchor.parentNode) {
anchor.parentNode.removeChild(anchor);
}
// Clean up any remaining popovers
document.querySelectorAll('.livecomponent-popover').forEach(el => el.remove());
});
describe('show', () => {
it('should create and show popover', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
content: 'Test content',
position: 'top'
});
expect(popover).toBeDefined();
expect(popover.element).toBeDefined();
const popoverElement = document.querySelector('.livecomponent-popover');
expect(popoverElement).toBeTruthy();
});
it('should return null when anchorId is missing', () => {
const popover = manager.show('test-popover', {
content: 'Test content'
});
expect(popover).toBeNull();
});
it('should return null when anchor element not found', () => {
const popover = manager.show('test-popover', {
anchorId: 'non-existent',
content: 'Test content'
});
expect(popover).toBeNull();
});
it('should position popover relative to anchor', () => {
anchor.style.position = 'absolute';
anchor.style.top = '100px';
anchor.style.left = '200px';
anchor.style.width = '100px';
anchor.style.height = '50px';
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
content: 'Test',
position: 'top',
offset: 10
});
expect(popover).toBeDefined();
const popoverElement = popover.element;
// Check that popover is positioned
expect(popoverElement.style.position).toBe('fixed');
expect(popoverElement.style.top).toBeTruthy();
expect(popoverElement.style.left).toBeTruthy();
});
it('should include title when provided', () => {
manager.show('test-popover', {
anchorId: 'test-anchor',
title: 'Test Title',
content: 'Test content'
});
const titleElement = document.querySelector('.popover-title');
expect(titleElement).toBeTruthy();
expect(titleElement.textContent).toBe('Test Title');
});
it('should include arrow when showArrow is true', () => {
manager.show('test-popover', {
anchorId: 'test-anchor',
showArrow: true,
content: 'Test'
});
const arrow = document.querySelector('.popover-arrow');
expect(arrow).toBeTruthy();
});
it('should not include arrow when showArrow is false', () => {
manager.show('test-popover', {
anchorId: 'test-anchor',
showArrow: false,
content: 'Test'
});
const arrow = document.querySelector('.popover-arrow');
expect(arrow).toBeFalsy();
});
});
describe('hide', () => {
it('should hide popover', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
content: 'Test'
});
expect(manager.popovers.has('test-popover')).toBe(true);
manager.hide('test-popover');
expect(manager.popovers.has('test-popover')).toBe(false);
});
it('should handle hiding non-existent popover gracefully', () => {
expect(() => {
manager.hide('non-existent');
}).not.toThrow();
});
});
describe('position calculation', () => {
beforeEach(() => {
anchor.style.position = 'absolute';
anchor.style.top = '100px';
anchor.style.left = '200px';
anchor.style.width = '100px';
anchor.style.height = '50px';
});
it('should position popover on top', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'top',
offset: 10
});
const rect = popover.element.getBoundingClientRect();
const anchorRect = anchor.getBoundingClientRect();
expect(rect.bottom).toBeLessThan(anchorRect.top);
});
it('should position popover on bottom', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'bottom',
offset: 10
});
const rect = popover.element.getBoundingClientRect();
const anchorRect = anchor.getBoundingClientRect();
expect(rect.top).toBeGreaterThan(anchorRect.bottom);
});
it('should position popover on left', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'left',
offset: 10
});
const rect = popover.element.getBoundingClientRect();
const anchorRect = anchor.getBoundingClientRect();
expect(rect.right).toBeLessThan(anchorRect.left);
});
it('should position popover on right', () => {
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'right',
offset: 10
});
const rect = popover.element.getBoundingClientRect();
const anchorRect = anchor.getBoundingClientRect();
expect(rect.left).toBeGreaterThan(anchorRect.right);
});
});
describe('auto positioning', () => {
it('should choose best position when position is auto', () => {
anchor.style.position = 'absolute';
anchor.style.top = '50px';
anchor.style.left = '50px';
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'auto',
offset: 10
});
expect(popover).toBeDefined();
// Should position successfully
expect(popover.element.style.position).toBe('fixed');
});
});
describe('viewport boundary detection', () => {
it('should keep popover within viewport', () => {
// Position anchor near top-left corner
anchor.style.position = 'absolute';
anchor.style.top = '10px';
anchor.style.left = '10px';
const popover = manager.show('test-popover', {
anchorId: 'test-anchor',
position: 'top',
offset: 100 // Large offset that would push outside viewport
});
const rect = popover.element.getBoundingClientRect();
expect(rect.top).toBeGreaterThanOrEqual(0);
expect(rect.left).toBeGreaterThanOrEqual(0);
});
});
describe('destroy', () => {
it('should cleanup all popovers', () => {
manager.show('popover-1', { anchorId: 'test-anchor', content: 'Test 1' });
manager.show('popover-2', { anchorId: 'test-anchor', content: 'Test 2' });
expect(manager.popovers.size).toBeGreaterThan(0);
manager.destroy();
expect(manager.popovers.size).toBe(0);
});
});
describe('Popover API detection', () => {
it('should detect Popover API support', () => {
// This test checks if the manager correctly detects API support
// Actual behavior depends on browser environment
expect(manager.usePopoverAPI).toBeDefined();
expect(typeof manager.usePopoverAPI).toBe('boolean');
});
});
});