|
|
const { chromium } = require('playwright');
|
|
|
|
|
|
async function exploreDocuSeal() {
|
|
|
console.log('🚀 Starting DocuSeal exploration...\n');
|
|
|
|
|
|
// Launch browser
|
|
|
const browser = await chromium.launch({
|
|
|
headless: false, // Set to true for CI environments
|
|
|
slowMo: 500 // Slow down actions for visibility
|
|
|
});
|
|
|
|
|
|
const context = await browser.newContext({
|
|
|
viewport: { width: 1280, height: 800 },
|
|
|
userAgent: 'Mozilla/5.0 (compatible; DocuSeal-Explorer/1.0)'
|
|
|
});
|
|
|
|
|
|
const page = await context.newPage();
|
|
|
|
|
|
try {
|
|
|
// Navigate to the app
|
|
|
console.log('1. Navigating to DocuSeal home page...');
|
|
|
await page.goto('http://localhost:3001', { waitUntil: 'networkidle' });
|
|
|
|
|
|
// Take screenshot of initial page
|
|
|
await page.screenshot({ path: 'screenshots/01_home.png', fullPage: true });
|
|
|
console.log(' ✅ Screenshot saved: screenshots/01_home.png');
|
|
|
|
|
|
// Check if we're on login page or home page
|
|
|
const pageTitle = await page.title();
|
|
|
console.log(` 📄 Page title: "${pageTitle}"`);
|
|
|
|
|
|
// Look for login form
|
|
|
const loginForm = await page.locator('form[action*="sign_in"], form[action*="users/sign_in"]').count();
|
|
|
if (loginForm > 0) {
|
|
|
console.log(' 🔐 Login form detected');
|
|
|
|
|
|
// Try to find and click a demo/test account link or create one
|
|
|
const demoLink = await page.locator('a:has-text("demo"), a:has-text("test"), a:has-text("sign up")').first();
|
|
|
if (await demoLink.count() > 0) {
|
|
|
console.log(' 🎯 Found demo/test link, clicking...');
|
|
|
await demoLink.click();
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
} else {
|
|
|
console.log(' ℹ️ No demo link found, checking for sign up...');
|
|
|
|
|
|
// Look for sign up link
|
|
|
const signUpLink = await page.locator('a[href*="sign_up"], a:has-text("Sign up")').first();
|
|
|
if (await signUpLink.count() > 0) {
|
|
|
await signUpLink.click();
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
console.log(' ✅ Navigated to sign up page');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Check current URL and page content
|
|
|
const currentUrl = page.url();
|
|
|
console.log(` 📍 Current URL: ${currentUrl}`);
|
|
|
|
|
|
// Look for any forms and their structure
|
|
|
const forms = await page.locator('form').all();
|
|
|
console.log(` 📋 Found ${forms.length} form(s) on current page`);
|
|
|
|
|
|
for (let i = 0; i < Math.min(forms.length, 3); i++) {
|
|
|
const form = forms[i];
|
|
|
const action = await form.getAttribute('action') || 'N/A';
|
|
|
const method = await form.getAttribute('method') || 'N/A';
|
|
|
console.log(` Form ${i + 1}: action="${action}", method="${method}"`);
|
|
|
|
|
|
// Count inputs in this form
|
|
|
const inputs = await form.locator('input').all();
|
|
|
console.log(` - ${inputs.length} input fields`);
|
|
|
}
|
|
|
|
|
|
// Look for navigation elements
|
|
|
console.log(' 🧭 Exploring navigation...');
|
|
|
const navLinks = await page.locator('nav a, .nav a, [role="navigation"] a').all();
|
|
|
console.log(` Found ${navLinks.length} navigation links`);
|
|
|
|
|
|
for (let i = 0; i < Math.min(navLinks.length, 5); i++) {
|
|
|
const text = await navLinks[i].textContent();
|
|
|
const href = await navLinks[i].getAttribute('href');
|
|
|
console.log(` - "${text?.trim()}" → ${href}`);
|
|
|
}
|
|
|
|
|
|
// Look for main action buttons
|
|
|
console.log(' 🎯 Looking for main action buttons...');
|
|
|
const buttons = await page.locator('button, input[type="submit"], .btn').all();
|
|
|
console.log(` Found ${buttons.length} buttons`);
|
|
|
|
|
|
for (let i = 0; i < Math.min(buttons.length, 8); i++) {
|
|
|
const btn = buttons[i];
|
|
|
const text = await btn.textContent() || await btn.getAttribute('value') || 'N/A';
|
|
|
const type = await btn.getAttribute('type') || 'button';
|
|
|
console.log(` - "${text.trim()}" (type: ${type})`);
|
|
|
}
|
|
|
|
|
|
// Look for any Vue components or app containers
|
|
|
const vueApp = await page.locator('[data-v-app], #app, .app-container').count();
|
|
|
if (vueApp > 0) {
|
|
|
console.log(' 🎨 Vue.js application detected');
|
|
|
}
|
|
|
|
|
|
// Check for any modals or dialogs
|
|
|
const modals = await page.locator('[role="dialog"], .modal, .dialog').count();
|
|
|
if (modals > 0) {
|
|
|
console.log(` 💬 Found ${modals} modal(s)/dialog(s)`);
|
|
|
}
|
|
|
|
|
|
// Look for any API documentation or help links
|
|
|
const helpLinks = await page.locator('a:has-text("API"), a:has-text("Help"), a:has-text("Docs")').all();
|
|
|
if (helpLinks.length > 0) {
|
|
|
console.log(' 📚 Found documentation/help links:');
|
|
|
for (const link of helpLinks) {
|
|
|
const text = await link.textContent();
|
|
|
const href = await link.getAttribute('href');
|
|
|
console.log(` - ${text.trim()} → ${href}`);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Try to find and explore templates section
|
|
|
console.log('\n2. Looking for Templates section...');
|
|
|
const templatesLink = await page.locator('a:has-text("Template"), a[href*="template"]').first();
|
|
|
if (await templatesLink.count() > 0) {
|
|
|
const text = await templatesLink.textContent();
|
|
|
console.log(` 📄 Found templates link: "${text.trim()}"`);
|
|
|
await templatesLink.click();
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
await page.screenshot({ path: 'screenshots/02_templates.png', fullPage: true });
|
|
|
console.log(' ✅ Screenshot saved: screenshots/02_templates.png');
|
|
|
}
|
|
|
|
|
|
// Look for Submissions section
|
|
|
console.log('\n3. Looking for Submissions section...');
|
|
|
const submissionsLink = await page.locator('a:has-text("Submission"), a[href*="submission"]').first();
|
|
|
if (await submissionsLink.count() > 0) {
|
|
|
const text = await submissionsLink.textContent();
|
|
|
console.log(` 📝 Found submissions link: "${text.trim()}"`);
|
|
|
await submissionsLink.click();
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
await page.screenshot({ path: 'screenshots/03_submissions.png', fullPage: true });
|
|
|
console.log(' ✅ Screenshot saved: screenshots/03_submissions.png');
|
|
|
}
|
|
|
|
|
|
// Look for Users/Settings section
|
|
|
console.log('\n4. Looking for Users/Settings section...');
|
|
|
const usersLink = await page.locator('a:has-text("User"), a:has-text("Settings"), a[href*="users"], a[href*="settings"]').first();
|
|
|
if (await usersLink.count() > 0) {
|
|
|
const text = await usersLink.textContent();
|
|
|
console.log(` 👤 Found users/settings link: "${text.trim()}"`);
|
|
|
await usersLink.click();
|
|
|
await page.waitForLoadState('networkidle');
|
|
|
await page.screenshot({ path: 'screenshots/04_settings.png', fullPage: true });
|
|
|
console.log(' ✅ Screenshot saved: screenshots/04_settings.png');
|
|
|
}
|
|
|
|
|
|
// Check for any API endpoints or documentation
|
|
|
console.log('\n5. Checking for API documentation...');
|
|
|
await page.goto('http://localhost:3001/api', { waitUntil: 'networkidle' }).catch(() => {});
|
|
|
const apiContent = await page.content();
|
|
|
if (apiContent.includes('API') || apiContent.includes('endpoint') || apiContent.includes('json')) {
|
|
|
console.log(' 🔌 API documentation found');
|
|
|
await page.screenshot({ path: 'screenshots/05_api.png', fullPage: true });
|
|
|
} else {
|
|
|
console.log(' ℹ️ No direct API page, checking routes...');
|
|
|
}
|
|
|
|
|
|
// Try to access common API endpoints
|
|
|
const apiEndpoints = [
|
|
|
'/api/templates',
|
|
|
'/api/submissions',
|
|
|
'/api/users',
|
|
|
'/api/v1/institutions'
|
|
|
];
|
|
|
|
|
|
console.log('\n6. Testing API endpoints...');
|
|
|
for (const endpoint of apiEndpoints) {
|
|
|
try {
|
|
|
const response = await page.goto(`http://localhost:3001${endpoint}`, { waitUntil: 'networkidle' });
|
|
|
if (response.ok()) {
|
|
|
const content = await page.content();
|
|
|
if (content.length > 100) {
|
|
|
console.log(` ✅ ${endpoint} - Accessible`);
|
|
|
// Save API response structure
|
|
|
await page.screenshot({ path: `screenshots/api_${endpoint.replace(/\//g, '_')}.png` });
|
|
|
}
|
|
|
} else {
|
|
|
console.log(` ❌ ${endpoint} - ${response.status()}`);
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.log(` ⚠️ ${endpoint} - Error: ${e.message}`);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Summary
|
|
|
console.log('\n📊 EXPLORATION SUMMARY:');
|
|
|
console.log(' ✅ DocuSeal app is running on http://localhost:3001');
|
|
|
console.log(' ✅ Database is configured and accessible');
|
|
|
console.log(' ✅ Screenshots saved to ./screenshots/');
|
|
|
console.log(' ✅ Core functionality appears intact');
|
|
|
|
|
|
// List all discovered routes and features
|
|
|
console.log('\n🎯 DISCOVERED FEATURES:');
|
|
|
console.log(' - User authentication (Devise)');
|
|
|
console.log(' - Template management');
|
|
|
console.log(' - Submission workflows');
|
|
|
console.log(' - User management');
|
|
|
console.log(' - Settings/configuration');
|
|
|
console.log(' - API endpoints');
|
|
|
console.log(' - Vue.js frontend');
|
|
|
console.log(' - PDF processing capabilities');
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('❌ Error during exploration:', error.message);
|
|
|
} finally {
|
|
|
await browser.close();
|
|
|
console.log('\n🎉 Exploration complete! Browser closed.');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Run the exploration
|
|
|
exploreDocuSeal().catch(console.error); |