import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import './usa-alert.ts';
import type { USAAlert } from './usa-alert.js';
import {
testComponentAccessibility,
USWDS_A11Y_CONFIG,
} from '../../../__tests__/accessibility-utils.js';
import { quickUSWDSComplianceTest } from '../../../__tests__/uswds-compliance-utils.js';
import { validateComponentJavaScript } from '../../../__tests__/test-utils.js';
import {
testKeyboardNavigation,
verifyKeyboardOnlyUsable,
getFocusableElements,
} from '../../../__tests__/keyboard-navigation-utils.js';
import {
testARIAAccessibility,
testARIARoles,
testAccessibleName,
testLiveRegionAnnouncements,
} from '../../../__tests__/aria-screen-reader-utils.js';
type AlertVariant = 'info' | 'warning' | 'error' | 'success' | 'emergency';
describe('USAAlert', () => {
let element: USAAlert;
beforeEach(() => {
element = document.createElement('usa-alert') as USAAlert;
document.body.appendChild(element);
});
afterEach(() => {
element.remove();
});
describe('Default Properties', () => {
it('should have correct default properties', async () => {
await element.updateComplete;
expect(element.variant).toBe('info');
expect(element.heading).toBe('');
expect(element.slim).toBe(false);
expect(element.noIcon).toBe(false);
});
it('should set appropriate ARIA role by default', async () => {
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
});
});
describe('Variant Property', () => {
it('should render correct CSS class for each variant', async () => {
const variants = ['info', 'success', 'warning', 'error', 'emergency'] as const;
for (const variant of variants) {
element.variant = variant;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains(`usa-alert--${variant}`)).toBe(true);
}
});
it('should set alert role for urgent variants', async () => {
// Error and emergency should have alert role
element.variant = 'error';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('alert');
element.variant = 'emergency';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('alert');
// Info, success, warning should have status role
element.variant = 'info';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
element.variant = 'success';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
element.variant = 'warning';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
});
it('should pass comprehensive accessibility tests (same as Storybook)', async () => {
element.heading = 'Test Alert';
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
});
it('should pass comprehensive USWDS compliance tests (prevents structural issues)', async () => {
element.heading = 'Test Alert';
await element.updateComplete;
quickUSWDSComplianceTest(element, 'usa-alert');
});
});
describe('Heading Property', () => {
it('should render heading when provided', async () => {
element.heading = 'Test Heading';
await element.updateComplete;
const headingElement = element.querySelector('.usa-alert__heading');
expect(headingElement?.textContent).toBe('Test Heading');
});
it('should not render heading element when heading is empty', async () => {
element.heading = '';
await element.updateComplete;
const headingElement = element.querySelector('.usa-alert__heading');
expect(headingElement).toBeNull();
});
});
describe('Slim Property', () => {
it('should add slim CSS class when slim is true', async () => {
element.slim = true;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--slim')).toBe(true);
});
it('should not add slim CSS class when slim is false', async () => {
element.slim = false;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--slim')).toBe(false);
});
});
describe('NoIcon Property', () => {
it('should add no-icon CSS class when noIcon is true', async () => {
element.noIcon = true;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--no-icon')).toBe(true);
});
it('should not add no-icon CSS class when noIcon is false', async () => {
element.noIcon = false;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--no-icon')).toBe(false);
});
});
describe('Slot Content', () => {
it('should render text property content in alert text', async () => {
// Note: Slots don't work in jsdom, so we test using the text property
const testElement = document.createElement('usa-alert') as USAAlert;
testElement.variant = 'info';
testElement.heading = 'Test Heading';
testElement.text = 'This is test text content';
document.body.appendChild(testElement);
await testElement.updateComplete;
// Check structure exists
const alertDiv = testElement.querySelector('.usa-alert');
expect(alertDiv).toBeTruthy();
const alertBody = testElement.querySelector('.usa-alert__body');
expect(alertBody).toBeTruthy();
const alertText = testElement.querySelector('.usa-alert__text');
expect(alertText).toBeTruthy();
// Check that content appears in alert text
expect(alertText?.textContent?.trim()).toBe('This is test text content');
testElement.remove();
});
it('should render HTML structure correctly', async () => {
// Test that the component structure is set up correctly for content
// (Light DOM content handling - tested in Cypress/Storybook)
const newElement = document.createElement('usa-alert') as USAAlert;
newElement.variant = 'success';
newElement.heading = 'Success Message';
document.body.appendChild(newElement);
await newElement.updateComplete;
// Verify structure is correct
const alertText = newElement.querySelector('.usa-alert__text');
expect(alertText).toBeTruthy();
expect(alertText?.tagName.toLowerCase()).toBe('p');
// Verify USWDS structure
const alertBody = newElement.querySelector('.usa-alert__body');
expect(alertBody).toBeTruthy();
newElement.remove();
});
it('should render content without duplication', async () => {
// Test using text property (slots don't work in jsdom)
const testElement = document.createElement('usa-alert') as USAAlert;
testElement.variant = 'warning';
testElement.heading = 'Unique Test';
testElement.text = 'This is unique test content';
document.body.appendChild(testElement);
await testElement.updateComplete;
// Count occurrences of the unique text
const allText = testElement.innerHTML;
const uniquePhrase = 'unique test content';
const occurrences = (allText.toLowerCase().match(new RegExp(uniquePhrase, 'g')) || []).length;
// Should appear exactly once (in the alert text, not duplicated)
expect(occurrences).toBe(1);
// Verify it's in the correct location
const alertText = testElement.querySelector('.usa-alert__text');
expect(alertText?.textContent?.toLowerCase()).toContain(uniquePhrase);
testElement.remove();
});
});
describe('HTML Structure', () => {
it('should render correct USWDS HTML structure', async () => {
element.variant = 'info';
element.heading = 'Test Heading';
await element.updateComplete;
// Check main structure
const alertDiv = element.querySelector('.usa-alert.usa-alert--info');
expect(alertDiv).toBeTruthy();
const alertBody = element.querySelector('.usa-alert__body');
expect(alertBody).toBeTruthy();
const alertHeading = element.querySelector('.usa-alert__heading');
expect(alertHeading?.tagName.toLowerCase()).toBe('h4');
expect(alertHeading?.textContent).toBe('Test Heading');
const alertText = element.querySelector('.usa-alert__text');
expect(alertText?.tagName.toLowerCase()).toBe('p');
});
it('should not render dismiss button (USWDS compliance)', async () => {
// Verify no dismiss button exists in USWDS-compliant implementation
await element.updateComplete;
const dismissButton = element.querySelector('.usa-alert__dismiss');
expect(dismissButton).toBeNull();
});
});
describe('CSS Classes', () => {
it('should apply all appropriate USWDS classes', async () => {
element.variant = 'warning';
element.slim = true;
element.noIcon = true;
await element.updateComplete;
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert')).toBe(true);
expect(alertDiv?.classList.contains('usa-alert--warning')).toBe(true);
expect(alertDiv?.classList.contains('usa-alert--slim')).toBe(true);
expect(alertDiv?.classList.contains('usa-alert--no-icon')).toBe(true);
});
});
describe('Accessibility', () => {
it('should have proper ARIA roles for different variants', async () => {
// Test urgent variants (error, emergency) get alert role
const urgentVariants: AlertVariant[] = ['error', 'emergency'];
for (const variant of urgentVariants) {
element.variant = variant;
await element.updateComplete;
expect(element.getAttribute('role')).toBe('alert');
}
// Test non-urgent variants get status role
const nonUrgentVariants: AlertVariant[] = ['info', 'success', 'warning'];
for (const variant of nonUrgentVariants) {
element.variant = variant;
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
}
});
it('should use semantic HTML elements', async () => {
element.heading = 'Alert Heading';
await element.updateComplete;
const heading = element.querySelector('.usa-alert__heading');
expect(heading?.tagName.toLowerCase()).toBe('h4');
const text = element.querySelector('.usa-alert__text');
expect(text?.tagName.toLowerCase()).toBe('p');
});
});
describe('Property Updates', () => {
it('should update DOM when properties change', async () => {
// Initial state
await element.updateComplete;
let alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--info')).toBe(true);
// Change variant
element.variant = 'success';
await element.updateComplete;
alertDiv = element.querySelector('.usa-alert');
expect(alertDiv?.classList.contains('usa-alert--success')).toBe(true);
expect(alertDiv?.classList.contains('usa-alert--info')).toBe(false);
// Change heading
element.heading = 'New Heading';
await element.updateComplete;
const heading = element.querySelector('.usa-alert__heading');
expect(heading?.textContent).toBe('New Heading');
});
});
describe('Light DOM Rendering', () => {
it('should render in light DOM for USWDS compatibility', async () => {
await element.updateComplete;
// Content should be directly in the element (light DOM)
const alertDiv = element.querySelector('.usa-alert');
expect(alertDiv).toBeTruthy();
// Should not have shadow root
expect(element.shadowRoot).toBeNull();
});
describe('JavaScript Implementation Validation', () => {
it('should pass JavaScript implementation validation', async () => {
// Validate USWDS JavaScript implementation patterns
const componentPath =
`${process.cwd()}/src/components/alert/usa-alert.ts`;
const validation = validateComponentJavaScript(componentPath, 'alert');
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 info alert with heading
let element = document.createElement('usa-alert') as USAAlert;
element.variant = 'info';
element.heading = 'Information';
element.appendChild(document.createTextNode('This is an informational alert.'));
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Test success alert
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'success';
element.heading = 'Success';
element.appendChild(document.createTextNode('Your action was completed successfully.'));
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Test warning alert
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'warning';
element.heading = 'Warning';
element.appendChild(
document.createTextNode('Please review your information before continuing.')
);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Test error alert
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'error';
element.heading = 'Error';
element.appendChild(document.createTextNode('There was an error processing your request.'));
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
});
it('should maintain accessibility during dynamic state changes', async () => {
// Emergency alert with content
let element = document.createElement('usa-alert') as USAAlert;
element.variant = 'emergency';
element.heading = 'Emergency Alert';
element.appendChild(
document.createTextNode(
'This is an emergency notification that requires immediate attention.'
)
);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Alert without heading
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'info';
element.appendChild(
document.createTextNode('Alert message without heading for accessibility testing.')
);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Alert with complex content and links
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'warning';
element.heading = 'Alert with Links';
const linkText = document.createElement('span');
linkText.innerHTML =
'Your session will expire in 5 minutes. Extend session or save your work.';
element.appendChild(linkText);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
});
it('should be accessible in real-world government use cases', async () => {
// System maintenance notification
let element = document.createElement('usa-alert') as USAAlert;
element.variant = 'warning';
element.heading = 'Scheduled Maintenance';
const maintenanceText = document.createElement('span');
maintenanceText.innerHTML =
'This system will be unavailable for maintenance on Saturday, March 15th from 2:00 AM to 6:00 AM EST. Please save your work and log out before this time. For urgent matters, contact our 24-hour support line.';
element.appendChild(maintenanceText);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Security alert
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'error';
element.heading = 'Security Alert';
const securityText = document.createElement('span');
securityText.innerHTML =
'We detected unusual activity on your account. Please review your account security and change your password immediately. If you did not authorize this activity, contact support immediately.';
element.appendChild(securityText);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Application success notification
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'success';
element.heading = 'Application Submitted';
const successText = document.createElement('span');
successText.innerHTML =
'Your application has been successfully submitted. Application ID: APP-2024-001234. You will receive email updates at key milestones. Track your application status here.';
element.appendChild(successText);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Emergency notification
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'emergency';
element.heading = 'Emergency Services Alert';
const emergencyText = document.createElement('span');
emergencyText.innerHTML =
'Emergency services are currently experiencing high call volumes. For life-threatening emergencies, call 911 immediately. For non-emergency assistance, use our emergency contacts directory.';
element.appendChild(emergencyText);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
// Simple informational alert without heading
element = document.createElement('usa-alert') as USAAlert;
element.variant = 'info';
element.appendChild(
document.createTextNode(
'New features are now available in your dashboard. Explore the updated interface to access enhanced functionality.'
)
);
document.body.appendChild(element);
await element.updateComplete;
await testComponentAccessibility(element, USWDS_A11Y_CONFIG.FULL_COMPLIANCE);
element.remove();
});
});
describe('Keyboard Navigation (WCAG 2.1)', () => {
it('should allow keyboard navigation to links in alert content', async () => {
element.variant = 'info';
element.heading = 'System Update';
const content = document.createElement('div');
content.innerHTML = 'Please review the latest updates and configure your settings.';
element.appendChild(content);
await element.updateComplete;
// Get all focusable elements (links)
const focusableElements = getFocusableElements(element);
expect(focusableElements.length).toBe(2); // Two links
// Verify each link is keyboard accessible
focusableElements.forEach((link) => {
expect(link.tagName).toBe('A');
expect((link as HTMLElement).tabIndex).toBeGreaterThanOrEqual(0);
});
});
it('should be keyboard-only usable when containing interactive elements', async () => {
element.variant = 'warning';
element.heading = 'Action Required';
const content = document.createElement('div');
content.innerHTML = 'Your session will expire soon. or log out now.';
element.appendChild(content);
await element.updateComplete;
const result = await verifyKeyboardOnlyUsable(element);
expect(result.passed).toBe(true);
expect(result.report).toContain('keyboard accessible');
});
it('should pass keyboard navigation tests for interactive alerts', async () => {
element.variant = 'error';
element.heading = 'Error';
const content = document.createElement('div');
content.innerHTML = 'An error occurred. Get help or try again.';
element.appendChild(content);
await element.updateComplete;
const result = await testKeyboardNavigation(element, {
testEscapeKey: false, // Alerts don't close with Escape
testArrowKeys: false, // Alerts don't use arrow navigation
});
expect(result.passed).toBe(true);
expect(result.errors).toHaveLength(0);
});
it('should have no keyboard traps in alert content', async () => {
element.variant = 'success';
element.heading = 'Success';
const content = document.createElement('div');
content.innerHTML = 'Operation completed. View results, history, or reports.';
element.appendChild(content);
await element.updateComplete;
const links = element.querySelectorAll('a');
expect(links.length).toBe(3);
// Focus first link
(links[0] as HTMLElement).focus();
expect(document.activeElement).toBe(links[0]);
// Verify Tab key is not trapped
const tabEvent = new KeyboardEvent('keydown', {
key: 'Tab',
code: 'Tab',
keyCode: 9,
bubbles: true,
cancelable: true,
});
links[0].dispatchEvent(tabEvent);
expect(tabEvent.defaultPrevented).toBe(false);
});
it('should maintain proper tab order for multiple interactive elements', async () => {
element.variant = 'info';
element.heading = 'Multiple Actions';
const content = document.createElement('div');
content.innerHTML = `
First
Third
`;
element.appendChild(content);
await element.updateComplete;
const focusableElements = getFocusableElements(element);
expect(focusableElements.length).toBe(4);
// Verify tab order is sequential
focusableElements.forEach((el, index) => {
expect((el as HTMLElement).tabIndex).toBeGreaterThanOrEqual(0);
});
});
it('should handle alerts without interactive content (no focusable elements)', async () => {
element.variant = 'info';
element.heading = 'Information';
element.appendChild(document.createTextNode('This is a simple informational message.'));
await element.updateComplete;
const focusableElements = getFocusableElements(element);
expect(focusableElements.length).toBe(0); // No interactive elements
// Alert should still be accessible via screen readers (role="status")
expect(element.getAttribute('role')).toBe('status');
});
it('should support keyboard activation of buttons in alert content', async () => {
element.variant = 'warning';
element.heading = 'Warning';
const button = document.createElement('button');
button.type = 'button';
button.textContent = 'Dismiss';
let clicked = false;
button.addEventListener('click', () => {
clicked = true;
});
const content = document.createElement('div');
content.textContent = 'Unsaved changes detected. ';
content.appendChild(button);
element.appendChild(content);
await element.updateComplete;
// Focus the button
button.focus();
expect(document.activeElement).toBe(button);
// Activate with Enter key
const enterEvent = new KeyboardEvent('keydown', {
key: 'Enter',
bubbles: true,
cancelable: true,
});
button.dispatchEvent(enterEvent);
// Native buttons handle Enter automatically in browser
// In jsdom we verify the button is properly set up
expect(button.type).toBe('button');
expect((button as HTMLElement).tabIndex).toBeGreaterThanOrEqual(0);
});
it('should handle keyboard focus for emergency variant with multiple actions', async () => {
element.variant = 'emergency';
element.heading = 'Emergency';
const content = document.createElement('div');
content.innerHTML = `
Emergency!
Contact Emergency Services or
View Emergency Information.
`;
element.appendChild(content);
await element.updateComplete;
const result = await verifyKeyboardOnlyUsable(element);
expect(result.passed).toBe(true);
// Verify proper ARIA role for emergency
expect(element.getAttribute('role')).toBe('alert');
});
});
describe('ARIA/Screen Reader Accessibility (WCAG 4.1)', () => {
beforeEach(async () => {
element = document.createElement('usa-alert') as USAAlert;
document.body.appendChild(element);
await element.updateComplete;
});
afterEach(() => {
element.remove();
});
it('should have correct ARIA role for info variant', async () => {
element.variant = 'info';
element.heading = 'Information';
await element.updateComplete;
const result = testARIARoles(element, {
expectedRole: 'status',
});
expect(result.correct).toBe(true);
expect(result.violations.length).toBe(0);
});
it('should have correct ARIA role for error variant', async () => {
element.variant = 'error';
element.heading = 'Error occurred';
await element.updateComplete;
const result = testARIARoles(element, {
expectedRole: 'alert',
});
expect(result.correct).toBe(true);
});
it('should have correct ARIA role for warning variant', async () => {
element.variant = 'warning';
element.heading = 'Warning';
await element.updateComplete;
// Warning uses role="status", not role="alert"
const result = testARIARoles(element, {
expectedRole: 'status',
});
expect(result.correct).toBe(true);
});
it('should have correct ARIA role for success variant', async () => {
element.variant = 'success';
element.heading = 'Success!';
await element.updateComplete;
const result = testARIARoles(element, {
expectedRole: 'status',
});
expect(result.correct).toBe(true);
});
it('should have correct ARIA role for emergency variant', async () => {
element.variant = 'emergency';
element.heading = 'Emergency!';
await element.updateComplete;
const result = testARIARoles(element, {
expectedRole: 'alert',
});
expect(result.correct).toBe(true);
});
it('should have accessible text in heading element', async () => {
element.heading = 'Alert heading';
await element.updateComplete;
const heading = element.querySelector('.usa-alert__heading');
expect(heading).toBeTruthy();
expect(heading?.textContent).toContain('Alert heading');
// The element itself should be accessible as a status/alert region
const result = testAccessibleName(element);
// Alert components typically don't have explicit accessible names
// They rely on their role and content
expect(result).toBeDefined();
});
// ✅ CYPRESS COVERAGE: cypress/e2e/alert-announcements.cy.ts
// Tests ARIA role implementation (role="status" or role="alert")
// Browser testing validates actual screen reader accessibility
// ✅ CYPRESS COVERAGE: cypress/e2e/alert-announcements.cy.ts
// Tests error alert ARIA role and accessibility structure
it('should pass comprehensive ARIA accessibility tests', async () => {
element.variant = 'info';
element.heading = 'System notification';
const content = document.createElement('div');
content.textContent = 'Your changes have been saved.';
element.appendChild(content);
await element.updateComplete;
const result = await testARIAAccessibility(element, {
testLiveRegions: true,
testRoleState: true,
testNameRole: true,
});
expect(result.passed).toBe(true);
expect(result.details.rolesCorrect).toBe(true);
});
it('should maintain ARIA attributes when variant changes', async () => {
element.variant = 'info';
element.heading = 'Info';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
element.variant = 'error';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('alert');
element.variant = 'success';
await element.updateComplete;
expect(element.getAttribute('role')).toBe('status');
});
// ✅ CYPRESS COVERAGE: cypress/e2e/alert-announcements.cy.ts
// Tests all variant ARIA roles and accessibility in real browser
});
describe('Color/Contrast Accessibility (WCAG 1.4)', () => {
it('should verify info variant has USWDS classes for contrast', async () => {
const { testColorContrast } = await import('../../../__tests__/contrast-utils.js');
element.variant = 'info';
element.heading = 'Info Alert';
await element.updateComplete;
const alert = element.querySelector('.usa-alert');
expect(alert).toBeTruthy();
// Verify USWDS classes
expect(alert?.classList.contains('usa-alert--info')).toBe(true);
const result = testColorContrast(alert as Element);
// Structure validation
expect(result).toBeDefined();
expect(result.foreground).toBeDefined();
expect(result.background).toBeDefined();
});
it('should verify warning variant has USWDS classes for contrast', async () => {
element.variant = 'warning';
element.heading = 'Warning Alert';
await element.updateComplete;
const alert = element.querySelector('.usa-alert');
expect(alert).toBeTruthy();
// Verify USWDS classes
expect(alert?.classList.contains('usa-alert--warning')).toBe(true);
});
it('should verify error variant has USWDS classes for contrast', async () => {
element.variant = 'error';
element.heading = 'Error Alert';
await element.updateComplete;
const alert = element.querySelector('.usa-alert');
expect(alert).toBeTruthy();
// Verify USWDS classes
expect(alert?.classList.contains('usa-alert--error')).toBe(true);
});
it('should verify success variant has USWDS classes for contrast', async () => {
element.variant = 'success';
element.heading = 'Success Alert';
await element.updateComplete;
const alert = element.querySelector('.usa-alert');
expect(alert).toBeTruthy();
// Verify USWDS classes
expect(alert?.classList.contains('usa-alert--success')).toBe(true);
});
it('should calculate contrast correctly for alert text', async () => {
const { calculateContrastRatio } = await import('../../../__tests__/contrast-utils.js');
// USWDS alert colors should have sufficient contrast
// Test that our contrast calculator works correctly
// Typical dark text on light background
const textContrast = calculateContrastRatio('#1b1b1b', '#f0f0f0');
expect(textContrast).toBeGreaterThan(4.5);
// High contrast (black on white)
const highContrast = calculateContrastRatio('#000000', '#ffffff');
expect(highContrast).toBeCloseTo(21, 0);
});
it('should verify alert heading has adequate contrast', async () => {
const { testColorContrast } = await import('../../../__tests__/contrast-utils.js');
element.heading = 'Alert Heading';
element.text = 'Alert body text';
await element.updateComplete;
const heading = element.querySelector('.usa-alert__heading');
expect(heading).toBeTruthy();
const result = testColorContrast(heading as Element);
// Structure validation
expect(result).toBeDefined();
expect(result.isLargeText).toBe(false);
});
});
});