VALIDATION LAB•CONTACT FORM
Form Lab
Contact Form
Validate a support/contact request with required identity fields, message length, optional attachment upload, and a success toast.
Scenario
Contact and support forms are customer-facing intake pipes. QA must verify inline errors, upload handling, message length, and confirmation feedback so real requests are not silently lost.
Live widget · interact freely
Manual test checklist
- 1Submit empty fields and confirm required errors
- 2Enter an invalid email and verify the email message
- 3Enter a message under 20 characters and confirm the length error
- 4Attach a test file and confirm the result panel records the filename
- 5Submit valid data and verify the success toast
Expected result
Required fields, invalid email, and short messages are blocked; a valid message with an optional attachment produces a success toast.
Automation challenge
Use getByLabel() for text fields, setInputFiles() for the optional attachment, getByRole() to submit, and assert both the success toast and validation result panel.
Stable selectors
- Contact form
[data-testid="form-contact-form"] - Full Name
[data-testid="form-contact-full-name"] - Email
[data-testid="form-contact-email"] - Subject
[data-testid="form-contact-subject"] - Message
[data-testid="form-contact-message"] - Attachment
[data-testid="form-contact-attachment"] - Submit
[data-testid="form-contact-submit"] - Validation result
[data-testid="form-contact-result"] - Toast
[data-testid="form-contact-toast"]
Locator strategy
Three levels from simple IDs to scoped Playwright locators. IDs and names are easy to learn but are not always the best long-term choice when labels change or components repeat.
Use simple IDs and names to understand how locating elements works. Form Lab pages expose predictable field ids and data-testid values for every control.
1234
await page.goto('https://lab.hakdogan.com/practice/form-contact');
await page.locator('[data-testid="form-contact-form"]').waitFor();
await page.locator('[data-testid="form-contact-submit"]').click();Avoid as primary strategies
XPath (unless there is no alternative), long CSS chains, Tailwind-style utility class selectors, generated or unstable IDs, and volatile framework internals break when layout, styling, or DOM structure shifts.
12
await page.locator('.w-full.rounded-xl.border.bg-blue-500').fill('demo@example.com');
await page.locator('//div[2]/form/div[1]/input').fill('demo@example.com');Reference Playwright spec
12345678910111213141516171819
import { test, expect } from '@playwright/test';
test('contact form accepts a support request with attachment', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/form-contact');
await page.getByLabel('Full Name').fill('Hasan Akdogan');
await page.getByLabel('Email').fill('hasan@lab.dev');
await page.getByLabel('Subject').fill('Checkout issue');
await page.getByLabel('Message').fill('The checkout confirmation did not arrive after payment.');
await page.getByLabel('Attachment').setInputFiles({
name: 'evidence.txt',
mimeType: 'text/plain',
buffer: Buffer.from('test evidence only'),
});
await page.getByRole('button', { name: /send message/i }).click();
await expect(page.getByTestId('form-contact-toast')).toContainText(/success/i);
await expect(page.getByTestId('form-contact-result')).toContainText('evidence.txt');
});Headed Test Playback
Simulated headed-browser flow — no real browser is launched.
Automation-style playback (Playwright-shaped logs). No real browser; no commands run on your machine.
form-contact.spec.ts- Fill contact fields
- Attach optional evidence
- Submit message
- Assert success toast