refactor: extend vitest setup with full chrome/browser mocks and i18n utility mock

This commit is contained in:
雨霖铃
2026-05-22 23:02:41 +08:00
parent 7efed8673a
commit 756ece31d3
+36 -13
View File
@@ -1,18 +1,29 @@
import '@testing-library/jest-dom';
import { vi, beforeEach, afterEach } from 'vitest';
import { afterEach, beforeEach, vi } from 'vitest';
vi.mock('@/utils/useLazyTranslation', () => ({
useLazyTranslation: (ns?: string) => ({
// 自动承接命名空间前缀过滤,100% 模拟真实多语种直出
t: (key: string) => (ns ? `${ns}:${key}` : key),
i18n: {
changeLanguage: vi.fn().mockResolvedValue(undefined),
language: 'zh-CN',
},
isLoaded: true,
}),
}));
// Mock react-i18next
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
i18n: {
changeLanguage: vi.fn(),
changeLanguage: vi.fn().mockResolvedValue(undefined),
language: 'zh-CN',
},
}),
initReactI18next: {
type: '3rdParty',
init: vi.fn(),
init: vi.fn().mockResolvedValue(undefined),
},
}));
@@ -36,14 +47,14 @@ const storageMock = {
},
};
Object.defineProperty(global, 'chrome', {
value: {
const webExtensionMock = {
storage: storageMock,
tabs: {
query: vi.fn().mockResolvedValue([]),
get: vi.fn(),
get: vi.fn().mockResolvedValue({}),
sendMessage: vi.fn().mockResolvedValue(undefined),
create: vi.fn().mockResolvedValue({}),
reload: vi.fn().mockResolvedValue(undefined), // ✅ 承接 MessageAction.RELOAD_TAB 刷新单元测试
},
runtime: {
id: 'test-extension-id',
@@ -59,6 +70,7 @@ Object.defineProperty(global, 'chrome', {
addListener: vi.fn(),
removeListener: vi.fn(),
},
openPopup: vi.fn().mockResolvedValue(undefined),
},
sidePanel: {
open: vi.fn().mockResolvedValue(undefined),
@@ -70,6 +82,13 @@ Object.defineProperty(global, 'chrome', {
getAll: vi.fn().mockResolvedValue([]),
remove: vi.fn().mockResolvedValue(undefined),
},
alarms: {
create: vi.fn().mockResolvedValue(undefined),
onAlarm: {
addListener: vi.fn(),
removeListener: vi.fn(),
},
},
contextMenus: {
create: vi.fn(),
onClicked: {
@@ -92,13 +111,18 @@ Object.defineProperty(global, 'chrome', {
ACTION: 'action',
},
},
},
writable: true,
});
};
Object.defineProperty(globalThis, 'chrome', { value: webExtensionMock, writable: true });
Object.defineProperty(globalThis, 'browser', { value: webExtensionMock, writable: true });
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'chrome', { value: webExtensionMock, writable: true });
Object.defineProperty(window, 'browser', { value: webExtensionMock, writable: true });
}
beforeEach(() => {
vi.clearAllMocks();
// Ensure storage mocks return objects even after clearAllMocks
storageMock.local.get.mockResolvedValue({});
storageMock.session.get.mockResolvedValue({});
});
@@ -107,8 +131,7 @@ afterEach(() => {
vi.restoreAllMocks();
});
// 全局 matchMedia mockThemeModeProvider 依赖)
// 必须在 beforeEach 中设置,因为 afterEach 的 restoreAllMocks 会清除它
// 全局 matchMedia 极客级环境模拟ThemeModeProvider 依赖)
beforeEach(() => {
Object.defineProperty(window, 'matchMedia', {
writable: true,