aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorastarring <zouzhigang85@gmail.com>2026-09-09 02:35:42 +0800
committerGitHub <noreply@github.com>2026-09-09 00:05:42 +0530
commit8d7a067c8d82a592bfb3dcacf05305c39550cbc6 (patch)
treecf6641e0d8ab749542adc4e605787e4e525b24b6 /test
parent6f455ed015b1b39324c45813a42b33ddb63e4bc9 (diff)
feat: add per-tab request headers (#30)
Expose explicit set and clear tools so environment-routed pages can be opened without leaking header values or carrying headers across unrelated browsing. Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com Co-authored-by: zouzhigang <zouzhigang@bytedance.com>
Diffstat (limited to 'test')
-rw-r--r--test/cdp/commands-test.ts5
-rw-r--r--test/domains/headers-test.ts95
-rw-r--r--test/domains/registry-test.ts2
3 files changed, 102 insertions, 0 deletions
diff --git a/test/cdp/commands-test.ts b/test/cdp/commands-test.ts
index ad1b057..738189d 100644
--- a/test/cdp/commands-test.ts
+++ b/test/cdp/commands-test.ts
@@ -42,6 +42,11 @@ describe("cdp command table", () => {
const r = decodeResult("Nope.method" as "Page.enable", {});
assert.equal(r.success, false);
});
+
+ test("accepts an empty Network.setExtraHTTPHeaders response", () => {
+ const r = decodeResult("Network.setExtraHTTPHeaders", {});
+ assert.equal(r.success, true);
+ });
});
describe("Accessibility.getFullAXTree schema", () => {
diff --git a/test/domains/headers-test.ts b/test/domains/headers-test.ts
new file mode 100644
index 0000000..4a268c2
--- /dev/null
+++ b/test/domains/headers-test.ts
@@ -0,0 +1,95 @@
+import { describe, test } from "node:test";
+import assert from "node:assert/strict";
+import { Compile } from "typebox/compile";
+import { clearHeadersTool, setHeadersTool } from "../../src/domains/headers";
+import type { HandlerContext } from "../../src/util/tool";
+import { createFakeClient, type FakeClient } from "./fake-client";
+
+const ctxFor = (fake: FakeClient): HandlerContext => ({
+ client: fake.client,
+ signal: undefined,
+ onUpdate: () => {},
+ extensionCtx: undefined as never,
+});
+
+describe("browser_set_headers", () => {
+ test("sets headers on the current owned tab without echoing values", async () => {
+ const fake = await createFakeClient();
+ const result = await setHeadersTool.handler(
+ {
+ headers: {
+ "x-tt-env": "ppe_mini_game_rating_phase4",
+ "x-use-ppe": "1",
+ },
+ },
+ ctxFor(fake),
+ );
+
+ assert.equal(result.success, true);
+ if (!result.success) return;
+ assert.doesNotMatch(result.data.text, /ppe_mini_game_rating_phase4/);
+ assert.deepEqual(result.data.details, {
+ targetId: "t1",
+ headerNames: ["x-tt-env", "x-use-ppe"],
+ count: 2,
+ });
+ assert.deepEqual(fake.callsTo("Network.setExtraHTTPHeaders"), [
+ {
+ method: "Network.setExtraHTTPHeaders",
+ params: {
+ headers: {
+ "x-tt-env": "ppe_mini_game_rating_phase4",
+ "x-use-ppe": "1",
+ },
+ },
+ sessionId: "s1",
+ },
+ ]);
+ });
+
+ test("refuses a current tab that is not owned by the harness", async () => {
+ const fake = await createFakeClient();
+ fake.ownership.remove("t1");
+ const result = await setHeadersTool.handler({ headers: { "x-test": "value" } }, ctxFor(fake));
+
+ assert.equal(result.success, false);
+ if (result.success) return;
+ assert.equal(result.error.kind, "invalid_state");
+ assert.match(result.error.message, /not owned/);
+ assert.equal(fake.callsTo("Network.setExtraHTTPHeaders").length, 0);
+ });
+
+ test("schema rejects empty or malformed header sets", () => {
+ const validate = Compile(setHeadersTool.parameters);
+ assert.equal(validate.Check({ headers: {} }), false);
+ assert.equal(validate.Check({ headers: { "x-test": "line one\nline two" } }), false);
+ assert.equal(validate.Check({ headers: { "x-test": "value" } }), true);
+ });
+
+ test("handler rejects invalid HTTP header names", async () => {
+ const fake = await createFakeClient();
+ const result = await setHeadersTool.handler({ headers: { "bad name": "value" } }, ctxFor(fake));
+
+ assert.equal(result.success, false);
+ if (result.success) return;
+ assert.equal(result.error.kind, "invalid_state");
+ assert.match(result.error.message, /Invalid HTTP header name/);
+ assert.equal(fake.callsTo("Network.setExtraHTTPHeaders").length, 0);
+ });
+});
+
+describe("browser_clear_headers", () => {
+ test("clears extra headers on the current owned tab", async () => {
+ const fake = await createFakeClient();
+ const result = await clearHeadersTool.handler({}, ctxFor(fake));
+
+ assert.equal(result.success, true);
+ assert.deepEqual(fake.callsTo("Network.setExtraHTTPHeaders"), [
+ {
+ method: "Network.setExtraHTTPHeaders",
+ params: { headers: {} },
+ sessionId: "s1",
+ },
+ ]);
+ });
+});
diff --git a/test/domains/registry-test.ts b/test/domains/registry-test.ts
index 2003b6c..be020a3 100644
--- a/test/domains/registry-test.ts
+++ b/test/domains/registry-test.ts
@@ -34,6 +34,8 @@ const SERIALIZED = new Set([
"browser_print_to_pdf",
"browser_viewport_resize",
"browser_drag_and_drop",
+ "browser_set_headers",
+ "browser_clear_headers",
"browser_web_search",
]);