Files
cannaiq/backend/scripts/test-brands-selector.ts
Kelly 698995e46f chore: bump task worker version comment
Force new git SHA to avoid CI scientific notation bug.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-14 02:02:30 -07:00

131 lines
3.8 KiB
TypeScript

import puppeteer from 'puppeteer';
async function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
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 });
await page.setRequestInterception(true);
page.on('request', (req) => {
if (['image', 'font', 'media'].includes(req.resourceType())) {
req.abort();
} else {
req.continue();
}
});
await page.goto('https://shop.bestdispensary.com/brands', {
waitUntil: 'networkidle2',
timeout: 60000
});
await sleep(3000);
// Bypass age gate
const ageGate = await page.$('[data-testid="age-gate-modal"]');
if (ageGate) {
const btn = await page.$('[data-testid="age-gate-submit-button"]');
if (btn) await btn.click();
await sleep(2000);
}
// Use the selector hint: /html/body/main/section
console.log('Looking at main > section structure...\n');
const sectionInfo = await page.evaluate(() => {
const main = document.querySelector('main');
if (!main) return { error: 'No main element' };
const sections = main.querySelectorAll('section');
const results: any[] = [];
sections.forEach((section, i) => {
const children = section.children;
const childInfo: string[] = [];
for (let j = 0; j < Math.min(children.length, 10); j++) {
const child = children[j];
childInfo.push(child.tagName + '.' + (child.className?.slice(0, 30) || ''));
}
results.push({
index: i,
class: section.className?.slice(0, 50),
childCount: children.length,
sampleChildren: childInfo,
});
});
return results;
});
console.log('Sections in main:');
console.log(JSON.stringify(sectionInfo, null, 2));
// Look for brand cards within the section
console.log('\nLooking for brand cards in main > section...');
const brandCards = await page.evaluate(() => {
const section = document.querySelector('main > section');
if (!section) return [];
// Get all child elements that might be brand cards
const cards: { tag: string; text: string; href: string }[] = [];
section.querySelectorAll('a').forEach((a: Element) => {
const href = a.getAttribute('href') || '';
const text = a.textContent?.trim().slice(0, 50) || '';
cards.push({ tag: 'a', text, href });
});
return cards;
});
console.log(`Found ${brandCards.length} links in section:`);
brandCards.slice(0, 30).forEach(c => console.log(` ${c.text} -> ${c.href}`));
// Get the grid of brand cards
console.log('\nLooking for grid container...');
const gridCards = await page.evaluate(() => {
// Look for grid-like containers
const grids = document.querySelectorAll('[class*="grid"], [class*="Grid"], main section > div');
const results: any[] = [];
grids.forEach((grid, i) => {
const links = grid.querySelectorAll('a[href*="/brand/"]');
if (links.length > 5) {
const brands: string[] = [];
links.forEach((a: Element) => {
const text = a.textContent?.trim().split('\n')[0] || '';
if (text && !brands.includes(text)) brands.push(text);
});
results.push({
class: grid.className?.slice(0, 40),
brandCount: brands.length,
brands: brands.slice(0, 50),
});
}
});
return results;
});
console.log('Grid containers with brands:');
gridCards.forEach(g => {
console.log(`\n[${g.brandCount} brands] class="${g.class}"`);
g.brands.forEach((b: string, i: number) => console.log(` ${i+1}. ${b}`));
});
await browser.close();
}
main().catch(console.error);