import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as deesCatalog from '../ts_web/index.js'; tap.test('tabs indicator positioning - detailed measurements', async () => { // Create tabs element with different length labels const tabsElement = new deesCatalog.DeesAppuiTabs(); tabsElement.tabs = [ { key: 'Home', iconName: 'lucide:home', action: () => {} }, { key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => {} }, { key: 'User Settings', iconName: 'lucide:settings', action: () => {} }, ]; document.body.appendChild(tabsElement); await tabsElement.updateComplete; // Wait for fonts and indicator initialization await new Promise(resolve => setTimeout(resolve, 200)); // Get all elements const shadowRoot = tabsElement.shadowRoot; const wrapper = shadowRoot.querySelector('.tabs-wrapper') as HTMLElement; const container = shadowRoot.querySelector('.tabsContainer') as HTMLElement; const tabs = shadowRoot.querySelectorAll('.tab'); const firstTab = tabs[0] as HTMLElement; const firstContent = firstTab.querySelector('.tab-content') as HTMLElement; const indicator = shadowRoot.querySelector('.tabIndicator') as HTMLElement; // Verify all elements exist expect(wrapper).toBeInstanceOf(HTMLElement); expect(container).toBeInstanceOf(HTMLElement); expect(firstTab).toBeInstanceOf(HTMLElement); expect(firstContent).toBeInstanceOf(HTMLElement); expect(indicator).toBeInstanceOf(HTMLElement); // Get all measurements const wrapperRect = wrapper.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); const tabRect = firstTab.getBoundingClientRect(); const contentRect = firstContent.getBoundingClientRect(); const indicatorRect = indicator.getBoundingClientRect(); console.log('\n=== DETAILED MEASUREMENTS ==='); console.log('Document body left:', document.body.getBoundingClientRect().left); console.log('Wrapper left:', wrapperRect.left); console.log('Container left:', containerRect.left); console.log('Tab left:', tabRect.left); console.log('Content left:', contentRect.left); console.log('Indicator left (actual):', indicatorRect.left); console.log('\n=== RELATIVE POSITIONS ==='); console.log('Container padding (container - wrapper):', containerRect.left - wrapperRect.left); console.log('Tab position in container:', tabRect.left - containerRect.left); console.log('Content position in tab:', contentRect.left - tabRect.left); console.log('Content relative to wrapper:', contentRect.left - wrapperRect.left); console.log('Indicator relative to wrapper (actual):', indicatorRect.left - wrapperRect.left); console.log('\n=== WIDTHS ==='); console.log('Tab width:', tabRect.width); console.log('Content width:', contentRect.width); console.log('Indicator width:', indicatorRect.width); console.log('\n=== STYLES (what we set) ==='); console.log('Indicator style.left:', indicator.style.left); console.log('Indicator style.width:', indicator.style.width); console.log('\n=== CALCULATIONS ==='); const expectedIndicatorLeft = contentRect.left - wrapperRect.left - 4; // We subtract 4 to center const expectedIndicatorWidth = contentRect.width + 8; // We add 8 in the code console.log('Expected indicator left:', expectedIndicatorLeft); console.log('Expected indicator width:', expectedIndicatorWidth); console.log('Actual indicator left (from style):', parseFloat(indicator.style.left)); console.log('Actual indicator width (from style):', parseFloat(indicator.style.width)); console.log('\n=== VISUAL ALIGNMENT CHECK ==='); const tabCenter = tabRect.left + (tabRect.width / 2); const contentCenter = contentRect.left + (contentRect.width / 2); const indicatorCenter = indicatorRect.left + (indicatorRect.width / 2); console.log('Tab center:', tabCenter); console.log('Content center:', contentCenter); console.log('Indicator center:', indicatorCenter); console.log('Content offset from tab center:', contentCenter - tabCenter); console.log('Indicator offset from content center:', indicatorCenter - contentCenter); console.log('Indicator offset from tab center:', indicatorCenter - tabCenter); console.log('---'); console.log('Indicator extends left of content by:', contentRect.left - indicatorRect.left); console.log('Indicator extends right of content by:', (indicatorRect.left + indicatorRect.width) - (contentRect.left + contentRect.width)); // Check if icons are rendering const icon = firstContent.querySelector('dees-icon'); console.log('\n=== ICON CHECK ==='); console.log('Icon element found:', icon ? 'YES' : 'NO'); if (icon) { const iconRect = icon.getBoundingClientRect(); console.log('Icon width:', iconRect.width); console.log('Icon height:', iconRect.height); console.log('Icon visible:', iconRect.width > 0 && iconRect.height > 0 ? 'YES' : 'NO'); } // Verify indicator is visible expect(indicator.style.opacity).toEqual('1'); // Verify positioning calculations expect(parseFloat(indicator.style.left)).toBeCloseTo(expectedIndicatorLeft, 1); expect(parseFloat(indicator.style.width)).toBeCloseTo(expectedIndicatorWidth, 1); // Verify visual centering on content (should be perfectly centered) expect(Math.abs(indicatorCenter - contentCenter)).toBeLessThan(1); document.body.removeChild(tabsElement); }); tap.test('tabs indicator should move when tab is clicked', async () => { // Create tabs element const tabsElement = new deesCatalog.DeesAppuiTabs(); tabsElement.tabs = [ { key: 'Home', iconName: 'lucide:home', action: () => {} }, { key: 'Analytics', iconName: 'lucide:barChart', action: () => {} }, { key: 'Settings', iconName: 'lucide:settings', action: () => {} }, ]; document.body.appendChild(tabsElement); await tabsElement.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); const shadowRoot = tabsElement.shadowRoot; const tabs = shadowRoot.querySelectorAll('.tab'); const indicator = shadowRoot.querySelector('.tabIndicator') as HTMLElement; // Get initial position const initialLeft = parseFloat(indicator.style.left); // Click second tab (tabs[1] as HTMLElement).click(); await tabsElement.updateComplete; await new Promise(resolve => setTimeout(resolve, 100)); // Position should have changed const newLeft = parseFloat(indicator.style.left); expect(newLeft).not.toEqual(initialLeft); expect(newLeft).toBeGreaterThan(initialLeft); document.body.removeChild(tabsElement); }); export default tap.start();