// tests/main/services/screen-context-redteam-r1-3.test.ts // 선택 텍스트 캡처 회귀 테스트: // - 핫키 수정자(Alt 등)를 쥔 상태면 Ctrl+C 를 보내지 않고 클립보드도 건드리지 않는다 // - 캡처 후 클립보드는 저장한 모든 형식(text/html/rtf/image)을 한 번에 복원한다 import { describe, it, expect, beforeEach, vi } from 'vitest' import { clipboard } from 'electron' vi.mock('../../../src/main/services/LoggerService', () => ({ getLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }), })) vi.mock('../../../src/main/services/ConfigService', () => ({ configGet: vi.fn(() => true), configSet: vi.fn(), })) const modifiers = vi.hoisted(() => ({ released: true })) vi.mock('../../../src/main/services/modifier-state', () => ({ waitForModifiersReleased: vi.fn(async () => modifiers.released), })) const nut = vi.hoisted(() => ({ pressKey: vi.fn(async () => undefined), releaseKey: vi.fn(async () => undefined) })) vi.mock('@nut-tree-fork/nut-js', () => ({ keyboard: nut, Key: { LeftControl: 'LeftControl', C: 'C' }, })) type Module = typeof import('../../../src/main/services/ScreenContextService') let getScreenContextService: Module['getScreenContextService'] // 공용 electron 목에는 clipboard.clear 가 없다 — 이 테스트에서만 채운다 const clipboardClear = vi.fn() Object.assign(clipboard, { clear: clipboardClear }) beforeEach(async () => { vi.resetModules() vi.clearAllMocks() modifiers.released = true getScreenContextService = (await import('../../../src/main/services/ScreenContextService')).getScreenContextService }) describe('ScreenContextService.captureSelectedText', () => { it('수정자를 쥐고 있으면 Ctrl+C 를 보내지 않고 클립보드도 비우지 않는다', async () => { modifiers.released = false const text = await getScreenContextService().captureSelectedText() expect(text).toBeNull() expect(nut.pressKey).not.toHaveBeenCalled() expect(clipboardClear).not.toHaveBeenCalled() }) it('수정자를 뗀 뒤에는 복사하고, 모든 형식을 한 번에 복원한다', async () => { const image = { isEmpty: () => false, toPNG: () => Buffer.alloc(1) } vi.mocked(clipboard.readText).mockReturnValueOnce('원래 텍스트').mockReturnValueOnce('선택한 문장') vi.mocked(clipboard.readHTML).mockReturnValueOnce('원래') vi.mocked(clipboard.readRTF).mockReturnValueOnce('{\\rtf1 원래}') vi.mocked(clipboard.readImage).mockReturnValueOnce(image as unknown as Electron.NativeImage) const text = await getScreenContextService().captureSelectedText() expect(text).toBe('선택한 문장') expect(nut.pressKey).toHaveBeenCalledTimes(1) expect(clipboard.write).toHaveBeenCalledWith({ text: '원래 텍스트', html: '원래', rtf: '{\\rtf1 원래}', image, }) }) })