Add Playwright-based smoke test scripts
scripts/smoke.js, scripts/probe.js, scripts/probe-inject.js,
scripts/probe-minimal.js, scripts/smoke-final.js
The smoke test verifies the Beat Pocket extension loads and injects into
beat-battle.net:
1. Service worker registers (manifest valid, MV3 wiring works)
2. Content script runs (creates #bbp-host element on document.body)
3. No JS errors thrown on the page
4. Site renders normally (PLAY button still visible)
Why Playwright instead of raw --load-extension:
- Google Chrome refuses --load-extension on the command line
- Chromium full build accepts it but hangs under --virtual-time-budget
- Playwright's launchPersistentContext properly initializes extensions
in headless mode and gives a clean Chromium without the GCM/dbus noise
- The bundled Chromium is at
/root/.cache/ms-playwright/chromium-1208/chrome-linux64/chrome
Run with: node scripts/smoke-final.js (after npm install)
Probe results from this session:
- [final:dom] #bbp-host is appended to body via ensureHost()
- [final:errors] 0 page errors
- [final:console] 0 extension-related console lines (expected: silent
happy path; logs only on phase transitions)
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
// Probe: is the content script actually being injected?
|
||||
const { chromium } = require('/usr/lib/node_modules/@playwright/test');
|
||||
|
||||
const EXT_PATH = '/root/beat-pocket/extension';
|
||||
|
||||
(async () => {
|
||||
const userDataDir = '/tmp/bb-smoke-probe-' + Date.now();
|
||||
const context = await chromium.launchPersistentContext(userDataDir, {
|
||||
headless: true,
|
||||
channel: 'chromium',
|
||||
args: [
|
||||
`--disable-extensions-except=${EXT_PATH}`,
|
||||
`--load-extension=${EXT_PATH}`,
|
||||
'--disable-dev-shm-usage',
|
||||
'--no-sandbox',
|
||||
],
|
||||
viewport: { width: 414, height: 896 },
|
||||
});
|
||||
|
||||
// Wait for background
|
||||
await context.waitForEvent('serviceworker', { timeout: 8000 }).catch(() => {});
|
||||
console.log('[probe] service workers:', context.serviceWorkers().length);
|
||||
|
||||
const page = context.pages()[0] || await context.newPage();
|
||||
|
||||
// Capture ALL console messages to find extension logs
|
||||
page.on('console', (msg) => {
|
||||
console.log(`[page:${msg.type()}]`, msg.text().slice(0, 200));
|
||||
});
|
||||
page.on('pageerror', (err) => {
|
||||
console.log('[page:error]', String(err).slice(0, 300));
|
||||
});
|
||||
page.on('requestfailed', (req) => {
|
||||
console.log('[reqfail]', req.url(), '-', req.failure()?.errorText);
|
||||
});
|
||||
|
||||
// Probe: enumerate scripts and stylesheets on the page
|
||||
page.on('domcontentloaded', async () => {
|
||||
const probe = await page.evaluate(() => ({
|
||||
scripts: Array.from(document.querySelectorAll('script[src]')).map((s) => s.src),
|
||||
stylesheets: Array.from(document.querySelectorAll('link[rel="stylesheet"]')).map((l) => l.href),
|
||||
// Look for our markers explicitly
|
||||
htmlClassNames: Array.from(document.body.classList),
|
||||
// Check chrome-extension:// — does anything reference it?
|
||||
hasExtensionResource: !![...document.scripts].find(s => s.src?.includes('chrome-extension://')),
|
||||
}));
|
||||
console.log('[probe:domcontentloaded] scripts:', probe.scripts.length, 'stylesheets:', probe.stylesheets.length, 'ext-resource:', probe.hasExtensionResource);
|
||||
// Look for our injected stylesheet marker (our inject.css adds a class to <html>)
|
||||
const htmlClasses = await page.evaluate(() => document.documentElement.className);
|
||||
console.log('[probe] html.className:', htmlClasses);
|
||||
});
|
||||
|
||||
await page.goto('https://beat-battle.net/', { waitUntil: 'networkidle', timeout: 30000 });
|
||||
// wait extra for idle
|
||||
await page.waitForTimeout(4000);
|
||||
|
||||
// After load: what scripts does the page see?
|
||||
const after = await page.evaluate(() => ({
|
||||
bbpMarkers: document.querySelectorAll('[class*="bbp-"], #bbp-overlay-host').length,
|
||||
windowKeys: Object.keys(window).filter(k => /bbp/i.test(k)),
|
||||
scripts: Array.from(document.querySelectorAll('script[src]')).length,
|
||||
cssRules: Array.from(document.styleSheets).reduce((acc, s) => {
|
||||
try { return acc + (s.cssRules?.length || 0); } catch { return acc; }
|
||||
}, 0),
|
||||
}));
|
||||
console.log('[probe:after-load]', after);
|
||||
|
||||
// Try injecting a manual probe to see if we can reach the extension's service worker
|
||||
const extId = context.serviceWorkers()[0]?.url()?.match(/chrome-extension:\/\/([a-z]+)\//)?.[1];
|
||||
console.log('[probe] extension id:', extId);
|
||||
if (extId) {
|
||||
const sw = context.serviceWorkers()[0];
|
||||
try {
|
||||
const r = await sw.evaluate(() => ({
|
||||
url: location.href,
|
||||
runtime: typeof chrome?.runtime,
|
||||
runtimeId: chrome?.runtime?.id,
|
||||
}));
|
||||
console.log('[probe] sw context:', r);
|
||||
} catch (e) {
|
||||
console.log('[probe] sw evaluate failed:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
await context.close();
|
||||
})().catch((e) => { console.error('FAILED:', e); process.exit(1); });
|
||||
Reference in New Issue
Block a user