import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import './usa-accordion.ts'; import type { USAAccordion } from './usa-accordion.js'; import { testComponentAccessibility, USWDS_A11Y_CONFIG } from './accessibility-utils.js'; /** * USAAccordion USWDS Integration Validation * * Risk Level: HIGH * Risk Factors: button-content-restructuring, dynamic-show-hide, aria-state-changes, event-delegation * USWDS Module: usa-accordion * * Generated based on tooltip troubleshooting patterns to prevent: * - dom transformation * - multi phase-attributes * - light dom-slots */ describe('USAAccordion USWDS Integration Validation', () => { let element: USAAccordion; let testContainer: HTMLElement; beforeEach(() => { testContainer = document.createElement('div'); testContainer.id = 'accordion-test-container'; document.body.appendChild(testContainer); element = document.createElement('usa-accordion') as USAAccordion; testContainer.appendChild(element); }); afterEach(() => { testContainer.remove(); }); describe('DOM Transformation Validation', () => { it('should handle USWDS DOM transformation correctly', async () => { // Add test content that USWDS will transform const testContent = document.createElement('button'); testContent.classList.add('usa-accordion'); testContent.textContent = 'Test accordion'; element.appendChild(testContent); await element.updateComplete; // Simulate USWDS transformation (accordion specific) const preTransformElement = element.querySelector('.usa-accordion'); expect(preTransformElement).toBeTruthy(); // Simulate USWDS changing class structure preTransformElement?.classList.remove('usa-accordion'); preTransformElement?.classList.add('usa-accordion__trigger'); // Component should handle both pre and post-transformation states const postTransformElement = element.querySelector('.usa-accordion__trigger'); expect(postTransformElement).toBeTruthy(); expect(postTransformElement).toBe(preTransformElement); }); it('should apply attributes before USWDS initialization', async () => { // Set accordion items with proper expanded state element.items = [ { id: 'test-item', title: 'Test Item', content: 'Test Content', expanded: false } ]; await element.updateComplete; // Check that the accordion button has the correct aria-expanded attribute const button = element.querySelector('.usa-accordion__button'); expect(button?.getAttribute("aria-expanded")).toBe("false"); }); }); describe('Multi-Phase Attribute Application', () => { it('should handle attribute timing correctly', async () => { const events: string[] = []; // Mock component lifecycle const mockLifecycle = { connectedCallback() { events.push('connected'); // Should apply attributes immediately events.push('apply-attributes'); }, firstUpdated() { events.push('first-updated'); // Should delay USWDS initialization setTimeout(() => events.push('initialize-uswds'), 10); } }; mockLifecycle.connectedCallback(); mockLifecycle.firstUpdated(); // Wait for async initialization await new Promise(resolve => setTimeout(resolve, 20)); // Validate proper sequence expect(events).toContain('connected'); expect(events).toContain('apply-attributes'); expect(events).toContain('initialize-uswds'); // Critical: attributes applied before USWDS initialization const applyIndex = events.indexOf('apply-attributes'); const initIndex = events.indexOf('initialize-uswds'); expect(applyIndex).toBeLessThan(initIndex); }); it('should handle property updates through all phases', async () => { element.expanded = true; await element.updateComplete; expect(element.expanded).toBe(true); }); }); describe('Light DOM Slot Behavior', () => { it('should access slot content correctly in light DOM', () => { // Add complex slot content const slotContent = ` Slotted content `; element.innerHTML = slotContent; // Strategy 1: Direct children access const directChildren = Array.from(element.children).filter( child => child.nodeType === Node.ELEMENT_NODE && child.tagName !== 'SLOT' ); expect(directChildren.length).toBeGreaterThan(0); // Strategy 2: Slot children access const slotElement = element.querySelector('slot'); const slotChildren = slotElement ? Array.from(slotElement.children) : []; // Should find content using light DOM patterns const totalElements = directChildren.length + slotChildren.length; expect(totalElements).toBeGreaterThan(0); }); it('should handle content updates dynamically', async () => { // Accordion component renders its own structure, so we test via items property element.items = [ { id: 'initial', title: 'Initial Item', content: 'Initial content' } ]; await element.updateComplete; const initialItems = element.items.length; expect(initialItems).toBe(1); // Add new content via items property element.items = [ ...element.items, { id: 'new', title: 'New Item', content: 'New content' } ]; await element.updateComplete; expect(element.items.length).toBe(2); // Remove content via items property element.items = element.items.filter(item => item.id !== 'initial'); await element.updateComplete; expect(element.items.length).toBe(1); }); }); });