|
|
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 };
|
|
|
|