85 lines
3.2 KiB
TypeScript
85 lines
3.2 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
createConversationLinkMenuTemplate,
|
|
type ConversationLinkMenuActions,
|
|
} from '../../electron/main/ipc/conversation-link-context-menu';
|
|
|
|
function createActions(overrides: Partial<ConversationLinkMenuActions> = {}): ConversationLinkMenuActions {
|
|
return {
|
|
platform: 'darwin',
|
|
homePath: '/Users/tester',
|
|
openExternal: vi.fn().mockResolvedValue(undefined),
|
|
openPath: vi.fn().mockResolvedValue(''),
|
|
showItemInFolder: vi.fn(),
|
|
writeText: vi.fn(),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function click(template: Electron.MenuItemConstructorOptions[], index: number): void {
|
|
const handler = template[index]?.click;
|
|
expect(handler).toBeTypeOf('function');
|
|
(handler as () => void)();
|
|
}
|
|
|
|
describe('conversation link context menu', () => {
|
|
it('opens or copies an HTTP link without exposing local-file actions', () => {
|
|
const actions = createActions();
|
|
const template = createConversationLinkMenuTemplate({
|
|
kind: 'external',
|
|
target: 'https://example.com/docs',
|
|
}, actions);
|
|
|
|
expect(template.map((item) => item.label ?? item.type))
|
|
.toEqual(['用默认浏览器打开', 'separator', '复制链接地址']);
|
|
click(template, 0);
|
|
click(template, 2);
|
|
expect(actions.openExternal).toHaveBeenCalledWith('https://example.com/docs');
|
|
expect(actions.writeText).toHaveBeenCalledWith('https://example.com/docs');
|
|
expect(actions.showItemInFolder).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('opens, reveals, or copies a local HTML file and uses the platform label', () => {
|
|
const actions = createActions();
|
|
const template = createConversationLinkMenuTemplate({
|
|
kind: 'local-web',
|
|
target: '~/Desktop/site/index.html',
|
|
}, actions);
|
|
|
|
expect(template.map((item) => item.label ?? item.type)).toEqual([
|
|
'用默认浏览器打开',
|
|
'在访达中显示',
|
|
'separator',
|
|
'复制地址',
|
|
]);
|
|
click(template, 0);
|
|
click(template, 1);
|
|
click(template, 3);
|
|
expect(actions.openPath).toHaveBeenCalledWith('/Users/tester/Desktop/site/index.html');
|
|
expect(actions.showItemInFolder).toHaveBeenCalledWith('/Users/tester/Desktop/site/index.html');
|
|
expect(actions.writeText).toHaveBeenCalledWith('/Users/tester/Desktop/site/index.html');
|
|
|
|
const windowsTemplate = createConversationLinkMenuTemplate({
|
|
kind: 'local-web',
|
|
target: 'C:\\Users\\tester\\site\\index.html',
|
|
}, createActions({ platform: 'win32', homePath: 'C:\\Users\\tester' }));
|
|
expect(windowsTemplate[1]?.label).toBe('在文件夹中显示');
|
|
});
|
|
|
|
it('rejects executable URLs, credentials, and non-HTML local targets', () => {
|
|
const actions = createActions();
|
|
expect(() => createConversationLinkMenuTemplate({
|
|
kind: 'external',
|
|
target: 'javascript:alert(1)',
|
|
}, actions)).toThrow('Unsupported external URL');
|
|
expect(() => createConversationLinkMenuTemplate({
|
|
kind: 'external',
|
|
target: 'https://user:secret@example.com/',
|
|
}, actions)).toThrow('Unsupported external URL');
|
|
expect(() => createConversationLinkMenuTemplate({
|
|
kind: 'local-web',
|
|
target: '/tmp/run.command',
|
|
}, actions)).toThrow('Unsupported local web file');
|
|
});
|
|
});
|