// Smoke test for Beat Pocket extension. // Uses Playwright's bundled Chromium (unbranded — accepts --load-extension) // to load the extension into beat-battle.net and verify: // 1. The extension was loaded (extension context exists) // 2. The content script ran (our markers are in the DOM) // 3. The page reached a usable state (PLAY button exists) // // Run: node scripts/smoke.js const { chromium } = require('/usr/lib/node_modules/@playwright/test'); const EXT_PATH = '/root/beat-pocket/extension'; const TARGET = 'https://beat-battle.net/'; (async () => { const consoleMessages = []; const pageErrors = []; // Persistent context lets us pass --load-extension at browser launch. // (Regular chromium.launch ignores that flag.) const userDataDir = '/tmp/bb-smoke-pw-' + Date.now(); const context = await chromium.launchPersistentContext(userDataDir, { headless: true, channel: 'chromium', // use playwright's bundled build, not google-chrome args: [ `--disable-extensions-except=${EXT_PATH}`, `--load-extension=${EXT_PATH}`, '--disable-dev-shm-usage', '--no-sandbox', ], viewport: { width: 414, height: 896 }, }); console.log('[smoke] launched persistent context, userDataDir:', userDataDir); // Wait for any service worker (background.js) to register let backgroundWorkers = context.serviceWorkers(); if (backgroundWorkers.length === 0) { try { backgroundWorkers = [await context.waitForEvent('serviceworker', { timeout: 5000 })]; } catch (e) { console.log('[smoke] no service worker registered within 5s:', e.message); } } console.log('[smoke] background workers:', backgroundWorkers.length); for (const sw of backgroundWorkers) { console.log(' sw url:', sw.url()); } const page = context.pages()[0] || await context.newPage(); page.on('console', (msg) => { consoleMessages.push({ type: msg.type(), text: msg.text() }); }); page.on('pageerror', (err) => { pageErrors.push(String(err)); }); console.log('[smoke] navigating to', TARGET); await page.goto(TARGET, { waitUntil: 'domcontentloaded', timeout: 30000 }); // Give the content script time to run, since run_at is document_idle await page.waitForTimeout(3000); // === Check 1: extension context === const extensionIds = context.backgroundPages().length; console.log('[smoke] background pages:', extensionIds); // === Check 2: content script markers in DOM === const markers = await page.evaluate(() => { const all = document.querySelectorAll('[class*="bbp-"], [data-bbp], #bbp-overlay-host, #bbp-chat-drawer'); return Array.from(all).slice(0, 25).map((el) => ({ tag: el.tagName.toLowerCase(), id: el.id || null, cls: el.className && typeof el.className === 'string' ? el.className.slice(0, 120) : null, })); }); console.log('[smoke] BBP markers in DOM:', markers.length); for (const m of markers) console.log(' ', m); // === Check 3: page rendered (PLAY button) === const playVisible = await page.locator('button:has-text("PLAY")').first().isVisible().catch(() => false); const loginVisible = await page.locator('a:has-text("LOG IN")').first().isVisible().catch(() => false); console.log('[smoke] PLAY button visible:', playVisible); console.log('[smoke] LOG IN chip visible:', loginVisible); // === Check 4: did our bbp:phase events fire? === const phaseEvents = await page.evaluate(() => { const evt = new Event('bbp-test'); return { hasGlobalListener: !!window.__bbp_phase_history__ }; }); console.log('[smoke] phase event hook:', phaseEvents); // === Check 5: console output from our content script === const ourConsole = consoleMessages.filter((m) => /beat pocket|bbp:|beat-pocket/i.test(m.text) ); console.log('[smoke] console lines from extension:', ourConsole.length); for (const m of ourConsole.slice(0, 10)) console.log(' ', m.type, m.text); // === Check 6: page errors === console.log('[smoke] page errors:', pageErrors.length); for (const e of pageErrors.slice(0, 5)) console.log(' ', e.slice(0, 200)); // Screenshot for the report await page.screenshot({ path: '/tmp/bb-smoke.png', fullPage: false }); console.log('[smoke] screenshot saved: /tmp/bb-smoke.png'); await context.close(); console.log('[smoke] DONE'); })().catch((e) => { console.error('[smoke] FAILED:', e); process.exit(1); });