// Event-loop behaviors a guest can observe. import { test, expect } from "@playwright/test"; test("process.nextTick from an async continuation runs without another event", async ({ page }) => { await page.goto("/demo/fixture.html"); await page.waitForFunction(() => window.__runtime !== undefined, undefined, { timeout: 20_000 }); const text = await page.evaluate(async () => { const runtime = window.__runtime!; runtime.writeTree({ "/app/tick.cjs": [ 'require("node:http").createServer(async (req, res) => {', " await new Promise((resolve) => setTimeout(resolve, 5));", ' process.nextTick(() => res.end("ticked"));', "}).listen(3100);", ].join("\n"), }); runtime.exec("/app/tick.cjs"); const url = await runtime.waitForPort(3100); return await (await fetch(url)).text(); }); expect(text).toBe("ticked"); }); test("a fetch started from a callback keeps the process alive until its answer", async ({ page, context }) => { // Answered late, so a loop that ignored the fetch would exit first. await context.route("**/slow-answer.txt", async (route) => { await new Promise((resolve) => setTimeout(resolve, 300)); await route.fulfill({ status: 200, contentType: "text/plain", body: "late answer" }); }); const { runGuest } = await import("./guest"); const out = await runGuest(page, { "/app/main.cjs": 'setTimeout(async () => console.log((await fetch(new URL("/slow-answer.txt", location.origin))).status, "fetched"), 1);', }, "/app/main.cjs"); expect(out).toEqual({ code: 0, signal: null, stdout: "200 fetched\n", stderr: "" }); });