// Component tests for usa-text-input import './index.ts'; describe('USA Text Input Component Tests', () => { it('should render text input with default properties', () => { cy.mount(``); cy.get('usa-text-input').should('exist'); cy.get('usa-text-input input').should('have.class', 'usa-input'); }); it('should handle different input types', () => { const types = ['text', 'email', 'password', 'tel', 'url', 'search']; types.forEach((type) => { cy.mount(` `); cy.get(`#test-input-${type} input`).should('have.attr', 'type', type); }); }); it('should handle input value changes', () => { cy.mount(` `); cy.get('input').type('john.doe'); cy.get('input').should('have.value', 'john.doe'); cy.get('input').clear().type('jane.smith@example.com'); cy.get('input').should('have.value', 'jane.smith@example.com'); }); it('should emit input events', () => { cy.mount(` `); cy.window().then((win) => { const input = win.document.getElementById('test-input') as any; const inputSpy = cy.stub(); input.addEventListener('input', inputSpy); cy.get('input').type('test@example.gov'); cy.then(() => { expect(inputSpy).to.have.been.called; }); }); }); it('should emit change events', () => { cy.mount(` `); cy.window().then((win) => { const input = win.document.getElementById('test-input') as any; const changeSpy = cy.stub(); input.addEventListener('change', changeSpy); cy.get('input').type('555-123-4567').blur(); cy.then(() => { expect(changeSpy).to.have.been.called; }); }); }); it('should handle disabled state', () => { cy.mount(` `); cy.get('input').should('be.disabled'); cy.get('input').should('have.value', 'Cannot edit this'); cy.get('input').type('new text'); // Should not change cy.get('input').should('have.value', 'Cannot edit this'); }); it('should handle readonly state', () => { cy.mount(` `); cy.get('input').should('have.attr', 'readonly'); cy.get('input').type('attempt to change'); cy.get('input').should('have.value', 'Read only value'); }); it('should handle required state', () => { cy.mount(` `); cy.get('input').should('have.attr', 'required'); cy.get('input').should('have.attr', 'aria-required', 'true'); }); it('should handle error state', () => { cy.mount(` `); cy.get('input').should('have.class', 'usa-input--error'); cy.get('input').should('have.attr', 'aria-invalid', 'true'); cy.get('.usa-error-message').should('contain.text', 'Please enter a valid email address'); }); it('should handle success state', () => { cy.mount(` `); cy.get('input').should('have.class', 'usa-input--success'); }); it('should handle small size variant', () => { cy.mount(` `); cy.get('input').should('have.class', 'usa-input--small'); }); it('should handle large size variant', () => { cy.mount(` `); cy.get('input').should('have.class', 'usa-input--large'); }); it('should handle maxlength constraint', () => { cy.mount(` `); cy.get('input').should('have.attr', 'maxlength', '10'); cy.get('input').type('12345678901234567890'); cy.get('input').should('have.value', '1234567890'); // Limited to 10 chars }); it('should handle pattern validation', () => { cy.mount(` `); cy.get('input').should('have.attr', 'pattern', '[A-Za-z]{3,}'); }); it('should handle autocomplete attributes', () => { cy.mount(` `); cy.get('input').should('have.attr', 'autocomplete', 'email'); }); it('should handle spellcheck attribute', () => { cy.mount(` `); cy.get('input').should('have.attr', 'spellcheck', 'false'); }); it('should be keyboard accessible', () => { cy.mount(` `); // Tab to input cy.get('input').focus(); cy.focused().should('have.attr', 'name', 'accessible-field'); // Type in focused input cy.focused().type('accessible text'); cy.get('input').should('have.value', 'accessible text'); // Select all with Ctrl+A (Cmd+A on Mac) cy.focused().type('{cmd+a}'); cy.focused().type('replaced'); cy.get('input').should('have.value', 'replaced'); }); it('should handle aria attributes', () => { cy.mount(`
Enter your government email address
`); cy.get('input') .should('have.attr', 'aria-labelledby', 'input-label') .should('have.attr', 'aria-describedby', 'input-hint'); }); it('should work in form submission', () => { cy.mount(`
`); cy.window().then((win) => { const form = win.document.getElementById('test-form') as HTMLFormElement; const submitSpy = cy.stub(); form.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(form); submitSpy(formData.get('user-email')); }); cy.get('button[type="submit"]').click(); cy.then(() => { expect(submitSpy).to.have.been.calledWith('user@agency.gov'); }); }); }); it('should handle focus and blur events', () => { cy.mount(` `); cy.window().then((win) => { const input = win.document.getElementById('test-input') as any; const focusSpy = cy.stub(); const blurSpy = cy.stub(); input.addEventListener('focus', focusSpy); input.addEventListener('blur', blurSpy); cy.get('input').focus(); cy.get('input').blur(); cy.then(() => { expect(focusSpy).to.have.been.called; expect(blurSpy).to.have.been.called; }); }); }); it('should handle validation on blur', () => { cy.mount(` `); // Enter invalid email and blur cy.get('input').type('invalid-email').blur(); cy.get('input').should('have.attr', 'aria-invalid', 'true'); // Enter valid email and blur cy.get('input').clear().type('valid@example.gov').blur(); cy.get('input').should('not.have.attr', 'aria-invalid', 'true'); }); it('should be accessible', () => { cy.mount(`
We'll never share your email
`); cy.injectAxe(); cy.checkAccessibility(); }); it('should handle character counting', () => { cy.mount(` `); cy.get('input').type('This is a test message'); cy.get('.usa-character-count').should('contain', '22 characters of 50 used'); }); it('should handle custom CSS classes', () => { cy.mount(` `); cy.get('usa-text-input').should('have.class', 'custom-input-class'); cy.get('input').should('have.class', 'usa-input'); }); it('should handle copy and paste operations', () => { cy.mount(` `); // Type initial text cy.get('input').type('Initial text'); // Select all and copy would work in real browser cy.get('input').select(); // Select all text // Clear and type new text (simulating paste) cy.get('input').clear().type('Pasted content'); cy.get('input').should('have.value', 'Pasted content'); }); // Responsive Layout Tests describe('Mobile Responsive Behavior', () => { beforeEach(() => { cy.viewport(375, 667); // iPhone SE }); it('should display properly on mobile with touch targets', () => { cy.mount(`
`); // Input should be at least 44px high for touch targets cy.get('input') .should('be.visible') .and(($input) => { const height = $input.outerHeight(); expect(height).to.be.at.least(44); }); }); it('should handle mobile form layout stacking', () => { cy.mount(`
`); // Form should stack vertically on mobile cy.get('.usa-form-group').should('have.length', 3); cy.get('.usa-form-group').each(($group) => { cy.wrap($group) .should('have.css', 'width') .and('match', /375px|100%/); }); }); it('should handle touch interactions properly', () => { cy.mount(` `); // Touch events should work on mobile cy.get('input').trigger('touchstart').trigger('touchend').should('be.focused'); // Virtual keyboard should be appropriate for input type cy.get('input').should('have.attr', 'type', 'tel'); }); it('should handle mobile error states', () => { cy.mount(`
`); cy.get('.usa-error-message').should('be.visible'); cy.get('input').should('have.class', 'usa-input--error'); // Error message should be readable on mobile cy.get('.usa-error-message').should('have.css', 'font-size'); }); it('should handle mobile success states', () => { cy.mount(`
`); cy.get('input').should('have.class', 'usa-input--success'); }); it('should handle character count display on mobile', () => { cy.mount(` `); const testText = 'This is mobile content for testing'; cy.get('input').type(testText); cy.get('.usa-character-count') .should('be.visible') .should('contain', `${testText.length} characters of 50 used`); }); it('should handle different mobile input types', () => { const mobileInputTypes = [ { type: 'tel', placeholder: '(555) 123-4567' }, { type: 'email', placeholder: 'user@agency.gov' }, { type: 'url', placeholder: 'https://example.gov' }, { type: 'search', placeholder: 'Search...' }, ]; mobileInputTypes.forEach(({ type, placeholder }) => { cy.mount(` `); cy.get('input') .should('have.attr', 'type', type) .should('have.attr', 'placeholder', placeholder); // Test virtual keyboard activation cy.get('input').focus().should('be.focused'); }); }); }); describe('Tablet Responsive Behavior', () => { beforeEach(() => { cy.viewport(768, 1024); // iPad }); it('should display form in two-column layout on tablet', () => { cy.mount(`
`); // Check grid layout on tablet cy.get('.tablet\\:grid-col-6').should('have.length', 4); cy.get('.tablet\\:grid-col-6').each(($col) => { cy.wrap($col).should('have.css', 'width').and('not.equal', '768px'); }); }); it('should handle tablet touch and hover states', () => { cy.mount(` `); // Should work with both touch and mouse cy.get('input').trigger('touchstart').trigger('touchend').should('be.focused'); cy.get('input').trigger('mouseover').should('have.focus'); }); it('should handle tablet large size variant', () => { cy.mount(` `); cy.get('input').should('have.class', 'usa-input--large'); }); it('should handle tablet form with validation', () => { cy.mount(`
`); cy.get('input[name="password"]').type('password123'); cy.get('input[name="confirmPassword"]').type('password123'); cy.get('input[name="password"]').should('have.value', 'password123'); cy.get('input[name="confirmPassword"]').should('have.value', 'password123'); }); }); describe('Desktop Responsive Behavior', () => { beforeEach(() => { cy.viewport(1200, 800); // Desktop }); it('should display full desktop form layout', () => { cy.mount(`
`); // Check three-column layout on desktop cy.get('.desktop\\:grid-col-4').should('have.length', 3); cy.get('.desktop\\:grid-col-6').should('have.length', 2); }); it('should handle keyboard navigation efficiently on desktop', () => { cy.mount(`
`); // Tab through inputs cy.get('input').first().focus(); cy.focused().should('have.attr', 'name', 'first'); cy.focused().tab(); cy.focused().should('have.attr', 'name', 'second'); cy.focused().tab(); cy.focused().should('have.attr', 'name', 'third'); }); it('should handle desktop hover states', () => { cy.mount(` `); cy.get('input').trigger('mouseover').should('have.css', 'cursor', 'text'); }); it('should handle desktop focus indicators', () => { cy.mount(` `); cy.get('input') .focus() .should('have.focus') .should('have.css', 'outline-width') .and('not.equal', '0px'); }); it('should handle desktop autocomplete efficiently', () => { cy.mount(`
`); cy.get('input[autocomplete="name"]').should('have.attr', 'autocomplete', 'name'); cy.get('input[autocomplete="email"]').should('have.attr', 'autocomplete', 'email'); }); it('should handle desktop character counting', () => { cy.mount(`
`); const usernameText = 'john.doe'; const titleText = 'Senior Software Engineer'; cy.get('#desktop-username').type(usernameText); cy.get('#desktop-title').type(titleText); cy.get('.usa-character-count').should('have.length', 2); }); }); describe('Large Desktop Responsive Behavior', () => { beforeEach(() => { cy.viewport(1440, 900); // Large Desktop }); it('should maintain proper spacing on large screens', () => { cy.mount(`
`); // Should have proper four-column layout cy.get('.desktop\\:grid-col-3').should('have.length', 4); // Container should be properly centered cy.get('.grid-container').should('have.css', 'max-width'); // Inputs should have adequate width on large screens cy.get('input').each(($input) => { cy.wrap($input).then(($el) => { const width = $el.outerWidth(); expect(width).to.be.greaterThan(200); }); }); }); it('should handle large desktop forms with mixed input types', () => { cy.mount(`
`); // Test different input types work properly cy.get('input[type="search"]').should('have.class', 'usa-input--large'); cy.get('input[type="url"]').type('https://agency.gov'); cy.get('input[type="password"]').type('securePassword123'); cy.get('input[type="url"]').should('have.value', 'https://agency.gov'); cy.get('input[type="password"]').should('have.value', 'securePassword123'); }); }); describe('Responsive Edge Cases', () => { it('should handle viewport transitions smoothly', () => { cy.mount(`
`); const transitionText = 'This text tests smooth transitions'; // Test mobile to tablet transition cy.viewport(375, 667); cy.get('input').type(transitionText).should('be.visible'); cy.viewport(768, 1024); cy.get('input').should('be.visible').should('have.value', transitionText); cy.viewport(1200, 800); cy.get('input').should('be.visible').should('have.value', transitionText); }); it('should handle long placeholder text at different screen sizes', () => { const longPlaceholder = 'This is a very long placeholder text that might cause layout issues on smaller screens'; cy.mount(` `); // Test at different viewports const viewports = [ [320, 568], // Small mobile [768, 1024], // Tablet [1200, 800], // Desktop ]; viewports.forEach(([width, height]) => { cy.viewport(width, height); cy.get('input').should('be.visible'); // Should not cause horizontal overflow cy.get('input').then(($input) => { expect($input[0].scrollWidth).to.be.at.most($input[0].clientWidth + 5); }); }); }); it('should handle dynamic value updates at different screen sizes', () => { cy.mount(` `); const scenarios = [ { viewport: [375, 667], value: 'Mobile input' }, { viewport: [768, 1024], value: 'Tablet input with more content' }, { viewport: [1200, 800], value: 'Desktop input with even more detailed content that fits well on larger screens', }, ]; scenarios.forEach(({ viewport, value }) => { cy.viewport(viewport[0], viewport[1]); cy.get('input').clear().type(value); cy.get('input').should('have.value', value); }); }); it('should maintain accessibility at all screen sizes', () => { cy.mount(`
This input should be accessible at all screen sizes
`); const viewports = [ [375, 667], // Mobile [768, 1024], // Tablet [1200, 800], // Desktop ]; viewports.forEach(([width, height]) => { cy.viewport(width, height); cy.injectAxe(); cy.checkAccessibility(); // Check focus indicators work at all sizes cy.get('input') .focus() .should('have.focus') .should('have.css', 'outline-width') .and('not.equal', '0px'); }); }); it('should handle form validation at different screen sizes', () => { cy.mount(`
`); const scenarios = [ { viewport: [375, 667], input: 'invalid-email' }, { viewport: [768, 1024], input: 'user@agency.gov' }, { viewport: [1200, 800], input: 'another.user@department.gov' }, ]; scenarios.forEach(({ viewport, input }) => { cy.viewport(viewport[0], viewport[1]); cy.get('input').clear().type(input); // Check validity if (input.includes('@') && input.includes('.')) { cy.get('input').should('satisfy', ($el) => { return $el[0].checkValidity(); }); } }); }); it('should handle copy-paste operations at different screen sizes', () => { cy.mount(` `); const pasteContent = 'This is content that was copied from another source and pasted into the input field'; const viewports = [ [375, 667], // Mobile [768, 1024], // Tablet [1200, 800], // Desktop ]; viewports.forEach(([width, height]) => { cy.viewport(width, height); cy.get('input').clear().type(pasteContent); cy.get('input').should('have.value', pasteContent); // Select all and replace (simulating paste) cy.get('input').select().type('Replaced content at different viewport'); cy.get('input').should('have.value', 'Replaced content at different viewport'); }); }); }); });