import puppeteer from 'puppeteer';
import { spawn } from 'child_process';
import { setTimeout } from 'timers/promises';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const PORT = 8765;
const BASE_URL = `http://localhost:${PORT}`;
const __dirname = dirname(fileURLToPath(import.meta.url));
let server = null;
let browser = null;
async function startServer() {
return new Promise((resolve, reject) => {
server = spawn('python3', ['-m', 'http.server', String(PORT)], {
cwd: dirname(__dirname), stdio: ['ignore', 'pipe', 'pipe']
});
server.stderr.on('data', (data) => {
if (data.toString().includes('Serving HTTP')) {
resolve();
}
});
server.on('error', reject);
setTimeout(1000).then(resolve);
});
}
async function stopServer() {
if (server) {
server.kill();
server = null;
}
}
const EXPECTED_ERRORS = {
'Error Handling': /Caught error:|Validation failed|WASM/,
};
async function runTests() {
console.log('Starting local server...');
await startServer();
console.log('Launching browser...');
const useFirefox = process.env.BROWSER === 'firefox';
browser = await puppeteer.launch({
headless: true,
product: useFirefox ? 'firefox' : 'chrome',
args: useFirefox ? [] : ['--no-sandbox', '--disable-gpu', '--disable-software-rasterizer'],
protocolTimeout: 60000 });
const page = await browser.newPage();
const errors = [];
page.on('pageerror', err => {
console.log(' [PAGE ERROR]', err.message);
errors.push(err.message);
});
page.on('console', msg => {
if (msg.type() === 'error') {
console.log(' [CONSOLE ERROR]', msg.text());
errors.push(msg.text());
}
if (msg.text().includes('[WASM]')) {
console.log(` ${msg.text()}`);
}
if (msg.text().includes('[DEBUG]')) {
console.log(` ${msg.text()}`);
}
});
page.on('error', err => {
console.log(' [PAGE CRASHED]', err.message);
});
page.on('close', () => {
console.log(' [PAGE CLOSED]');
});
console.log(`Loading ${BASE_URL}...`);
await page.goto(BASE_URL, { waitUntil: 'networkidle0' });
await page.waitForSelector('#status.success', { timeout: 30000 });
console.log('WASM loaded successfully\n');
const examples = await page.evaluate(() => {
const select = document.getElementById('examples');
return Array.from(select.options).map(opt => ({
value: opt.value,
name: opt.textContent
}));
});
console.log(`Found ${examples.length} examples to test\n`);
const results = await page.evaluate(async (exampleData, expectedErrorPatterns) => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const results = [];
for (const example of exampleData) {
document.getElementById('examples').value = example.value;
document.getElementById('code').value = window.EXAMPLES?.[example.value]?.code || '';
await delay(100);
document.getElementById('run-btn').click();
const startTime = Date.now();
while (Date.now() - startTime < 30000) {
const status = document.getElementById('status');
if (status.classList.contains('success') || status.classList.contains('error')) {
break;
}
await delay(100);
}
await delay(50);
const statusEl = document.getElementById('status');
const outputEl = document.getElementById('output');
const errorLines = outputEl.querySelectorAll('.output-error');
const errorTexts = Array.from(errorLines).map(el => el.textContent);
const runtimeError = errorTexts.find(text =>
text.startsWith('Error:') ||
text.includes('Parse error') ||
text.includes('Unexpected token')
);
results.push({
name: example.name,
value: example.value,
status: statusEl.className,
hasError: !!runtimeError,
errorText: runtimeError || null
});
}
return results;
}, examples, EXPECTED_ERRORS);
let passed = 0;
let failed = 0;
for (const result of results) {
const expectedPattern = EXPECTED_ERRORS[result.name];
const unexpectedPageErrors = expectedPattern
? errors.filter(e => !expectedPattern.test(e))
: errors.filter(e => true);
const hasOutputError = result.hasError;
if (hasOutputError) {
console.log(`✗ ${result.name}`);
if (hasOutputError) {
console.log(` Runtime error: ${result.errorText}`);
}
failed++;
} else {
console.log(`✓ ${result.name}`);
passed++;
}
}
console.log('\n═══════════════════════════════════════════════════════════════');
console.log(`Results: ${passed} passed, ${failed} failed`);
console.log('═══════════════════════════════════════════════════════════════\n');
await browser.close();
await stopServer();
process.exit(failed > 0 ? 1 : 0);
}
runTests().catch(async err => {
console.error('Test failed:', err);
if (browser) await browser.close();
await stopServer();
process.exit(1);
});