const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); // ======================================== // CONFIGURATION - Customize for your site // ======================================== const SITE_URL = 'https://example.com'; const LOGIN_REQUIRED = true; const LOGIN_CREDENTIALS = { username: 'your_username', password: 'your_password' }; const FORM_DATA = { field1: 'Value 1', field2: 'Value 2', description: 'Long description text here...' }; // ======================================== // CORE UTILITY: Page Dumping System // ======================================== /** * Dumps page information for debugging: * - Full HTML content * - Screenshot (full page) * - All form elements with their properties * * Use this BEFORE filling forms and AFTER errors */ async function dumpPageInfo(page, prefix) { const timestamp = Date.now(); const dumpDir = path.join(__dirname, 'page-dumps'); // Create dumps directory if not exists if (!fs.existsSync(dumpDir)) { fs.mkdirSync(dumpDir, { recursive: true }); } console.log('πŸ” Dumping page for debugging...'); try { // 1. Save full HTML const html = await page.content(); const htmlPath = path.join(dumpDir, `${prefix}-${timestamp}.html`); fs.writeFileSync(htmlPath, html); console.log(` πŸ“„ HTML saved: ${htmlPath}`); // 2. Take screenshot const screenshotPath = path.join(dumpDir, `${prefix}-${timestamp}.png`); await page.screenshot({ path: screenshotPath, fullPage: true }); console.log(` πŸ“Έ Screenshot saved: ${screenshotPath}`); // 3. Extract all form elements const elements = await page.$$eval('input, textarea, select, button', els => els.map(el => ({ tag: el.tagName.toLowerCase(), type: el.type || '', name: el.name || '', id: el.id || '', placeholder: el.placeholder || '', value: el.value || '', class: el.className || '' })) ); const selectorsPath = path.join(dumpDir, `${prefix}-${timestamp}-selectors.txt`); fs.writeFileSync(selectorsPath, JSON.stringify(elements, null, 2)); console.log(` πŸ“‹ Form elements saved: ${selectorsPath}`); } catch (error) { console.error(`❌ Error during page dump: ${error.message}`); } } // ======================================== // LOGIN HANDLER with Fallback // ======================================== async function handleLogin(page, credentials) { console.log('πŸ” Attempting automatic login...'); try { // Dump login page first to understand structure await dumpPageInfo(page, 'login-page-initial'); // Fill login form await page.fill('input[name="username"]', credentials.username); await page.fill('input[name="password"]', credentials.password); // Submit (click button, don't use form.submit()) await page.click('input[type="submit"], button[type="submit"]'); // Wait for redirect after successful login // Adjust the URL pattern to match your site's post-login URL await page.waitForURL(/.*\/(?!login|signin)/, { timeout: 30000 }); console.log('βœ… Login successful!\n'); } catch (loginError) { console.warn('⚠️ Auto-login failed, trying manual intervention...'); await dumpPageInfo(page, 'login-error'); console.log('\n⏸️ Please log in manually in the browser window.'); console.log(' Waiting up to 5 minutes for manual login...\n'); // Wait for user to login manually await page.waitForURL(/.*\/(?!login|signin)/, { timeout: 300000 }); console.log('βœ… Manual login detected!\n'); } } // ======================================== // MAIN AUTOMATION FUNCTION // ======================================== async function automateFormSubmission() { console.log('πŸš€ Starting form automation...\n'); // Launch browser (headless: false to see what's happening) const browser = await chromium.launch({ headless: false, slowMo: 100 // Slow down operations for visibility }); const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); const page = await context.newPage(); try { // ======================================== // STEP 1: Navigate to site // ======================================== console.log('πŸ“‹ Step 1: Navigating to site...'); await page.goto(SITE_URL); await page.waitForLoadState('networkidle'); // ======================================== // STEP 2: Handle login if required // ======================================== if (LOGIN_REQUIRED) { // Check if login is needed (adjust selector to your site) const needsLogin = await page.locator('a:has-text("Login"), a:has-text("Sign in")').count() > 0; if (needsLogin) { console.log('⚠️ Login required!\n'); // Navigate to login page (adjust URL) await page.goto(`${SITE_URL}/login`); await handleLogin(page, LOGIN_CREDENTIALS); } else { console.log('βœ… Already logged in!\n'); } } // ======================================== // STEP 3: Navigate to form page // ======================================== console.log('πŸ“‹ Step 2: Navigating to form page...'); await page.goto(`${SITE_URL}/submit-form`); // Adjust URL await page.waitForLoadState('networkidle'); // ======================================== // STEP 4: Dump page to understand structure // ======================================== console.log('πŸ“ Step 3: Analyzing form structure...'); await dumpPageInfo(page, 'form-initial'); // ======================================== // STEP 5: Fill form fields // ======================================== console.log('πŸ“ Step 4: Filling form...'); try { // Simple text input await page.fill('input[name="field1"]', FORM_DATA.field1); console.log(' βœ“ Field1 filled'); // Another text input await page.fill('input[name="field2"]', FORM_DATA.field2); console.log(' βœ“ Field2 filled'); // Textarea await page.fill('textarea[name="description"]', FORM_DATA.description); console.log(' βœ“ Description filled'); // Example: Select dropdown (standard) // await page.selectOption('select[name="category"]', 'option-value'); // console.log(' βœ“ Category selected'); // Example: Select2 dropdown (jQuery plugin) // await page.click('span.select2-selection--multiple'); // await page.waitForTimeout(500); // await page.click('li.select2-results__option:has-text("Option Name")'); // console.log(' βœ“ Select2 option selected'); // Example: Checkbox // await page.check('input[name="agree"]'); // console.log(' βœ“ Checkbox checked'); // Example: File upload // await page.setInputFiles('input[type="file"]', '/path/to/file.png'); // console.log(' βœ“ File uploaded'); } catch (fillError) { console.error(`❌ Error filling form: ${fillError.message}`); await dumpPageInfo(page, 'form-fill-error'); throw fillError; } // ======================================== // STEP 6: Review before submit // ======================================== console.log('\n⏸️ Form filled! Review in browser and press Enter to submit...'); await new Promise(resolve => { process.stdin.once('data', resolve); }); // ======================================== // STEP 7: Submit form // ======================================== console.log('πŸ“€ Step 5: Submitting form...'); await page.click('button[type="submit"], input[type="submit"]'); // Wait for success page (adjust URL pattern) await page.waitForURL(/success|confirmation|thank-you/, { timeout: 30000 }); console.log('βœ… Form submitted successfully!\n'); // Take final screenshot await page.screenshot({ path: path.join(__dirname, 'page-dumps', 'success.png'), fullPage: true }); } catch (error) { console.error(`\n❌ Automation failed: ${error.message}\n`); await dumpPageInfo(page, 'fatal-error'); throw error; } finally { console.log('🏁 Closing browser...'); await browser.close(); } } // ======================================== // RUN AUTOMATION // ======================================== if (require.main === module) { automateFormSubmission() .then(() => { console.log('βœ… Automation completed successfully!'); process.exit(0); }) .catch(error => { console.error('❌ Automation failed:', error); process.exit(1); }); } module.exports = { automateFormSubmission, dumpPageInfo };