import { test, expect } from '@playwright/test'; import { waitForLiveComponent, fillAndSubmitForm, assertValidationError, assertNoValidationErrors, waitForSuccessMessage } from '../support/test-helpers'; /** * LiveComponents: Form Validation Tests * * Tests real-time form validation with LiveComponents */ test.describe('LiveComponents Form Validation', () => { test.beforeEach(async ({ page }) => { // Navigate to a page with LiveComponent form // Adjust URL based on your actual routes await page.goto('/'); }); test('should show validation errors on invalid input', async ({ page }) => { // Skip if no form is present on homepage const formCount = await page.locator('form').count(); if (formCount === 0) { test.skip(); return; } const form = page.locator('form').first(); // Try to submit empty form await form.locator('button[type="submit"]').click(); // Wait a bit for validation to trigger await page.waitForTimeout(500); // Check if any validation messages appear const errorMessages = page.locator('.error-message, [class*="error-"], .invalid-feedback'); const errorCount = await errorMessages.count(); // If there are required fields, there should be error messages const requiredFields = await form.locator('[required]').count(); if (requiredFields > 0) { expect(errorCount).toBeGreaterThan(0); } }); test('should validate email format in real-time', async ({ page }) => { // Look for email input const emailInput = page.locator('input[type="email"]').first(); const emailCount = await emailInput.count(); if (emailCount === 0) { test.skip(); return; } // Enter invalid email await emailInput.fill('invalid-email'); await emailInput.blur(); // Wait for validation await page.waitForTimeout(500); // Check for error message (if client-side validation is present) // Note: HTML5 validation or custom validation might trigger const validity = await emailInput.evaluate((el: HTMLInputElement) => el.validity.valid); expect(validity).toBe(false); }); test('should clear validation errors on valid input', async ({ page }) => { const emailInput = page.locator('input[type="email"]').first(); const emailCount = await emailInput.count(); if (emailCount === 0) { test.skip(); return; } // Enter invalid email first await emailInput.fill('invalid'); await emailInput.blur(); await page.waitForTimeout(300); // Now enter valid email await emailInput.fill('valid@example.com'); await emailInput.blur(); await page.waitForTimeout(300); // Check validity const validity = await emailInput.evaluate((el: HTMLInputElement) => el.validity.valid); expect(validity).toBe(true); }); test('should prevent submission with validation errors', async ({ page }) => { const formCount = await page.locator('form').count(); if (formCount === 0) { test.skip(); return; } const form = page.locator('form').first(); const currentUrl = page.url(); // Try to submit form with invalid data const submitButton = form.locator('button[type="submit"]'); await submitButton.click(); // Wait a bit await page.waitForTimeout(1000); // URL should not change if validation failed // (assuming no AJAX submission that stays on page) const newUrl = page.url(); // Form should still be visible (not submitted) await expect(form).toBeVisible(); }); test('should handle required fields', async ({ page }) => { const requiredInputs = page.locator('input[required], textarea[required], select[required]'); const requiredCount = await requiredInputs.count(); if (requiredCount === 0) { test.skip(); return; } // Check first required field const firstRequired = requiredInputs.first(); // Should have required attribute await expect(firstRequired).toHaveAttribute('required'); // Should have appropriate ARIA attributes const ariaRequired = await firstRequired.getAttribute('aria-required'); expect(['true', null]).toContain(ariaRequired); }); test('should handle max length validation', async ({ page }) => { const maxLengthInputs = page.locator('input[maxlength], textarea[maxlength]'); const count = await maxLengthInputs.count(); if (count === 0) { test.skip(); return; } const input = maxLengthInputs.first(); const maxLength = await input.getAttribute('maxlength'); if (maxLength) { const maxLengthNum = parseInt(maxLength, 10); // Try to enter text longer than maxlength const longText = 'a'.repeat(maxLengthNum + 10); await input.fill(longText); // Value should be truncated to maxlength const value = await input.inputValue(); expect(value.length).toBeLessThanOrEqual(maxLengthNum); } }); test('should show character counter for textarea (if present)', async ({ page }) => { const textarea = page.locator('textarea[maxlength]').first(); const count = await textarea.count(); if (count === 0) { test.skip(); return; } // Look for character counter const counter = page.locator('[data-char-counter], .char-counter, .character-count'); const counterCount = await counter.count(); // Enter some text await textarea.fill('Hello World'); // If counter exists, it should update if (counterCount > 0) { await page.waitForTimeout(500); const counterText = await counter.first().textContent(); expect(counterText).toBeTruthy(); } }); });