// 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,
})
})
})