136 lines
4.7 KiB
TypeScript
136 lines
4.7 KiB
TypeScript
// closeToTray=false 로 메인 창을 닫으면 창 없는 프로세스로 남지 않고 종료한다. 창이 사라진 뒤 트레이
|
|
// '표시'·두 번째 실행은 창을 다시 만든다.
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
type Listener = (...args: unknown[]) => void
|
|
|
|
const state = vi.hoisted(() => ({
|
|
windows: [] as Array<{ listeners: Map<string, Listener>; destroyed: boolean }>,
|
|
quit: vi.fn(),
|
|
}))
|
|
|
|
vi.unmock('../../../src/main/windows/WindowManager')
|
|
|
|
vi.mock('electron', () => {
|
|
const quit = state.quit
|
|
class FakeBrowserWindow {
|
|
listeners = new Map<string, Listener>()
|
|
destroyed = false
|
|
webContents = {
|
|
on: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
openDevTools: vi.fn(),
|
|
insertCSS: vi.fn(async () => ''),
|
|
send: vi.fn(),
|
|
}
|
|
constructor() {
|
|
state.windows.push(this)
|
|
}
|
|
on(event: string, listener: Listener): this {
|
|
this.listeners.set(event, listener)
|
|
return this
|
|
}
|
|
once(event: string, listener: Listener): this {
|
|
return this.on(event, listener)
|
|
}
|
|
setSkipTaskbar = vi.fn()
|
|
setMenu = vi.fn()
|
|
loadURL = vi.fn(async () => undefined)
|
|
loadFile = vi.fn(async () => undefined)
|
|
center = vi.fn()
|
|
restore = vi.fn()
|
|
show = vi.fn()
|
|
focus = vi.fn()
|
|
hide = vi.fn()
|
|
setAlwaysOnTop = vi.fn()
|
|
flashFrame = vi.fn()
|
|
isMinimized = vi.fn(() => false)
|
|
isDestroyed(): boolean {
|
|
return this.destroyed
|
|
}
|
|
}
|
|
return {
|
|
app: { quit, getPath: vi.fn(() => '.'), on: vi.fn(), getVersion: vi.fn(() => '1.0.0'), isPackaged: false },
|
|
BrowserWindow: Object.assign(FakeBrowserWindow, { getAllWindows: vi.fn(() => []) }),
|
|
screen: {
|
|
getPrimaryDisplay: vi.fn(() => ({ workAreaSize: { width: 1920, height: 1080 }, workArea: { x: 0, y: 0, width: 1920, height: 1080 } })),
|
|
getCursorScreenPoint: vi.fn(() => ({ x: 0, y: 0 })),
|
|
getDisplayNearestPoint: vi.fn(() => ({ workArea: { x: 0, y: 0, width: 1920, height: 1080 } })),
|
|
},
|
|
ipcMain: { on: vi.fn(), handle: vi.fn(), removeHandler: vi.fn() },
|
|
Menu: { setApplicationMenu: vi.fn(), buildFromTemplate: vi.fn() },
|
|
clipboard: { writeText: vi.fn() },
|
|
shell: { openExternal: vi.fn(async () => undefined) },
|
|
safeStorage: { isEncryptionAvailable: vi.fn(() => false) },
|
|
nativeImage: { createFromPath: vi.fn(), createEmpty: vi.fn() },
|
|
Tray: vi.fn(),
|
|
dialog: { showErrorBox: vi.fn() },
|
|
}
|
|
})
|
|
|
|
vi.mock('@electron-toolkit/utils', () => ({ is: { dev: false } }))
|
|
|
|
vi.mock('../../../src/main/lifecycle', () => {
|
|
let quitting = false
|
|
return {
|
|
getIsQuitting: () => quitting,
|
|
setIsQuitting: (value: boolean) => {
|
|
quitting = value
|
|
},
|
|
}
|
|
})
|
|
|
|
const config: Record<string, unknown> = { closeToTray: false, theme: 'dark', language: 'ko' }
|
|
vi.mock('../../../src/main/services/ConfigService', () => ({
|
|
configGet: (key: string) => config[key],
|
|
configSet: (key: string, value: unknown) => {
|
|
config[key] = value
|
|
},
|
|
}))
|
|
|
|
beforeEach(async () => {
|
|
state.windows.length = 0
|
|
state.quit.mockClear()
|
|
const lifecycle = await import('../../../src/main/lifecycle')
|
|
lifecycle.setIsQuitting(false)
|
|
})
|
|
|
|
describe('main window close', () => {
|
|
it('closeToTray=false 이면 창 닫기가 앱 종료로 이어진다', async () => {
|
|
config.closeToTray = false
|
|
const { createMainWindow } = await import('../../../src/main/windows/WindowManager')
|
|
createMainWindow()
|
|
const win = state.windows[0]
|
|
const event = { preventDefault: vi.fn() }
|
|
win.listeners.get('close')?.(event)
|
|
expect(event.preventDefault).not.toHaveBeenCalled()
|
|
expect(state.quit).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('closeToTray=true 이면 숨기기만 하고 종료하지 않는다', async () => {
|
|
vi.resetModules()
|
|
config.closeToTray = true
|
|
const { createMainWindow } = await import('../../../src/main/windows/WindowManager')
|
|
createMainWindow()
|
|
const win = state.windows[0]
|
|
const event = { preventDefault: vi.fn() }
|
|
win.listeners.get('close')?.(event)
|
|
expect(event.preventDefault).toHaveBeenCalled()
|
|
expect(state.quit).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('창이 파괴된 뒤 showMainWindow 는 창을 다시 만든다(부트스트랩 전에는 만들지 않는다)', async () => {
|
|
vi.resetModules()
|
|
const { createMainWindow, showMainWindow, getMainWindow } = await import('../../../src/main/windows/WindowManager')
|
|
expect(showMainWindow()).toBeNull()
|
|
expect(state.windows).toHaveLength(0)
|
|
createMainWindow()
|
|
const first = state.windows[0]
|
|
first.destroyed = true
|
|
first.listeners.get('closed')?.()
|
|
expect(getMainWindow()).toBeNull()
|
|
expect(showMainWindow()).not.toBeNull()
|
|
expect(state.windows).toHaveLength(2)
|
|
})
|
|
})
|