#!/usr/bin/env node /** * Playwright integration test runner for preloaded package detection. * * Usage: * node run_integ.js [--headed] * * Starts an HTTP server, runs tests in a browser, reports results. */ const http = require('http'); const fs = require('fs'); const path = require('path'); const { createRequire } = require('module'); const PORT = 8766; const TIMEOUT = 60000; // 60 seconds max test time // When run by dune, __filename is in _build/default/js_top_worker/test/integration/. // We serve files from that build directory. For node_modules (playwright), we // compute the source directory by stripping _build/default/ from the path. const buildDir = path.dirname(__filename); // Compute source directory: replace _build/default/ segment with empty // e.g. /path/_build/default/js_top_worker/test/integration -> /path/js_top_worker/test/integration function computeSourceDir(dir) { const marker = path.sep + '_build' + path.sep + 'default' + path.sep; const idx = dir.indexOf(marker); if (idx >= 0) { return dir.substring(0, idx) + path.sep + dir.substring(idx + marker.length); } return dir; } const sourceDir = computeSourceDir(buildDir); // Load playwright from source directory's node_modules const sourceRequire = createRequire(path.join(sourceDir, 'package.json')); const { chromium } = sourceRequire('playwright'); // MIME types for serving files const mimeTypes = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', }; function startServer() { return new Promise((resolve, reject) => { const server = http.createServer((req, res) => { let filePath = req.url === '/' ? '/integ_test.html' : req.url; // Strip query string filePath = filePath.split('?')[0]; // Try build directory first, then source directory let fullPath = path.join(buildDir, filePath); if (!fs.existsSync(fullPath)) { fullPath = path.join(sourceDir, filePath); } if (!fs.existsSync(fullPath)) { console.log(`404: ${filePath}`); res.writeHead(404); res.end('Not found: ' + filePath); return; } const ext = path.extname(fullPath); const contentType = mimeTypes[ext] || 'application/octet-stream'; fs.readFile(fullPath, (err, content) => { if (err) { res.writeHead(500); res.end('Error reading file'); return; } res.writeHead(200, { 'Content-Type': contentType }); res.end(content); }); }); server.listen(PORT, () => { console.log(`Integration test server running at http://localhost:${PORT}/`); resolve(server); }); server.on('error', reject); }); } async function runTests(headed = false) { let server; let browser; let exitCode = 0; try { // Start the HTTP server server = await startServer(); // Launch browser browser = await chromium.launch({ headless: !headed }); const page = await browser.newPage(); // Collect console messages const logs = []; page.on('console', msg => { const text = msg.text(); logs.push(text); console.log(`[browser] ${text}`); }); // Navigate to test page console.log('Loading integration test page...'); await page.goto(`http://localhost:${PORT}/`); // Wait for tests to complete console.log('Waiting for tests to complete...'); await page.waitForFunction( () => window.testResults && window.testResults.done, { timeout: TIMEOUT } ); // Get final results const testResults = await page.evaluate(() => ({ total: window.testResults.total, passed: window.testResults.passed, failed: window.testResults.failed, })); console.log('\n========================================'); console.log(`Integration Test Results: ${testResults.passed}/${testResults.total} passed`); console.log('========================================\n'); // Additional check: verify Crc_mismatch appeared in browser console // (worker console.log is captured by Playwright but not by the page's JS) const hasCrcMismatch = logs.some(line => line.includes('Crc_mismatch')); if (!hasCrcMismatch) { console.log('WARNING: Crc_mismatch not found in console logs'); } if (testResults.failed > 0) { console.log('FAILED: Some integration tests did not pass'); exitCode = 1; } else if (!hasCrcMismatch) { console.log('FAILED: Crc_mismatch exception was not raised'); exitCode = 1; } else { console.log('SUCCESS: All integration tests passed'); } } catch (err) { console.error('Error running integration tests:', err.message); exitCode = 1; } finally { if (browser) await browser.close(); if (server) server.close(); } process.exit(exitCode); } // Parse command line args const headed = process.argv.includes('--headed'); runTests(headed);