223 lines
		
	
	
		
			No EOL
		
	
	
		
			7.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			No EOL
		
	
	
		
			7.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { STAGING_URL, PATHS, TIMEOUTS } from './config/staging-config';
 | |
| import { test, expect } from '@playwright/test';
 | |
| 
 | |
| // STAGING_URL is now imported from config
 | |
| 
 | |
| test.describe('Investigate Form Submission', () => {
 | |
|   test('analyze form submission mechanism', async ({ page }) => {
 | |
|     // Capture console messages and errors
 | |
|     page.on('console', msg => {
 | |
|       console.log(`Console ${msg.type()}: ${msg.text()}`);
 | |
|     });
 | |
|     
 | |
|     page.on('pageerror', err => {
 | |
|       console.log('Page error:', err.message);
 | |
|     });
 | |
|     
 | |
|     // Login
 | |
|     await page.goto(PATHS.login);
 | |
|     await page.fill('#user_login', 'test_trainer');
 | |
|     await page.fill('#user_pass', 'Test123!');
 | |
|     await page.click('#wp-submit');
 | |
|     await page.waitForURL('**/hvac-dashboard/');
 | |
|     
 | |
|     // Navigate to create event
 | |
|     await page.click('a:has-text("CREATE EVENT")');
 | |
|     await page.waitForLoadState('networkidle');
 | |
|     await page.waitForTimeout(3000);
 | |
|     
 | |
|     // Analyze the form structure
 | |
|     const formInfo = await page.evaluate(() => {
 | |
|       const form = document.querySelector('form');
 | |
|       if (!form) return { hasForm: false };
 | |
|       
 | |
|       return {
 | |
|         hasForm: true,
 | |
|         action: form.action,
 | |
|         method: form.method,
 | |
|         id: form.id,
 | |
|         classes: form.className,
 | |
|         onsubmit: form.onsubmit ? 'has onsubmit handler' : 'no onsubmit',
 | |
|         fields: Array.from(form.elements).map(el => ({
 | |
|           name: (el as any).name,
 | |
|           type: (el as any).type,
 | |
|           required: (el as any).required,
 | |
|           value: (el as any).value
 | |
|         })).filter(f => f.name)
 | |
|       };
 | |
|     });
 | |
|     
 | |
|     console.log('Form info:', JSON.stringify(formInfo, null, 2));
 | |
|     
 | |
|     // Check for jQuery form handlers
 | |
|     const jqueryHandlers = await page.evaluate(() => {
 | |
|       if (typeof jQuery === 'undefined') return { hasJquery: false };
 | |
|       
 | |
|       const form = jQuery('form').first();
 | |
|       if (!form.length) return { hasJquery: true, hasForm: false };
 | |
|       
 | |
|       // Get event handlers
 | |
|       const events = jQuery._data(form[0], 'events') || {};
 | |
|       
 | |
|       return {
 | |
|         hasJquery: true,
 | |
|         hasForm: true,
 | |
|         submitHandlers: events.submit ? events.submit.length : 0,
 | |
|         clickHandlers: jQuery('input[type="submit"], button[type="submit"]').length
 | |
|       };
 | |
|     });
 | |
|     
 | |
|     console.log('jQuery handlers:', jqueryHandlers);
 | |
|     
 | |
|     // Fill minimal required fields
 | |
|     await page.fill('input[name="post_title"]', `Test Event ${Date.now()}`);
 | |
|     
 | |
|     // Try to set description directly in multiple ways
 | |
|     await page.evaluate(() => {
 | |
|       // Method 1: Direct TinyMCE
 | |
|       if (typeof tinymce !== 'undefined' && tinymce.activeEditor) {
 | |
|         tinymce.activeEditor.setContent('Test description content');
 | |
|         tinymce.activeEditor.save();
 | |
|       }
 | |
|       
 | |
|       // Method 2: Find actual textarea
 | |
|       const textareas = document.querySelectorAll('textarea');
 | |
|       textareas.forEach(ta => {
 | |
|         if (ta.name.includes('content') || ta.id.includes('content')) {
 | |
|           (ta as HTMLTextAreaElement).value = 'Test description content';
 | |
|         }
 | |
|       });
 | |
|       
 | |
|       // Method 3: Hidden inputs
 | |
|       const hiddenInputs = document.querySelectorAll('input[type="hidden"]');
 | |
|       hiddenInputs.forEach(input => {
 | |
|         if (input.name.includes('content')) {
 | |
|           (input as HTMLInputElement).value = 'Test description content';
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|     
 | |
|     // Set dates
 | |
|     const today = new Date();
 | |
|     const dateStr = `${(today.getMonth() + 1).toString().padStart(2, '0')}/${today.getDate().toString().padStart(2, '0')}/${today.getFullYear()}`;
 | |
|     
 | |
|     await page.fill('input#EventStartDate', dateStr);
 | |
|     await page.fill('input#EventEndDate', dateStr);
 | |
|     
 | |
|     // Listen to network requests
 | |
|     const requests: any[] = [];
 | |
|     page.on('request', request => {
 | |
|       if (request.method() === 'POST') {
 | |
|         requests.push({
 | |
|           url: request.url(),
 | |
|           method: request.method(),
 | |
|           postData: request.postData()
 | |
|         });
 | |
|       }
 | |
|     });
 | |
|     
 | |
|     // Take screenshot before submit
 | |
|     await page.screenshot({ path: 'test-results/before-submit-investigate.png' });
 | |
|     
 | |
|     // Find submit button and get its properties
 | |
|     const submitInfo = await page.evaluate(() => {
 | |
|       const submitBtn = document.querySelector('input[type="submit"][value="Submit Event"]');
 | |
|       if (!submitBtn) return null;
 | |
|       
 | |
|       return {
 | |
|         id: submitBtn.id,
 | |
|         name: (submitBtn as HTMLInputElement).name,
 | |
|         value: (submitBtn as HTMLInputElement).value,
 | |
|         onclick: submitBtn.onclick ? 'has onclick' : 'no onclick',
 | |
|         form: (submitBtn as HTMLInputElement).form ? 'has form' : 'no form'
 | |
|       };
 | |
|     });
 | |
|     
 | |
|     console.log('Submit button info:', submitInfo);
 | |
|     
 | |
|     // Try to submit and catch any navigation
 | |
|     let navigationHappened = false;
 | |
|     let formStayed = false;
 | |
|     
 | |
|     try {
 | |
|       const navigationPromise = page.waitForNavigation({ timeout: 5000 });
 | |
|       await page.click('input[type="submit"][value="Submit Event"]');
 | |
|       await navigationPromise;
 | |
|       navigationHappened = true;
 | |
|     } catch (e) {
 | |
|       formStayed = true;
 | |
|       console.log('No navigation occurred');
 | |
|     }
 | |
|     
 | |
|     await page.waitForTimeout(3000);
 | |
|     
 | |
|     // Check current state
 | |
|     const currentUrl = page.url();
 | |
|     console.log('Current URL:', currentUrl);
 | |
|     console.log('Navigation happened:', navigationHappened);
 | |
|     console.log('Form stayed:', formStayed);
 | |
|     console.log('POST requests:', requests);
 | |
|     
 | |
|     // Check for validation errors in DOM
 | |
|     const validationErrors = await page.evaluate(() => {
 | |
|       const errors: any[] = [];
 | |
|       
 | |
|       // Check for WordPress admin notices
 | |
|       document.querySelectorAll('.notice, .error, .updated').forEach(el => {
 | |
|         errors.push({
 | |
|           type: 'wordpress-notice',
 | |
|           text: el.textContent?.trim(),
 | |
|           classes: el.className
 | |
|         });
 | |
|       });
 | |
|       
 | |
|       // Check for inline errors
 | |
|       document.querySelectorAll('.error-message, .field-error, .validation-error').forEach(el => {
 | |
|         errors.push({
 | |
|           type: 'inline-error',
 | |
|           text: el.textContent?.trim(),
 | |
|           classes: el.className
 | |
|         });
 | |
|       });
 | |
|       
 | |
|       // Check for HTML5 validation
 | |
|       const inputs = document.querySelectorAll('input, textarea, select');
 | |
|       inputs.forEach(input => {
 | |
|         if ((input as any).validationMessage) {
 | |
|           errors.push({
 | |
|             type: 'html5-validation',
 | |
|             field: (input as any).name,
 | |
|             message: (input as any).validationMessage
 | |
|           });
 | |
|         }
 | |
|       });
 | |
|       
 | |
|       return errors;
 | |
|     });
 | |
|     
 | |
|     console.log('Validation errors:', validationErrors);
 | |
|     
 | |
|     // Get final form data
 | |
|     const finalFormData = await page.evaluate(() => {
 | |
|       const form = document.querySelector('form');
 | |
|       if (!form) return null;
 | |
|       
 | |
|       const formData = new FormData(form as HTMLFormElement);
 | |
|       const data: Record<string, any> = {};
 | |
|       
 | |
|       formData.forEach((value, key) => {
 | |
|         data[key] = value;
 | |
|       });
 | |
|       
 | |
|       return data;
 | |
|     });
 | |
|     
 | |
|     console.log('Final form data:', finalFormData);
 | |
|     
 | |
|     // Take final screenshot
 | |
|     await page.screenshot({ path: 'test-results/after-submit-investigate.png', fullPage: true });
 | |
|     
 | |
|     // Pass test to see output
 | |
|     expect(true).toBe(true);
 | |
|   });
 | |
| }); |