This commit is contained in:
2026-03-13 10:28:10 +08:00
parent f53f43a6b9
commit 4ec09661cd
9 changed files with 1071 additions and 18 deletions

142
tests/mocks/electron.ts Normal file
View File

@@ -0,0 +1,142 @@
/**
* Electron API mocks for testing
* Mocks safeStorage, app, and other Electron APIs
*/
import { vi } from "vitest";
// In-memory storage for encrypted passwords (simulates OS keychain)
const encryptedStore = new Map<string, string>();
/**
* Mock safeStorage for password encryption
* In tests, we use a simple reversible encoding instead of actual encryption
*/
export const safeStorage = {
/**
* Encrypt a string (simulated)
* In production, this uses OS-specific encryption
*/
encryptString: vi.fn((plaintext: string): Buffer => {
const encoded = Buffer.from(`encrypted:${plaintext}`).toString("base64");
return Buffer.from(encoded);
}),
/**
* Decrypt a buffer (simulated)
*/
decryptString: vi.fn((encrypted: Buffer): string => {
const decoded = encrypted.toString();
const base64Content = decoded.replace("encrypted:", "");
return Buffer.from(base64Content, "base64")
.toString()
.replace("encrypted:", "");
}),
/**
* Check if encryption is available
*/
isEncryptionAvailable: vi.fn((): boolean => true),
/**
* Get the current storage backend
*/
getSelectedStorageBackend: vi.fn((): string => "mock_backend"),
};
/**
* Mock Electron app
*/
export const app = {
getName: vi.fn(() => "Kintone Customize Manager"),
getVersion: vi.fn(() => "1.0.0"),
getPath: vi.fn((key: string): string => {
const paths: Record<string, string> = {
userData: "/tmp/kintone-manager-test/userData",
home: "/tmp/kintone-manager-test/home",
temp: "/tmp/kintone-manager-test/temp",
appData: "/tmp/kintone-manager-test/appData",
desktop: "/tmp/kintone-manager-test/desktop",
documents: "/tmp/kintone-manager-test/documents",
downloads: "/tmp/kintone-manager-test/downloads",
};
return paths[key] || "/tmp/kintone-manager-test";
}),
whenReady: vi.fn(() => Promise.resolve()),
on: vi.fn(),
quit: vi.fn(),
isReady: vi.fn(() => true),
};
/**
* Mock ipcMain for IPC handler tests
*/
class IPCMainMock {
private handlers = new Map<string, Function>();
handle = vi.fn((channel: string, handler: Function) => {
this.handlers.set(channel, handler);
});
handleOnce = vi.fn((channel: string, handler: Function) => {
this.handlers.set(channel, handler);
});
removeHandler = vi.fn((channel: string) => {
this.handlers.delete(channel);
});
// Helper to call a handler directly in tests
async invoke(channel: string, ...args: unknown[]): Promise<unknown> {
const handler = this.handlers.get(channel);
if (!handler) {
throw new Error(`No handler registered for channel: ${channel}`);
}
return handler({}, ...args);
}
}
export const ipcMain = new IPCMainMock();
/**
* Mock BrowserWindow
*/
export const BrowserWindow = vi.fn().mockImplementation(() => ({
loadURL: vi.fn(),
loadFile: vi.fn(),
on: vi.fn(),
webContents: {
on: vi.fn(),
send: vi.fn(),
openDevTools: vi.fn(),
},
show: vi.fn(),
close: vi.fn(),
}));
/**
* Mock dialog
*/
export const dialog = {
showOpenDialog: vi.fn().mockResolvedValue({ canceled: false, filePaths: [] }),
showMessageBox: vi.fn().mockResolvedValue({ response: 0 }),
showSaveDialog: vi.fn().mockResolvedValue({ canceled: false, filePath: "" }),
};
/**
* Mock clipboard
*/
export const clipboard = {
writeText: vi.fn(),
readText: vi.fn(() => ""),
};
// Default export with all mocked APIs
export default {
app,
safeStorage,
ipcMain,
BrowserWindow,
dialog,
clipboard,
};

14
tests/setup.ts Normal file
View File

@@ -0,0 +1,14 @@
/**
* Test setup file
* Configures mocks before tests run
*/
import { vi } from "vitest";
// Mock electron module before any imports
vi.mock("electron", () => {
return import("./mocks/electron");
});
// Increase timeout for integration tests
vi.setConfig({ testTimeout: 30000 });