// Component tests for usa-breadcrumb import './index.ts'; import { testRapidClicking, testRapidKeyboardInteraction, COMMON_BUG_PATTERNS, } from '../../../cypress/support/rapid-interaction-tests.ts'; describe('Breadcrumb Component Tests', () => { beforeEach(() => { // Set up console error tracking cy.window().then((win) => { cy.stub(win.console, 'error').as('consoleError'); }); }); it('should render component with default properties', () => { cy.mount(''); cy.get('usa-breadcrumb').should('exist'); cy.get('usa-breadcrumb').should('be.visible'); }); it('should handle rapid clicking without visual glitches', () => { cy.mount(''); // Rapid clicking without waiting - simulates real user behavior cy.get('usa-breadcrumb').as('component'); // Multiple rapid clicks cy.get('@component').click().click().click().click().click(); cy.wait(500); // Let events settle // Component should remain functional cy.get('@component').should('exist'); cy.get('@component').should('be.visible'); }); it('should handle interaction during CSS transitions', () => { cy.mount(''); // Click during potential transitions cy.get('usa-breadcrumb').click().click(); // Immediate second click cy.wait(1000); // Wait for animations // Should be in consistent state cy.get('usa-breadcrumb').should('exist'); }); // Stress tests using utility functions describe('Stress Testing', () => { it('should handle event listener duplication pattern', () => { cy.mount(''); // Test for event listener duplication testRapidClicking({ selector: 'usa-breadcrumb', clickCount: 15, description: 'event listener duplication', }); }); it('should handle race condition patterns', () => { cy.mount(''); // Test for race conditions during state changes cy.get('usa-breadcrumb').as('component'); // Rapid interactions that might cause race conditions cy.get('@component').click().click().trigger('focus').trigger('blur').click(); cy.wait(1000); // Wait for all async operations // Component should still be functional cy.get('@component').should('exist'); cy.get('@component').should('be.visible'); }); }); // Accessibility testing - critical for government components it('should be accessible', () => { cy.mount(''); cy.injectAxe(); cy.checkAccessibility(); }); // Test that component maintains accessibility after interactions it('should maintain accessibility after rapid interactions', () => { cy.mount(''); // Perform various rapid interactions cy.get('usa-breadcrumb').click().focus().blur().click().click(); cy.wait(500); // Accessibility should still be intact cy.injectAxe(); cy.checkAccessibility(); }); // Performance regression test it('should not cause memory leaks with rapid mounting/unmounting', () => { // This catches memory leaks and cleanup issues for (let i = 0; i < 5; i++) { cy.mount(''); cy.get('usa-breadcrumb').should('exist'); // Cypress automatically cleans up between mounts } }); // Console error test - should not generate any JavaScript errors it('should not generate console errors during interactions', () => { cy.mount(''); // Various interactions that might cause errors cy.get('usa-breadcrumb').click().trigger('mouseenter').trigger('mouseleave').focus().blur(); cy.wait(500); // No console errors should have occurred cy.get('@consoleError').should('not.have.been.called'); }); // Event Propagation Control Testing (Critical Gap Fix) describe('Event Propagation Control', () => { it('should prevent default navigation when preventDefault is called', () => { const breadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Section', href: '/section' }, { id: '3', text: 'Current Page', current: true }, ]; cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('test-breadcrumb') as any; breadcrumb.items = breadcrumbItems; }); // Click on breadcrumb link should prevent default navigation cy.get('usa-breadcrumb a[href="/section"]').click(); // Verify URL hasn't changed (preventDefault worked) cy.url().should('include', 'localhost'); cy.url().should('not.include', '/section'); }); it('should emit custom events without interfering with parent listeners', () => { let parentClicked = false; let breadcrumbEventEmitted = false; const breadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Section', href: '/section' }, { id: '3', text: 'Current Page', current: true }, ]; cy.mount(`
`); cy.window().then((win) => { const breadcrumb = win.document.getElementById('test-breadcrumb') as any; const parent = win.document.getElementById('parent-container') as any; breadcrumb.items = breadcrumbItems; // Listen for parent clicks parent.addEventListener('click', () => { parentClicked = true; }); // Listen for breadcrumb events breadcrumb.addEventListener('breadcrumb-click', () => { breadcrumbEventEmitted = true; }); }); // Click breadcrumb item cy.get('usa-breadcrumb a[href="/home"]') .click() .then(() => { // Breadcrumb event should be emitted expect(breadcrumbEventEmitted).to.be.true; // Parent click should not be triggered (event should not bubble inappropriately) // Note: This tests if the component properly handles event propagation }); }); it('should handle nested click contexts properly', () => { let formSubmitted = false; const breadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Current', current: true }, ]; cy.mount(`
`); cy.window().then((win) => { const breadcrumb = win.document.getElementById('nested-breadcrumb') as any; const form = win.document.getElementById('test-form') as any; breadcrumb.items = breadcrumbItems; form.addEventListener('submit', (e: Event) => { e.preventDefault(); formSubmitted = true; }); }); // Click breadcrumb link should not trigger form submission cy.get('usa-breadcrumb a[href="/home"]') .click() .then(() => { expect(formSubmitted).to.be.false; }); // But clicking submit button should trigger form submission cy.get('button[type="submit"]') .click() .then(() => { expect(formSubmitted).to.be.true; }); }); it('should prevent double navigation when clicked rapidly', () => { let eventCount = 0; const breadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Section', href: '/section' }, { id: '3', text: 'Current', current: true }, ]; cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('rapid-breadcrumb') as any; breadcrumb.items = breadcrumbItems; breadcrumb.addEventListener('breadcrumb-click', () => { eventCount++; }); }); // Rapid clicks should be handled properly cy.get('usa-breadcrumb a[href="/home"]').click().click().click(); cy.wait(100).then(() => { // Should have received events for each click expect(eventCount).to.be.greaterThan(0); // But URL should still be localhost (preventDefault working) cy.url().should('include', 'localhost'); cy.url().should('not.include', '/home'); }); }); it('should work correctly in complex DOM hierarchies', () => { let outerDivClicked = false; let innerDivClicked = false; let breadcrumbClicked = false; const breadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Current', current: true }, ]; cy.mount(`
`); cy.window().then((win) => { const breadcrumb = win.document.getElementById('hierarchy-breadcrumb') as any; const outerDiv = win.document.getElementById('outer-div') as any; const innerDiv = win.document.getElementById('inner-div') as any; breadcrumb.items = breadcrumbItems; outerDiv.addEventListener('click', () => { outerDivClicked = true; }); innerDiv.addEventListener('click', () => { innerDivClicked = true; }); breadcrumb.addEventListener('breadcrumb-click', () => { breadcrumbClicked = true; }); }); // Click breadcrumb cy.get('usa-breadcrumb a[href="/home"]') .click() .then(() => { expect(breadcrumbClicked).to.be.true; // Test that event propagation behaves as expected // (Component should control whether parent elements receive events) }); }); }); // Responsive Layout Testing (Critical Gap Fix) describe('Responsive Layout Testing', () => { const simpleBreadcrumbItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Services', href: '/services' }, { id: '3', text: 'Current Page', current: true }, ]; const deepBreadcrumbItems = [ { id: '1', text: 'U.S. Department of Health and Human Services', href: '/home' }, { id: '2', text: 'Centers for Disease Control and Prevention', href: '/cdc' }, { id: '3', text: 'Health and Safety Guidelines', href: '/health-guidelines' }, { id: '4', text: 'Workplace Safety Standards', href: '/workplace-safety' }, { id: '5', text: 'Industrial Hygiene Protocols', href: '/hygiene-protocols' }, { id: '6', text: 'Chemical Safety Management', href: '/chemical-safety' }, { id: '7', text: 'Emergency Response Procedures', current: true }, ]; const veryLongLabelItems = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Department of Environmental Protection and Sustainability Management', href: '/environmental', }, { id: '3', text: 'Climate Change Adaptation and Mitigation Strategies for Federal Agencies', href: '/climate-change', }, { id: '4', text: 'Comprehensive Environmental Impact Assessment Guidelines and Implementation Framework', current: true, }, ]; const viewports = [ { name: 'Mobile Portrait', width: 375, height: 667 }, { name: 'Mobile Landscape', width: 667, height: 375 }, { name: 'Tablet Portrait', width: 768, height: 1024 }, { name: 'Tablet Landscape', width: 1024, height: 768 }, { name: 'Desktop', width: 1200, height: 800 }, { name: 'Large Desktop', width: 1920, height: 1080 }, ]; describe('Basic Responsive Behavior', () => { viewports.forEach((viewport) => { it(`should render correctly on ${viewport.name} (${viewport.width}x${viewport.height})`, () => { cy.viewport(viewport.width, viewport.height); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('responsive-breadcrumb') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Basic visibility test cy.get('usa-breadcrumb').should('be.visible'); cy.get('.usa-breadcrumb').should('be.visible'); // Breadcrumb should fit within viewport cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 20); }); // Breadcrumb items should be visible cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Accessibility at all sizes cy.injectAxe(); cy.checkAccessibility(); }); }); it('should handle viewport orientation changes', () => { cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('orientation-breadcrumb') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Portrait tablet cy.viewport(768, 1024); cy.get('.usa-breadcrumb').should('be.visible'); cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Landscape tablet cy.viewport(1024, 768); cy.get('.usa-breadcrumb').should('be.visible'); cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Component should adapt without breaking cy.injectAxe(); cy.checkAccessibility(); }); }); describe('Mobile Breadcrumb Behavior', () => { it('should show simplified breadcrumb on mobile', () => { cy.viewport(375, 667); // iPhone SE cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-simple') as any; breadcrumb.items = deepBreadcrumbItems; }); // On mobile, should show simplified view (typically home + current) cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Should not cause horizontal overflow cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 30); }); }); it('should handle text truncation on mobile', () => { cy.viewport(320, 568); // Very narrow mobile cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-truncation') as any; breadcrumb.items = veryLongLabelItems; }); // Long text should be truncated or wrapped appropriately cy.get('.usa-breadcrumb__link').should('be.visible'); // Should not cause horizontal scrolling cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 40); }); // Text should have ellipsis or proper wrapping cy.get('.usa-breadcrumb__link') .should('have.css', 'text-overflow', 'ellipsis') .or('have.css', 'word-wrap', 'break-word'); }); it('should handle touch interactions on mobile', () => { cy.viewport(375, 667); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-touch') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Test touch targets are at least 44px cy.get('.usa-breadcrumb__link').each(($link) => { const rect = $link[0].getBoundingClientRect(); expect(Math.min(rect.width, rect.height)).to.be.at.least(44); }); // Simulate touch on breadcrumb link cy.get('.usa-breadcrumb__link') .first() .trigger('touchstart', { touches: [{ clientX: 100, clientY: 100 }] }) .trigger('touchend', { changedTouches: [{ clientX: 100, clientY: 100 }] }); cy.get('.usa-breadcrumb').should('be.visible'); }); it('should show mobile-optimized separators', () => { cy.viewport(375, 667); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-separators') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Separators should be visible and appropriately sized cy.get('.usa-breadcrumb__list-item').should('contain.text', '>').or('contain.text', '/'); // Check that separators don't take up too much space cy.get('.usa-breadcrumb').should('be.visible'); }); it('should handle mobile wrapping when truncation is disabled', () => { cy.viewport(375, 667); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-wrapping') as any; breadcrumb.items = veryLongLabelItems; breadcrumb.wrap = true; }); // When wrapping is enabled, breadcrumb should expand vertically cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Multiple lines should be acceptable cy.get('.usa-breadcrumb').should('be.visible'); }); }); describe('Tablet Breadcrumb Behavior', () => { it('should show more breadcrumb items on tablet', () => { cy.viewport(768, 1024); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('tablet-breadcrumb') as any; breadcrumb.items = deepBreadcrumbItems; }); // Should show more items than mobile but may still truncate long paths cy.get('.usa-breadcrumb__list-item').should('have.length.at.least', 3); // Should fit within tablet width cy.get('.usa-breadcrumb').should('be.visible'); }); it('should handle medium-length labels on tablet', () => { cy.viewport(768, 1024); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('tablet-labels') as any; breadcrumb.items = [ { id: '1', text: 'Home', href: '/home' }, { id: '2', text: 'Department of Education', href: '/education' }, { id: '3', text: 'Student Financial Aid', href: '/financial-aid' }, { id: '4', text: 'Application Process', current: true }, ]; }); // Medium-length labels should display well on tablet cy.get('.usa-breadcrumb__link').should('be.visible'); cy.get('.usa-breadcrumb__link').each(($link) => { expect($link.text().trim()).to.not.be.empty; }); }); it('should handle tablet landscape orientation', () => { cy.viewport(1024, 768); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('tablet-landscape') as any; breadcrumb.items = deepBreadcrumbItems; }); // Should show more items in landscape mode cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Better horizontal space utilization cy.get('.usa-breadcrumb').should('be.visible'); }); }); describe('Desktop Breadcrumb Behavior', () => { it('should show full breadcrumb trail on desktop', () => { cy.viewport(1200, 800); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('desktop-full') as any; breadcrumb.items = deepBreadcrumbItems; }); // Should show all breadcrumb items on desktop cy.get('.usa-breadcrumb__list-item').should('have.length', deepBreadcrumbItems.length); // All links should be visible cy.get('.usa-breadcrumb__link').should('be.visible'); // Should fit comfortably cy.get('.usa-breadcrumb').should('be.visible'); }); it('should handle very long breadcrumb paths on large desktop', () => { cy.viewport(1920, 1080); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('desktop-long') as any; breadcrumb.items = veryLongLabelItems; }); // Even very long labels should display well on large screens cy.get('.usa-breadcrumb__link').should('be.visible'); cy.get('.usa-breadcrumb__link').each(($link) => { const text = $link.text().trim(); expect(text).to.not.be.empty; }); // Should not overflow cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 20); }); }); it('should handle hover states on desktop', () => { cy.viewport(1200, 800); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('desktop-hover') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Test hover effects cy.get('.usa-breadcrumb__link').first().trigger('mouseover'); cy.get('.usa-breadcrumb__link').first().should('be.visible'); // Hover should not break layout cy.get('.usa-breadcrumb').should('be.visible'); }); it('should handle keyboard navigation on desktop', () => { cy.viewport(1200, 800); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('desktop-keyboard') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Focus first breadcrumb link cy.get('.usa-breadcrumb__link').first().focus(); cy.focused().should('exist'); // Tab through breadcrumb links cy.focused().tab(); cy.focused().should('exist'); // Enter should trigger navigation cy.focused().type('{enter}'); cy.get('.usa-breadcrumb').should('be.visible'); }); }); describe('Responsive Breadcrumb Features', () => { it('should handle dynamic breadcrumb updates across viewports', () => { cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-breadcrumb') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Start on desktop cy.viewport(1200, 800); cy.get('.usa-breadcrumb__list-item').should('have.length', simpleBreadcrumbItems.length); // Update breadcrumb items cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-breadcrumb') as any; breadcrumb.items = deepBreadcrumbItems; }); // Switch to mobile cy.viewport(375, 667); cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Switch back to desktop cy.viewport(1200, 800); cy.get('.usa-breadcrumb__list-item').should('have.length', deepBreadcrumbItems.length); }); it('should maintain current page indication across viewports', () => { const testViewports = [ { width: 375, height: 667 }, { width: 768, height: 1024 }, { width: 1200, height: 800 }, ]; testViewports.forEach((vp) => { cy.viewport(vp.width, vp.height); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById(`current-page-${vp.width}`) as any; breadcrumb.items = simpleBreadcrumbItems; }); // Current page should always be indicated cy.get('.usa-breadcrumb__list-item') .last() .should('have.attr', 'aria-current', 'page') .or('have.class', 'usa-current'); }); }); it('should handle breadcrumb overflow strategies', () => { cy.viewport(375, 667); // Mobile cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('overflow-strategy') as any; breadcrumb.items = deepBreadcrumbItems; breadcrumb.showOverflow = true; }); // Should handle overflow with ellipsis or collapse strategy cy.get('.usa-breadcrumb').should('be.visible'); // May show ellipsis for hidden items cy.get('.usa-breadcrumb').should('contain.text', '...').or('not.contain.text', '...'); // Should not cause horizontal scroll cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 30); }); }); }); describe('Responsive Edge Cases', () => { it('should handle breadcrumb with single item responsively', () => { const singleItem = [{ id: '1', text: 'Home', current: true }]; viewports.forEach((viewport) => { cy.viewport(viewport.width, viewport.height); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById(`single-item-${viewport.width}`) as any; breadcrumb.items = singleItem; }); // Single item should display correctly cy.get('.usa-breadcrumb__list-item').should('have.length', 1); cy.get('.usa-breadcrumb').should('be.visible'); }); }); it('should handle empty breadcrumb state responsively', () => { viewports.forEach((viewport) => { cy.viewport(viewport.width, viewport.height); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById( `empty-breadcrumb-${viewport.width}` ) as any; breadcrumb.items = []; }); // Empty state should not break layout cy.get('usa-breadcrumb').should('be.visible'); // No layout issues with empty state cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 10); }); }); }); it('should handle special characters and internationalization', () => { const i18nItems = [ { id: '1', text: 'Accueil', href: '/accueil' }, { id: '2', text: 'Départements', href: '/departements' }, { id: '3', text: 'Services Sociaux', href: '/services' }, { id: '4', text: "Formulaires d'Application", current: true }, ]; cy.viewport(375, 667); // Mobile cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('i18n-breadcrumb') as any; breadcrumb.items = i18nItems; }); // International characters should display correctly cy.get('.usa-breadcrumb__link').should('contain.text', 'Accueil'); cy.get('.usa-breadcrumb__link').should('contain.text', 'Départements'); // Should not break layout cy.get('.usa-breadcrumb').should('be.visible'); }); it('should handle dynamic content changes during viewport transitions', () => { cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-transition') as any; breadcrumb.items = simpleBreadcrumbItems; }); // Start on desktop cy.viewport(1200, 800); cy.get('.usa-breadcrumb__list-item').should('have.length', simpleBreadcrumbItems.length); // Update items while transitioning to mobile cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-transition') as any; breadcrumb.items = deepBreadcrumbItems; }); cy.viewport(375, 667); // Switch to mobile cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Layout should adapt to new content and viewport cy.get('.usa-breadcrumb').should('be.visible'); }); it('should maintain accessibility across all responsive states', () => { const testViewports = [ { width: 375, height: 667 }, { width: 768, height: 1024 }, { width: 1200, height: 800 }, ]; testViewports.forEach((viewport) => { cy.viewport(viewport.width, viewport.height); cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById( `a11y-breadcrumb-${viewport.width}` ) as any; breadcrumb.items = simpleBreadcrumbItems; }); // Verify semantic structure at all sizes cy.get('nav') .should('have.attr', 'aria-label') .and('match', /breadcrumb/i); cy.get('.usa-breadcrumb__list') .should('have.attr', 'role', 'list') .or('have.tagName', 'ol'); // Current page should be marked cy.get('[aria-current="page"]').should('exist'); // Check keyboard navigation works cy.get('.usa-breadcrumb__link').first().focus(); cy.focused().tab(); // Run accessibility test cy.injectAxe(); cy.checkAccessibility(); }); }); it('should handle breadcrumb with very long single item', () => { const veryLongSingleItem = [ { id: '1', text: 'This is an extremely long breadcrumb item that tests how the component handles very long single items that might exceed the available viewport width', current: true, }, ]; cy.viewport(320, 568); // Very narrow mobile cy.mount(``); cy.window().then((win) => { const breadcrumb = win.document.getElementById('long-single-item') as any; breadcrumb.items = veryLongSingleItem; }); // Long single item should be handled gracefully cy.get('.usa-breadcrumb__list-item').should('have.length', 1); // Should not cause horizontal overflow cy.get('usa-breadcrumb').should(($el) => { expect($el[0].scrollWidth).to.be.at.most($el[0].clientWidth + 50); }); // Text should be visible but may be truncated cy.get('.usa-breadcrumb').should('be.visible'); }); }); }); describe('Wrapping Behavior Regression Tests', () => { const longBreadcrumbs = [ { label: 'Home', href: '/' }, { label: 'Company', href: '/company' }, { label: 'Technology and Innovation', href: '/company/technology' }, { label: 'Development Team', href: '/company/technology/development' }, { label: 'Web Services Division', href: '/company/technology/development/web' }, { label: 'Current Documentation', current: true }, ]; it('should apply correct CSS classes for wrapping vs non-wrapping at desktop viewport', () => { // Test at desktop viewport where responsive behavior should work cy.viewport(1024, 768); // Test wrap=false cy.mount(''); cy.window().then((win) => { const breadcrumb = win.document.getElementById('no-wrap-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = false; }); cy.get('.usa-breadcrumb').should('exist'); cy.get('.usa-breadcrumb').should('not.have.class', 'usa-breadcrumb--wrap'); // Test wrap=true cy.window().then((win) => { const breadcrumb = win.document.getElementById('no-wrap-test') as any; breadcrumb.wrap = true; }); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); }); it('should show all breadcrumb items at desktop viewport regardless of wrap setting', () => { cy.viewport(1200, 800); // Desktop viewport cy.mount(''); cy.window().then((win) => { const breadcrumb = win.document.getElementById('desktop-items-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = true; }); // All breadcrumb items should be visible at desktop size cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); // Each item should contain the expected text longBreadcrumbs.forEach((item, index) => { cy.get('.usa-breadcrumb__list-item').eq(index).should('contain', item.label); }); // Current item should have proper styling cy.get('.usa-current').should('contain', 'Current Documentation'); }); it('should handle mobile responsive behavior correctly', () => { cy.viewport(375, 667); // Mobile viewport (below 480px) cy.mount(''); cy.window().then((win) => { const breadcrumb = win.document.getElementById('mobile-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = true; }); // At mobile size, USWDS shows condensed view regardless of wrap setting // This is expected behavior - the component should still apply the wrap class cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); // The breadcrumb should still render all items (USWDS CSS handles the mobile display) cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); }); it('should toggle wrap behavior dynamically at desktop viewport', () => { cy.viewport(1024, 768); cy.mount(''); cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-wrap-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = false; }); // Initially no wrap class cy.get('.usa-breadcrumb').should('not.have.class', 'usa-breadcrumb--wrap'); // Toggle to wrap=true cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-wrap-test') as any; breadcrumb.wrap = true; }); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); // Toggle back to wrap=false cy.window().then((win) => { const breadcrumb = win.document.getElementById('dynamic-wrap-test') as any; breadcrumb.wrap = false; }); cy.get('.usa-breadcrumb').should('not.have.class', 'usa-breadcrumb--wrap'); }); it('should validate the specific reported issue is fixed', () => { // This test addresses the original issue: // "The breadcrumb is supposed to have a wrapping options where the breadcrumbs go to a second line" cy.viewport(600, 400); // Constrained width but above 480px cy.mount(`
`); cy.window().then((win) => { const breadcrumb = win.document.getElementById('regression-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = true; }); // Should apply wrap class cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); // Should show all items, not just a condensed mobile view cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); // Should not show mobile back arrow pattern (which only appears at very small sizes) cy.get('.usa-breadcrumb__list-item').should('be.visible'); // Current item should be properly marked cy.get('.usa-current').should('contain', 'Current Documentation'); // Links should be functional cy.get('.usa-breadcrumb__link').first().should('have.attr', 'href', '/'); }); it('should maintain wrapping behavior across viewport changes', () => { cy.mount(''); cy.window().then((win) => { const breadcrumb = win.document.getElementById('viewport-change-test') as any; breadcrumb.items = longBreadcrumbs; breadcrumb.wrap = true; }); // Start at desktop cy.viewport(1200, 800); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); // Switch to tablet cy.viewport(768, 1024); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); // Switch to large mobile (still above 480px) cy.viewport(500, 800); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); // Switch to mobile (below 480px) - CSS takes over but class remains cy.viewport(400, 600); cy.get('.usa-breadcrumb').should('have.class', 'usa-breadcrumb--wrap'); cy.get('.usa-breadcrumb__list-item').should('have.length', longBreadcrumbs.length); }); }); });