- Add backend stale process monitoring API (/api/stale-processes) - Add users management route - Add frontend landing page and stale process monitor UI on /scraper-tools - Move old development scripts to backend/archive/ - Update frontend build with new features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
152 lines
5.1 KiB
TypeScript
152 lines
5.1 KiB
TypeScript
import { chromium } from 'playwright';
|
||
|
||
const TEST_URL = 'https://curaleaf.com/stores/curaleaf-dispensary-48th-street';
|
||
|
||
async function testCuraleafWithPlaywright() {
|
||
console.log('\n🎭 Testing Curaleaf Age Gate with Playwright\n');
|
||
console.log(`URL: ${TEST_URL}\n`);
|
||
|
||
const browser = await chromium.launch({
|
||
headless: true,
|
||
args: [
|
||
'--no-sandbox',
|
||
'--disable-setuid-sandbox',
|
||
'--disable-blink-features=AutomationControlled'
|
||
]
|
||
});
|
||
|
||
try {
|
||
const context = await browser.newContext({
|
||
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||
viewport: { width: 1280, height: 720 }
|
||
});
|
||
|
||
const page = await context.newPage();
|
||
|
||
console.log('📍 Step 1: Setting age gate cookies...');
|
||
await context.addCookies([
|
||
{
|
||
name: 'age_gate_passed',
|
||
value: 'true',
|
||
domain: '.curaleaf.com',
|
||
path: '/',
|
||
expires: Date.now() / 1000 + 365 * 24 * 60 * 60,
|
||
httpOnly: false,
|
||
secure: false,
|
||
sameSite: 'Lax'
|
||
},
|
||
{
|
||
name: 'selected_state',
|
||
value: 'Arizona',
|
||
domain: '.curaleaf.com',
|
||
path: '/',
|
||
expires: Date.now() / 1000 + 365 * 24 * 60 * 60,
|
||
httpOnly: false,
|
||
secure: false,
|
||
sameSite: 'Lax'
|
||
},
|
||
{
|
||
name: 'age_verified',
|
||
value: 'true',
|
||
domain: '.curaleaf.com',
|
||
path: '/',
|
||
expires: Date.now() / 1000 + 365 * 24 * 60 * 60,
|
||
httpOnly: false,
|
||
secure: false,
|
||
sameSite: 'Lax'
|
||
}
|
||
]);
|
||
|
||
console.log('📍 Step 2: Navigating to page...');
|
||
await page.goto(TEST_URL, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
||
await page.waitForTimeout(3000);
|
||
|
||
const currentUrl = page.url();
|
||
console.log(`Current URL: ${currentUrl}`);
|
||
|
||
console.log('\n📍 Step 3: Checking for age gate...');
|
||
const bodyText = await page.textContent('body');
|
||
const hasAgeGate = bodyText?.includes('Please select your state') ||
|
||
bodyText?.includes('age verification') ||
|
||
currentUrl.includes('/age-gate');
|
||
|
||
if (hasAgeGate) {
|
||
console.log('✅ Age gate detected!');
|
||
console.log('\n📍 Step 4: Attempting to bypass age gate with Playwright...');
|
||
|
||
// Take screenshot before bypass
|
||
await page.screenshot({ path: '/tmp/curaleaf-playwright-before.png' });
|
||
console.log('📸 Screenshot saved: /tmp/curaleaf-playwright-before.png');
|
||
|
||
// Method 1: Try to find and click the state dropdown button
|
||
const stateButton = page.locator('button#state, button[id="state"]');
|
||
const stateButtonExists = await stateButton.count() > 0;
|
||
|
||
if (stateButtonExists) {
|
||
console.log('Found state dropdown button, clicking...');
|
||
await stateButton.click();
|
||
await page.waitForTimeout(1000);
|
||
|
||
// Find and click Arizona option
|
||
const arizonaOption = page.locator('[role="option"]').filter({ hasText: /^Arizona$/i });
|
||
const arizonaExists = await arizonaOption.count() > 0;
|
||
|
||
if (arizonaExists) {
|
||
console.log('Clicking Arizona option...');
|
||
await arizonaOption.click();
|
||
await page.waitForTimeout(1500);
|
||
|
||
// Look for submit/continue button
|
||
const submitButton = page.locator('button, [role="button"]').filter({
|
||
hasText: /continue|submit|enter|confirm/i
|
||
});
|
||
const submitExists = await submitButton.count() > 0;
|
||
|
||
if (submitExists) {
|
||
console.log('Clicking submit button...');
|
||
await submitButton.first().click();
|
||
|
||
// Wait for navigation
|
||
try {
|
||
await page.waitForURL(url => !url.includes('/age-gate'), { timeout: 10000 });
|
||
} catch (e) {
|
||
console.log('No navigation detected, waiting...');
|
||
await page.waitForTimeout(3000);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Check final URL
|
||
const finalUrl = page.url();
|
||
console.log(`\nFinal URL: ${finalUrl}`);
|
||
|
||
if (finalUrl.includes('/age-gate')) {
|
||
console.log('❌ Age gate bypass FAILED - still at age gate');
|
||
await page.screenshot({ path: '/tmp/curaleaf-playwright-failed.png' });
|
||
console.log('📸 Screenshot saved: /tmp/curaleaf-playwright-failed.png');
|
||
} else {
|
||
console.log('✅ Age gate bypass SUCCEEDED!');
|
||
await page.screenshot({ path: '/tmp/curaleaf-playwright-success.png' });
|
||
console.log('📸 Screenshot saved: /tmp/curaleaf-playwright-success.png');
|
||
|
||
// Check if we can see the menu
|
||
const hasMenu = await page.locator('text=/menu|shop|products/i').count() > 0;
|
||
console.log(`Can see menu: ${hasMenu ? '✅' : '❌'}`);
|
||
}
|
||
} else {
|
||
console.log('ℹ️ No age gate detected - cookies may have worked!');
|
||
await page.screenshot({ path: '/tmp/curaleaf-playwright-no-gate.png' });
|
||
console.log('📸 Screenshot saved: /tmp/curaleaf-playwright-no-gate.png');
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('❌ Error:', error);
|
||
} finally {
|
||
await browser.close();
|
||
console.log('\n✅ Test completed');
|
||
}
|
||
}
|
||
|
||
testCuraleafWithPlaywright();
|