(pkg)
| 24 | }; |
| 25 | |
| 26 | async function runPackage(pkg) { |
| 27 | const dir = `${ROOT}${pkg}`; |
| 28 | // Import the package's `.py` entry when it has one, else the built wasm. |
| 29 | const hasPy = existsSync(`${dir}/src/entry.py`); |
| 30 | const wasmUrl = `/${pkg}/target/wasm32-unknown-unknown/release/${pkg}.wasm`; |
| 31 | |
| 32 | let entry; |
| 33 | if (hasPy) { |
| 34 | entry = `/${pkg}/src/entry.py`; |
| 35 | } else { |
| 36 | if (!existsSync(`${ROOT}${wasmUrl.slice(1)}`)) { |
| 37 | throw new Error(`built artifact not found for '${pkg}' at ${ROOT}${wasmUrl.slice(1)}\nrun (from ${pkg}/): cargo build --release --target wasm32-unknown-unknown`); |
| 38 | } |
| 39 | entry = wasmUrl; |
| 40 | } |
| 41 | |
| 42 | const cases = JSON.parse(readFileSync(`${dir}/${pkg}.json`, "utf-8")); |
| 43 | // The tag's packages.json, synthesized: the package keyed by name -> its .py or wasm. |
| 44 | const manifest = JSON.stringify({ imports: { [pkg]: entry } }); |
| 45 | |
| 46 | const browser = await chromium.launch(); |
| 47 | const page = await browser.newPage(); |
| 48 | const errors = []; |
| 49 | page.on("console", (m) => { if (m.type() === "error") errors.push(m.text()); }); |
| 50 | page.on("pageerror", (e) => errors.push(e.message)); |
| 51 | |
| 52 | /* Serve repo files from disk; synthesize the manifest. External CDNs (cdn.edgepython.com) pass through. */ |
| 53 | await page.route("**/*", (route) => { |
| 54 | const url = new URL(route.request().url()); |
| 55 | if (url.host !== "localhost") return route.continue(); |
| 56 | if (url.pathname === MANIFEST) return route.fulfill({ contentType: "application/json", body: manifest }); |
| 57 | const path = ROOT + url.pathname.slice(1); |
| 58 | try { |
| 59 | const ext = path.slice(path.lastIndexOf(".")); |
| 60 | return route.fulfill({ body: readFileSync(path), contentType: TYPES[ext] ?? "application/octet-stream" }); |
| 61 | } catch { |
| 62 | return route.fulfill({ status: 404 }); |
| 63 | } |
| 64 | }); |
| 65 | |
| 66 | const failures = []; |
| 67 | try { |
| 68 | await page.goto("http://localhost/tests/index.html"); |
| 69 | // Boot the tag once without an entry, reuse its worker, and capture stdout via onOutput. |
| 70 | await page.evaluate(async (manifestPath) => { |
| 71 | const el = document.createElement("edge-python"); |
| 72 | el.setAttribute("packages", manifestPath); |
| 73 | const ready = new Promise((res) => el.addEventListener("ready", res, { once: true })); |
| 74 | document.head.appendChild(el); |
| 75 | await ready; |
| 76 | // Byte-stream stdout: one chunk per print() call (body + its `end`); collect verbatim. |
| 77 | globalThis.chunks = []; |
| 78 | el.onOutput((chunk) => { globalThis.chunks.push(chunk); }); |
| 79 | globalThis.el = el; |
| 80 | }, MANIFEST); |
| 81 | |
| 82 | for (const [i, c] of cases.entries()) { |
| 83 | const src = `from ${pkg} import *\n${c.src}`; |
no test coverage detected