/** * Explore Treez site structure to find full product catalog * * Usage: npx ts-node scripts/explore-treez-structure.ts */ import puppeteer from 'puppeteer'; const STORE_ID = 'best'; async function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } async function main() { console.log('='.repeat(60)); console.log('Exploring Treez Site Structure'); console.log('='.repeat(60)); const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); try { // Navigate to base menu URL const baseUrl = `https://${STORE_ID}.treez.io/onlinemenu/?customerType=ADULT`; console.log(`\n[1] Navigating to: ${baseUrl}`); await page.goto(baseUrl, { waitUntil: 'networkidle2', timeout: 60000 }); await sleep(3000); // Bypass age gate if present const ageGate = await page.$('[data-testid="age-gate-modal"]'); if (ageGate) { console.log('[1] Age gate detected, bypassing...'); const btn = await page.$('[data-testid="age-gate-submit-button"]'); if (btn) await btn.click(); await sleep(2000); } // Get all navigation links console.log('\n[2] Extracting navigation structure...'); const navInfo = await page.evaluate(() => { const links: { text: string; href: string }[] = []; // Look for nav links document.querySelectorAll('nav a, [class*="nav"] a, [class*="menu"] a, header a').forEach(el => { const text = el.textContent?.trim() || ''; const href = el.getAttribute('href') || ''; if (text && href && !links.some(l => l.href === href)) { links.push({ text, href }); } }); // Look for category tabs/buttons document.querySelectorAll('[class*="category"], [class*="tab"], [role="tab"]').forEach(el => { const text = el.textContent?.trim() || ''; const href = el.getAttribute('href') || el.getAttribute('data-href') || ''; if (text && !links.some(l => l.text === text)) { links.push({ text, href: href || `(click: ${el.className})` }); } }); // Get current URL const currentUrl = window.location.href; // Count products on page const productCount = document.querySelectorAll('[class*="product_product__"]').length; return { links, currentUrl, productCount }; }); console.log(`Current URL: ${navInfo.currentUrl}`); console.log(`Products on homepage: ${navInfo.productCount}`); console.log('\nNavigation links found:'); navInfo.links.forEach(l => { console.log(` "${l.text}" → ${l.href}`); }); // Look for category buttons/tabs specifically console.log('\n[3] Looking for category navigation...'); const categories = await page.evaluate(() => { const cats: { text: string; className: string; tagName: string }[] = []; // Find all clickable elements that might be categories const selectors = [ '[class*="CategoryNav"]', '[class*="category"]', '[class*="Category"]', '[class*="nav"] button', '[class*="tab"]', '[role="tablist"] *', '.MuiTab-root', '[class*="filter"]', ]; selectors.forEach(sel => { document.querySelectorAll(sel).forEach(el => { const text = el.textContent?.trim() || ''; if (text && text.length < 50 && !cats.some(c => c.text === text)) { cats.push({ text, className: el.className?.toString().slice(0, 80) || '', tagName: el.tagName, }); } }); }); return cats; }); console.log('Category-like elements:'); categories.forEach(c => { console.log(` [${c.tagName}] "${c.text}" (class: ${c.className})`); }); // Try clicking on "Flower" or "All" if found console.log('\n[4] Looking for "Flower" or "All Products" link...'); const clickTargets = ['Flower', 'All', 'All Products', 'Shop All', 'View All']; for (const target of clickTargets) { const element = await page.evaluate((targetText) => { const els = Array.from(document.querySelectorAll('a, button, [role="tab"], [class*="category"]')); const match = els.find(el => el.textContent?.trim().toLowerCase() === targetText.toLowerCase() ); if (match) { return { found: true, text: match.textContent?.trim(), tag: match.tagName, }; } return { found: false }; }, target); if (element.found) { console.log(`Found "${element.text}" (${element.tag}), clicking...`); await page.evaluate((targetText) => { const els = Array.from(document.querySelectorAll('a, button, [role="tab"], [class*="category"]')); const match = els.find(el => el.textContent?.trim().toLowerCase() === targetText.toLowerCase() ); if (match) (match as HTMLElement).click(); }, target); await sleep(3000); const newUrl = page.url(); const newCount = await page.evaluate(() => document.querySelectorAll('[class*="product_product__"]').length ); console.log(` New URL: ${newUrl}`); console.log(` Products after click: ${newCount}`); if (newCount > navInfo.productCount) { console.log(` ✓ Found more products! (${navInfo.productCount} → ${newCount})`); } break; } } // Check page height and scroll behavior console.log('\n[5] Checking scroll behavior on current page...'); let previousHeight = 0; let scrollCount = 0; let previousProductCount = await page.evaluate(() => document.querySelectorAll('[class*="product_product__"]').length ); while (scrollCount < 10) { const currentHeight = await page.evaluate(() => document.body.scrollHeight); if (currentHeight === previousHeight) { console.log(` Scroll ${scrollCount + 1}: No height change, stopping`); break; } await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); await sleep(1500); const currentProductCount = await page.evaluate(() => document.querySelectorAll('[class*="product_product__"]').length ); console.log(` Scroll ${scrollCount + 1}: height=${currentHeight}, products=${currentProductCount}`); if (currentProductCount === previousProductCount && scrollCount > 2) { console.log(' No new products loading, stopping'); break; } previousHeight = currentHeight; previousProductCount = currentProductCount; scrollCount++; } // Try direct URL patterns console.log('\n[6] Testing URL patterns...'); const urlPatterns = [ '/onlinemenu/flower?customerType=ADULT', '/onlinemenu/all?customerType=ADULT', '/onlinemenu?category=flower&customerType=ADULT', '/onlinemenu?view=all&customerType=ADULT', ]; for (const pattern of urlPatterns) { const testUrl = `https://${STORE_ID}.treez.io${pattern}`; console.log(`\nTrying: ${testUrl}`); await page.goto(testUrl, { waitUntil: 'networkidle2', timeout: 30000 }); await sleep(2000); // Bypass age gate again if needed const gate = await page.$('[data-testid="age-gate-modal"]'); if (gate) { const btn = await page.$('[data-testid="age-gate-submit-button"]'); if (btn) await btn.click(); await sleep(2000); } const productCount = await page.evaluate(() => document.querySelectorAll('[class*="product_product__"]').length ); console.log(` Products found: ${productCount}`); } // Screenshot the final state await page.screenshot({ path: '/tmp/treez-explore.png', fullPage: true }); console.log('\n[7] Screenshot saved to /tmp/treez-explore.png'); } catch (error: any) { console.error('Error:', error.message); } finally { await browser.close(); } } main().catch(console.error);