commit
914e09876f
6 changed files with 962 additions and 0 deletions
@ -0,0 +1,6 @@
|
||||
node_modules/ |
||||
page-dumps/*.html |
||||
page-dumps/*.png |
||||
page-dumps/*.txt |
||||
*.log |
||||
.DS_Store |
||||
@ -0,0 +1,248 @@
|
||||
# Playwright Form Automation Toolkit |
||||
|
||||
🤖 Sistema completo per automatizzare form submission su siti web con debugging intelligente. |
||||
|
||||
## Features |
||||
|
||||
✨ **Page Dumping System** - Estrazione automatica di HTML, screenshot e form selectors |
||||
🔐 **Smart Login** - Auto-login con fallback manuale |
||||
🎯 **Error Recovery** - Dump automatico ad ogni errore |
||||
📸 **Visual Debugging** - Screenshot full-page ad ogni step |
||||
🔄 **Iterative Workflow** - Ciclo rapido test → dump → fix → retest |
||||
|
||||
## Quick Start |
||||
|
||||
```bash |
||||
# 1. Installa dipendenze |
||||
npm install |
||||
|
||||
# 2. Installa browser Chromium |
||||
npm run install-browsers |
||||
|
||||
# 3. Modifica template-automation.js con i tuoi dati |
||||
# - SITE_URL |
||||
# - LOGIN_CREDENTIALS |
||||
# - FORM_DATA |
||||
# - Selettori specifici per il tuo sito |
||||
|
||||
# 4. Esegui |
||||
npm test |
||||
``` |
||||
|
||||
## Structure |
||||
|
||||
``` |
||||
playwright-form-automation/ |
||||
├── .github/ |
||||
│ └── copilot-instructions.md # Guida completa workflow |
||||
├── package.json # Dipendenze npm |
||||
├── template-automation.js # Template script automation |
||||
├── page-dumps/ # Output debug (auto-creata) |
||||
│ ├── form-initial-*.html |
||||
│ ├── form-initial-*.png |
||||
│ ├── form-initial-*-selectors.txt |
||||
│ └── ... |
||||
└── README.md # Questo file |
||||
``` |
||||
|
||||
## Core Concepts |
||||
|
||||
### 1. Page Dumping |
||||
|
||||
Ad ogni step importante (e ad ogni errore), lo script salva: |
||||
|
||||
- **HTML completo** - Per analisi struttura DOM |
||||
- **Screenshot** - Per vedere visivamente cosa è successo |
||||
- **Form selectors** - JSON con tutti gli elementi form (input, select, textarea, button) |
||||
|
||||
```javascript |
||||
await dumpPageInfo(page, 'step-name'); |
||||
// Crea: |
||||
// - page-dumps/step-name-<timestamp>.html |
||||
// - page-dumps/step-name-<timestamp>.png |
||||
// - page-dumps/step-name-<timestamp>-selectors.txt |
||||
``` |
||||
|
||||
### 2. Iterative Debugging |
||||
|
||||
```bash |
||||
# Run 1: Script fallisce |
||||
node template-automation.js |
||||
# ❌ Error: Timeout waiting for 'input[name="username"]' |
||||
|
||||
# Analizza dump |
||||
cat page-dumps/login-error-*-selectors.txt |
||||
# Scopri che il campo è 'input[name="user"]' non "username" |
||||
|
||||
# Fix nello script |
||||
# Cambia: await page.fill('input[name="username"]', ...) |
||||
# In: await page.fill('input[name="user"]', ...) |
||||
|
||||
# Run 2: Riprova |
||||
node template-automation.js |
||||
# ✅ Success! |
||||
``` |
||||
|
||||
### 3. Select2 Dropdown Handling |
||||
|
||||
Select2 (jQuery plugin usato da molti siti) nasconde i `<select>` standard. |
||||
|
||||
**Identificazione** (in selectors.txt): |
||||
```json |
||||
{ |
||||
"tag": "select", |
||||
"name": "category", |
||||
"class": "select2-hidden-accessible" // ← Questo indica Select2 |
||||
} |
||||
``` |
||||
|
||||
**Soluzione**: |
||||
```javascript |
||||
// ❌ NON funziona |
||||
await page.selectOption('select[name="category"]', 'value'); |
||||
|
||||
// ✅ Funziona |
||||
await page.click('span.select2-selection--multiple'); // Apre dropdown |
||||
await page.waitForTimeout(500); |
||||
await page.click('li.select2-results__option:has-text("Option")'); // Seleziona |
||||
``` |
||||
|
||||
## Common Patterns |
||||
|
||||
### Login con CSRF Token |
||||
```javascript |
||||
// Il token viene gestito automaticamente dal browser |
||||
// Basta compilare username/password e cliccare submit |
||||
await page.fill('input[name="username"]', 'user'); |
||||
await page.fill('input[name="password"]', 'pass'); |
||||
await page.click('input[type="submit"]'); // Click, NON form.submit()! |
||||
``` |
||||
|
||||
### File Upload |
||||
```javascript |
||||
await page.setInputFiles('input[type="file"]', '/path/to/file.png'); |
||||
``` |
||||
|
||||
### Checkbox/Radio |
||||
```javascript |
||||
await page.check('input[name="agree"]'); |
||||
await page.check('input[name="gender"][value="male"]'); |
||||
``` |
||||
|
||||
### Wait for Navigation |
||||
```javascript |
||||
// Dopo submit, aspetta che URL cambi |
||||
await page.waitForURL(/success|confirmation/); |
||||
``` |
||||
|
||||
## Debugging Checklist |
||||
|
||||
Script fallito? Segui questa lista: |
||||
|
||||
1. ✅ **Leggi selectors.txt** - Nomi/ID corretti? |
||||
2. ✅ **Guarda screenshot** - Elemento visibile? Serve scroll? |
||||
3. ✅ **Controlla HTML** - Iframe? Shadow DOM? JavaScript che modifica DOM? |
||||
4. ✅ **Prova manualmente** - L'azione funziona a mano nel browser? |
||||
5. ✅ **Console errors** - Apri DevTools nel browser Playwright |
||||
|
||||
## Examples |
||||
|
||||
### Esempio 1: Form Semplice |
||||
```javascript |
||||
await page.fill('input[name="name"]', 'John Doe'); |
||||
await page.fill('input[name="email"]', 'john@example.com'); |
||||
await page.fill('textarea[name="message"]', 'Hello world!'); |
||||
await page.click('button[type="submit"]'); |
||||
``` |
||||
|
||||
### Esempio 2: Multi-step Form |
||||
```javascript |
||||
// Step 1 |
||||
await page.fill('input[name="email"]', 'user@mail.com'); |
||||
await page.click('button:has-text("Next")'); |
||||
await page.waitForURL(/step-2/); |
||||
|
||||
// Step 2 |
||||
await page.fill('input[name="address"]', '123 Main St'); |
||||
await page.click('button:has-text("Submit")'); |
||||
``` |
||||
|
||||
### Esempio 3: Login + Form |
||||
```javascript |
||||
// Login |
||||
await page.goto('https://site.com/login'); |
||||
await page.fill('input[name="username"]', 'user'); |
||||
await page.fill('input[name="password"]', 'pass'); |
||||
await page.click('button[type="submit"]'); |
||||
await page.waitForURL(/dashboard/); |
||||
|
||||
// Navigate to form |
||||
await page.goto('https://site.com/submit'); |
||||
|
||||
// Fill and submit |
||||
await page.fill('input[name="title"]', 'My Title'); |
||||
await page.click('button[type="submit"]'); |
||||
``` |
||||
|
||||
## Tips & Tricks |
||||
|
||||
### Slow Down for Visibility |
||||
```javascript |
||||
const browser = await chromium.launch({ |
||||
headless: false, |
||||
slowMo: 100 // Rallenta di 100ms ogni azione |
||||
}); |
||||
``` |
||||
|
||||
### Custom Viewport |
||||
```javascript |
||||
const context = await browser.newContext({ |
||||
viewport: { width: 1920, height: 1080 } |
||||
}); |
||||
``` |
||||
|
||||
### Network Interception |
||||
```javascript |
||||
await page.route('**/api/spam', route => route.abort()); |
||||
``` |
||||
|
||||
### Take Extra Screenshots |
||||
```javascript |
||||
await page.screenshot({ |
||||
path: 'debug-step.png', |
||||
fullPage: true |
||||
}); |
||||
``` |
||||
|
||||
## Troubleshooting |
||||
|
||||
### "Timeout waiting for selector" |
||||
→ Elemento non esiste o ha nome diverso. Controlla `selectors.txt`. |
||||
|
||||
### "Element is not visible" |
||||
→ Serve scroll: `await page.locator('selector').scrollIntoViewIfNeeded();` |
||||
|
||||
### "Element is covered" |
||||
→ Modal/popup sopra. Chiudi: `await page.click('button.close-modal');` |
||||
|
||||
### Select2 non funziona |
||||
→ Usa pattern "click container → click option" (vedi sopra). |
||||
|
||||
### Submit non fa niente |
||||
→ Usa `page.click()` non `form.submit()`. JavaScript handlers servono click event. |
||||
|
||||
## Real-World Example |
||||
|
||||
Vedi nella parent folder: |
||||
- `publish-rats-lutris.js` - Script completo per pubblicare gioco su Lutris.net |
||||
- Include: login, Select2, file upload, multi-step form |
||||
|
||||
## License |
||||
|
||||
MIT - Free to use and modify |
||||
|
||||
--- |
||||
|
||||
**Created**: October 25, 2025 |
||||
**Author**: enne2 |
||||
**Tested on**: Debian GNU/Linux 13, Node.js v20.19.2, Playwright 1.40.0 |
||||
@ -0,0 +1,23 @@
|
||||
{ |
||||
"name": "playwright-form-automation", |
||||
"version": "1.0.0", |
||||
"description": "Automated form submission with Playwright - intelligent page dumping for debugging", |
||||
"main": "template-automation.js", |
||||
"scripts": { |
||||
"install-browsers": "npx playwright install chromium", |
||||
"test": "node template-automation.js", |
||||
"clean-dumps": "rm -rf page-dumps/*" |
||||
}, |
||||
"keywords": [ |
||||
"playwright", |
||||
"automation", |
||||
"form", |
||||
"web-scraping", |
||||
"testing" |
||||
], |
||||
"author": "enne2", |
||||
"license": "MIT", |
||||
"dependencies": { |
||||
"playwright": "^1.40.0" |
||||
} |
||||
} |
||||
@ -0,0 +1,44 @@
|
||||
# Playwright Form Automation - Page Dumps |
||||
|
||||
This directory is automatically created by the automation scripts. |
||||
|
||||
## Contents |
||||
|
||||
Each dump consists of 3 files with the same timestamp: |
||||
|
||||
1. **`<prefix>-<timestamp>.html`** - Full HTML content of the page |
||||
2. **`<prefix>-<timestamp>.png`** - Full-page screenshot |
||||
3. **`<prefix>-<timestamp>-selectors.txt`** - JSON array of all form elements |
||||
|
||||
## How to Use |
||||
|
||||
When your script fails or you need to understand page structure: |
||||
|
||||
1. **Check the screenshot** - Visual representation of what the page looked like |
||||
2. **Read selectors.txt** - Find the correct selectors (name, id, class) for form elements |
||||
3. **Search HTML** - Deep dive into DOM structure if needed |
||||
|
||||
## Example |
||||
|
||||
```bash |
||||
# View latest selectors |
||||
cat page-dumps/*-selectors.txt | tail -100 |
||||
|
||||
# Open latest screenshot |
||||
xdg-open $(ls -t page-dumps/*.png | head -1) |
||||
|
||||
# Search for specific field in HTML |
||||
grep -i "username" page-dumps/login-*.html |
||||
``` |
||||
|
||||
## Cleanup |
||||
|
||||
Remove old dumps to save space: |
||||
|
||||
```bash |
||||
# From parent directory |
||||
npm run clean-dumps |
||||
|
||||
# Or manually |
||||
rm -rf page-dumps/* |
||||
``` |
||||
Loading…
Reference in new issue