Files
plainleaf/e2e/multi-space-admin.test.ts
T

86 lines
3.1 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { type ChildProcess, spawn } from "node:child_process";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { getFreePort, waitForEditorReady, waitForServer } from "./fixtures";
let proc: ChildProcess;
let rootDir: string;
let base: string;
test.beforeAll(async () => {
rootDir = await mkdtemp(join(tmpdir(), "sb-multi-e2e-"));
const port = await getFreePort();
proc = spawn(
"./target/debug/silverbullet",
[rootDir, "-p", String(port), "-L", "127.0.0.1"],
{
cwd: join(import.meta.dirname, ".."),
stdio: ["ignore", "pipe", "pipe"],
env: {
...process.env,
SB_MULTI_SPACE: "1",
SB_USER: "admin:adminpw",
// See fixtures.ts: with the service worker disabled and
// `?headless=1` on navigation, the client uses its own in-page
// runtime, so the server never needs to spawn a headless
// Chrome for the runtime API.
SB_RUNTIME_API: "0",
SB_DISABLE_SERVICE_WORKER: "1",
},
},
);
base = `http://127.0.0.1:${port}`;
await waitForServer(`${base}/.admin/`);
});
test.afterAll(async () => {
proc?.kill();
await rm(rootDir, { recursive: true, force: true });
});
test("first run: login, create a space, open it, edit a page", async ({
page,
}) => {
// Root redirects to the admin UI on a fresh server.
await page.goto(`${base}/`);
await expect(page).toHaveURL(/\/\.admin\//);
// Log in.
await page.getByLabel("Username").fill("admin");
await page.getByLabel("Password").fill("adminpw");
await page.getByRole("button", { name: "Log in" }).click();
// Empty list -> create a space.
await expect(page.getByText("No spaces yet")).toBeVisible();
await page.getByRole("button", { name: "Create space" }).click();
await page.getByLabel("Name").fill("Playground");
// The binding-value input's label is dynamic ("Prefix"/"Hostname")
// and defaults to "Prefix" for the default "URL prefix" binding type.
await page.getByLabel("Prefix").fill("/play");
await page.getByLabel("Authentication").selectOption("none");
await page.getByRole("button", { name: "Create" }).click();
// It shows as running.
await expect(page.getByText("Playground")).toBeVisible();
await expect(page.locator(".sb-badge.running")).toBeVisible();
// Open the space and verify the editor loads. Mirror the boot conventions
// from e2e/first-load.test.ts / fixtures.ts: navigate with `?headless=1`
// (so the server doesn't need a headless-Chrome runtime API), wait for
// `#sb-editor .cm-editor` to be visible, then wait for the client runtime
// to report ready before interacting with the page.
await page.goto(`${base}/play/?headless=1`);
await page
.locator("#sb-editor .cm-editor")
.waitFor({ state: "visible", timeout: 30_000 });
await waitForEditorReady(page);
// Type into the page and confirm content sticks.
const editor = page.locator("#sb-editor .cm-content");
await editor.click();
await page.keyboard.type("Hello from multi-space");
await expect(editor).toContainText("Hello from multi-space");
});