145 lines
4.0 KiB
TypeScript
145 lines
4.0 KiB
TypeScript
// @vitest-environment node
|
||
|
||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||
|
||
const mocks = vi.hoisted(() => ({
|
||
appendMessage: vi.fn(),
|
||
setActiveRun: vi.fn(),
|
||
clearActiveRun: vi.fn(),
|
||
extractBrowserOpenIntent: vi.fn(),
|
||
openUrlInBrowser: vi.fn(),
|
||
appendTranscriptLine: vi.fn(),
|
||
logger: {
|
||
error: vi.fn(),
|
||
},
|
||
}));
|
||
|
||
vi.mock('../electron/gateway/session-store', () => ({
|
||
sessionStore: {
|
||
appendMessage: mocks.appendMessage,
|
||
setActiveRun: mocks.setActiveRun,
|
||
clearActiveRun: mocks.clearActiveRun,
|
||
},
|
||
}));
|
||
|
||
vi.mock('@electron/service/browser-open-service', () => ({
|
||
extractBrowserOpenIntent: mocks.extractBrowserOpenIntent,
|
||
openUrlInBrowser: mocks.openUrlInBrowser,
|
||
}));
|
||
|
||
vi.mock('@electron/utils/token-usage-writer', () => ({
|
||
appendTranscriptLine: mocks.appendTranscriptLine,
|
||
}));
|
||
|
||
vi.mock('@electron/service/logger', () => ({
|
||
default: mocks.logger,
|
||
}));
|
||
|
||
function flushAsyncTasks(): Promise<void> {
|
||
return new Promise((resolve) => {
|
||
setTimeout(resolve, 0);
|
||
});
|
||
}
|
||
|
||
describe('gateway browser shortcut', () => {
|
||
beforeEach(() => {
|
||
vi.resetModules();
|
||
vi.clearAllMocks();
|
||
mocks.extractBrowserOpenIntent.mockImplementation((text: string) => (
|
||
text === '打开 http://www.baidu.com'
|
||
? { url: 'http://www.baidu.com/' }
|
||
: null
|
||
));
|
||
});
|
||
|
||
it('starts a browser-open run and emits a final assistant message on success', async () => {
|
||
mocks.openUrlInBrowser.mockResolvedValue({
|
||
url: 'http://www.baidu.com/',
|
||
pageUrl: 'http://www.baidu.com/',
|
||
title: '百度一下,你就知道',
|
||
});
|
||
|
||
const { maybeHandleBrowserOpenMessage } = await import('../electron/gateway/browser-shortcut');
|
||
const broadcast = vi.fn();
|
||
|
||
const handled = maybeHandleBrowserOpenMessage(
|
||
'agent:test:main',
|
||
'run-1',
|
||
{ role: 'user', content: '打开 http://www.baidu.com' },
|
||
broadcast,
|
||
);
|
||
|
||
expect(handled).toBe(true);
|
||
expect(mocks.setActiveRun).toHaveBeenCalledWith(
|
||
'agent:test:main',
|
||
'run-1',
|
||
expect.any(AbortController),
|
||
);
|
||
|
||
await flushAsyncTasks();
|
||
|
||
expect(mocks.openUrlInBrowser).toHaveBeenCalledWith(
|
||
'http://www.baidu.com/',
|
||
expect.objectContaining({ signal: expect.any(AbortSignal) }),
|
||
);
|
||
expect(mocks.appendMessage).toHaveBeenCalledWith(
|
||
'agent:test:main',
|
||
expect.objectContaining({
|
||
role: 'assistant',
|
||
content: '已为你打开 http://www.baidu.com/(百度一下,你就知道)',
|
||
}),
|
||
);
|
||
expect(broadcast).toHaveBeenCalledWith(expect.objectContaining({
|
||
type: 'chat:final',
|
||
sessionKey: 'agent:test:main',
|
||
runId: 'run-1',
|
||
}));
|
||
});
|
||
|
||
it('emits a failure assistant message when browser open fails', async () => {
|
||
mocks.openUrlInBrowser.mockRejectedValue(new Error('No browser context available'));
|
||
|
||
const { maybeHandleBrowserOpenMessage } = await import('../electron/gateway/browser-shortcut');
|
||
const broadcast = vi.fn();
|
||
|
||
const handled = maybeHandleBrowserOpenMessage(
|
||
'agent:test:main',
|
||
'run-2',
|
||
{ role: 'user', content: '打开 http://www.baidu.com' },
|
||
broadcast,
|
||
);
|
||
|
||
expect(handled).toBe(true);
|
||
|
||
await flushAsyncTasks();
|
||
|
||
expect(mocks.appendMessage).toHaveBeenCalledWith(
|
||
'agent:test:main',
|
||
expect.objectContaining({
|
||
role: 'assistant',
|
||
content: '打开失败:No browser context available',
|
||
}),
|
||
);
|
||
expect(broadcast).toHaveBeenCalledWith(expect.objectContaining({
|
||
type: 'chat:final',
|
||
runId: 'run-2',
|
||
}));
|
||
});
|
||
|
||
it('returns false when the user message is not an explicit browser-open command', async () => {
|
||
mocks.extractBrowserOpenIntent.mockReturnValue(null);
|
||
|
||
const { maybeHandleBrowserOpenMessage } = await import('../electron/gateway/browser-shortcut');
|
||
|
||
expect(
|
||
maybeHandleBrowserOpenMessage(
|
||
'agent:test:main',
|
||
'run-3',
|
||
{ role: 'user', content: '帮我总结一下百度首页' },
|
||
vi.fn(),
|
||
),
|
||
).toBe(false);
|
||
expect(mocks.openUrlInBrowser).not.toHaveBeenCalled();
|
||
});
|
||
});
|