945780def8
feat: optimize dashboard/search UX and simplify extension architecture Redesign Dashboard with compact tool grid and recently used tools Improve TopBar search UX with Cmd/Ctrl+K shortcut and better history navigation Reorganize project structure into src/ Migrate i18n from react-i18next to chrome.i18n Remove runtime language switch and settings page Remove HTML/Markdown conversion tools Clean up unused code, dead animations, redundant comments, and imports Improve component consistency with shadcn/ui patterns Replace hardcoded strings/colors with i18n tokens and theme tokens Add comprehensive project documentation and coding standards Fix CI artifact upload workflow and multiple TypeScript/test issues Includes various refactors, UI polish, i18n cleanup, CI improvements, and maintenance updates across the codebase.
160 lines
5.4 KiB
TypeScript
160 lines
5.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
getActiveTab,
|
|
getActiveTabDomain,
|
|
openExtensionPage,
|
|
ensureContentScriptInjected,
|
|
} from '@/utils/chromeTabs';
|
|
|
|
describe('chromeTabs', () => {
|
|
describe('getActiveTab', () => {
|
|
it('应该返回当前活动标签页', async () => {
|
|
const mockTab = { id: 1, url: 'https://example.com', title: 'Example' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTab();
|
|
|
|
expect(result).toEqual(mockTab);
|
|
expect(chrome.tabs.query).toHaveBeenCalledWith({ active: true, currentWindow: true });
|
|
});
|
|
|
|
it('当没有活动标签页时应返回 null', async () => {
|
|
(chrome.tabs.query as any).mockResolvedValue([]);
|
|
|
|
const result = await getActiveTab();
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('当查询失败时应返回 null 并记录错误', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
(chrome.tabs.query as any).mockRejectedValue(new Error('Permission denied'));
|
|
|
|
const result = await getActiveTab();
|
|
|
|
expect(result).toBeNull();
|
|
expect(consoleSpy).toHaveBeenCalledWith('获取活动标签页失败:', expect.any(Error));
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('getActiveTabDomain', () => {
|
|
it('应该返回当前活动标签页的域名', async () => {
|
|
const mockTab = { id: 1, url: 'https://example.com/path?query=1' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('example.com');
|
|
});
|
|
|
|
it('应该处理带有端口的 URL', async () => {
|
|
const mockTab = { id: 1, url: 'https://example.com:8080/path' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('example.com');
|
|
});
|
|
|
|
it('当标签页没有 URL 时应返回空字符串', async () => {
|
|
const mockTab = { id: 1 } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('');
|
|
});
|
|
|
|
it('当没有活动标签页时应返回空字符串', async () => {
|
|
(chrome.tabs.query as any).mockResolvedValue([]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('');
|
|
});
|
|
|
|
it('当 URL 解析失败时应返回空字符串并记录错误', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
const mockTab = { id: 1, url: 'not-a-valid-url' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('');
|
|
expect(consoleSpy).toHaveBeenCalledWith('解析域名失败:', expect.any(Error));
|
|
consoleSpy.mockRestore();
|
|
});
|
|
|
|
it('应该处理 chrome-extension URL', async () => {
|
|
const mockTab = { id: 1, url: 'chrome-extension://abc123/popup.html' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await getActiveTabDomain();
|
|
|
|
expect(result).toBe('abc123');
|
|
});
|
|
});
|
|
|
|
describe('openExtensionPage', () => {
|
|
it('应该在新标签页中打开扩展页面', async () => {
|
|
await openExtensionPage('popup.html');
|
|
|
|
expect(chrome.runtime.getURL).toHaveBeenCalledWith('popup.html');
|
|
expect(chrome.tabs.create).toHaveBeenCalledWith({
|
|
url: 'chrome-extension://test-extension-id/popup.html',
|
|
});
|
|
});
|
|
|
|
it('当创建标签页失败时应记录错误', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
(chrome.tabs.create as any).mockRejectedValue(new Error('Tab creation failed'));
|
|
|
|
await openExtensionPage('popup.html');
|
|
|
|
expect(consoleSpy).toHaveBeenCalledWith('打开扩展页面失败:', expect.any(Error));
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('ensureContentScriptInjected', () => {
|
|
it('当存在活动标签页时应返回 true', async () => {
|
|
const mockTab = { id: 123, url: 'https://example.com' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await ensureContentScriptInjected();
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('当没有活动标签页时应返回 false', async () => {
|
|
(chrome.tabs.query as any).mockResolvedValue([]);
|
|
|
|
const result = await ensureContentScriptInjected();
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('当标签页没有 id 时应返回 false', async () => {
|
|
const mockTab = { url: 'https://example.com' } as chrome.tabs.Tab;
|
|
(chrome.tabs.query as any).mockResolvedValue([mockTab]);
|
|
|
|
const result = await ensureContentScriptInjected();
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('当整体操作失败时应返回 false 并记录错误', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
(chrome.tabs.query as any).mockRejectedValue(new Error('Query failed'));
|
|
|
|
const result = await ensureContentScriptInjected();
|
|
|
|
expect(result).toBe(false);
|
|
// getActiveTab catches the error and logs "获取活动标签页失败"
|
|
expect(consoleSpy).toHaveBeenCalledWith('获取活动标签页失败:', expect.any(Error));
|
|
consoleSpy.mockRestore();
|
|
});
|
|
});
|
|
});
|