Files
2026-09-09 10:09:14 +04:00

135 lines
3.9 KiB
TypeScript

/** `withProfile` launches, hands over the CDP endpoint, and stops. */
import assert from "node:assert/strict";
import { test } from "node:test";
import { Conflict, DonutError, RunSession } from "../src/index.mts";
import { withClient } from "./support.mts";
const RUN_BODY = { profile_id: "p1", remote_debugging_port: 9222, headless: true };
test("the callback gets the CDP endpoint", async () => {
await withClient(async (client, fake) => {
fake.enqueueJson(RUN_BODY);
fake.enqueueEmpty(204);
const seen = await client.withProfile(
"p1",
{ url: "https://example.com", headless: true },
(session) => {
assert.ok(session instanceof RunSession);
assert.equal(session.remoteDebuggingPort, 9222);
assert.equal(session.headless, true);
assert.equal(session.cdpUrl, "http://127.0.0.1:9222");
assert.deepEqual(session.response, RUN_BODY);
return session.cdpUrl;
},
);
assert.equal(seen, "http://127.0.0.1:9222");
assert.deepEqual(
fake.requests.map((sent) => `${sent.method} ${sent.path}`),
["POST /v1/profiles/p1/run", "POST /v1/profiles/p1/kill"],
);
assert.deepEqual(fake.requests[0]?.json, { url: "https://example.com", headless: true });
});
});
test("the browser is stopped when the callback throws", async () => {
await withClient(async (client, fake) => {
fake.enqueueJson(RUN_BODY);
fake.enqueueEmpty(204);
await assert.rejects(
client.withProfile("p1", {}, () => {
throw new RangeError("the body failed");
}),
RangeError,
);
assert.deepEqual(
fake.requests.map((sent) => sent.path),
["/v1/profiles/p1/run", "/v1/profiles/p1/kill"],
);
});
});
test("a failed stop never hides why the callback failed", async () => {
await withClient(async (client, fake) => {
fake.enqueueJson(RUN_BODY);
fake.enqueueError(409, "PROFILE_LOCKED_ELSEWHERE");
let captured: RunSession | undefined;
await assert.rejects(
client.withProfile("p1", {}, (session) => {
captured = session;
throw new RangeError("the body failed");
}),
RangeError,
);
assert.ok(captured?.cleanupError instanceof Conflict);
});
});
test("a failed stop is thrown when the callback was fine", async () => {
await withClient(async (client, fake) => {
fake.enqueueJson(RUN_BODY);
fake.enqueueError(503, "the fleet could not be reached");
await assert.rejects(
client.withProfile("p1", {}, () => "done"),
DonutError,
);
});
});
test("a failed launch never runs the callback and stops nothing", async () => {
await withClient(async (client, fake) => {
fake.enqueueError(409, "PROFILE_RUNNING");
await assert.rejects(
client.withProfile("p1", {}, () => {
throw new Error("the callback must not run when the launch failed");
}),
Conflict,
);
assert.deepEqual(
fake.requests.map((sent) => sent.path),
["/v1/profiles/p1/run"],
);
});
});
test("an async callback is awaited before the browser is stopped", async () => {
await withClient(async (client, fake) => {
fake.enqueueJson(RUN_BODY);
fake.enqueueJson({ profiles: [], total: 0 });
fake.enqueueEmpty(204);
await client.withProfile("p1", {}, async () => {
await client.listProfiles();
});
assert.deepEqual(
fake.requests.map((sent) => sent.path),
["/v1/profiles/p1/run", "/v1/profiles", "/v1/profiles/p1/kill"],
);
});
});
test("a session also disposes itself", async () => {
// `withProfile` is the portable form, but a runtime with `await using` can
// hold a RunSession directly.
await withClient(async (client, fake) => {
fake.enqueueEmpty(204);
const session = new RunSession(client, "p1", RUN_BODY);
await session[Symbol.asyncDispose]();
assert.deepEqual(
fake.requests.map((sent) => sent.path),
["/v1/profiles/p1/kill"],
);
});
});