/** * ============================================================ * TREEZ CLIENT TEST SCRIPT * ============================================================ * * Tests the Treez CDP interception client using Best Dispensary. * * This verifies: * - Stealth plugin bypasses headless detection * - CDP intercepts Elasticsearch API responses * - Products are captured and normalized correctly * - Inventory data is available * * Usage: npx ts-node scripts/test-treez-client.ts * * ============================================================ */ import { fetchProductsFromUrl } from '../src/platforms/treez'; const TEST_URL = 'https://shop.bestdispensary.com/shop'; async function main() { console.log('='.repeat(60)); console.log('TREEZ CLIENT TEST - CDP INTERCEPTION'); console.log('='.repeat(60)); console.log(`URL: ${TEST_URL}`); console.log('Method: Puppeteer + Stealth + CDP response capture'); console.log(''); try { console.log('[Starting] Launching browser with Stealth plugin...\n'); const result = await fetchProductsFromUrl(TEST_URL); console.log('\n' + '='.repeat(60)); console.log('RESULTS'); console.log('='.repeat(60)); console.log(`Total products: ${result.totalCaptured}`); console.log(`Store ID: ${result.storeId || 'N/A (custom domain)'}`); console.log(`Source URL: ${result.sourceUrl}`); console.log(`Fetched at: ${result.fetchedAt.toISOString()}`); if (result.products.length === 0) { console.log('\n[WARNING] No products captured!'); console.log('This could mean:'); console.log(' - Stealth plugin is not bypassing detection'); console.log(' - CDP is not intercepting the correct URLs'); console.log(' - Page structure has changed'); process.exit(1); } // Show sample raw product console.log('\n' + '='.repeat(60)); console.log('SAMPLE RAW PRODUCT (from Elasticsearch)'); console.log('='.repeat(60)); const raw = result.products[0]; console.log(JSON.stringify({ id: raw.id, name: raw.name, menuTitle: raw.menuTitle, brand: raw.brand, category: raw.category, subtype: raw.subtype, status: raw.status, availableUnits: raw.availableUnits, customMinPrice: raw.customMinPrice, customMaxPrice: raw.customMaxPrice, isActive: raw.isActive, isAboveThreshold: raw.isAboveThreshold, }, null, 2)); // Show sample normalized product console.log('\n' + '='.repeat(60)); console.log('SAMPLE NORMALIZED PRODUCT'); console.log('='.repeat(60)); const normalized = result.normalized[0]; console.log(JSON.stringify({ id: normalized.id, name: normalized.name, brand: normalized.brand, category: normalized.category, subtype: normalized.subtype, price: normalized.price, priceMin: normalized.priceMin, priceMax: normalized.priceMax, discountedPrice: normalized.discountedPrice, discountPercent: normalized.discountPercent, availableUnits: normalized.availableUnits, inStock: normalized.inStock, thcPercent: normalized.thcPercent, cbdPercent: normalized.cbdPercent, strainType: normalized.strainType, effects: normalized.effects, flavors: normalized.flavors, imageUrl: normalized.imageUrl, images: normalized.images?.slice(0, 2), }, null, 2)); // Brand breakdown console.log('\n' + '='.repeat(60)); console.log('BRANDS (top 15)'); console.log('='.repeat(60)); const brandCounts = new Map(); for (const p of result.normalized) { const brand = p.brand || 'Unknown'; brandCounts.set(brand, (brandCounts.get(brand) || 0) + 1); } const sorted = [...brandCounts.entries()].sort((a, b) => b[1] - a[1]); console.log(`Total unique brands: ${sorted.length}\n`); sorted.slice(0, 15).forEach(([brand, count]) => { console.log(` ${brand}: ${count} products`); }); // Category breakdown console.log('\n' + '='.repeat(60)); console.log('CATEGORIES'); console.log('='.repeat(60)); const categoryCounts = new Map(); for (const p of result.normalized) { const cat = p.category || 'Unknown'; categoryCounts.set(cat, (categoryCounts.get(cat) || 0) + 1); } const catSorted = [...categoryCounts.entries()].sort((a, b) => b[1] - a[1]); catSorted.forEach(([cat, count]) => { console.log(` ${cat}: ${count} products`); }); // Inventory stats console.log('\n' + '='.repeat(60)); console.log('INVENTORY STATS'); console.log('='.repeat(60)); const inStock = result.normalized.filter(p => p.inStock).length; const outOfStock = result.normalized.filter(p => !p.inStock).length; const hasInventoryData = result.normalized.filter(p => p.availableUnits > 0).length; console.log(`In stock: ${inStock}`); console.log(`Out of stock: ${outOfStock}`); console.log(`With inventory levels: ${hasInventoryData}`); // Show inventory examples if (hasInventoryData > 0) { console.log('\nSample inventory levels:'); result.normalized .filter(p => p.availableUnits > 0) .slice(0, 5) .forEach(p => { console.log(` ${p.name}: ${p.availableUnits} units`); }); } // Check for THC/CBD data const hasThc = result.normalized.filter(p => p.thcPercent !== null).length; const hasCbd = result.normalized.filter(p => p.cbdPercent !== null).length; console.log(`\nWith THC data: ${hasThc} (${Math.round(hasThc / result.totalCaptured * 100)}%)`); console.log(`With CBD data: ${hasCbd} (${Math.round(hasCbd / result.totalCaptured * 100)}%)`); // Check for images const hasImages = result.normalized.filter(p => p.imageUrl).length; console.log(`With images: ${hasImages} (${Math.round(hasImages / result.totalCaptured * 100)}%)`); console.log('\n' + '='.repeat(60)); console.log('TEST PASSED'); console.log('='.repeat(60)); } catch (error: any) { console.error('\n' + '='.repeat(60)); console.error('TEST FAILED'); console.error('='.repeat(60)); console.error(`Error: ${error.message}`); console.error(error.stack); process.exit(1); } } main().catch(console.error);