eigent/test/unit/electron/main/windowLifecycle.test.ts
2025-10-03 03:52:56 +03:00

407 lines
No EOL
13 KiB
TypeScript

/**
* 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 { describe, it, expect, beforeEach, afterEach, 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)
})
})
})