// Component tests for usa-identifier import './index.ts'; import { testRapidClicking, testRapidKeyboardInteraction, COMMON_BUG_PATTERNS, } from '../../cypress/support/rapid-interaction-tests.ts'; describe('Identifier 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-identifier').should('exist'); cy.get('usa-identifier').should('be.visible'); }); it('should handle rapid clicking without visual glitches', () => { cy.mount(''); // Rapid clicking without waiting - simulates real user behavior cy.get('usa-identifier').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-identifier').click().click(); // Immediate second click cy.wait(1000); // Wait for animations // Should be in consistent state cy.get('usa-identifier').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-identifier', clickCount: 15, description: 'event listener duplication', }); }); it('should handle race condition patterns', () => { cy.mount(''); // Test for race conditions during state changes cy.get('usa-identifier').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-identifier').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-identifier').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-identifier').click().trigger('mouseenter').trigger('mouseleave').focus().blur(); cy.wait(500); // No console errors should have occurred cy.get('@consoleError').should('not.have.been.called'); }); // Form Integration Testing (Critical Gap Fix) describe('Form Integration', () => { it('should not interfere with form submission when identifier links are clicked', () => { let formSubmitted = false; let linkClicked = false; cy.mount(`
Contact Information
`); cy.window().then((win) => { const form = win.document.getElementById('identifier-form-test') as HTMLFormElement; form.addEventListener('submit', (e: Event) => { e.preventDefault(); formSubmitted = true; }); // Listen for identifier link clicks const identifier = win.document.getElementById('form-identifier'); identifier?.addEventListener('link-click', () => { linkClicked = true; }); }); // Identifier link clicks should not trigger form submission cy.get('.usa-identifier__required-link') .first() .click() .then(() => { expect(linkClicked).to.be.true; expect(formSubmitted).to.be.false; }); // Form submission should work independently cy.get('#contact-name').type('John Doe'); cy.get('#contact-email').type('john@example.com'); cy.get('button[type="submit"]') .click() .then(() => { expect(formSubmitted).to.be.true; }); }); it('should properly handle navigation vs form submission conflicts', () => { let navigationPrevented = false; let formSubmitted = false; cy.mount(` `); cy.window().then((win) => { const form = win.document.getElementById('navigation-form') as HTMLFormElement; form.addEventListener('submit', (e: Event) => { e.preventDefault(); formSubmitted = true; }); // Prevent actual navigation for testing win.document.addEventListener('click', (e: Event) => { const target = e.target as HTMLElement; if (target.tagName === 'A' && target.getAttribute('href')) { e.preventDefault(); navigationPrevented = true; } }); }); // Clicking identifier agency link should not submit form cy.get('.usa-identifier__logo .usa-link') .click() .then(() => { expect(navigationPrevented).to.be.true; expect(formSubmitted).to.be.false; }); // Form submission should still work independently cy.get('#username').type('testuser'); cy.get('button[type="submit"]') .click() .then(() => { expect(formSubmitted).to.be.true; }); }); it('should maintain proper focus management within forms', () => { cy.mount(`
`); // Tab navigation should skip identifier (it's not interactive as a unit) cy.get('#first-input').focus().tab(); // Should move to identifier links cy.focused().should('match', '.usa-identifier__required-link'); // Should be able to navigate through identifier links cy.focused().tab(); cy.focused().should('match', '.usa-identifier__required-link'); // Continue tabbing should eventually reach the last input cy.get('#last-input').focus(); cy.focused().should('match', '#last-input'); // Identifier interactions should not disrupt form focus cy.get('.usa-identifier__required-link').first().click(); // Focus should remain manageable cy.get('#first-input').focus(); cy.focused().should('match', '#first-input'); }); it('should work correctly in footer forms without conflicts', () => { let subscriptionSubmitted = false; let identifierLinkClicked = false; cy.mount(` `); cy.window().then((win) => { const form = win.document.getElementById('newsletter-form') as HTMLFormElement; form.addEventListener('submit', (e: Event) => { e.preventDefault(); subscriptionSubmitted = true; }); const identifier = win.document.getElementById('footer-identifier'); identifier?.addEventListener('link-click', () => { identifierLinkClicked = true; }); }); // Identifier should work in footer context cy.get('.usa-identifier__required-link') .first() .click() .then(() => { expect(identifierLinkClicked).to.be.true; expect(subscriptionSubmitted).to.be.false; }); // Newsletter form should work independently cy.get('#email-subscription').type('user@example.com'); cy.get('#newsletter-form button[type="submit"]') .click() .then(() => { expect(subscriptionSubmitted).to.be.true; }); }); it('should handle form validation states without interference', () => { cy.mount(`
Required Information
`); // Form validation should work normally with identifier present cy.get('button[type="submit"]').click(); // Identifier links should still be clickable during validation states cy.get('.usa-identifier__required-link').first().should('be.visible').click(); // Form should still be in validation state cy.get('#required-field').should('exist'); // Filling the field should allow submission cy.get('#required-field').type('Valid input'); cy.get('button[type="submit"]').click(); // Form should handle validation without JavaScript errors cy.get('#validation-form-identifier').should('exist'); }); it('should preserve form data when identifier interactions occur', () => { cy.mount(`
Personal Information
Additional Details
`); // Verify initial values cy.get('#full-name').should('have.value', 'Initial Name'); cy.get('#phone').should('have.value', '555-1234'); cy.get('#comments').should('have.value', 'Initial comments'); // Interact with identifier links cy.get('.usa-identifier__required-link').first().click(); cy.get('.usa-identifier__required-link').eq(1).click(); // Click identifier logo if present cy.get('.usa-identifier__logo').first().click(); // Form values should be preserved cy.get('#full-name').should('have.value', 'Initial Name'); cy.get('#phone').should('have.value', '555-1234'); cy.get('#comments').should('have.value', 'Initial comments'); // User should still be able to modify form values cy.get('#full-name').clear().type('Updated Name'); cy.get('#full-name').should('have.value', 'Updated Name'); }); it('should work correctly in multi-step forms with navigation', () => { let step1Completed = false; let step2Completed = false; let identifierNavigation = false; cy.mount(`
Step 1: Basic Info
`); cy.window().then((win) => { const nextButton = win.document.getElementById('next-step-btn'); const step1Form = win.document.getElementById('step-1-form') as HTMLFormElement; const step2Form = win.document.getElementById('step-2-form') as HTMLFormElement; nextButton?.addEventListener('click', () => { if (step1Form.checkValidity()) { step1Completed = true; step1Form.style.display = 'none'; step2Form.style.display = 'block'; } }); step2Form.addEventListener('submit', (e: Event) => { e.preventDefault(); if (step2Form.checkValidity()) { step2Completed = true; } }); const identifier = win.document.getElementById('multi-step-identifier'); identifier?.addEventListener('link-click', () => { identifierNavigation = true; }); }); // Complete step 1 with identifier interactions cy.get('#step1-name').type('Test User'); cy.get('.usa-identifier__required-link').first().click(); cy.get('#next-step-btn') .click() .then(() => { expect(step1Completed).to.be.true; expect(identifierNavigation).to.be.true; }); // Step 2 should be visible cy.get('#step-2-form').should('be.visible'); cy.get('#step-1-form').should('not.be.visible'); // Complete step 2 with more identifier interactions cy.get('#step2-email').type('test@example.com'); cy.get('.usa-identifier__required-link').eq(1).click(); cy.get('#step-2-form button[type="submit"]') .click() .then(() => { expect(step2Completed).to.be.true; }); }); it('should handle custom event propagation correctly in forms', () => { let customEventFired = false; let formSubmitted = false; let linkClickEventFired = false; cy.mount(`
Event Test
`); cy.window().then((win) => { const form = win.document.getElementById('custom-event-form') as HTMLFormElement; const identifier = win.document.getElementById('custom-event-identifier'); form.addEventListener('submit', (e: Event) => { e.preventDefault(); formSubmitted = true; }); form.addEventListener('custom-test-event', () => { customEventFired = true; }); identifier?.addEventListener('link-click', (e) => { linkClickEventFired = true; // Dispatch custom event to test propagation const customEvent = new CustomEvent('custom-test-event', { bubbles: true, detail: { source: 'identifier' }, }); (e.target as HTMLElement)?.dispatchEvent(customEvent); }); }); // Trigger identifier link click which should fire custom event cy.get('.usa-identifier__required-link') .first() .click() .then(() => { expect(linkClickEventFired).to.be.true; expect(customEventFired).to.be.true; expect(formSubmitted).to.be.false; }); // Form submission should still work normally cy.get('#event-input').type('test input'); cy.get('button[type="submit"]') .click() .then(() => { expect(formSubmitted).to.be.true; }); }); }); });