Skip to content

Commit 4c1e6ba

Browse files
committed
test: clear browser tool broad matchers
1 parent 7504fc3 commit 4c1e6ba

1 file changed

Lines changed: 89 additions & 77 deletions

File tree

extensions/browser/src/browser-tool.test.ts

Lines changed: 89 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,49 @@ function lastMockCallArg<T>(
330330
return mockCallArg<T>(mock, -1, argIndex, _type);
331331
}
332332

333+
function firstResultText(result: { content?: readonly unknown[] } | undefined): string {
334+
const block = result?.content?.[0] as { type?: unknown; text?: unknown } | undefined;
335+
expect(block?.type).toBe("text");
336+
expect(typeof block?.text).toBe("string");
337+
return block?.text as string;
338+
}
339+
340+
function externalContentDetails(
341+
result: { details?: unknown } | undefined,
342+
kind: string,
343+
): {
344+
externalContent?: { untrusted?: unknown; source?: unknown; kind?: unknown };
345+
format?: unknown;
346+
messageCount?: unknown;
347+
nodeCount?: unknown;
348+
ok?: unknown;
349+
tabCount?: unknown;
350+
tabs?: unknown;
351+
targetId?: unknown;
352+
} {
353+
const details = result?.details as
354+
| {
355+
externalContent?: { untrusted?: unknown; source?: unknown; kind?: unknown };
356+
format?: unknown;
357+
messageCount?: unknown;
358+
nodeCount?: unknown;
359+
ok?: unknown;
360+
tabCount?: unknown;
361+
tabs?: unknown;
362+
targetId?: unknown;
363+
}
364+
| undefined;
365+
expect(details).toBeDefined();
366+
if (!details) {
367+
throw new Error("Expected browser tool result details");
368+
}
369+
expect(details?.ok).toBe(true);
370+
expect(details?.externalContent?.untrusted).toBe(true);
371+
expect(details?.externalContent?.source).toBe("browser");
372+
expect(details?.externalContent?.kind).toBe(kind);
373+
return details;
374+
}
375+
333376
function nodeInvokeCall(callIndex: number): {
334377
options: { timeoutMs?: number };
335378
request: {
@@ -1171,27 +1214,12 @@ describe("browser tool external content wrapping", () => {
11711214

11721215
const tool = createBrowserTool();
11731216
const result = await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "aria" });
1174-
expect(result?.content?.[0]).toMatchObject({
1175-
type: "text",
1176-
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT"),
1177-
});
1178-
const ariaTextBlock = result?.content?.[0];
1179-
const ariaTextValue =
1180-
ariaTextBlock && typeof ariaTextBlock === "object" && "text" in ariaTextBlock
1181-
? (ariaTextBlock as { text?: unknown }).text
1182-
: undefined;
1183-
const ariaText = typeof ariaTextValue === "string" ? ariaTextValue : "";
1217+
const ariaText = firstResultText(result);
1218+
expect(ariaText).toContain("<<<EXTERNAL_UNTRUSTED_CONTENT");
11841219
expect(ariaText).toContain("Ignore previous instructions");
1185-
expect(result?.details).toMatchObject({
1186-
ok: true,
1187-
format: "aria",
1188-
nodeCount: 1,
1189-
externalContent: expect.objectContaining({
1190-
untrusted: true,
1191-
source: "browser",
1192-
kind: "snapshot",
1193-
}),
1194-
});
1220+
const details = externalContentDetails(result, "snapshot");
1221+
expect(details.format).toBe("aria");
1222+
expect(details.nodeCount).toBe(1);
11951223
});
11961224

