test/manual/e2e-test.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
import { createIpcServer } from "../../src/daemon/server";
import { createCdpBridge, type SendToClient } from "../../src/daemon/bridge";
import { createDaemonTransport } from "../../src/daemon/transport";
import { DAEMON_SOCKET_PATH } from "../../src/daemon/protocol";
import type { WireRequest } from "../../src/daemon/protocol";
import { unlinkSync } from "node:fs";
let passed = 0;
let failed = 0;
const check = (cond: boolean, label: string) => {
if (cond) { passed++; console.log(` ✓ ${label}`); }
else { failed++; console.error(` ✗ ${label}`); }
};
async function main() {
try { unlinkSync(DAEMON_SOCKET_PATH); } catch {}
console.log("Starting daemon (IpcServer + CdpBridge)...");
const ipcServer = createIpcServer();
const cdpBridge = createCdpBridge();
ipcServer.onMessage((msg, client) => {
if (msg.type !== "request") return;
const send: SendToClient = (cid, resp) => ipcServer.send(cid, resp);
cdpBridge.handleRequest(msg, client.id, send);
});
cdpBridge.onEvent((event, targetClientIds) => {
for (const cid of targetClientIds) ipcServer.send(cid, event);
});
ipcServer.onDisconnect((client) => cdpBridge.removeClient(client.id));
await ipcServer.start();
console.log("Daemon started ✓");
console.log("\nConnecting pi client (DaemonTransport)...");
const transport = createDaemonTransport("pi-e2e-test");
const connectResult = await transport.connect("");
check(connectResult.success, `Client connect: ${connectResult.success ? "ok" : connectResult.error.message}`);
check(transport.state() === "open", "Transport state is open");
let rawRequests: WireRequest[] = [];
ipcServer.onMessage((msg, client) => {
if (msg.type === "request") {
rawRequests.push(msg);
ipcServer.send(client.id, {
type: "response",
id: msg.id,
result: { simulated: true, method: msg.method },
});
}
});
const res1 = await transport.request("Page.navigate", { url: "https://example.com" });
check(res1.success, "CDP request succeeded");
if (res1.success) {
const d = res1.data as any;
check(d?.simulated === true, "Response contains simulated flag");
check(d?.method === "Page.navigate", "Response echoes method");
}
check(rawRequests.length === 1, "Server received exactly 1 request");
check(rawRequests[0]!.method === "Page.navigate", "Correct method forwarded");
rawRequests.length = 0;
const res2 = await transport.request("Runtime.evaluate", { expression: "1+1" }, { sessionId: "session-abc" });
check(res2.success, "Session-scoped request succeeded");
check(rawRequests[0]?.sessionId === "session-abc", "SessionId forwarded correctly");
rawRequests.length = 0;
const [r3a, r3b, r3c] = await Promise.all([
transport.request("Target.getTargets", {}),
transport.request("Browser.getVersion", {}),
transport.request("Page.captureScreenshot", {}),
]);
check(r3a.success && r3b.success && r3c.success, "All 3 parallel requests succeeded");
check(rawRequests.length === 3, "Server received all 3 requests");
const eventPromise = new Promise<string | null>((resolve) => {
const timeout = setTimeout(() => resolve(null), 2000);
(async () => {
for await (const evt of transport.events()) {
clearTimeout(timeout);
resolve(evt.method);
break;
}
})();
});
ipcServer.broadcast({
type: "event",
method: "Target.targetCreated",
params: { targetInfo: { type: "page", targetId: "e2e-test-target" } },
});
const eventMethod = await eventPromise;
check(eventMethod === "Target.targetCreated", `Event received: ${eventMethod ?? "TIMEOUT"}`);
await transport.close();
check(transport.state() === "closed", "Transport closed");
await new Promise(r => setTimeout(r, 500));
const reconnectResult = await transport.connect("");
check(reconnectResult.success, "Transport reconnected (simulated session restart)");
const res4 = await transport.request("Target.getTargets", {});
check(res4.success, "Request after reconnect succeeded");
check(transport.state() === "open", "Transport state is open after reconnect");
check(ipcServer.clientCount() === 1, "Server reports 1 connected client");
await transport.close();
await new Promise(r => setTimeout(r, 500));
check(ipcServer.clientCount() === 0, "Server reports 0 clients after disconnect");
await ipcServer.stop();
console.log("\nDaemon stopped ✓");
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);
}
main().catch((e) => {
console.error("E2E test failed:", e);
process.exit(1);
});
|