mirror of
https://github.com/Tencent/BrowserSkill.git
synced 2026-09-10 13:01:23 +08:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95571f8b70 | ||
|
|
8344e311fa |
@@ -23,7 +23,7 @@ describe("BorrowConfirmationOverlay", () => {
|
|||||||
id: "req-1",
|
id: "req-1",
|
||||||
isActiveTab: true,
|
isActiveTab: true,
|
||||||
tabTitle: "Example",
|
tabTitle: "Example",
|
||||||
timeoutMs: 5000,
|
timeoutMs: 60_000,
|
||||||
onAllow,
|
onAllow,
|
||||||
onDeny,
|
onDeny,
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@ describe("BorrowConfirmationOverlay", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByText("允许借用标签页?")).toBeTruthy();
|
expect(screen.getByText("允许借用标签页?")).toBeTruthy();
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 60; i++) {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await vi.advanceTimersByTimeAsync(1000);
|
await vi.advanceTimersByTimeAsync(1000);
|
||||||
});
|
});
|
||||||
@@ -66,7 +66,7 @@ describe("BorrowConfirmationOverlay", () => {
|
|||||||
id: "req-fallback",
|
id: "req-fallback",
|
||||||
isActiveTab: true,
|
isActiveTab: true,
|
||||||
tabTitle: "Example",
|
tabTitle: "Example",
|
||||||
timeoutMs: 5000,
|
timeoutMs: 60_000,
|
||||||
onAllow,
|
onAllow,
|
||||||
onDeny,
|
onDeny,
|
||||||
},
|
},
|
||||||
@@ -74,7 +74,7 @@ describe("BorrowConfirmationOverlay", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 60; i++) {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await vi.advanceTimersByTimeAsync(1000);
|
await vi.advanceTimersByTimeAsync(1000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -127,6 +127,38 @@ describe("requestBorrowConfirmation", () => {
|
|||||||
expect(message.requestId.length).toBeGreaterThan(0);
|
expect(message.requestId.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("proactively focuses the user window before sending the overlay message", async () => {
|
||||||
|
tabs.get.mockResolvedValueOnce({ id: 42, title: "Tab" });
|
||||||
|
windows.getLastFocused.mockResolvedValueOnce(
|
||||||
|
userWindowWithActiveTab({ windowId: 77, tabId: 7, url: "https://app.example/" }),
|
||||||
|
);
|
||||||
|
tabs.sendMessage.mockResolvedValueOnce({ type: "borrow-response", allowed: true });
|
||||||
|
|
||||||
|
const pending = requestBorrowConfirmation(42, {
|
||||||
|
deps: { tabs, windows, notifications },
|
||||||
|
});
|
||||||
|
await vi.runAllTimersAsync();
|
||||||
|
await pending;
|
||||||
|
|
||||||
|
expect(windows.update).toHaveBeenCalledWith(77, { focused: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still proceeds when proactive window focus fails", async () => {
|
||||||
|
tabs.get.mockResolvedValueOnce({ id: 42, title: "Tab" });
|
||||||
|
windows.getLastFocused.mockResolvedValueOnce(
|
||||||
|
userWindowWithActiveTab({ windowId: 77, tabId: 7, url: "https://app.example/" }),
|
||||||
|
);
|
||||||
|
windows.update.mockRejectedValueOnce(new Error("window gone"));
|
||||||
|
tabs.sendMessage.mockResolvedValueOnce({ type: "borrow-response", allowed: true });
|
||||||
|
|
||||||
|
const pending = requestBorrowConfirmation(42, {
|
||||||
|
deps: { tabs, windows, notifications },
|
||||||
|
});
|
||||||
|
await vi.runAllTimersAsync();
|
||||||
|
|
||||||
|
expect(await pending).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("sends confirmation to the borrow target when it is the active tab", async () => {
|
it("sends confirmation to the borrow target when it is the active tab", async () => {
|
||||||
tabs.get.mockResolvedValueOnce({ id: 42, title: "Active Tab" });
|
tabs.get.mockResolvedValueOnce({ id: 42, title: "Active Tab" });
|
||||||
windows.getLastFocused.mockResolvedValueOnce(
|
windows.getLastFocused.mockResolvedValueOnce(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export interface BorrowResponseMessage {
|
|||||||
allowed: boolean;
|
allowed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CONFIRMATION_TIMEOUT_MS = 5000;
|
export const CONFIRMATION_TIMEOUT_MS = 60_000;
|
||||||
const EXIT_ANIMATION_MS = 150;
|
const EXIT_ANIMATION_MS = 150;
|
||||||
/** Matches BorrowConfirmationOverlay progress ring/bar transition (duration-1000). */
|
/** Matches BorrowConfirmationOverlay progress ring/bar transition (duration-1000). */
|
||||||
export const PROGRESS_TRANSITION_MS = 1000;
|
export const PROGRESS_TRANSITION_MS = 1000;
|
||||||
@@ -480,6 +480,13 @@ export async function requestBorrowConfirmation(
|
|||||||
settle(false);
|
settle(false);
|
||||||
}, BACKGROUND_TIMEOUT_MS);
|
}, BACKGROUND_TIMEOUT_MS);
|
||||||
|
|
||||||
|
// Bring the user window to the front so the overlay is visible even
|
||||||
|
// when the Agent Window has stolen focus. This is fire-and-forget: if
|
||||||
|
// it fails the overlay / OS notification still give the user a path.
|
||||||
|
void windowsApi.update(notificationAnchor.windowId, { focused: true }).catch((err) => {
|
||||||
|
console.debug("[bsk borrow] proactive focus of user window failed", err);
|
||||||
|
});
|
||||||
|
|
||||||
// Surface the OS notification *before* messaging any candidate so the
|
// Surface the OS notification *before* messaging any candidate so the
|
||||||
// user has a parallel signal even if every content script is missing.
|
// user has a parallel signal even if every content script is missing.
|
||||||
// The Allow / Deny buttons let the user authorize explicitly when the
|
// The Allow / Deny buttons let the user authorize explicitly when the
|
||||||
|
|||||||
Reference in New Issue
Block a user