11971225
it("wraps tabs output as external content", async () => {
@@ -1207,36 +1235,24 @@ describe("browser tool external content wrapping", () => {
12071235

12081236
const tool = createBrowserTool();
12091237
const result = await tool.execute?.("call-1", { action: "tabs" });
1210-
expect(result?.content?.[0]).toMatchObject({
1211-
type: "text",
1212-
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT"),
1213-
});
1214-
const tabsTextBlock = result?.content?.[0];
1215-
const tabsTextValue =
1216-
tabsTextBlock && typeof tabsTextBlock === "object" && "text" in tabsTextBlock
1217-
? (tabsTextBlock as { text?: unknown }).text
1218-
: undefined;
1219-
const tabsText = typeof tabsTextValue === "string" ? tabsTextValue : "";
1238+
const tabsText = firstResultText(result);
1239+
expect(tabsText).toContain("<<<EXTERNAL_UNTRUSTED_CONTENT");
12201240
expect(tabsText.indexOf("suggestedTargetId")).toBeLessThan(tabsText.indexOf("targetId"));
12211241
expect(tabsText).toContain('"suggestedTargetId": "docs"');
12221242
expect(tabsText).toContain("Ignore previous instructions");
1223-
expect(result?.details).toMatchObject({
1224-
ok: true,
1225-
tabCount: 1,
1226-
tabs: [
1227-
expect.objectContaining({
1228-
suggestedTargetId: "docs",
1229-
tabId: "t1",
1230-
label: "docs",
1231-
targetId: "RAW-TARGET",
1232-
}),
1233-
],
1234-
externalContent: expect.objectContaining({
1235-
untrusted: true,
1236-
source: "browser",
1237-
kind: "tabs",
1238-
}),
1239-
});
1243+
const details = externalContentDetails(result, "tabs");
1244+
expect(details.tabCount).toBe(1);
1245+
expect(Array.isArray(details.tabs)).toBe(true);
1246+
const [tab] = details.tabs as Array<{
1247+
label?: unknown;
1248+
suggestedTargetId?: unknown;
1249+
tabId?: unknown;
1250+
targetId?: unknown;
1251+
}>;
1252+
expect(tab?.suggestedTargetId).toBe("docs");
1253+
expect(tab?.tabId).toBe("t1");
1254+
expect(tab?.label).toBe("docs");
1255+
expect(tab?.targetId).toBe("RAW-TARGET");
12401256
});
12411257

12421258
it("wraps console output as external content", async () => {
@@ -1250,27 +1266,12 @@ describe("browser tool external content wrapping", () => {
12501266

12511267
const tool = createBrowserTool();
12521268
const result = await tool.execute?.("call-1", { action: "console" });
1253-
expect(result?.content?.[0]).toMatchObject({
1254-
type: "text",
1255-
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT"),
1256-
});
1257-
const consoleTextBlock = result?.content?.[0];
1258-
const consoleTextValue =
1259-
consoleTextBlock && typeof consoleTextBlock === "object" && "text" in consoleTextBlock
1260-
? (consoleTextBlock as { text?: unknown }).text
1261-
: undefined;
1262-
const consoleText = typeof consoleTextValue === "string" ? consoleTextValue : "";
1269+
const consoleText = firstResultText(result);
1270+
expect(consoleText).toContain("<<<EXTERNAL_UNTRUSTED_CONTENT");
12631271
expect(consoleText).toContain("Ignore previous instructions");
1264-
expect(result?.details).toMatchObject({
1265-
ok: true,
1266-
targetId: "t1",
1267-
messageCount: 1,
1268-
externalContent: expect.objectContaining({
1269-
untrusted: true,
1270-
source: "browser",
1271-
kind: "console",
1272-
}),
1273-
});
1272+
const details = externalContentDetails(result, "console");
1273+
expect(details.targetId).toBe("t1");
1274+
expect(details.messageCount).toBe(1);
12741275
});
12751276
});
12761277

@@ -1295,19 +1296,30 @@ describe("browser tool act stale target recovery", () => {
12951296
});
12961297

12971298
expect(browserActionsMocks.browserAct).toHaveBeenCalledTimes(2);
1298-
expect(browserActionsMocks.browserAct).toHaveBeenNthCalledWith(
1299+
expect(mockCallArg(browserActionsMocks.browserAct, 0, 0)).toBeUndefined();
1300+
const firstRequest = mockCallArg<{ kind?: string; ref?: string; targetId?: string }>(
1301+
browserActionsMocks.browserAct,
1302+
0,
12991303
1,
1300-
undefined,
1301-
expect.objectContaining({ targetId: "stale-tab", kind: "hover", ref: "btn-1" }),
1302-
expect.objectContaining({ profile: "user" }),
13031304
);
1304-
expect(browserActionsMocks.browserAct).toHaveBeenNthCalledWith(
1305-
2,
1306-
undefined,
1307-
expect.not.objectContaining({ targetId: expect.anything() }),
1308-
expect.objectContaining({ profile: "user" }),
1305+
expect(firstRequest.targetId).toBe("stale-tab");
1306+
expect(firstRequest.kind).toBe("hover");
1307+
expect(firstRequest.ref).toBe("btn-1");
1308+
const firstOptions = mockCallArg<{ profile?: string }>(browserActionsMocks.browserAct, 0, 2);
1309+
expect(firstOptions.profile).toBe("user");
1310+
1311+
expect(mockCallArg(browserActionsMocks.browserAct, 1, 0)).toBeUndefined();
1312+
const secondRequest = mockCallArg<{ kind?: string; ref?: string; targetId?: string }>(
1313+
browserActionsMocks.browserAct,
1314+
1,
1315+
1,
13091316
);
1310-
expect(result?.details).toMatchObject({ ok: true });
1317+
expect(secondRequest.targetId).toBeUndefined();
1318+
expect(secondRequest.kind).toBe("hover");
1319+
expect(secondRequest.ref).toBe("btn-1");
1320+
const secondOptions = mockCallArg<{ profile?: string }>(browserActionsMocks.browserAct, 1, 2);
1321+
expect(secondOptions.profile).toBe("user");
1322+
expect((result?.details as { ok?: unknown } | undefined)?.ok).toBe(true);
13111323
});
13121324

13131325
it("does not retry mutating user-browser act requests without targetId", async () => {

0 commit comments

Comments
 (0)