Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172import { expect, test, type Page } from "@playwright/test";import { kernelFile, sandboxFrame } from "./fixtures/sandbox.ts";
const content = (page: Page, id: string) => page.locator(`#${id}`).locator(".cm-content");const lineWith = (page: Page, id: string, text: string) => content(page, id).locator(".cm-line", { hasText: text });const kernelText = (page: Page) => kernelFile(page, "/work/notes.md");
test.beforeEach(async ({ page }) => { await page.goto("/kernel.html"); await expect(page.locator("#kernel-status")).toContainText("Kernel ready"); await expect(page.locator("#console")).toContainText("watch: watching /work/notes.md");});
test("the kernel runs in an isolated sandbox on another origin, not on this page", async ({ page }) => { const sandbox = sandboxFrame(page); expect(sandbox, "the sandbox iframe").toBeDefined(); expect(new URL(sandbox!.url()).origin).not.toBe(new URL(page.url()).origin); expect(await sandbox!.evaluate(() => crossOriginIsolated)).toBe(true); expect(await page.evaluate(() => Symbol.for("nib.runtime") in globalThis), "the page booted no kernel").toBe(false); expect(await page.evaluate(() => navigator.serviceWorker.getRegistrations().then((all) => all.length))).toBe(0);});
test("the kernel file holds the doc, and editor typing reaches it and its watchers", async ({ page }) => { expect(await kernelText(page)).toContain("# Notes"); await lineWith(page, "ada", "Type here while").click(); await page.keyboard.press("End"); await page.keyboard.type(" (from Ada)"); await expect.poll(() => kernelText(page)).toContain("Type here while a process runs (from Ada)"); await expect(page.locator("#console")).toContainText("watch:"); await expect(page.locator("#console")).toContainText("characters");});
test("a process typing word by word keeps what a person types meanwhile, and shows its cursor", async ({ page }) => { await page.click("#run-typist"); await expect(content(page, "grace")).toContainText("The typist reads"); await expect(page.locator("#ada .loro-cursor", { hasText: "" })).not.toHaveCount(0); const label = await page.locator("#grace .loro-cursor").evaluateAll((els) => els.map((el) => getComputedStyle(el, "::before").content), ); expect(label.some((l) => l.includes("typist.js"))).toBe(true);
// A short line: End on a wrapped line stops at the end of its visual line. await lineWith(page, "ada", "Ideas").click(); await page.keyboard.press("End"); await page.keyboard.type(" (Ada typed this)");
await expect(page.locator("#console")).toContainText("typist: done", { timeout: 15_000 }); const sentence = "The typist reads the file before every word, so whatever you type meanwhile is kept."; for (const id of ["ada", "grace"]) { await expect(content(page, id)).toContainText(sentence); await expect(content(page, id)).toContainText("Ideas (Ada typed this)"); } await expect.poll(() => kernelText(page)).toContain(`- ${sentence}`); await expect.poll(() => kernelText(page)).toContain("## Ideas (Ada typed this)");});
test("an atomic save computed from a stale read merges with edits made since", async ({ page }) => { await page.click("#run-rewrite"); await expect(page.locator("#console")).toContainText("rewrite: read", { timeout: 10_000 }); await lineWith(page, "grace", "Type here while").click(); await page.keyboard.press("End"); await page.keyboard.type(" (typed during the rewrite)"); await expect(page.locator("#console")).toContainText("rewrite: saved", { timeout: 10_000 });
for (const id of ["ada", "grace"]) { await expect(content(page, id)).toContainText("NOTES"); await expect(content(page, id)).toContainText("Headings uppercased by rewrite.js"); await expect(content(page, id)).toContainText("(typed during the rewrite)"); } await expect.poll(() => kernelText(page)).toContain("(typed during the rewrite)");});