Some checks failed
Deploy Application / deploy (push) Has been cancelled
265 lines
8.5 KiB
JavaScript
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');
|
|
});
|
|
});
|
|
});
|
|
|