import { describe, it, expect, vi, beforeEach } from 'vitest'; describe('preload.js - fakeIpcRenderer', () => { let fakeIpcRenderer, fakeElectronModule, fakePathModule; beforeEach(() => { vi.clearAllMocks(); }); describe('fakeIpcRenderer', () => { it('defines invoke method', () => { const fakeIpcRenderer = { invoke: (channel, ...args) => 'invoke', on: (channel, callback) => 'on', }; expect(typeof fakeIpcRenderer.invoke).toBe('function'); expect(typeof fakeIpcRenderer.on).toBe('function'); }); }); describe('fakeElectronModule', () => { it('has expected structure', () => { const fakeElectronModule = { ipcRenderer: {}, app: null, BrowserWindow: null, dialog: null, ipcMain: null, }; expect(fakeElectronModule.app).toBeNull(); expect(fakeElectronModule.BrowserWindow).toBeNull(); expect(fakeElectronModule.dialog).toBeNull(); expect(fakeElectronModule.ipcMain).toBeNull(); }); }); describe('fakePathModule', () => { const path = require('path'); it('joins paths', () => { const fakePathModule = { join: (...args) => path.join(...args), dirname: (p) => path.dirname(p), basename: (p) => path.basename(p), extname: (p) => path.extname(p), sep: path.sep, resolve: (...args) => path.resolve(...args), }; expect(fakePathModule.join('a', 'b', 'c')).toBe(path.join('a', 'b', 'c')); expect(fakePathModule.dirname('/path/to/file.txt')).toBe('/path/to'); expect(fakePathModule.basename('/path/to/file.txt')).toBe('file.txt'); expect(fakePathModule.extname('/path/to/file.txt')).toBe('.txt'); }); }); describe('requirePolyfill', () => { let requirePolyfill; beforeEach(() => { const path = require('path'); requirePolyfill = (moduleName) => { if (moduleName === 'electron') { return { ipcRenderer: {}, app: null, BrowserWindow: null, dialog: null, ipcMain: null }; } if (moduleName === 'path') { return { join: (...args) => path.join(...args), dirname: (p) => path.dirname(p), basename: (p) => path.basename(p), extname: (p) => path.extname(p), sep: path.sep, resolve: (...args) => path.resolve(...args), }; } if (moduleName === 'fs') { throw new Error('Direct fs access disabled. Use IPC.'); } if (moduleName.startsWith('./')) { const baseName = moduleName.replace('./', '').replace('.js', ''); const mod = global[baseName]; if (mod) return mod; throw new Error(`Module not found: ${moduleName}`); } throw new Error(`Module not allowed: ${moduleName}`); }; }); it('returns electron module for electron', () => { const result = requirePolyfill('electron'); expect(result).toBeDefined(); expect(result.app).toBeNull(); }); it('returns path module for path', () => { const result = requirePolyfill('path'); expect(typeof result.join).toBe('function'); expect(typeof result.dirname).toBe('function'); expect(typeof result.basename).toBe('function'); expect(typeof result.extname).toBe('function'); expect(typeof result.sep).toBe('string'); expect(typeof result.resolve).toBe('function'); }); it('throws for fs module', () => { expect(() => requirePolyfill('fs')).toThrow('Direct fs access disabled. Use IPC.'); }); it('throws for unallowed modules', () => { expect(() => requirePolyfill('http')).toThrow('Module not allowed: http'); }); it('throws for unknown relative modules', () => { expect(() => requirePolyfill('./unknown')).toThrow('Module not found:'); }); it('handles relative module with .js extension', () => { global.UIManager = { test: true }; const result = requirePolyfill('./UIManager.js'); expect(result.test).toBe(true); delete global.UIManager; }); it('handles relative module without .js extension', () => { global.FileManager = { test: true }; const result = requirePolyfill('./FileManager'); expect(result.test).toBe(true); delete global.FileManager; }); }); });