const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.goto('http://127.0.0.1:8000/test-modal'); // Make modal visible for accurate computed CSS await page.evaluate(() => { const modal = document.getElementById('deleteModal'); if (modal) { modal.classList.remove('hidden'); modal.style.display = 'flex'; } }); const data = await page.evaluate(() => { const modal = document.getElementById('deleteModal'); if (!modal) return { error: 'Modal not found' }; // 1. DOM Path let current = modal; let path = []; while (current && current.nodeType === 1) { let desc = current.tagName.toLowerCase(); if (current.id) desc += '#' + current.id; if (current.className && typeof current.className === 'string') { desc += '.' + current.className.split(' ').join('.'); } path.unshift(desc); current = current.parentNode; } // 2. Computed CSS for modal const getStyles = (el) => { const cs = window.getComputedStyle(el); return { position: cs.position, top: cs.top, right: cs.right, bottom: cs.bottom, left: cs.left, display: cs.display, zIndex: cs.zIndex, transform: cs.transform !== 'none' ? cs.transform : 'none', contain: cs.contain !== 'none' ? cs.contain : 'none', filter: cs.filter !== 'none' ? cs.filter : 'none', backdropFilter: cs.backdropFilter !== 'none' ? cs.backdropFilter : 'none', perspective: cs.perspective !== 'none' ? cs.perspective : 'none', overflow: cs.overflow, overflowY: cs.overflowY, willChange: cs.willChange !== 'auto' ? cs.willChange : 'auto' }; }; const modalCSS = getStyles(modal); // 4. Ancestor trace let ancestors = []; current = modal.parentNode; while (current && current.nodeType === 1) { const cs = window.getComputedStyle(current); const hasContext = cs.transform !== 'none' || cs.filter !== 'none' || cs.perspective !== 'none' || cs.contain !== 'none' || cs.willChange !== 'auto' || cs.position !== 'static' || cs.zIndex !== 'auto' || cs.isolation !== 'auto' || cs.overflow !== 'visible'; if (hasContext) { ancestors.push({ tagName: current.tagName, id: current.id, className: current.className, position: cs.position, zIndex: cs.zIndex, transform: cs.transform !== 'none' ? cs.transform : 'none', filter: cs.filter !== 'none' ? cs.filter : 'none', perspective: cs.perspective !== 'none' ? cs.perspective : 'none', contain: cs.contain !== 'none' ? cs.contain : 'none', willChange: cs.willChange !== 'auto' ? cs.willChange : 'auto', overflow: cs.overflow, isolation: cs.isolation !== 'auto' ? cs.isolation : 'auto' }); } current = current.parentNode; } // Find element that has large scrollHeight const bodyHeight = document.body.scrollHeight; const mainContent = document.querySelector('.main-content'); const scrollContainer = document.querySelector('.overflow-y-auto'); return { path, modalCSS, ancestors, scrollHeights: { body: bodyHeight, mainContent: mainContent ? mainContent.scrollHeight : null, scrollContainer: scrollContainer ? scrollContainer.scrollHeight : null } }; }); console.log(JSON.stringify(data, null, 2)); await browser.close(); })();