import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import './usa-process-list.ts'; import type { USAProcessList, ProcessItem } from './usa-process-list.js'; import { testComponentAccessibility, USWDS_A11Y_CONFIG, } from '../../../__tests__/accessibility-utils.js'; import { setupTestEnvironment, validateComponentJavaScript, } from '../../../__tests__/test-utils.js'; describe('USAProcessList', () => { let element: USAProcessList; let cleanup: () => void; beforeEach(() => { cleanup = setupTestEnvironment(); element = document.createElement('usa-process-list') as USAProcessList; document.body.appendChild(element); }); afterEach(() => { element.remove(); cleanup?.(); }); describe('Default Properties', () => { it('should have correct default properties', async () => { await element.updateComplete; expect(element.items).toEqual([]); expect(element.headingLevel).toBe('h4'); }); }); describe('Basic Rendering', () => { it('should render slot when items array is empty', async () => { await element.updateComplete; // In light DOM pattern, slot elements are replaced with slotted content // When no slotted content exists, the slot is removed const slot = element.querySelector('slot'); expect(slot).toBeFalsy(); // Slot should be replaced/removed by moveSlottedContent() // But the container should always exist const list = element.querySelector('.usa-process-list'); expect(list).toBeTruthy(); }); it('should render ordered list when items are provided', async () => { element.items = [ { heading: 'Step 1', content: 'First step content' }, { heading: 'Step 2', content: 'Second step content' }, ]; await element.updateComplete; const list = element.querySelector('ol.usa-process-list'); expect(list).toBeTruthy(); }); it('should render correct number of list items', async () => { const testItems: ProcessItem[] = [ { heading: 'Step 1', content: 'Content 1' }, { heading: 'Step 2', content: 'Content 2' }, { heading: 'Step 3', content: 'Content 3' }, ]; element.items = testItems; await element.updateComplete; const listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(3); }); it('should apply USWDS process list classes', async () => { element.items = [{ heading: 'Test', content: 'Content' }]; await element.updateComplete; const list = element.querySelector('ol'); expect(list?.classList.contains('usa-process-list')).toBe(true); const item = element.querySelector('li'); expect(item?.classList.contains('usa-process-list__item')).toBe(true); }); }); describe('Process Item Content', () => { it('should render item headings', async () => { element.items = [ { heading: 'Apply Online', content: 'Visit our website' }, { heading: 'Submit Documents', content: 'Upload required files' }, { heading: 'Await Review', content: 'Processing takes 5-7 days' }, ]; await element.updateComplete; const headings = element.querySelectorAll('.usa-process-list__heading'); expect(headings.length).toBe(3); expect(headings[0].textContent).toBe('Apply Online'); expect(headings[1].textContent).toBe('Submit Documents'); expect(headings[2].textContent).toBe('Await Review'); }); it('should render item content', async () => { element.items = [ { heading: 'Step 1', content: 'First step description' }, { heading: 'Step 2', content: 'Second step description' }, ]; await element.updateComplete; const contents = element.querySelectorAll('.usa-process-list__item'); expect(contents.length).toBe(2); // Check that each item contains both heading and content expect(contents[0].textContent?.trim()).toContain('Step 1'); expect(contents[0].textContent?.trim()).toContain('First step description'); expect(contents[1].textContent?.trim()).toContain('Step 2'); expect(contents[1].textContent?.trim()).toContain('Second step description'); }); it('should render HTML content correctly', async () => { element.items = [ { heading: 'Step 1', content: 'Important: Bring your ID', }, ]; await element.updateComplete; const listItem = element.querySelector('.usa-process-list__item'); expect(listItem?.querySelector('strong')).toBeTruthy(); expect(listItem?.querySelector('em')).toBeTruthy(); expect(listItem?.querySelector('strong')?.textContent).toBe('Important:'); expect(listItem?.querySelector('em')?.textContent).toBe('ID'); }); it('should handle complex HTML content', async () => { element.items = [ { heading: 'Documentation', content: `

Required documents:

`, }, ]; await element.updateComplete; const listItem = element.querySelector('.usa-process-list__item'); const paragraph = listItem?.querySelector('p'); const list = listItem?.querySelector('ul'); const listItems = listItem?.querySelectorAll('li'); expect(paragraph?.textContent).toBe('Required documents:'); expect(list).toBeTruthy(); expect(listItems?.length).toBe(3); }); }); describe('Heading Level Customization', () => { it('should use default h4 heading level', async () => { element.items = [{ heading: 'Default Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h4'); }); it('should render h1 headings when specified', async () => { element.headingLevel = 'h1'; element.items = [{ heading: 'H1 Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h1'); }); it('should render h2 headings when specified', async () => { element.headingLevel = 'h2'; element.items = [{ heading: 'H2 Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h2'); }); it('should render h3 headings when specified', async () => { element.headingLevel = 'h3'; element.items = [{ heading: 'H3 Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h3'); }); it('should render h5 headings when specified', async () => { element.headingLevel = 'h5'; element.items = [{ heading: 'H5 Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h5'); }); it('should render h6 headings when specified', async () => { element.headingLevel = 'h6'; element.items = [{ heading: 'H6 Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h6'); }); it('should fall back to h4 for invalid heading level', async () => { element.headingLevel = 'h7' as any; // Invalid level element.items = [{ heading: 'Fallback Heading', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h4'); }); it('should update heading level dynamically', async () => { element.items = [{ heading: 'Dynamic Heading', content: 'Content' }]; element.headingLevel = 'h3'; await element.updateComplete; let heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h3'); element.headingLevel = 'h5'; await element.updateComplete; heading = element.querySelector('.usa-process-list__heading'); expect(heading?.tagName.toLowerCase()).toBe('h5'); }); }); describe('Slot Content', () => { it('should render slot content when no items provided', async () => { // Create new element with slotted content from the start const testElement = document.createElement('usa-process-list') as USAProcessList; const slotContent = document.createElement('ol'); slotContent.className = 'usa-process-list'; slotContent.innerHTML = `
  • Custom Step

    Custom content

  • `; testElement.appendChild(slotContent); document.body.appendChild(testElement); await testElement.updateComplete; // In light DOM pattern, slot is replaced with actual slotted content const slot = testElement.querySelector('slot'); expect(slot).toBeFalsy(); // Slot should be replaced by moveSlottedContent() // But the slotted content should be visible expect(testElement.textContent).toContain('Custom Step'); expect(testElement.textContent).toContain('Custom content'); testElement.remove(); }); it('should override slot content when items are provided', async () => { // Create new element with slotted content from the start const testElement = document.createElement('usa-process-list') as USAProcessList; const slotContent = document.createElement('div'); slotContent.textContent = 'Slot content'; testElement.appendChild(slotContent); document.body.appendChild(testElement); // Items property takes precedence over slot testElement.items = [{ heading: 'Item Heading', content: 'Item content' }]; await testElement.updateComplete; const list = testElement.querySelector('ol.usa-process-list'); expect(list).toBeTruthy(); expect(testElement.textContent).toContain('Item Heading'); // When items are provided, slot is not rendered (items.length > 0) // So slot content might still be in DOM but hidden by CSS testElement.remove(); }); }); describe('Dynamic Updates', () => { it('should update when items are added', async () => { element.items = [{ heading: 'Initial Step', content: 'Initial content' }]; await element.updateComplete; let listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(1); element.items = [...element.items, { heading: 'Added Step', content: 'Added content' }]; await element.updateComplete; listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(2); expect(listItems[1].textContent).toContain('Added Step'); }); it('should update when items are removed', async () => { element.items = [ { heading: 'Step 1', content: 'Content 1' }, { heading: 'Step 2', content: 'Content 2' }, { heading: 'Step 3', content: 'Content 3' }, ]; await element.updateComplete; let listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(3); element.items = element.items.slice(0, 2); await element.updateComplete; listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(2); }); it('should update when item content changes', async () => { element.items = [{ heading: 'Original Heading', content: 'Original content' }]; await element.updateComplete; let heading = element.querySelector('.usa-process-list__heading'); expect(heading?.textContent).toBe('Original Heading'); element.items = [{ heading: 'Updated Heading', content: 'Updated content' }]; await element.updateComplete; heading = element.querySelector('.usa-process-list__heading'); expect(heading?.textContent).toBe('Updated Heading'); }); it('should clear list when items are emptied', async () => { element.items = [{ heading: 'Step', content: 'Content' }]; await element.updateComplete; expect(element.querySelector('.usa-process-list')).toBeTruthy(); element.items = []; await element.updateComplete; // Container always exists now, but should be empty or show slot expect(element.querySelector('.usa-process-list')).toBeTruthy(); // Slot would have been removed by moveSlottedContent() in firstUpdated // When items are emptied, slot is rendered but then removed const listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(0); }); }); describe('Accessibility Features', () => { it('should use semantic ordered list', async () => { element.items = [ { heading: 'Step 1', content: 'Content 1' }, { heading: 'Step 2', content: 'Content 2' }, ]; await element.updateComplete; const list = element.querySelector('ol'); expect(list).toBeTruthy(); expect(list?.tagName.toLowerCase()).toBe('ol'); }); it('should maintain proper heading hierarchy', async () => { element.headingLevel = 'h3'; element.items = [{ heading: 'Process Step', content: 'Step description' }]; await element.updateComplete; const heading = element.querySelector('h3.usa-process-list__heading'); expect(heading).toBeTruthy(); expect(heading?.textContent).toBe('Process Step'); }); it('should structure content semantically', async () => { element.items = [{ heading: 'Apply', content: '

    Application instructions

    ' }]; await element.updateComplete; const item = element.querySelector('.usa-process-list__item'); const heading = item?.querySelector('.usa-process-list__heading'); expect(heading).toBeTruthy(); expect(item?.querySelector('p')).toBeTruthy(); }); }); describe('Edge Cases', () => { it('should handle empty headings', async () => { element.items = [{ heading: '', content: 'Content with no heading' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading).toBeTruthy(); expect(heading?.textContent).toBe(''); }); it('should handle empty content', async () => { element.items = [{ heading: 'Heading with no content', content: '' }]; await element.updateComplete; // For empty content, just verify the item exists and has only the heading const item = element.querySelector('.usa-process-list__item'); const heading = item?.querySelector('.usa-process-list__heading'); expect(item).toBeTruthy(); expect(heading).toBeTruthy(); expect(heading?.textContent?.trim()).toBe('Heading with no content'); // The item should not contain any content beyond the heading const itemText = item?.textContent?.trim() || ''; const headingText = heading?.textContent?.trim() || ''; expect(itemText).toBe(headingText); }); it('should handle special characters in heading', async () => { element.items = [{ heading: 'Step & Process "quotes"', content: 'Content' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.textContent).toBe('Step & Process "quotes"'); }); it('should handle script tags in content safely', async () => { element.items = [ { heading: 'Test', content: '

    Safe content

    ', }, ]; await element.updateComplete; // Note: unsafeHTML does render script tags, but they don't execute in this context const listItem = element.querySelector('.usa-process-list__item'); expect(listItem?.querySelector('p')?.textContent).toBe('Safe content'); }); it('should handle very long content', async () => { const longContent = 'A'.repeat(1000); element.items = [{ heading: 'Long Step', content: longContent }]; await element.updateComplete; const item = element.querySelector('.usa-process-list__item'); expect(item).toBeTruthy(); expect(item?.textContent?.trim()).toContain(longContent); }); it('should handle unicode characters', async () => { element.items = [{ heading: '步骤 1 🚀', content: 'مرحبا العالم' }]; await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); const item = element.querySelector('.usa-process-list__item'); expect(heading?.textContent).toBe('步骤 1 🚀'); expect(item?.textContent?.trim()).toContain('مرحبا العالم'); }); }); describe('Light DOM Rendering', () => { it('should render in light DOM for USWDS compatibility', async () => { element.items = [{ heading: 'Test', content: 'Content' }]; await element.updateComplete; expect(element.shadowRoot).toBeNull(); expect(element.querySelector('.usa-process-list')).toBeTruthy(); }); }); describe('USWDS CSS Classes', () => { it('should apply all required USWDS classes', async () => { element.items = [{ heading: 'Step', content: 'Description' }]; await element.updateComplete; const list = element.querySelector('ol'); const item = element.querySelector('li'); const heading = element.querySelector('[class*="heading"]'); expect(list?.classList.contains('usa-process-list')).toBe(true); expect(item?.classList.contains('usa-process-list__item')).toBe(true); expect(heading?.classList.contains('usa-process-list__heading')).toBe(true); // Verify the item contains the content text (no specific content wrapper class) expect(item?.textContent?.trim()).toContain('Description'); }); }); describe('Performance Considerations', () => { it('should handle large lists efficiently', async () => { const largeList = Array.from({ length: 100 }, (_, i) => ({ heading: `Step ${i + 1}`, content: `Description for step ${i + 1}`, })); const startTime = performance.now(); element.items = largeList; await element.updateComplete; const endTime = performance.now(); const listItems = element.querySelectorAll('.usa-process-list__item'); expect(listItems.length).toBe(100); // Should render within reasonable time (500ms for 100 items) expect(endTime - startTime).toBeLessThan(500); }); it('should handle rapid updates efficiently', async () => { for (let i = 0; i < 10; i++) { element.items = [{ heading: `Heading ${i}`, content: `Content ${i}` }]; } await element.updateComplete; const heading = element.querySelector('.usa-process-list__heading'); expect(heading?.textContent).toBe('Heading 9'); }); }); describe('CRITICAL: Component Lifecycle Stability', () => { beforeEach(() => { element = document.createElement('usa-process-list') as USAProcessList; document.body.appendChild(element); }); it('should remain in DOM after property changes', async () => { await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); element.headingLevel = 'h2'; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); element.items = [ { heading: 'Test Step 1', content: 'Test content 1' }, { heading: 'Test Step 2', content: 'Test content 2' }, ]; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); element.headingLevel = 'h5'; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); }); it('should maintain element stability during process item updates', async () => { const originalElement = element; const processItems = [ { heading: 'Apply', content: 'Submit your application online' }, { heading: 'Review', content: 'Wait for processing review' }, { heading: 'Approve', content: 'Receive approval notification' }, { heading: 'Complete', content: 'Process completed successfully' }, ]; for (const item of processItems) { element.items = [...element.items, item]; await element.updateComplete; expect(element).toBe(originalElement); expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); it('should preserve DOM connection through heading level changes', async () => { element.items = [{ heading: 'Process Step', content: 'Step description' }]; const headingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const; for (const level of headingLevels) { element.headingLevel = level; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); it('should maintain stability during complex content updates', async () => { const complexItems = [ { heading: 'Step 1', content: 'Important: Required documentation', }, { heading: 'Step 2', content: '', }, { heading: 'Step 3', content: '

    Final verification step

    ', }, ]; for (const item of complexItems) { element.items = [item]; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); }); describe('CRITICAL: Event System Stability', () => { beforeEach(async () => { element = document.createElement('usa-process-list') as USAProcessList; element.items = [ { heading: 'Event Step 1', content: 'Event content 1' }, { heading: 'Event Step 2', content: 'Event content 2' }, ]; document.body.appendChild(element); await element.updateComplete; }); it('should not pollute global event handling', async () => { const globalClickSpy = vi.fn(); document.addEventListener('click', globalClickSpy); // Test clicking on process list content const content = element.querySelector('div'); if (content) { content.dispatchEvent(new MouseEvent('click', { bubbles: true })); await element.updateComplete; } expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); document.removeEventListener('click', globalClickSpy); }); it('should maintain stability during rapid property changes', async () => { const headingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; for (let i = 0; i < 5; i++) { element.headingLevel = headingLevels[i % headingLevels.length] as any; await new Promise((resolve) => setTimeout(resolve, 10)); expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); it('should maintain stability during rapid item array changes', async () => { const itemSets = [ [{ heading: 'Set 1 Step 1', content: 'Content 1' }], [ { heading: 'Set 2 Step 1', content: 'Content 1' }, { heading: 'Set 2 Step 2', content: 'Content 2' }, ], [ { heading: 'Set 3 Step 1', content: 'Content 1' }, { heading: 'Set 3 Step 2', content: 'Content 2' }, { heading: 'Set 3 Step 3', content: 'Content 3' }, ], [], ]; for (const itemSet of itemSets) { element.items = itemSet; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); }); describe('CRITICAL: Process List State Management Stability', () => { beforeEach(async () => { element = document.createElement('usa-process-list') as USAProcessList; document.body.appendChild(element); await element.updateComplete; }); it('should maintain DOM connection during slot to items transition', async () => { // In light DOM pattern, slot is replaced/removed by moveSlottedContent() // Container should always exist expect(element.querySelector('.usa-process-list')).toBeTruthy(); expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); // Switch to items element.items = [{ heading: 'Transition Step', content: 'Transition content' }]; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); // Switch back to empty (renders slot, but it gets removed by firstUpdated logic) element.items = []; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); }); it('should preserve element stability during content rendering', async () => { const originalElement = element; // Test various content types const contentTypes = [ 'Plain text content', 'Bold content', 'Italic content', '

    Paragraph with link

    ', '', 'Unicode content 🚀 步骤 مرحبا', ]; for (const content of contentTypes) { element.items = [{ heading: 'Test Heading', content }]; await element.updateComplete; expect(element).toBe(originalElement); expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); it('should maintain stability during large list operations', async () => { // Test with large list const largeList = Array.from({ length: 50 }, (_, i) => ({ heading: `Large Step ${i + 1}`, content: `Large content ${i + 1}`, })); element.items = largeList; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); // Clear the large list element.items = []; await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); }); }); describe('CRITICAL: Storybook Integration', () => { it('should render in Storybook-like environment without auto-dismiss', async () => { const storyContainer = document.createElement('div'); storyContainer.id = 'storybook-root'; document.body.appendChild(storyContainer); element = document.createElement('usa-process-list') as USAProcessList; element.headingLevel = 'h3'; element.items = [ { heading: 'Storybook Step 1', content: 'Storybook content 1' }, { heading: 'Storybook Step 2', content: 'Storybook content 2' }, ]; storyContainer.appendChild(element); await element.updateComplete; // Simulate Storybook control updates element.headingLevel = 'h2'; element.items = [ { heading: 'Updated Step 1', content: 'Updated content 1' }, { heading: 'Updated Step 2', content: 'Updated content 2' }, { heading: 'New Step 3', content: 'New content 3' }, ]; await element.updateComplete; expect(storyContainer.contains(element)).toBe(true); expect(element.isConnected).toBe(true); expect(element.headingLevel).toBe('h2'); storyContainer.remove(); }); it('should handle Storybook args updates without component removal', async () => { element = document.createElement('usa-process-list') as USAProcessList; document.body.appendChild(element); await element.updateComplete; const storyArgs = [ { headingLevel: 'h1', items: [{ heading: 'H1 Process', content: 'H1 content' }], }, { headingLevel: 'h3', items: [ { heading: 'H3 Step 1', content: 'H3 content 1' }, { heading: 'H3 Step 2', content: 'H3 content 2' }, ], }, { headingLevel: 'h5', items: [], }, ]; for (const args of storyArgs) { Object.assign(element, args); await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); it('should maintain stability during complex Storybook interactions', async () => { element = document.createElement('usa-process-list') as USAProcessList; document.body.appendChild(element); // Simulate complex Storybook scenario const interactions = [ () => { element.headingLevel = 'h2'; }, () => { element.items = [{ heading: 'Interactive Step', content: 'Interactive content' }]; }, () => { element.headingLevel = 'h4'; }, () => { element.items = []; }, () => { element.items = [ { heading: 'Final Step 1', content: 'Final content 1' }, { heading: 'Final Step 2', content: 'Final content 2' }, ]; }, ]; for (const interaction of interactions) { interaction(); await element.updateComplete; expect(document.body.contains(element)).toBe(true); expect(element.isConnected).toBe(true); } }); describe('JavaScript Implementation Validation', () => { it('should pass JavaScript implementation validation', async () => { // Validate USWDS JavaScript implementation patterns const componentPath = `${process.cwd()}/src/components/process-list/usa-process-list.ts`; const validation = validateComponentJavaScript(componentPath, 'process-list'); if (!validation.isValid) { console.warn('JavaScript validation issues:', validation.issues); } // JavaScript validation should pass for critical integration patterns expect(validation.score).toBeGreaterThan(50); // Allow some non-critical issues // Critical USWDS integration should be present const criticalIssues = validation.issues.filter((issue) => issue.includes('Missing USWDS JavaScript integration') ); expect(criticalIssues.length).toBe(0); }); }); }); describe('Accessibility Compliance (CRITICAL)', () => { it('should pass comprehensive accessibility tests (same as Storybook)', async () => { // Test default empty process list (slot-based) await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Test simple process list with items element.items = [ { heading: 'Apply for Benefits', content: 'Complete the online application form with your personal information and required documentation.', }, { heading: 'Document Review', content: 'Our team will review your application and supporting documents within 5-7 business days.', }, { heading: 'Approval Decision', content: 'You will receive notification of our decision via email and postal mail.', }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Test with different heading level element.headingLevel = 'h3'; element.items = [ { heading: 'Register for Services', content: 'Create your government services account to access federal programs and benefits.', }, { heading: 'Verify Identity', content: 'Upload required identification documents for verification.', }, { heading: 'Select Programs', content: 'Choose which federal programs and services you wish to enroll in.', }, { heading: 'Complete Enrollment', content: 'Review and submit your enrollment information to finalize registration.', }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Test with rich content including HTML element.headingLevel = 'h2'; element.items = [ { heading: 'Gather Required Documents', content: 'You will need the following documents:', }, { heading: 'Submit Application Online', content: 'Visit our secure application portal to submit your application electronically.', }, { heading: 'Track Application Status', content: 'Use your confirmation number to track your application status and receive updates.', }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); }); it('should maintain accessibility during dynamic updates', async () => { // Set initial accessible state element.items = [ { heading: 'Initial Step', content: 'Initial content for accessibility testing.' }, ]; element.headingLevel = 'h4'; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Update heading level element.headingLevel = 'h2'; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Add more items element.items = [ { heading: 'Step 1', content: 'First step in the process.' }, { heading: 'Step 2', content: 'Second step with additional details.' }, { heading: 'Step 3', content: 'Final step to complete the process.' }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Change heading level again element.headingLevel = 'h5'; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Clear items (back to slot mode) element.items = []; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); }); it('should pass accessibility with government use cases', async () => { // Federal tax filing process element.headingLevel = 'h3'; element.items = [ { heading: 'Prepare Your Tax Documents', content: 'Gather all necessary tax documents including W-2 forms, 1099 forms, receipts for deductions, and your prior year tax return.', }, { heading: 'Choose Your Filing Method', content: 'You can file your taxes online through IRS Free File, use tax preparation software, hire a professional tax preparer, or file paper forms by mail.', }, { heading: 'Complete Your Tax Return', content: 'Fill out all required forms accurately, including Form 1040 and any necessary schedules. Double-check all information before submission.', }, { heading: 'Submit Your Return', content: 'File your completed tax return electronically for faster processing, or mail paper forms to the appropriate IRS processing center by the deadline.', }, { heading: 'Track Your Refund', content: 'If you are expecting a refund, you can track its status using the IRS "Where\'s My Refund?" tool online or by calling the automated phone system.', }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); // Medicare enrollment process element.headingLevel = 'h4'; element.items = [ { heading: 'Determine Your Eligibility', content: 'You are eligible for Medicare if you are 65 or older, have certain disabilities, or have End-Stage Renal Disease (ESRD).', }, { heading: 'Learn About Medicare Parts', content: 'Understand the different parts of Medicare: Part A (hospital insurance), Part B (medical insurance), Part C (Medicare Advantage), and Part D (prescription drugs).', }, { heading: 'Compare Plan Options', content: 'Use the Medicare Plan Finder tool at Medicare.gov to compare available plans in your area based on your healthcare needs and budget.', }, { heading: 'Enroll in Medicare', content: 'Enroll during your Initial Enrollment Period (7-month window around your 65th birthday) or during Open Enrollment (October 15 - December 7 annually).', }, { heading: 'Receive Your Medicare Card', content: 'Your Medicare card will arrive by mail, typically 1-3 months before your coverage begins. Keep this card with you whenever you receive healthcare services.', }, ]; await element.updateComplete; await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE); }); }); });