import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './usa-date-picker.ts';
import type { USADatePicker } from './usa-date-picker.js';
/**
* Date Picker Structure Regression Tests
*
* These tests prevent the specific regression where the date picker
* only shows the label but not the input field due to incorrect HTML structure.
*
* CRITICAL: These tests validate that the basic date picker structure
* follows the official USWDS pattern and remains visible to users.
*/
describe('Date Picker Structure Regression Prevention', () => {
let element: USADatePicker;
beforeEach(async () => {
element = document.createElement('usa-date-picker') as USADatePicker;
element.label = 'Test Date';
element.hint = 'Select a date';
element.placeholder = 'mm/dd/yyyy';
document.body.appendChild(element);
await element.updateComplete;
});
afterEach(() => {
element.remove();
});
describe('Basic Structure Validation (Prevents "label only" regression)', () => {
it('should render both label AND input field (prevents label-only bug)', async () => {
await element.updateComplete;
// These are the core elements that MUST be visible
const label = element.querySelector('.usa-label');
const input = element.querySelector('.usa-input');
const datePicker = element.querySelector('.usa-date-picker');
// CRITICAL: All three elements must exist for basic functionality
expect(label, 'Label should be present').toBeTruthy();
expect(input, 'Input field should be present - this was missing in the regression').toBeTruthy();
expect(datePicker, 'Date picker container should be present').toBeTruthy();
// Verify label text is visible
expect(label?.textContent?.trim()).toBe('Test Date');
// CRITICAL: Input must be functional
expect(input?.getAttribute('type')).toBe('text');
expect(input?.getAttribute('placeholder')).toBe('mm/dd/yyyy');
});
it('should follow official USWDS HTML structure pattern', async () => {
await element.updateComplete;
// Official USWDS pattern: input directly inside usa-date-picker
const datePicker = element.querySelector('.usa-date-picker');
const input = datePicker?.querySelector('.usa-input');
expect(datePicker, 'usa-date-picker container must exist').toBeTruthy();
expect(input, 'Input must be direct child of usa-date-picker').toBeTruthy();
// Verify the input is the direct child (no intermediate wrapper)
const directInput = datePicker?.children[0];
expect(directInput?.classList.contains('usa-input')).toBe(true);
});
it('should NOT have incorrect wrapper structure that causes visibility issues', async () => {
await element.updateComplete;
// The regression was caused by incorrectly nesting:
//
// This structure should NOT exist in the initial render
const incorrectWrapper = element.querySelector('.usa-date-picker__wrapper .usa-date-picker .usa-input');
expect(incorrectWrapper, 'Should NOT have nested wrapper structure in initial render').toBeNull();
// The correct structure should be: usa-date-picker > input (direct child)
const correctStructure = element.querySelector('.usa-date-picker > .usa-input');
expect(correctStructure, 'Input should be direct child of usa-date-picker').toBeTruthy();
});
});
describe('Visual Element Presence (Prevents invisible component regression)', () => {
it('should have visible label text', async () => {
await element.updateComplete;
const label = element.querySelector('.usa-label');
expect(label?.textContent?.trim()).toBe('Test Date');
// Check that label is not empty or hidden
expect(label?.textContent?.length).toBeGreaterThan(0);
});
it('should have visible input field with proper attributes', async () => {
await element.updateComplete;
const input = element.querySelector('.usa-input') as HTMLInputElement;
expect(input, 'Input field must be present and visible').toBeTruthy();
// Verify input is properly configured
expect(input.type).toBe('text');
expect(input.placeholder).toBe('mm/dd/yyyy');
expect(input.disabled).toBe(false);
// Verify input has proper USWDS class
expect(input.classList.contains('usa-input')).toBe(true);
});
it('should have visible hint text when provided', async () => {
await element.updateComplete;
const hint = element.querySelector('.usa-hint');
expect(hint, 'Hint should be present when hint prop is set').toBeTruthy();
expect(hint?.textContent?.trim()).toBe('Select a date');
});
it('should render all elements in a form group container', async () => {
await element.updateComplete;
const formGroup = element.querySelector('.usa-form-group');
expect(formGroup, 'Form group container should be present').toBeTruthy();
// Verify form group contains all expected elements
const label = formGroup?.querySelector('.usa-label');
const hint = formGroup?.querySelector('.usa-hint');
const datePicker = formGroup?.querySelector('.usa-date-picker');
const input = formGroup?.querySelector('.usa-input');
expect(label, 'Label should be in form group').toBeTruthy();
expect(hint, 'Hint should be in form group').toBeTruthy();
expect(datePicker, 'Date picker should be in form group').toBeTruthy();
expect(input, 'Input should be in form group').toBeTruthy();
});
});
describe('Functional Validation (Prevents broken component regression)', () => {
it('should allow typing in the input field', async () => {
await element.updateComplete;
const input = element.querySelector('.usa-input') as HTMLInputElement;
expect(input, 'Input must be present for typing').toBeTruthy();
// Simulate typing
input.value = '01/15/2024';
input.dispatchEvent(new Event('input', { bubbles: true }));
// Component should reflect the change
expect(input.value).toBe('01/15/2024');
});
it('should have proper accessibility attributes', async () => {
await element.updateComplete;
const input = element.querySelector('.usa-input');
const label = element.querySelector('.usa-label');
const hint = element.querySelector('.usa-hint');
// Verify label-input connection
expect(label?.getAttribute('for')).toBe(input?.getAttribute('id'));
// Verify hint connection
const hintId = hint?.getAttribute('id');
const ariaDescribedBy = input?.getAttribute('aria-describedby');
expect(ariaDescribedBy).toContain(hintId);
});
it('should handle value property correctly', async () => {
element.value = '2024-01-15';
await element.updateComplete;
const input = element.querySelector('.usa-input') as HTMLInputElement;
expect(input.value).toBe('2024-01-15');
// Test property updates
element.value = '2024-12-25';
await element.updateComplete;
expect(input.value).toBe('2024-12-25');
});
});
describe('USWDS Compatibility (Prevents integration regression)', () => {
it('should have correct data attributes for USWDS JavaScript', async () => {
element.minDate = '2024-01-01';
element.maxDate = '2024-12-31';
await element.updateComplete;
const datePicker = element.querySelector('.usa-date-picker');
expect(datePicker?.getAttribute('data-min-date')).toBe('2024-01-01');
expect(datePicker?.getAttribute('data-max-date')).toBe('2024-12-31');
});
it('should have structure ready for USWDS JavaScript enhancement', async () => {
await element.updateComplete;
// The structure should be ready for USWDS to add:
// - usa-date-picker__button
// - usa-date-picker__calendar
// - usa-date-picker__wrapper (dynamically)
const datePicker = element.querySelector('.usa-date-picker');
const input = element.querySelector('.usa-input');
// Basic structure must be correct for enhancement
expect(datePicker, 'Date picker container required for USWDS enhancement').toBeTruthy();
expect(input, 'Input required for USWDS enhancement').toBeTruthy();
expect(datePicker?.contains(input as Node)).toBe(true);
});
it('should not interfere with USWDS dynamic element creation', async () => {
await element.updateComplete;
// Ensure we don't have elements that would conflict with USWDS
const existingButton = element.querySelector('.usa-date-picker__button');
const existingCalendar = element.querySelector('.usa-date-picker__calendar');
const existingWrapper = element.querySelector('.usa-date-picker__wrapper');
// These should not exist initially (USWDS creates them)
expect(existingButton, 'Button should not exist initially - USWDS creates it').toBeNull();
expect(existingCalendar, 'Calendar should not exist initially - USWDS creates it').toBeNull();
expect(existingWrapper, 'Wrapper should not exist initially - USWDS creates it').toBeNull();
});
});
describe('Regression Test for Specific Bug (GitHub Issue #XXX)', () => {
it('REGRESSION: should show input field, not just label (fixes date picker invisibility)', async () => {
// This test specifically prevents the regression where:
// "The date label is visible but nothing else"
await element.updateComplete;
// Get all visible elements
const allElements = element.querySelectorAll('*');
const visibleElements = Array.from(allElements).filter(el => {
const style = window.getComputedStyle(el);
return style.display !== 'none' && style.visibility !== 'hidden';
});
// Must have label, input, hint, and containers
const label = element.querySelector('.usa-label');
const input = element.querySelector('.usa-input');
const hint = element.querySelector('.usa-hint');
const datePicker = element.querySelector('.usa-date-picker');
// All critical elements must be present
expect(label, 'REGRESSION: Label missing').toBeTruthy();
expect(input, 'REGRESSION: Input field missing - this was the main issue').toBeTruthy();
expect(hint, 'REGRESSION: Hint missing').toBeTruthy();
expect(datePicker, 'REGRESSION: Date picker container missing').toBeTruthy();
// The bug was that only label was visible, so we specifically verify:
expect(visibleElements.length, 'Should have multiple visible elements, not just label').toBeGreaterThan(3);
// Verify the structure that caused the regression is NOT present
const nestedWrapperStructure = element.querySelector('.usa-date-picker__wrapper > .usa-date-picker > .usa-input');
expect(nestedWrapperStructure, 'REGRESSION: Nested wrapper structure should not exist').toBeNull();
});
});
});