Learn to automate form interactions, handle validations, and navigate complex multi-step forms
Master the fundamental form interactions: typing, clicking, and selecting elements.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Type text into input field
await page.type('#username', 'john_doe');
// Clear field and type new text
await page.click('#email', { clickCount: 3 }); // Select all
await page.type('#email', 'john@example.com');
// Type with delay (simulate human typing)
await page.type('#message', 'Hello World!', { delay: 100 });
// Focus on field and type
await page.focus('#password');
await page.keyboard.type('secretPassword123');
// Type special characters
await page.type('#special', 'Price: $19.99 (20% off)');
console.log('Text input completed');
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Simple click
await page.click('#submit-button');
// Click with options
await page.click('#options-button', {
button: 'left',
clickCount: 1,
delay: 100
});
// Right click (context menu)
await page.click('#context-menu', { button: 'right' });
// Double click
await page.click('#double-click-area', { clickCount: 2 });
// Click at specific coordinates
await page.mouse.click(100, 200);
// Hover before click
await page.hover('#hover-button');
await page.click('#hover-button');
// Wait for button to be clickable
await page.waitForSelector('#dynamic-button:not([disabled])');
await page.click('#dynamic-button');
console.log('Button interactions completed');
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Select all text (Ctrl+A)
await page.keyboard.down('Control');
await page.keyboard.press('KeyA');
await page.keyboard.up('Control');
// Copy text (Ctrl+C)
await page.keyboard.down('Control');
await page.keyboard.press('KeyC');
await page.keyboard.up('Control');
// Paste text (Ctrl+V)
await page.focus('#another-field');
await page.keyboard.down('Control');
await page.keyboard.press('KeyV');
await page.keyboard.up('Control');
// Tab navigation
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
// Enter key
await page.keyboard.press('Enter');
// Escape key
await page.keyboard.press('Escape');
// Arrow keys
await page.keyboard.press('ArrowDown');
await page.keyboard.press('ArrowUp');
console.log('Keyboard shortcuts completed');
await browser.close();
})();
Learn to handle various form elements including dropdowns, checkboxes, radio buttons, and file uploads.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Select by value
await page.select('#country', 'usa');
// Select by visible text
await page.select('#language', 'english');
// Select multiple options
await page.select('#skills', ['javascript', 'python', 'react']);
// Custom dropdown handling
await page.click('#custom-dropdown-trigger');
await page.waitForSelector('#custom-dropdown-options');
await page.click('#custom-dropdown-options li[data-value="option1"]');
// React Select component
await page.click('.react-select__control');
await page.waitForSelector('.react-select__option');
await page.click('.react-select__option:first-child');
// Material UI Select
await page.click('[data-testid="select-trigger"]');
await page.waitForSelector('[role="listbox"]');
await page.click('[role="option"][data-value="value1"]');
// Get selected value
const selectedValue = await page.$eval('#country', el => el.value);
console.log('Selected country:', selectedValue);
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Check/uncheck checkbox
await page.click('#newsletter-checkbox');
// Check if checkbox is checked
const isChecked = await page.$eval('#newsletter-checkbox', el => el.checked);
console.log('Newsletter checkbox is checked:', isChecked);
// Check multiple checkboxes
const checkboxes = ['#option1', '#option2', '#option3'];
for (const checkbox of checkboxes) {
await page.click(checkbox);
}
// Radio button selection
await page.click('#gender-male');
// Get selected radio button value
const selectedGender = await page.$eval('input[name="gender"]:checked', el => el.value);
console.log('Selected gender:', selectedGender);
// Handle custom checkbox/radio designs
await page.click('.custom-checkbox-label');
await page.click('.custom-radio-label');
// Toggle checkbox state
const toggleCheckbox = async (selector) => {
const isCurrentlyChecked = await page.$eval(selector, el => el.checked);
if (!isCurrentlyChecked) {
await page.click(selector);
}
};
await toggleCheckbox('#terms-checkbox');
await browser.close();
})();
const puppeteer = require('puppeteer');
const path = require('path');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/upload');
// Upload single file
const filePath = path.join(__dirname, 'test-file.txt');
await page.waitForSelector('#file-input');
const fileInput = await page.$('#file-input');
await fileInput.uploadFile(filePath);
// Upload multiple files
const multiplePaths = [
path.join(__dirname, 'file1.txt'),
path.join(__dirname, 'file2.txt'),
path.join(__dirname, 'file3.txt')
];
const multipleFileInput = await page.$('#multiple-file-input');
await multipleFileInput.uploadFile(...multiplePaths);
// Handle drag and drop upload
const dragDropArea = await page.$('#drag-drop-area');
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
// Simulate drag and drop
await page.dispatchEvent('#drag-drop-area', 'dragenter', { dataTransfer });
await page.dispatchEvent('#drag-drop-area', 'dragover', { dataTransfer });
await page.dispatchEvent('#drag-drop-area', 'drop', { dataTransfer });
// Wait for upload progress
await page.waitForSelector('.upload-progress');
// Wait for upload completion
await page.waitForSelector('.upload-complete', { timeout: 30000 });
console.log('File upload completed');
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Date input
await page.type('#date-input', '2024-12-25');
// Time input
await page.type('#time-input', '14:30');
// DateTime-local input
await page.type('#datetime-input', '2024-12-25T14:30');
// Month input
await page.type('#month-input', '2024-12');
// Week input
await page.type('#week-input', '2024-W52');
// Handle date picker widgets
await page.click('#date-picker-trigger');
await page.waitForSelector('.date-picker-calendar');
// Select specific date in calendar
await page.click('.date-picker-calendar [data-date="2024-12-25"]');
// Material UI DatePicker
await page.click('[data-testid="date-picker-input"]');
await page.waitForSelector('.MuiPickersDay-root');
await page.click('.MuiPickersDay-root[data-day="25"]');
// React DatePicker
await page.click('.react-datepicker__input-container input');
await page.waitForSelector('.react-datepicker__day');
await page.click('.react-datepicker__day--025');
console.log('Date and time inputs completed');
await browser.close();
})();
Learn to handle form validation, error messages, and retry logic.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Function to check for validation errors
const checkValidationErrors = async () => {
const errors = await page.$$eval('.error-message', elements =>
elements.map(el => el.textContent.trim())
);
return errors;
};
// Fill form with invalid data first
await page.type('#email', 'invalid-email');
await page.type('#password', '123'); // Too short
await page.click('#submit-button');
// Wait for validation errors to appear
await page.waitForSelector('.error-message');
// Check validation errors
const validationErrors = await checkValidationErrors();
console.log('Validation errors found:', validationErrors);
// Fix validation errors
await page.click('#email', { clickCount: 3 });
await page.type('#email', 'valid@email.com');
await page.click('#password', { clickCount: 3 });
await page.type('#password', 'strongPassword123!');
// Check if errors are cleared
await page.waitForFunction(() => {
const errors = document.querySelectorAll('.error-message');
return errors.length === 0;
});
// Submit form again
await page.click('#submit-button');
// Wait for success message or redirect
try {
await page.waitForSelector('.success-message', { timeout: 5000 });
console.log('Form submitted successfully');
} catch (error) {
console.log('Form submission failed or redirected');
}
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
// Monitor real-time validation
const monitorValidation = async (fieldSelector, validationSelector) => {
let isValid = false;
while (!isValid) {
// Get current validation state
const validationMessage = await page.$eval(validationSelector,
el => el.textContent.trim()
).catch(() => '');
const hasError = await page.$(validationSelector + '.error') !== null;
if (!hasError && validationMessage === '') {
isValid = true;
console.log(`Field ${fieldSelector} is now valid`);
} else {
console.log(`Field ${fieldSelector} validation: ${validationMessage}`);
// Wait a bit before checking again
await page.waitForTimeout(500);
}
}
};
// Type email and monitor validation
await page.focus('#email');
await page.type('#email', 'test');
// Wait for validation to trigger
await page.waitForTimeout(500);
// Continue typing until valid
await page.type('#email', '@example.com');
// Wait for validation to pass
await page.waitForFunction(() => {
const emailField = document.querySelector('#email');
const validationMessage = document.querySelector('#email-validation');
return emailField.checkValidity() &&
(!validationMessage || !validationMessage.textContent.trim());
});
console.log('Email validation passed');
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form-with-captcha');
// Handle reCAPTCHA
const handleRecaptcha = async () => {
// Check if reCAPTCHA is present
const recaptchaFrame = await page.$('iframe[src*="recaptcha"]');
if (recaptchaFrame) {
console.log('reCAPTCHA detected');
// Switch to reCAPTCHA frame
const frame = await recaptchaFrame.contentFrame();
// Click the checkbox
await frame.click('.recaptcha-checkbox');
// Wait for verification or challenge
await page.waitForTimeout(3000);
// Check if challenge appeared
const challengeFrame = await page.$('iframe[src*="recaptcha"][src*="bframe"]');
if (challengeFrame) {
console.log('reCAPTCHA challenge appeared - manual intervention needed');
// Pause for manual solving
await page.waitForSelector('.recaptcha-checkbox[aria-checked="true"]',
{ timeout: 60000 }
);
}
}
};
// Handle simple image CAPTCHA
const handleImageCaptcha = async () => {
const captchaImage = await page.$('#captcha-image');
if (captchaImage) {
console.log('Image CAPTCHA detected');
// Save CAPTCHA image
await captchaImage.screenshot({ path: 'captcha.png' });
// Here you would typically:
// 1. Use OCR to read the CAPTCHA
// 2. Use a CAPTCHA solving service
// 3. Ask for manual input
// For demo, we'll simulate manual input
const captchaText = 'DEMO123'; // Would be from OCR or manual input
await page.type('#captcha-input', captchaText);
}
};
// Fill form
await page.type('#username', 'testuser');
await page.type('#email', 'test@example.com');
// Handle security measures
await handleRecaptcha();
await handleImageCaptcha();
// Submit form
await page.click('#submit-button');
// Wait for response
await page.waitForNavigation({ timeout: 10000 });
console.log('Form with security measures submitted');
await browser.close();
})();
Master complex form scenarios including multi-step forms, dynamic fields, and form testing.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/multi-step-form');
// Step 1: Personal Information
console.log('Filling Step 1: Personal Information');
await page.type('#first-name', 'John');
await page.type('#last-name', 'Doe');
await page.type('#email', 'john.doe@example.com');
await page.type('#phone', '+1234567890');
// Validate step 1
const step1Valid = await page.$eval('#step1-validation', el =>
el.classList.contains('valid')
);
if (!step1Valid) {
console.log('Step 1 validation failed');
return;
}
// Go to step 2
await page.click('#next-step-1');
await page.waitForSelector('#step-2.active');
// Step 2: Address Information
console.log('Filling Step 2: Address Information');
await page.type('#street-address', '123 Main St');
await page.type('#city', 'New York');
await page.select('#state', 'NY');
await page.type('#zip-code', '10001');
await page.select('#country', 'USA');
// Go to step 3
await page.click('#next-step-2');
await page.waitForSelector('#step-3.active');
// Step 3: Payment Information
console.log('Filling Step 3: Payment Information');
await page.type('#card-number', '4111111111111111');
await page.type('#expiry-date', '12/25');
await page.type('#cvv', '123');
await page.type('#cardholder-name', 'John Doe');
// Review step
await page.click('#review-step');
await page.waitForSelector('#review-section');
// Verify information
const reviewData = await page.evaluate(() => {
return {
name: document.querySelector('#review-name').textContent,
email: document.querySelector('#review-email').textContent,
address: document.querySelector('#review-address').textContent,
card: document.querySelector('#review-card').textContent
};
});
console.log('Review data:', reviewData);
// Submit form
await page.click('#final-submit');
// Wait for confirmation
await page.waitForSelector('#confirmation-message');
const confirmationText = await page.$eval('#confirmation-message',
el => el.textContent
);
console.log('Form submitted successfully:', confirmationText);
await browser.close();
})();
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/dynamic-form');
// Handle conditional fields
await page.select('#user-type', 'business');
// Wait for business fields to appear
await page.waitForSelector('#business-fields', { visible: true });
await page.type('#company-name', 'Tech Corp');
await page.type('#tax-id', '12-3456789');
// Add dynamic repeating fields
const addSkill = async (skillName, level) => {
await page.click('#add-skill-button');
// Wait for new skill field to appear
await page.waitForSelector('.skill-item:last-child .skill-name');
const skillItems = await page.$$('.skill-item');
const lastSkillItem = skillItems[skillItems.length - 1];
await lastSkillItem.$eval('.skill-name', (el, name) => {
el.value = name;
}, skillName);
await lastSkillItem.$eval('.skill-level', (el, lvl) => {
el.value = lvl;
}, level);
};
// Add multiple skills
await addSkill('JavaScript', 'Expert');
await addSkill('Python', 'Intermediate');
await addSkill('React', 'Advanced');
// Handle dependent dropdowns
await page.select('#category', 'technology');
// Wait for subcategory options to load
await page.waitForFunction(() => {
const subcategory = document.querySelector('#subcategory');
return subcategory && subcategory.options.length > 1;
});
await page.select('#subcategory', 'web-development');
// Wait for specific technology options
await page.waitForFunction(() => {
const technology = document.querySelector('#technology');
return technology && technology.options.length > 1;
});
await page.select('#technology', 'frontend');
// Handle auto-complete fields
await page.type('#location', 'New Y');
await page.waitForSelector('#location-suggestions');
await page.click('#location-suggestions li:first-child');
// Handle calculated fields
await page.type('#quantity', '5');
await page.type('#price', '10.50');
// Wait for total to be calculated
await page.waitForFunction(() => {
const total = document.querySelector('#total');
return total && total.value === '52.50';
});
console.log('Dynamic form fields handled successfully');
await browser.close();
})();
const puppeteer = require('puppeteer');
class FormTester {
constructor(page) {
this.page = page;
this.testResults = [];
}
async testField(selector, testCases) {
const results = [];
for (const testCase of testCases) {
console.log(`Testing ${selector} with: ${testCase.input}`);
try {
// Clear field
await this.page.click(selector, { clickCount: 3 });
await this.page.type(selector, testCase.input);
// Trigger validation
await this.page.keyboard.press('Tab');
await this.page.waitForTimeout(500);
// Check validation result
const hasError = await this.page.$(testCase.errorSelector) !== null;
const errorMessage = hasError ?
await this.page.$eval(testCase.errorSelector, el => el.textContent) : '';
const result = {
input: testCase.input,
expectedValid: testCase.expectedValid,
actualValid: !hasError,
errorMessage: errorMessage,
passed: testCase.expectedValid === !hasError
};
results.push(result);
if (!result.passed) {
console.log(`❌ Test failed for ${selector}: ${JSON.stringify(result)}`);
} else {
console.log(`✅ Test passed for ${selector}`);
}
} catch (error) {
results.push({
input: testCase.input,
error: error.message,
passed: false
});
}
}
return results;
}
async testForm(formTests) {
const allResults = {};
for (const [fieldSelector, testCases] of Object.entries(formTests)) {
allResults[fieldSelector] = await this.testField(fieldSelector, testCases);
}
return allResults;
}
generateReport(results) {
let totalTests = 0;
let passedTests = 0;
console.log('\n=== FORM TESTING REPORT ===');
for (const [field, fieldResults] of Object.entries(results)) {
console.log(`\nField: ${field}`);
fieldResults.forEach(result => {
totalTests++;
if (result.passed) passedTests++;
const status = result.passed ? '✅' : '❌';
console.log(` ${status} Input: "${result.input}" | Expected: ${result.expectedValid ? 'Valid' : 'Invalid'} | Actual: ${result.actualValid ? 'Valid' : 'Invalid'}`);
if (result.error) {
console.log(` Error: ${result.error}`);
}
});
}
console.log(`\n=== SUMMARY ===`);
console.log(`Total Tests: ${totalTests}`);
console.log(`Passed: ${passedTests}`);
console.log(`Failed: ${totalTests - passedTests}`);
console.log(`Success Rate: ${((passedTests / totalTests) * 100).toFixed(2)}%`);
}
}
// Usage
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/form');
const tester = new FormTester(page);
const formTests = {
'#email': [
{ input: 'valid@example.com', expectedValid: true, errorSelector: '#email-error' },
{ input: 'invalid-email', expectedValid: false, errorSelector: '#email-error' },
{ input: '', expectedValid: false, errorSelector: '#email-error' }
],
'#password': [
{ input: 'StrongPass123!', expectedValid: true, errorSelector: '#password-error' },
{ input: '123', expectedValid: false, errorSelector: '#password-error' },
{ input: 'weakpass', expectedValid: false, errorSelector: '#password-error' }
],
'#phone': [
{ input: '+1234567890', expectedValid: true, errorSelector: '#phone-error' },
{ input: '123', expectedValid: false, errorSelector: '#phone-error' },
{ input: 'abc', expectedValid: false, errorSelector: '#phone-error' }
]
};
const results = await tester.testForm(formTests);
tester.generateReport(results);
await browser.close();
})();
Always wait for forms to be fully loaded and interactive before interacting
// Wait for form to be ready
await page.waitForSelector('#myform', { visible: true });
await page.waitForSelector('#myform input:not([disabled])');
// Wait for dynamic content to load
await page.waitForFunction(() => {
return document.querySelector('#myform').getAttribute('data-ready') === 'true';
});
Respect rate limits, handle CAPTCHAs, and avoid overwhelming servers
// Add delays to simulate human behavior
await page.type('#input', 'text', { delay: 100 });
await page.waitForTimeout(1000);
// Handle rate limiting
const submitWithRetry = async (maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
await page.click('#submit');
return;
} catch (error) {
if (i === maxRetries - 1) throw error;
await page.waitForTimeout(5000 * (i + 1));
}
}
};
Implement robust error handling and recovery mechanisms
const fillFormSafely = async (formData) => {
try {
for (const [selector, value] of Object.entries(formData)) {
await page.waitForSelector(selector, { timeout: 5000 });
await page.type(selector, value);
}
} catch (error) {
console.error('Form filling failed:', error);
// Take screenshot for debugging
await page.screenshot({ path: 'form-error.png' });
throw error;
}
};
Always verify that forms were submitted successfully
// Submit and verify
await page.click('#submit-button');
// Wait for success indicators
const success = await Promise.race([
page.waitForSelector('.success-message').then(() => true),
page.waitForSelector('.error-message').then(() => false),
page.waitForNavigation().then(() => true)
]);
if (success) {
console.log('Form submitted successfully');
} else {
console.log('Form submission failed');
}