542 lines
22 KiB
TypeScript
542 lines
22 KiB
TypeScript
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { createServer, type Server } from "node:http";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { type ElectronApplication, _electron as electron, expect, test } from "@playwright/test";
|
|
|
|
const APP_MARKER = "Existing BangSo Bot instance ready";
|
|
|
|
let server: Server;
|
|
let serverUrl: string;
|
|
let closedUrl: string;
|
|
let userData: string;
|
|
let app: ElectronApplication | undefined;
|
|
|
|
/** A port nothing listens on, so a connection attempt is refused rather than blocked. */
|
|
async function reserveClosedPort() {
|
|
const probe = createServer();
|
|
await new Promise<void>((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
|
const address = probe.address();
|
|
if (address === null || typeof address === "string") throw new Error("probe has no port");
|
|
const { port } = address;
|
|
await new Promise<void>((resolve, reject) => {
|
|
probe.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
return `http://127.0.0.1:${port}`;
|
|
}
|
|
|
|
test.beforeAll(async () => {
|
|
server = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(
|
|
`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>BangSo Bot</title></head><body><main>${APP_MARKER}</main></body></html>`,
|
|
);
|
|
});
|
|
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const address = server.address();
|
|
if (address === null || typeof address === "string") throw new Error("stub server has no port");
|
|
serverUrl = `http://127.0.0.1:${address.port}`;
|
|
closedUrl = await reserveClosedPort();
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
await new Promise<void>((resolve, reject) => {
|
|
server.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
});
|
|
|
|
test.beforeEach(async () => {
|
|
userData = await mkdtemp(path.join(tmpdir(), "rakazo-desktop-e2e-"));
|
|
});
|
|
|
|
test.afterEach(async () => {
|
|
await app?.close();
|
|
app = undefined;
|
|
await rm(userData, { recursive: true, force: true });
|
|
});
|
|
|
|
function launch(extraEnv: Record<string, string> = {}) {
|
|
const env = { ...process.env, RAKAZO_PERFORMANCE_USER_DATA: userData };
|
|
// A stale RAKAZO_WEB_URL from the developer's shell would bypass setup entirely.
|
|
delete env.RAKAZO_WEB_URL;
|
|
return electron.launch({
|
|
args: ["."],
|
|
cwd: path.resolve(import.meta.dirname, ".."),
|
|
env: { ...env, ...extraEnv },
|
|
});
|
|
}
|
|
|
|
test("first run asks whether to use a local or existing instance", async () => {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
|
|
await expect(setup.getByRole("heading", { name: "Welcome to BangSo Bot" })).toBeVisible();
|
|
await expect(setup.getByText("This computer")).toBeVisible();
|
|
await expect(setup.getByText("Existing instance")).toBeVisible();
|
|
|
|
// A new instance is the default and points at the local development stack.
|
|
await expect(setup.getByRole("radio", { name: /This computer/ })).toBeChecked();
|
|
await expect(setup.locator("#local-url")).toHaveValue("http://127.0.0.1:5173");
|
|
await expect(setup.locator("#panel-existing")).toBeHidden();
|
|
|
|
await setup.screenshot({
|
|
path: path.join(import.meta.dirname, "screenshots", "01-setup-new-instance.png"),
|
|
});
|
|
});
|
|
|
|
test("connecting to an existing instance verifies, saves, and opens it", async () => {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await expect(setup.locator("#panel-new")).toBeHidden();
|
|
|
|
await setup.locator("#server-url").fill(serverUrl);
|
|
await setup.getByRole("button", { name: "Check connection" }).click();
|
|
await expect(setup.locator("#status")).toHaveText(`BangSo Bot answered at ${serverUrl}.`);
|
|
await expect(setup.locator("#status")).toHaveAttribute("data-tone", "ok");
|
|
|
|
await setup.screenshot({
|
|
path: path.join(import.meta.dirname, "screenshots", "02-setup-existing-verified.png"),
|
|
});
|
|
|
|
const appWindow = await Promise.all([
|
|
app.waitForEvent("window"),
|
|
setup.getByRole("button", { name: "Continue" }).click(),
|
|
]).then(([window]) => window);
|
|
|
|
await expect(appWindow.getByText(APP_MARKER)).toBeVisible();
|
|
await appWindow.screenshot({
|
|
path: path.join(import.meta.dirname, "screenshots", "03-connected-instance.png"),
|
|
});
|
|
|
|
// Continue can paint the app window before setup.json finishes flushing to disk.
|
|
await expect
|
|
.poll(async () => {
|
|
try {
|
|
return JSON.parse(await readFile(path.join(userData, "setup.json"), "utf8"));
|
|
} catch {
|
|
return null;
|
|
}
|
|
})
|
|
.toEqual({ mode: "existing", serverUrl });
|
|
});
|
|
|
|
test("Continue verifies and remembers the instance so setup does not run again", async () => {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(serverUrl);
|
|
const firstRun = await Promise.all([
|
|
app.waitForEvent("window"),
|
|
setup.getByRole("button", { name: "Continue" }).click(),
|
|
]).then(([window]) => window);
|
|
await expect(firstRun.getByText(APP_MARKER)).toBeVisible();
|
|
// Continue can paint the app window before setup.json finishes flushing to disk.
|
|
await expect
|
|
.poll(async () => {
|
|
try {
|
|
return JSON.parse(await readFile(path.join(userData, "setup.json"), "utf8"));
|
|
} catch {
|
|
return null;
|
|
}
|
|
})
|
|
.toEqual({ mode: "existing", serverUrl });
|
|
await app.close();
|
|
|
|
app = await launch();
|
|
const relaunched = await app.firstWindow();
|
|
await expect(relaunched.getByText(APP_MARKER)).toBeVisible();
|
|
await expect(relaunched.locator("#setup")).toHaveCount(0);
|
|
});
|
|
|
|
test("an unreachable address is reported instead of being saved", async () => {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(closedUrl);
|
|
await setup.getByRole("button", { name: "Check connection" }).click();
|
|
|
|
await expect(setup.locator("#status")).toHaveAttribute("data-tone", "error");
|
|
await expect(setup.locator("#status")).toHaveText("Nothing is listening at that address yet.");
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
await expect(setup.locator("#status")).toHaveText("Nothing is listening at that address yet.");
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
await setup.screenshot({
|
|
path: path.join(import.meta.dirname, "screenshots", "04-setup-unreachable.png"),
|
|
});
|
|
});
|
|
|
|
test("an HTTP error document is not accepted after a healthy probe", async () => {
|
|
const broken = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(503, { "content-type": "text/html; charset=utf-8" });
|
|
response.end("<!doctype html><html><body><h1>Unavailable</h1></body></html>");
|
|
});
|
|
await new Promise<void>((resolve) => broken.listen(0, "127.0.0.1", resolve));
|
|
const address = broken.address();
|
|
if (address === null || typeof address === "string") throw new Error("broken server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toContainText("Could not open that server.");
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
broken.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("a session-pending shell skeleton is not accepted as a ready app", async () => {
|
|
const skeletonHtml = `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>BangSo Bot</title></head>
|
|
<body><div id="root"><div data-rakazo-app-state="session-pending"><aside></aside><main><div>Opening your Space…</div></main></div></div></body></html>`;
|
|
const skeleton = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(skeletonHtml);
|
|
});
|
|
await new Promise<void>((resolve) => skeleton.listen(0, "127.0.0.1", resolve));
|
|
const address = skeleton.address();
|
|
if (address === null || typeof address === "string")
|
|
throw new Error("skeleton server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toContainText("Could not open that server.", {
|
|
timeout: 15_000,
|
|
});
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
skeleton.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("a post-session ready app mount is accepted", async () => {
|
|
const readyHtml = `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>BangSo Bot</title>
|
|
<script>performance.mark("rk:renderer:session-committed");performance.mark("rk:renderer:shell-ready");</script>
|
|
</head>
|
|
<body><div id="root"><div data-rakazo-app-state="ready"><div data-testid="shell-root" data-ready="true">Workspace</div></div></div></body></html>`;
|
|
const ready = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(readyHtml);
|
|
});
|
|
await new Promise<void>((resolve) => ready.listen(0, "127.0.0.1", resolve));
|
|
const address = ready.address();
|
|
if (address === null || typeof address === "string") throw new Error("ready server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
const appWindow = await Promise.all([
|
|
app.waitForEvent("window"),
|
|
setup.getByRole("button", { name: "Continue" }).click(),
|
|
]).then(([window]) => window);
|
|
|
|
await expect(appWindow.getByTestId("shell-root")).toBeVisible();
|
|
await expect
|
|
.poll(async () => {
|
|
try {
|
|
return JSON.parse(await readFile(path.join(userData, "setup.json"), "utf8"));
|
|
} catch {
|
|
return null;
|
|
}
|
|
})
|
|
.toEqual({
|
|
mode: "existing",
|
|
serverUrl: `http://127.0.0.1:${address.port}`,
|
|
});
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
ready.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("a shell mount before workspace bootstrap is not accepted", async () => {
|
|
const preBootstrapHtml = `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>BangSo Bot</title></head>
|
|
<body><div id="root"><div data-rakazo-app-state="ready"><div data-testid="shell-root" data-ready="false">Workspace</div></div></div></body></html>`;
|
|
const preBootstrap = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(preBootstrapHtml);
|
|
});
|
|
await new Promise<void>((resolve) => preBootstrap.listen(0, "127.0.0.1", resolve));
|
|
const address = preBootstrap.address();
|
|
if (address === null || typeof address === "string")
|
|
throw new Error("pre-bootstrap server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toContainText("Could not open that server.", {
|
|
timeout: 15_000,
|
|
});
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
preBootstrap.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("a session-ready marker without a route surface is not accepted", async () => {
|
|
const emptyReadyHtml = `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>BangSo Bot</title></head>
|
|
<body><div id="root"><div data-rakazo-app-state="ready" class="h-full"></div></div></body></html>`;
|
|
const emptyReady = createServer((request, response) => {
|
|
if (request.url === "/rpc/health" && request.method === "POST") {
|
|
response.writeHead(200, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({ json: { ok: true, version: "0.1.0" } }));
|
|
return;
|
|
}
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(emptyReadyHtml);
|
|
});
|
|
await new Promise<void>((resolve) => emptyReady.listen(0, "127.0.0.1", resolve));
|
|
const address = emptyReady.address();
|
|
if (address === null || typeof address === "string")
|
|
throw new Error("empty-ready server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toContainText("Could not open that server.", {
|
|
timeout: 15_000,
|
|
});
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
emptyReady.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("a malformed address is rejected before anything is written", async () => {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill("not a server");
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toContainText("Enter a valid server address.");
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
});
|
|
|
|
test("a generic web page is not accepted as a BangSo Bot server", async () => {
|
|
const plain = createServer((_request, response) => {
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end("<!doctype html><p>not BangSo Bot</p>");
|
|
});
|
|
await new Promise<void>((resolve) => plain.listen(0, "127.0.0.1", resolve));
|
|
const address = plain.address();
|
|
if (address === null || typeof address === "string") throw new Error("plain server has no port");
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
await expect(setup.locator("#status")).toHaveText(
|
|
"That address did not respond like a BangSo Bot server.",
|
|
);
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
plain.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("the setup probe refuses redirects instead of following them", async () => {
|
|
const redirect = createServer((_request, response) => {
|
|
response.writeHead(302, { location: `${serverUrl}/rpc/health` });
|
|
response.end();
|
|
});
|
|
await new Promise<void>((resolve) => redirect.listen(0, "127.0.0.1", resolve));
|
|
const address = redirect.address();
|
|
if (address === null || typeof address === "string") {
|
|
throw new Error("redirect server has no port");
|
|
}
|
|
|
|
try {
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
await setup.getByRole("radio", { name: /Existing instance/ }).check();
|
|
await setup.locator("#server-url").fill(`http://127.0.0.1:${address.port}`);
|
|
await setup.getByRole("button", { name: "Continue" }).click();
|
|
|
|
// Electron's net.fetch with redirect:"manual" surfaces redirects as a
|
|
// network failure rather than an HTTP 3xx body we can classify.
|
|
await expect(setup.locator("#status")).toHaveText("Could not reach that address.");
|
|
await expect(async () => {
|
|
await expect(readFile(path.join(userData, "setup.json"), "utf8")).rejects.toThrow();
|
|
}).toPass();
|
|
} finally {
|
|
await new Promise<void>((resolve, reject) => {
|
|
redirect.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
}
|
|
});
|
|
|
|
test("an unreachable saved server falls back to setup with a recovery message", async () => {
|
|
await writeFile(
|
|
path.join(userData, "setup.json"),
|
|
`${JSON.stringify({ mode: "existing", serverUrl: closedUrl }, null, 2)}\n`,
|
|
{ encoding: "utf8", mode: 0o600 },
|
|
);
|
|
|
|
app = await launch();
|
|
const setup = await app.firstWindow();
|
|
|
|
await expect(setup.getByRole("heading", { name: "Welcome to BangSo Bot" })).toBeVisible();
|
|
await expect(setup.getByRole("radio", { name: /Existing instance/ })).toBeChecked();
|
|
await expect(setup.locator("#server-url")).toHaveValue(closedUrl);
|
|
await expect(setup.locator("#status")).toContainText("Could not reconnect to the saved server.");
|
|
await setup.screenshot({
|
|
path: path.join(import.meta.dirname, "screenshots", "05-saved-server-recovery.png"),
|
|
});
|
|
});
|
|
|
|
test("the native application menu can reopen setup without exposing setup IPC to the server", async () => {
|
|
app = await launch({ RAKAZO_WEB_URL: serverUrl });
|
|
const appWindow = await app.firstWindow();
|
|
await expect(appWindow.getByText(APP_MARKER)).toBeVisible();
|
|
|
|
const setupPromise = app.waitForEvent("window");
|
|
await app.evaluate(({ Menu }) => {
|
|
const item = Menu.getApplicationMenu()?.getMenuItemById("change-rakazo-server");
|
|
if (!item) throw new Error("Change server menu item is missing");
|
|
item.click();
|
|
});
|
|
const setup = await setupPromise;
|
|
|
|
await expect(setup.getByRole("heading", { name: "Welcome to BangSo Bot" })).toBeVisible();
|
|
await expect(setup.locator("#status")).toBeEmpty();
|
|
|
|
// Closing setup without saving restores the connected instance.
|
|
await setup.close();
|
|
await expect(appWindow.getByText(APP_MARKER)).toBeVisible();
|
|
});
|
|
|
|
test("servers on the same host but different ports do not share login cookies", async () => {
|
|
const first = createServer((_request, response) => {
|
|
response.writeHead(200, {
|
|
"content-type": "text/html; charset=utf-8",
|
|
"set-cookie": "rakazo_session=fake-one; Path=/; SameSite=Lax",
|
|
});
|
|
response.end("<!doctype html><main>Cookie stored</main>");
|
|
});
|
|
const second = createServer((request, response) => {
|
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
response.end(`<!doctype html><main>Cookies: ${request.headers.cookie ?? "none"}</main>`);
|
|
});
|
|
await Promise.all([
|
|
new Promise<void>((resolve) => first.listen(0, "127.0.0.1", resolve)),
|
|
new Promise<void>((resolve) => second.listen(0, "127.0.0.1", resolve)),
|
|
]);
|
|
const firstAddress = first.address();
|
|
const secondAddress = second.address();
|
|
if (
|
|
firstAddress === null ||
|
|
typeof firstAddress === "string" ||
|
|
secondAddress === null ||
|
|
typeof secondAddress === "string"
|
|
) {
|
|
throw new Error("cookie fixture server has no port");
|
|
}
|
|
|
|
try {
|
|
app = await launch({ RAKAZO_WEB_URL: `http://127.0.0.1:${firstAddress.port}` });
|
|
const firstWindow = await app.firstWindow();
|
|
await expect(firstWindow.getByText("Cookie stored")).toBeVisible();
|
|
await expect.poll(() => firstWindow.evaluate(() => document.cookie)).toContain("fake-one");
|
|
await app.close();
|
|
|
|
app = await launch({ RAKAZO_WEB_URL: `http://127.0.0.1:${secondAddress.port}` });
|
|
const secondWindow = await app.firstWindow();
|
|
await expect(secondWindow.getByText("Cookies: none")).toBeVisible();
|
|
} finally {
|
|
await Promise.all([
|
|
new Promise<void>((resolve, reject) =>
|
|
first.close((error) => (error ? reject(error) : resolve())),
|
|
),
|
|
new Promise<void>((resolve, reject) =>
|
|
second.close((error) => (error ? reject(error) : resolve())),
|
|
),
|
|
]);
|
|
}
|
|
});
|
|
|
|
test("setup IPC is not reachable from the connected app window", async () => {
|
|
app = await launch({ RAKAZO_WEB_URL: serverUrl });
|
|
const appWindow = await app.firstWindow();
|
|
await expect(appWindow.getByText(APP_MARKER)).toBeVisible();
|
|
|
|
const exposed = await appWindow.evaluate(() =>
|
|
Object.keys((window as typeof window & { rakazoSetup?: unknown }).rakazoSetup ?? {}),
|
|
);
|
|
expect(exposed).toEqual([]);
|
|
});
|