// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= /** * Tests for window event setup and lifecycle management in createWindow function * Covers dev tools shortcuts, external link handling, before close handling, * auto-update integration, webview manager, and file reader initialization */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { setupMockEnvironment } from '../../../mocks/environmentMocks'; describe('createWindow - Window Event Setup and Lifecycle', () => { let mockEnv: ReturnType; let mockWebContents: any; let mockWindow: any; let mockFileReader: any; let mockWebViewManager: any; let mockUpdate: any; let mockMenu: any; beforeEach(() => { mockEnv = setupMockEnvironment(); // Mock webContents mockWebContents = { on: vi.fn(), once: vi.fn(), executeJavaScript: vi.fn(), send: vi.fn(), loadURL: vi.fn(), loadFile: vi.fn(), openDevTools: vi.fn(), toggleDevTools: vi.fn(), }; // Mock window mockWindow = { webContents: mockWebContents, reload: vi.fn(), }; // Mock FileReader class mockFileReader = vi.fn(); // Mock WebViewManager class mockWebViewManager = vi.fn().mockImplementation(() => ({ createWebview: vi.fn(), })); // Mock update function mockUpdate = vi.fn(); // Mock Menu mockMenu = { setApplicationMenu: vi.fn(), }; // Reset all mocks vi.clearAllMocks(); }); afterEach(() => { mockEnv.reset(); }); describe('FileReader and WebViewManager Initialization', () => { it.skip('should create 8 webviews with correct IDs', () => { const _webViewManager = new mockWebViewManager(mockWindow); const instance = mockWebViewManager.mock.instances[0]; // Simulate the loop that creates webviews for (let i = 1; i <= 8; i++) { instance.createWebview(i === 1 ? undefined : i.toString()); } expect(instance.createWebview).toHaveBeenCalledTimes(8); expect(instance.createWebview).toHaveBeenNthCalledWith(1, undefined); expect(instance.createWebview).toHaveBeenNthCalledWith(2, '2'); expect(instance.createWebview).toHaveBeenNthCalledWith(3, '3'); expect(instance.createWebview).toHaveBeenNthCalledWith(4, '4'); expect(instance.createWebview).toHaveBeenNthCalledWith(5, '5'); expect(instance.createWebview).toHaveBeenNthCalledWith(6, '6'); expect(instance.createWebview).toHaveBeenNthCalledWith(7, '7'); expect(instance.createWebview).toHaveBeenNthCalledWith(8, '8'); }); }); describe('Window Event Listeners Setup', () => { it('should disable application menu', () => { // Simulate setupWindowEventListeners mockMenu.setApplicationMenu(null); expect(mockMenu.setApplicationMenu).toHaveBeenCalledWith(null); }); it('should set up application menu only once', () => { // Simulate multiple calls to setupWindowEventListeners mockMenu.setApplicationMenu(null); mockMenu.setApplicationMenu(null); expect(mockMenu.setApplicationMenu).toHaveBeenCalledTimes(2); expect(mockMenu.setApplicationMenu).toHaveBeenCalledWith(null); }); }); describe('DevTools Shortcuts Setup', () => { it('should set up before-input-event listener for dev tools shortcuts', () => { // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', expect.any(Function)); expect(mockWebContents.on).toHaveBeenCalledWith( 'before-input-event', expect.any(Function) ); }); it('should handle F12 key to toggle dev tools', () => { let beforeInputCallback: any; mockWebContents.on.mockImplementation((event: string, callback: any) => { if (event === 'before-input-event') { beforeInputCallback = callback; } }); // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', (event: any, input: any) => { if (input.key === 'F12' && input.type === 'keyDown') { mockWebContents.toggleDevTools(); } }); // Trigger F12 key if (beforeInputCallback) { const mockEvent = { preventDefault: vi.fn() }; const mockInput = { key: 'F12', type: 'keyDown' }; beforeInputCallback(mockEvent, mockInput); } expect(mockWebContents.toggleDevTools).toHaveBeenCalled(); }); it('should handle Ctrl+Shift+I to toggle dev tools on Windows/Linux', () => { let beforeInputCallback: any; mockWebContents.on.mockImplementation((event: string, callback: any) => { if (event === 'before-input-event') { beforeInputCallback = callback; } }); // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', (event: any, input: any) => { if ( input.control && input.shift && input.key.toLowerCase() === 'i' && input.type === 'keyDown' ) { mockWebContents.toggleDevTools(); } }); // Trigger Ctrl+Shift+I if (beforeInputCallback) { const mockEvent = { preventDefault: vi.fn() }; const mockInput = { control: true, shift: true, key: 'I', type: 'keyDown', }; beforeInputCallback(mockEvent, mockInput); } expect(mockWebContents.toggleDevTools).toHaveBeenCalled(); }); it('should handle Cmd+Shift+I to toggle dev tools on Mac', () => { let beforeInputCallback: any; mockWebContents.on.mockImplementation((event: string, callback: any) => { if (event === 'before-input-event') { beforeInputCallback = callback; } }); // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', (event: any, input: any) => { if ( input.meta && input.shift && input.key.toLowerCase() === 'i' && input.type === 'keyDown' ) { mockWebContents.toggleDevTools(); } }); // Trigger Cmd+Shift+I if (beforeInputCallback) { const mockEvent = { preventDefault: vi.fn() }; const mockInput = { meta: true, shift: true, key: 'I', type: 'keyDown', }; beforeInputCallback(mockEvent, mockInput); } expect(mockWebContents.toggleDevTools).toHaveBeenCalled(); }); it('should not trigger dev tools on key up events', () => { let beforeInputCallback: any; mockWebContents.on.mockImplementation((event: string, callback: any) => { if (event === 'before-input-event') { beforeInputCallback = callback; } }); // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', (event: any, input: any) => { if (input.key === 'F12' && input.type === 'keyDown') { mockWebContents.toggleDevTools(); } }); // Trigger F12 key up (should not toggle) if (beforeInputCallback) { const mockEvent = { preventDefault: vi.fn() }; const mockInput = { key: 'F12', type: 'keyUp' }; beforeInputCallback(mockEvent, mockInput); } expect(mockWebContents.toggleDevTools).not.toHaveBeenCalled(); }); it('should not trigger dev tools on wrong key combinations', () => { let beforeInputCallback: any; mockWebContents.on.mockImplementation((event: string, callback: any) => { if (event === 'before-input-event') { beforeInputCallback = callback; } }); // Simulate setupDevToolsShortcuts mockWebContents.on('before-input-event', (event: any, input: any) => { if ( input.control && input.shift && input.key.toLowerCase() === 'i' && input.type === 'keyDown' ) { mockWebContents.toggleDevTools(); } }); // Trigger wrong combination (Ctrl+I without Shift) if (beforeInputCallback) { const mockEvent = { preventDefault: vi.fn() }; const mockInput = { control: true, shift: false, key: 'I', type: 'keyDown', }; beforeInputCallback(mockEvent, mockInput); } expect(mockWebContents.toggleDevTools).not.toHaveBeenCalled(); }); }); describe('Auto-Update Integration', () => { it('should call update function with window reference', () => { // Simulate auto-update setup mockUpdate(mockWindow); expect(mockUpdate).toHaveBeenCalledWith(mockWindow); }); it('should call update function only once', () => { // Simulate auto-update setup mockUpdate(mockWindow); expect(mockUpdate).toHaveBeenCalledTimes(1); }); }); describe('Event Handler Organization', () => { it('should set up event handlers in correct order', () => { const eventSetupOrder: string[] = []; // Mock all the setup functions to track order const setupWindowEventListeners = () => { eventSetupOrder.push('windowEventListeners'); mockMenu.setApplicationMenu(null); }; const setupDevToolsShortcuts = () => { eventSetupOrder.push('devToolsShortcuts'); mockWebContents.on('before-input-event', vi.fn()); }; const setupExternalLinkHandling = () => { eventSetupOrder.push('externalLinkHandling'); }; const handleBeforeClose = () => { eventSetupOrder.push('beforeClose'); }; // Simulate the order in createWindow setupWindowEventListeners(); setupDevToolsShortcuts(); setupExternalLinkHandling(); handleBeforeClose(); expect(eventSetupOrder).toEqual([ 'windowEventListeners', 'devToolsShortcuts', 'externalLinkHandling', 'beforeClose', ]); }); }); describe('Window State Management', () => { it('should handle window ready state correctly', async () => { let didFinishLoadCallback: (() => void) | undefined; // Mock the did-finish-load event listener mockWebContents.once.mockImplementation( (event: string, callback: () => void) => { if (event === 'did-finish-load') { didFinishLoadCallback = callback; } } ); // Simulate waiting for window ready const windowReadyPromise = new Promise((resolve) => { mockWebContents.once('did-finish-load', () => { resolve(); }); }); // Trigger the event if (didFinishLoadCallback) { didFinishLoadCallback(); } // Should resolve without throwing await expect(windowReadyPromise).resolves.toBeUndefined(); }); it('should log appropriate messages during window setup', () => { // In a real test, you would verify that appropriate log messages are called // This ensures the window setup process is properly logged const mockLog = { info: vi.fn(), error: vi.fn(), }; // Simulate logging calls that would happen during window setup mockLog.info( 'Window content loaded, starting dependency check immediately...' ); mockLog.info('.eigent directory structure ensured'); expect(mockLog.info).toHaveBeenCalledWith( 'Window content loaded, starting dependency check immediately...' ); expect(mockLog.info).toHaveBeenCalledWith( '.eigent directory structure ensured' ); }); }); describe('Integration Points', () => { it('should properly coordinate between file reader and webview manager', () => { const _fileReader = new mockFileReader(mockWindow); const _webViewManager = new mockWebViewManager(mockWindow); // Both should be initialized with the same window expect(mockFileReader).toHaveBeenCalledWith(mockWindow); expect(mockWebViewManager).toHaveBeenCalledWith(mockWindow); }); it('should handle window initialization errors gracefully', () => { // Mock FileReader to throw during initialization mockFileReader.mockImplementation(() => { throw new Error('FileReader initialization failed'); }); // Should handle gracefully in real implementation expect(() => { try { new mockFileReader(mockWindow); } catch (error) { // Log error but don't stop execution console.error('FileReader initialization error:', error); } }).not.toThrow(); }); }); describe('Memory Management', () => { it('should properly clean up event listeners when window is destroyed', () => { // In a real scenario, you would test that event listeners are removed // when the window is closed to prevent memory leaks const mockRemoveListener = vi.fn(); mockWebContents.removeListener = mockRemoveListener; // Simulate cleanup const cleanup = () => { mockWebContents.removeListener('before-input-event', vi.fn()); mockWebContents.removeListener('dom-ready', vi.fn()); }; cleanup(); expect(mockRemoveListener).toHaveBeenCalledTimes(2); }); }); });