mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
440 lines
14 KiB
TypeScript
440 lines
14 KiB
TypeScript
/* oxlint-disable max-lines */
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const { browserWindowMock, openExternalMock, attachGuestPoliciesMock, isMock } = vi.hoisted(() => ({
|
|
browserWindowMock: vi.fn(),
|
|
openExternalMock: vi.fn(),
|
|
attachGuestPoliciesMock: vi.fn(),
|
|
isMock: { dev: false }
|
|
}))
|
|
|
|
vi.mock('electron', () => ({
|
|
BrowserWindow: browserWindowMock,
|
|
ipcMain: { on: vi.fn(), removeListener: vi.fn() },
|
|
nativeTheme: { shouldUseDarkColors: false },
|
|
shell: { openExternal: openExternalMock }
|
|
}))
|
|
|
|
vi.mock('@electron-toolkit/utils', () => ({
|
|
is: isMock
|
|
}))
|
|
|
|
vi.mock('../../../resources/icon.png?asset', () => ({
|
|
default: 'icon'
|
|
}))
|
|
|
|
vi.mock('../../../resources/icon-dev.png?asset', () => ({
|
|
default: 'icon-dev'
|
|
}))
|
|
|
|
vi.mock('../browser/browser-manager', () => ({
|
|
browserManager: {
|
|
attachGuestPolicies: attachGuestPoliciesMock
|
|
}
|
|
}))
|
|
|
|
import { createMainWindow } from './createMainWindow'
|
|
|
|
describe('createMainWindow', () => {
|
|
beforeEach(() => {
|
|
browserWindowMock.mockReset()
|
|
openExternalMock.mockReset()
|
|
attachGuestPoliciesMock.mockReset()
|
|
isMock.dev = false
|
|
})
|
|
|
|
it('enables renderer sandboxing and opens external links safely', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn((handler) => {
|
|
windowHandlers.windowOpen = handler
|
|
}),
|
|
send: vi.fn(),
|
|
isDevToolsOpened: vi.fn(),
|
|
openDevTools: vi.fn(),
|
|
closeDevTools: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
expect(browserWindowMock).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
webPreferences: expect.objectContaining({ sandbox: true })
|
|
})
|
|
)
|
|
|
|
expect(windowHandlers.windowOpen({ url: 'https://example.com' })).toEqual({ action: 'deny' })
|
|
expect(windowHandlers.windowOpen({ url: 'localhost:3000' })).toEqual({ action: 'deny' })
|
|
expect(windowHandlers.windowOpen({ url: 'file:///etc/passwd' })).toEqual({ action: 'deny' })
|
|
expect(windowHandlers.windowOpen({ url: 'not a url' })).toEqual({ action: 'deny' })
|
|
|
|
expect(openExternalMock).toHaveBeenCalledTimes(2)
|
|
expect(openExternalMock).toHaveBeenCalledWith('https://example.com/')
|
|
expect(openExternalMock).toHaveBeenCalledWith('http://localhost:3000/')
|
|
|
|
const preventDefault = vi.fn()
|
|
windowHandlers['will-navigate']({ preventDefault } as never, 'https://example.com/docs')
|
|
expect(preventDefault).toHaveBeenCalledTimes(1)
|
|
expect(openExternalMock).toHaveBeenCalledTimes(3)
|
|
expect(openExternalMock).toHaveBeenLastCalledWith('https://example.com/docs')
|
|
|
|
const localhostPreventDefault = vi.fn()
|
|
windowHandlers['will-navigate'](
|
|
{ preventDefault: localhostPreventDefault } as never,
|
|
'localhost:3000'
|
|
)
|
|
expect(localhostPreventDefault).toHaveBeenCalledTimes(1)
|
|
expect(openExternalMock).toHaveBeenCalledTimes(4)
|
|
expect(openExternalMock).toHaveBeenLastCalledWith('http://localhost:3000/')
|
|
|
|
const fileNavigationPreventDefault = vi.fn()
|
|
windowHandlers['will-navigate'](
|
|
{ preventDefault: fileNavigationPreventDefault } as never,
|
|
'file:///etc/passwd'
|
|
)
|
|
expect(fileNavigationPreventDefault).toHaveBeenCalledTimes(1)
|
|
expect(openExternalMock).toHaveBeenCalledTimes(4)
|
|
|
|
const allowBlankEvent = { preventDefault: vi.fn() }
|
|
const allowBlankPrefs = { partition: 'persist:orca-browser' }
|
|
windowHandlers['will-attach-webview'](
|
|
allowBlankEvent as never,
|
|
allowBlankPrefs as never,
|
|
{ src: 'data:text/html,' } as never
|
|
)
|
|
expect(allowBlankEvent.preventDefault).not.toHaveBeenCalled()
|
|
|
|
const denyInlineHtmlEvent = { preventDefault: vi.fn() }
|
|
windowHandlers['will-attach-webview'](
|
|
denyInlineHtmlEvent as never,
|
|
{ partition: 'persist:orca-browser' } as never,
|
|
{ src: 'data:text/html,<script>alert(1)</script>' } as never
|
|
)
|
|
expect(denyInlineHtmlEvent.preventDefault).toHaveBeenCalledTimes(1)
|
|
|
|
const guest = { marker: 'guest' }
|
|
windowHandlers['did-attach-webview']({} as never, guest as never)
|
|
expect(attachGuestPoliciesMock).toHaveBeenCalledWith(guest)
|
|
})
|
|
|
|
it('supports all minus key variants for terminal zoom out', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
const beforeInputEvent = windowHandlers['before-input-event']
|
|
|
|
for (const input of [
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: '-' },
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: '_' },
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: 'Minus' },
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: 'Subtract' },
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: '', code: 'Minus' },
|
|
{ type: 'keyDown', control: true, meta: true, alt: false, key: '', code: 'NumpadSubtract' }
|
|
]) {
|
|
const preventDefault = vi.fn()
|
|
beforeInputEvent({ preventDefault } as never, input as never)
|
|
expect(preventDefault).toHaveBeenCalledTimes(1)
|
|
}
|
|
|
|
expect(webContents.send).toHaveBeenCalledTimes(6)
|
|
expect(webContents.send).toHaveBeenNthCalledWith(1, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(2, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(3, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(4, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(5, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(6, 'terminal:zoom', 'out')
|
|
})
|
|
|
|
it('routes Electron zoom command events to terminal zoom', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
const onZoomChanged = windowHandlers['zoom-changed']
|
|
const preventDefault = vi.fn()
|
|
onZoomChanged({ preventDefault } as never, 'out')
|
|
onZoomChanged({ preventDefault } as never, 'in')
|
|
|
|
expect(preventDefault).toHaveBeenCalledTimes(2)
|
|
expect(webContents.send).toHaveBeenCalledTimes(2)
|
|
expect(webContents.send).toHaveBeenNthCalledWith(1, 'terminal:zoom', 'out')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(2, 'terminal:zoom', 'in')
|
|
})
|
|
|
|
it('does not intercept ctrl/cmd+r in before-input-event', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn(),
|
|
isDevToolsOpened: vi.fn(),
|
|
openDevTools: vi.fn(),
|
|
closeDevTools: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
for (const input of [
|
|
{ type: 'keyDown', code: 'KeyR', key: 'r', meta: false, control: true, alt: false },
|
|
{ type: 'keyDown', code: 'KeyR', key: 'r', meta: true, control: false, alt: false }
|
|
]) {
|
|
const preventDefault = vi.fn()
|
|
windowHandlers['before-input-event']({ preventDefault } as never, input as never)
|
|
expect(preventDefault).not.toHaveBeenCalled()
|
|
}
|
|
|
|
expect(webContents.send).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('forwards ctrl/cmd+j to the worktree palette toggle event', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn(),
|
|
isDevToolsOpened: vi.fn(),
|
|
openDevTools: vi.fn(),
|
|
closeDevTools: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
const isDarwin = process.platform === 'darwin'
|
|
for (const input of [
|
|
{
|
|
type: 'keyDown',
|
|
code: 'KeyJ',
|
|
key: 'j',
|
|
meta: isDarwin,
|
|
control: !isDarwin,
|
|
alt: false,
|
|
shift: !isDarwin
|
|
},
|
|
{
|
|
type: 'keyDown',
|
|
code: 'KeyJ',
|
|
key: '',
|
|
meta: isDarwin,
|
|
control: !isDarwin,
|
|
alt: false,
|
|
shift: !isDarwin
|
|
}
|
|
]) {
|
|
const preventDefault = vi.fn()
|
|
windowHandlers['before-input-event']({ preventDefault } as never, input as never)
|
|
expect(preventDefault).toHaveBeenCalledTimes(1)
|
|
}
|
|
|
|
expect(webContents.send).toHaveBeenCalledTimes(2)
|
|
expect(webContents.send).toHaveBeenNthCalledWith(1, 'ui:toggleWorktreePalette')
|
|
expect(webContents.send).toHaveBeenNthCalledWith(2, 'ui:toggleWorktreePalette')
|
|
})
|
|
|
|
it('toggles devtools on F12 in development', () => {
|
|
isMock.dev = true
|
|
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn(),
|
|
isDevToolsOpened: vi.fn(() => false),
|
|
openDevTools: vi.fn(),
|
|
closeDevTools: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn(),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null)
|
|
|
|
const preventDefault = vi.fn()
|
|
windowHandlers['before-input-event'](
|
|
{ preventDefault } as never,
|
|
{ type: 'keyDown', code: 'F12', key: 'F12', meta: false, control: false, alt: false } as never
|
|
)
|
|
|
|
expect(preventDefault).toHaveBeenCalledTimes(1)
|
|
expect(webContents.openDevTools).toHaveBeenCalledWith({ mode: 'undocked' })
|
|
expect(webContents.closeDevTools).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('clears the quit latch when the renderer prevents unload', () => {
|
|
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
|
const webContents = {
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
setZoomLevel: vi.fn(),
|
|
setBackgroundThrottling: vi.fn(),
|
|
invalidate: vi.fn(),
|
|
setWindowOpenHandler: vi.fn(),
|
|
send: vi.fn()
|
|
}
|
|
const browserWindowInstance = {
|
|
webContents,
|
|
on: vi.fn((event, handler) => {
|
|
windowHandlers[event] = handler
|
|
}),
|
|
isDestroyed: vi.fn(() => false),
|
|
isMaximized: vi.fn(() => true),
|
|
isFullScreen: vi.fn(() => false),
|
|
getSize: vi.fn(() => [1200, 800]),
|
|
setSize: vi.fn(),
|
|
maximize: vi.fn(),
|
|
show: vi.fn(),
|
|
loadFile: vi.fn(),
|
|
loadURL: vi.fn()
|
|
}
|
|
const onQuitAborted = vi.fn()
|
|
browserWindowMock.mockImplementation(function () {
|
|
return browserWindowInstance
|
|
})
|
|
|
|
createMainWindow(null, { getIsQuitting: () => true, onQuitAborted })
|
|
|
|
const preventDefault = vi.fn()
|
|
windowHandlers.close({ preventDefault } as never)
|
|
expect(preventDefault).toHaveBeenCalledTimes(1)
|
|
expect(webContents.send).toHaveBeenCalledWith('window:close-requested', { isQuitting: true })
|
|
|
|
windowHandlers['will-prevent-unload']()
|
|
expect(onQuitAborted).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|