mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-23 21:06:50 +00:00
Co-authored-by: a7m-1st <Ahmed.jimi.awelkeir500@gmail.com> Co-authored-by: eigent-ai <camel@eigent.ai> Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com> Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
443 lines
14 KiB
TypeScript
443 lines
14 KiB
TypeScript
// ========= 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<typeof setupMockEnvironment>;
|
|
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<void>((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);
|
|
});
|
|
});
|
|
});
|