mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
test: remove low-value authoring, CLI, and preload suites
This commit is contained in:
@@ -4210,7 +4210,6 @@
|
||||
"src/preload/renderer-heap-statistics-reader.test.ts": 50,
|
||||
"src/preload/renderer-process-memory-reader.test.ts": 66,
|
||||
"src/preload/renderer-restart-wiring.test.ts": 96,
|
||||
"src/preload/runtime-environment-subscriptions.test.ts": 71,
|
||||
"src/preload/ssh-authority-forwarding.test.ts": 1111,
|
||||
"src/preload/updater-package-recovery.test.ts": 1102,
|
||||
"src/preload/usage-provider-api.test.ts": 46,
|
||||
@@ -6600,7 +6599,6 @@
|
||||
"src/shared/plugins/declarative/runtime/declarative-storage-sync.test.ts": 190,
|
||||
"src/shared/plugins/declarative/testing/orca-testing-hooks.test.ts": 506,
|
||||
"src/shared/plugins/declarative/testing/orca-testing-worker.test.ts": 480,
|
||||
"src/shared/plugins/declarative/testing/orca-testing.test.ts": 489,
|
||||
"src/shared/plugins/declarative/testing/testing-editor-host.test.ts": 197,
|
||||
"src/shared/plugins/frames/plugin-frame-document-session.test.ts": 404,
|
||||
"src/shared/plugins/frames/plugin-frame-document.test.ts": 426,
|
||||
@@ -6608,7 +6606,6 @@
|
||||
"src/shared/plugins/frames/plugin-panel-shell.test.ts": 376,
|
||||
"src/shared/plugins/images/plugin-image-format.test.ts": 104,
|
||||
"src/shared/plugins/images/plugin-image-url.test.ts": 42,
|
||||
"src/shared/plugins/installation/plugin-file-validation.test.ts": 363,
|
||||
"src/shared/plugins/manifest/plugin-display-text.test.ts": 285,
|
||||
"src/shared/plugins/manifest/plugin-manifest-v2-rules.test.ts": 239,
|
||||
"src/shared/plugins/manifest/plugin-manifest.test.ts": 234,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||
import { activateMobileUiLocale, mobileI18n } from '../i18n/mobile-i18n'
|
||||
import { textGenerationErrorText } from './text-generation-failure-copy'
|
||||
|
||||
beforeEach(async () => {
|
||||
mobileI18n.addResourceBundle('de', 'translation', {
|
||||
'sourceControl.textGenerationFailure.cliFailedWithDetail':
|
||||
'{{label}} fehlgeschlagen ({{exitCode}}): {{detail}}',
|
||||
'sourceControl.textGenerationFailure.noStagedChanges': 'Keine Änderungen vorgemerkt.',
|
||||
'sourceControl.textGenerationFailure.planModelUnavailable':
|
||||
'Modell {{model}} für {{label}} nicht verfügbar.',
|
||||
'sourceControl.textGenerationFailure.kimiConflictingOptions':
|
||||
'Kimi: {{option}} und {{otherOption}} widersprechen sich.'
|
||||
})
|
||||
await activateMobileUiLocale('de')
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await activateMobileUiLocale('en')
|
||||
mobileI18n.removeResourceBundle('de', 'translation')
|
||||
})
|
||||
|
||||
describe('textGenerationErrorText', () => {
|
||||
it('translates coded failures and preserves agent output verbatim', () => {
|
||||
expect(
|
||||
textGenerationErrorText({
|
||||
error: 'host error',
|
||||
errorCode: 'cliFailedWithDetail',
|
||||
errorParams: { label: 'Codex', exitCode: 0, detail: 'ignored' },
|
||||
errorDetail: '{{label}}: $t(secret) <stderr>'
|
||||
})
|
||||
).toBe('Codex fehlgeschlagen (0): {{label}}: $t(secret) <stderr>')
|
||||
expect(textGenerationErrorText({ error: 'host error', errorCode: 'noStagedChanges' })).toBe(
|
||||
'Keine Änderungen vorgemerkt.'
|
||||
)
|
||||
})
|
||||
|
||||
it.each([
|
||||
{},
|
||||
{ errorCode: 'newerHostCode' },
|
||||
{ errorCode: 'toString' },
|
||||
{ errorCode: 42 },
|
||||
{ errorCode: 'cliFailedWithDetail', errorParams: { label: 'Codex', exitCode: 1 } },
|
||||
{
|
||||
errorCode: 'cliFailedWithDetail',
|
||||
errorParams: { label: 'Codex', exitCode: null },
|
||||
errorDetail: 'detail'
|
||||
},
|
||||
{
|
||||
errorCode: 'cliFailedWithDetail',
|
||||
errorParams: { label: 'Codex', exitCode: 1, detail: 'not errorDetail' }
|
||||
},
|
||||
{ errorCode: 'agentCouldNotStart', errorParams: 'Codex' }
|
||||
])('keeps the host error when the code or required values are unavailable: %j', (fields) => {
|
||||
expect(textGenerationErrorText({ error: 'Host English', ...fields })).toBe('Host English')
|
||||
})
|
||||
})
|
||||
@@ -107,27 +107,3 @@ it('Windows automatic timeout joins tracked tree lifetime beyond the caller wait
|
||||
expect(spawn.mock.calls.every(([spec]) => spec.detached === false)).toBe(true)
|
||||
expect(vi.getTimerCount()).toBe(0)
|
||||
})
|
||||
|
||||
it('asynchronous spawn error releases readers before synchronous fallback failure and final refusal', async () => {
|
||||
const child = probe()
|
||||
spawn
|
||||
.mockImplementationOnce(() => {
|
||||
queueMicrotask(() => child.emit('error', new Error('ENOENT')))
|
||||
return child
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error('unlaunchable fallback')
|
||||
})
|
||||
const owner = session()
|
||||
await expect(resolveOpenCodeLoginCommand({}, owner)).rejects.toThrow(
|
||||
'Install alongside your existing CLI'
|
||||
)
|
||||
expect(spawn).toHaveBeenCalledTimes(2)
|
||||
expect(child.stdout.destroyed && child.stderr.destroyed && child.stdin.destroyed).toBe(true)
|
||||
expect(owner.child).toBeNull()
|
||||
expect(owner.stopPhase).toBeUndefined()
|
||||
expect(signalTree).not.toHaveBeenCalled()
|
||||
child.emit('error', new Error('late error'))
|
||||
child.emit('exit', 0)
|
||||
child.emit('close', 0)
|
||||
})
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { shouldUseRendererBackedCodexTerminal } from './codex-command-classification'
|
||||
|
||||
describe('shouldUseRendererBackedCodexTerminal', () => {
|
||||
it('keeps one-shot Codex commands on the background path', () => {
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex exec summarize')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex -m gpt-5 review')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex login status')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex login --with-api-key')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex cloud list --json')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex -c active=cloud cloud list --json')).toBe(
|
||||
false
|
||||
)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex cloud --enable foo list --json')).toBe(false)
|
||||
expect(
|
||||
shouldUseRendererBackedCodexTerminal(
|
||||
'env -u DEBUG CODEX_HOME=/tmp/codex codex exec summarize'
|
||||
)
|
||||
).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex cloud exec "fix it"')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex cloud --version')).toBe(false)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex --help')).toBe(false)
|
||||
})
|
||||
|
||||
it('reads --no-daemon as a flag, not the subcommand', () => {
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex --no-daemon resume --last')).toBe(true)
|
||||
expect(shouldUseRendererBackedCodexTerminal('codex --no-daemon exec summarize')).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -1,461 +0,0 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
subscribeRuntimeEnvironmentFromPreload,
|
||||
subscribeCrewAttemptFromPreload,
|
||||
cancelRuntimeEnvironmentSubscriptionFromPreload
|
||||
} from './runtime-environment-subscriptions'
|
||||
|
||||
function deferred<T>(): {
|
||||
promise: Promise<T>
|
||||
resolve: (value: T) => void
|
||||
reject: (error: unknown) => void
|
||||
} {
|
||||
let resolve!: (value: T) => void
|
||||
let reject!: (error: unknown) => void
|
||||
const promise = new Promise<T>((promiseResolve, promiseReject) => {
|
||||
resolve = promiseResolve
|
||||
reject = promiseReject
|
||||
})
|
||||
return { promise, resolve, reject }
|
||||
}
|
||||
|
||||
type SubscriptionEvent =
|
||||
| {
|
||||
subscriptionId: string
|
||||
type: 'response'
|
||||
response: { ok: true; id: string; result: unknown; _meta: { runtimeId: string } }
|
||||
}
|
||||
| { subscriptionId: string; type: 'binary'; bytes: Uint8Array<ArrayBufferLike> }
|
||||
| { subscriptionId: string; type: 'error'; code: string; message: string }
|
||||
| { subscriptionId: string; type: 'close' }
|
||||
|
||||
type SubscriptionEventListener = (_event: unknown, payload: SubscriptionEvent) => void
|
||||
|
||||
function createIpc() {
|
||||
const listeners = new Set<SubscriptionEventListener>()
|
||||
return {
|
||||
invoke: vi.fn((_channel: string, _args?: unknown) => Promise.resolve({}) as Promise<unknown>),
|
||||
send: vi.fn(),
|
||||
on: vi.fn((_channel: string, listener: SubscriptionEventListener) => {
|
||||
listeners.add(listener)
|
||||
}),
|
||||
removeListener: vi.fn((_channel: string, listener: SubscriptionEventListener) => {
|
||||
listeners.delete(listener)
|
||||
}),
|
||||
emitSubscriptionEvent: (event: SubscriptionEvent): void => {
|
||||
const currentListeners = Array.from(listeners)
|
||||
for (const listener of currentListeners) {
|
||||
listener(null, event)
|
||||
}
|
||||
},
|
||||
listenerCount: (): number => listeners.size
|
||||
}
|
||||
}
|
||||
|
||||
function dispatch(ipc: ReturnType<typeof createIpc>, event: SubscriptionEvent): void {
|
||||
ipc.emitSubscriptionEvent(event)
|
||||
}
|
||||
|
||||
describe('subscribeRuntimeEnvironmentFromPreload', () => {
|
||||
it('registers the subscription event listener before invoking main', async () => {
|
||||
const subscription = deferred<{ subscriptionId: string; requestId: string }>()
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? (subscription.promise as Promise<unknown>)
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onResponse = vi.fn()
|
||||
const onBinary = vi.fn()
|
||||
|
||||
const cleanupPromise = subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'terminal.subscribe' },
|
||||
{ onResponse, onBinary },
|
||||
() => 'sub-1'
|
||||
)
|
||||
|
||||
expect(ipc.on).toHaveBeenCalledWith(
|
||||
'runtimeEnvironments:subscriptionEvent',
|
||||
expect.any(Function)
|
||||
)
|
||||
expect(ipc.invoke).toHaveBeenCalledWith('runtimeEnvironments:subscribe', {
|
||||
selector: 'desk',
|
||||
method: 'terminal.subscribe',
|
||||
subscriptionId: 'sub-1'
|
||||
})
|
||||
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-1',
|
||||
type: 'response',
|
||||
response: {
|
||||
id: 'rpc-1',
|
||||
ok: true,
|
||||
result: { type: 'subscribed' },
|
||||
_meta: { runtimeId: 'rt' }
|
||||
}
|
||||
})
|
||||
expect(onResponse).toHaveBeenCalledWith({
|
||||
id: 'rpc-1',
|
||||
ok: true,
|
||||
result: { type: 'subscribed' },
|
||||
_meta: { runtimeId: 'rt' }
|
||||
})
|
||||
const inboundBytes = new Uint8Array([4, 5, 6])
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-1',
|
||||
type: 'binary',
|
||||
bytes: inboundBytes
|
||||
})
|
||||
expect(onBinary).toHaveBeenCalledWith(inboundBytes)
|
||||
|
||||
subscription.resolve({ subscriptionId: 'sub-1', requestId: 'rpc-1' })
|
||||
const cleanup = await cleanupPromise
|
||||
const bytes = new Uint8Array([1, 2, 3])
|
||||
cleanup.sendBinary(bytes)
|
||||
expect(ipc.send).toHaveBeenCalledWith('runtimeEnvironments:subscriptionBinary', {
|
||||
subscriptionId: 'sub-1',
|
||||
bytes
|
||||
})
|
||||
cleanup.unsubscribe()
|
||||
expect(ipc.invoke).toHaveBeenCalledWith('runtimeEnvironments:unsubscribe', {
|
||||
subscriptionId: 'sub-1'
|
||||
})
|
||||
expect(ipc.removeListener).toHaveBeenCalledWith(
|
||||
'runtimeEnvironments:subscriptionEvent',
|
||||
ipc.on.mock.calls[0][1]
|
||||
)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
|
||||
onResponse.mockClear()
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-1',
|
||||
type: 'response',
|
||||
response: { id: 'rpc-2', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
expect(onResponse).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shares a single channel listener across many subscriptions on one ipc', async () => {
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string, args: unknown) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? Promise.resolve({
|
||||
subscriptionId: (args as { subscriptionId: string }).subscriptionId,
|
||||
requestId: 'rpc'
|
||||
})
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
|
||||
let counter = 0
|
||||
const onResponses = Array.from({ length: 25 }, () => vi.fn())
|
||||
const handles = await Promise.all(
|
||||
onResponses.map((onResponse) =>
|
||||
subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'session.tabs.subscribe' },
|
||||
{ onResponse },
|
||||
() => `sub-${counter++}`
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
expect(ipc.on).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.removeListener).not.toHaveBeenCalled()
|
||||
expect(handles).toHaveLength(25)
|
||||
|
||||
handles[0].unsubscribe()
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-0',
|
||||
type: 'response',
|
||||
response: { id: 'rpc', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-1',
|
||||
type: 'response',
|
||||
response: { id: 'rpc', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
expect(onResponses[0]).not.toHaveBeenCalled()
|
||||
expect(onResponses[1]).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.removeListener).not.toHaveBeenCalled()
|
||||
expect(ipc.listenerCount()).toBe(1)
|
||||
|
||||
for (const handle of handles.slice(1)) {
|
||||
handle.unsubscribe()
|
||||
}
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
})
|
||||
|
||||
it('keeps the subscription mapped on error frames but releases it on unsubscribe', async () => {
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? Promise.resolve({ subscriptionId: 'sub-err', requestId: 'rpc-err' })
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onResponse = vi.fn()
|
||||
const onError = vi.fn()
|
||||
|
||||
const cleanup = await subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'runtime.clientEvents.subscribe' },
|
||||
{ onResponse, onError },
|
||||
() => 'sub-err'
|
||||
)
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-err',
|
||||
type: 'error',
|
||||
code: 'TIMEOUT',
|
||||
message: 'Timed out waiting for the remote Orca runtime to respond.'
|
||||
})
|
||||
}
|
||||
expect(onError).toHaveBeenCalledTimes(50)
|
||||
expect(ipc.removeListener).not.toHaveBeenCalled()
|
||||
expect(ipc.listenerCount()).toBe(1)
|
||||
|
||||
cleanup.unsubscribe()
|
||||
expect(ipc.invoke).toHaveBeenCalledWith('runtimeEnvironments:unsubscribe', {
|
||||
subscriptionId: 'sub-err'
|
||||
})
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
onError.mockClear()
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-err',
|
||||
type: 'error',
|
||||
code: 'TIMEOUT',
|
||||
message: 'still erroring'
|
||||
})
|
||||
expect(onError).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('removes the subscription from dispatch when main rejects the subscribe call', async () => {
|
||||
const subscription = deferred<{ subscriptionId: string; requestId: string }>()
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? (subscription.promise as Promise<unknown>)
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onResponse = vi.fn()
|
||||
|
||||
const cleanupPromise = subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'terminal.subscribe' },
|
||||
{ onResponse },
|
||||
() => 'sub-2'
|
||||
)
|
||||
|
||||
const error = new Error('subscribe failed')
|
||||
subscription.reject(error)
|
||||
await expect(cleanupPromise).rejects.toThrow(error)
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-2',
|
||||
type: 'response',
|
||||
response: { id: 'rpc', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
expect(onResponse).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('releases the subscription from dispatch when main resolves a different id', async () => {
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? Promise.resolve({ subscriptionId: 'sub-other', requestId: 'rpc' })
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onResponse = vi.fn()
|
||||
|
||||
await expect(
|
||||
subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'terminal.subscribe' },
|
||||
{ onResponse },
|
||||
() => 'sub-expected'
|
||||
)
|
||||
).rejects.toThrow('Runtime environment subscription id mismatch')
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'sub-expected',
|
||||
type: 'response',
|
||||
response: { id: 'rpc', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
expect(onResponse).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('releases the subscription when main reports the remote subscription closed', async () => {
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? Promise.resolve({ subscriptionId: 'sub-closed', requestId: 'rpc-closed' })
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onClose = vi.fn()
|
||||
|
||||
const cleanup = await subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'terminal.subscribe' },
|
||||
{ onResponse: vi.fn(), onClose },
|
||||
() => 'sub-closed'
|
||||
)
|
||||
|
||||
dispatch(ipc, { subscriptionId: 'other-sub', type: 'close' })
|
||||
expect(onClose).not.toHaveBeenCalled()
|
||||
|
||||
dispatch(ipc, { subscriptionId: 'sub-closed', type: 'close' })
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
|
||||
onClose.mockClear()
|
||||
cleanup.unsubscribe()
|
||||
dispatch(ipc, { subscriptionId: 'sub-closed', type: 'close' })
|
||||
expect(onClose).not.toHaveBeenCalled()
|
||||
expect(ipc.invoke).toHaveBeenCalledWith('runtimeEnvironments:unsubscribe', {
|
||||
subscriptionId: 'sub-closed'
|
||||
})
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('releases close frames before calling onClose', async () => {
|
||||
const ipc = createIpc()
|
||||
ipc.invoke.mockImplementation((channel: string) =>
|
||||
channel === 'runtimeEnvironments:subscribe'
|
||||
? Promise.resolve({ subscriptionId: 'sub-throw', requestId: 'rpc-throw' })
|
||||
: (Promise.resolve({}) as Promise<unknown>)
|
||||
)
|
||||
const onClose = vi.fn(() => {
|
||||
throw new Error('close failed')
|
||||
})
|
||||
|
||||
await subscribeRuntimeEnvironmentFromPreload(
|
||||
ipc,
|
||||
{ selector: 'desk', method: 'terminal.subscribe' },
|
||||
{ onResponse: vi.fn(), onClose },
|
||||
() => 'sub-throw'
|
||||
)
|
||||
|
||||
expect(() => dispatch(ipc, { subscriptionId: 'sub-throw', type: 'close' })).toThrow(
|
||||
'close failed'
|
||||
)
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('opt-in crew setup registration', () => {
|
||||
const args = {
|
||||
selector: 'desk',
|
||||
method: 'orchestration.crewSubscribe',
|
||||
subscriptionId: 'crew',
|
||||
expectedEnvironmentPairingRevision: 1,
|
||||
expectedEnvironmentRuntimeId: null
|
||||
} as const
|
||||
|
||||
it('forwards plain failure after a terminal event and releases the exact registration', async () => {
|
||||
const ipc = createIpc()
|
||||
const pending = deferred<unknown>()
|
||||
ipc.invoke.mockReturnValue(pending.promise)
|
||||
const onClose = vi.fn()
|
||||
const onError = vi.fn()
|
||||
const first = subscribeCrewAttemptFromPreload(ipc, args, {
|
||||
onResponse: vi.fn(),
|
||||
onClose,
|
||||
onError
|
||||
})
|
||||
expect(ipc.invoke).toHaveBeenCalledWith('runtimeEnvironments:subscribe', {
|
||||
...args,
|
||||
setupResult: 'crew'
|
||||
})
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'crew',
|
||||
type: 'error',
|
||||
code: 'remote_runtime_unavailable',
|
||||
message: 'offline'
|
||||
})
|
||||
dispatch(ipc, { subscriptionId: 'crew', type: 'close' })
|
||||
const failure = {
|
||||
subscriptionId: 'crew',
|
||||
ok: false,
|
||||
failure: { message: 'revoked', fact: { kind: 'remote', code: 'unauthorized' } }
|
||||
}
|
||||
pending.resolve(failure)
|
||||
await expect(first).resolves.toBe(failure)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
expect(onError).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('releases cancelled registrations while held invoke tails settle in either order', async () => {
|
||||
const count = 2
|
||||
const ipc = createIpc()
|
||||
const held = Array.from({ length: count }, () => deferred<unknown>())
|
||||
let next = 0
|
||||
ipc.invoke.mockImplementation((channel) =>
|
||||
channel === 'runtimeEnvironments:subscribe' ? held[next++].promise : Promise.resolve({})
|
||||
)
|
||||
const responses = vi.fn()
|
||||
const attempts = held.map((_, index) =>
|
||||
subscribeCrewAttemptFromPreload(
|
||||
ipc,
|
||||
{ ...args, subscriptionId: `crew-${index}` },
|
||||
{ onResponse: responses }
|
||||
).catch((error: unknown) => error)
|
||||
)
|
||||
expect(ipc.listenerCount()).toBe(1)
|
||||
for (let index = 0; index < count; index++) {
|
||||
await cancelRuntimeEnvironmentSubscriptionFromPreload(ipc, `crew-${index}`)
|
||||
}
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
expect(ipc.on).toHaveBeenCalledTimes(1)
|
||||
expect(ipc.removeListener).toHaveBeenCalledTimes(1)
|
||||
for (let index = 0; index < count; index++) {
|
||||
if (index % 2) {
|
||||
held[index].reject(new Error('late invoke rejection'))
|
||||
} else {
|
||||
held[index].resolve({ subscriptionId: `crew-${index}`, ok: true })
|
||||
}
|
||||
dispatch(ipc, {
|
||||
subscriptionId: `crew-${index}`,
|
||||
type: 'response',
|
||||
response: { id: 'late', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
}
|
||||
await Promise.all(attempts)
|
||||
expect(ipc.listenerCount()).toBe(0)
|
||||
expect(responses).not.toHaveBeenCalled()
|
||||
expect(ipc.invoke).toHaveBeenCalledTimes(count * 2)
|
||||
})
|
||||
|
||||
it('keeps a replacement registration when an old cancelled invoke later rejects', async () => {
|
||||
const ipc = createIpc()
|
||||
const old = deferred<unknown>()
|
||||
ipc.invoke.mockImplementation((channel) =>
|
||||
channel === 'runtimeEnvironments:subscribe' ? old.promise : Promise.resolve({})
|
||||
)
|
||||
const first = subscribeCrewAttemptFromPreload(ipc, args, { onResponse: vi.fn() })
|
||||
const rejected = expect(first).rejects.toThrow('old invoke')
|
||||
await cancelRuntimeEnvironmentSubscriptionFromPreload(ipc, 'crew')
|
||||
ipc.invoke.mockResolvedValue({ subscriptionId: 'crew', ok: true })
|
||||
const response = vi.fn()
|
||||
await subscribeCrewAttemptFromPreload(ipc, args, { onResponse: response })
|
||||
old.reject(new Error('old invoke'))
|
||||
await rejected
|
||||
dispatch(ipc, {
|
||||
subscriptionId: 'crew',
|
||||
type: 'response',
|
||||
response: { id: 'current', ok: true, result: {}, _meta: { runtimeId: 'rt' } }
|
||||
})
|
||||
expect(response).toHaveBeenCalledOnce()
|
||||
expect(ipc.listenerCount()).toBe(1)
|
||||
await cancelRuntimeEnvironmentSubscriptionFromPreload(ipc, 'crew')
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,4 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { terminalSendHookPayloadSchema } from '../../events/plugin-hook-payloads'
|
||||
import { atom, read, set } from '../runtime/declarative-atoms'
|
||||
import { h } from '../runtime/declarative-elements'
|
||||
import { plugin } from '../runtime/orca-module'
|
||||
@@ -20,60 +19,12 @@ type Orca = {
|
||||
storage: { set(key: string, value: unknown): Promise<void> }
|
||||
}
|
||||
|
||||
type HookedOrca = Orca & {
|
||||
hooks: {
|
||||
on(hook: string, handler: (event: unknown, next: (e: unknown) => unknown) => unknown): unknown
|
||||
}
|
||||
}
|
||||
|
||||
let panel: TestPanel | null = null
|
||||
afterEach(async () => {
|
||||
await panel?.unmount()
|
||||
panel = null
|
||||
})
|
||||
|
||||
describe('mountWorker', () => {
|
||||
it('fires hooks as Orca would and returns what the chain decided', async () => {
|
||||
const mounted = await mountWorker(
|
||||
{
|
||||
default(orca: HookedOrca) {
|
||||
orca.hooks.on('terminal.send', (event, next) => {
|
||||
const { text } = terminalSendHookPayloadSchema.parse(event)
|
||||
if (text.includes('rm -rf')) {
|
||||
return { deny: 'blocked' }
|
||||
}
|
||||
if (text === 'boom') {
|
||||
throw new Error('hook failed')
|
||||
}
|
||||
return next({ ...terminalSendHookPayloadSchema.parse(event), text: text.trim() })
|
||||
})
|
||||
}
|
||||
},
|
||||
{ events: [], commands: [], hooks: ['terminal.send'] }
|
||||
)
|
||||
const send = (text: string) => ({ terminalId: 't', text, enter: true, inputKind: 'driving' })
|
||||
await expect(mounted.hooks.fire('terminal.send', send(' ls '))).resolves.toEqual({
|
||||
kind: 'continue',
|
||||
event: send('ls')
|
||||
})
|
||||
await expect(mounted.hooks.fire('terminal.send', send('rm -rf /'))).resolves.toEqual({
|
||||
kind: 'deny',
|
||||
reason: 'blocked'
|
||||
})
|
||||
await expect(mounted.hooks.fire('terminal.send', send('boom'))).resolves.toEqual({
|
||||
kind: 'continue',
|
||||
event: send('boom')
|
||||
})
|
||||
expect(mounted.logs.at(-1)).toMatch(/hook terminal\.send skipped after \d+ms: hook failed/)
|
||||
await expect(mounted.hooks.fire('terminal.send', { text: 1 })).rejects.toThrow(
|
||||
/not one Orca sends/
|
||||
)
|
||||
await expect(mounted.hooks.fire('workspace.create.after', {})).rejects.toThrow(
|
||||
/not in contributes.hooks/
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('a panel and its worker on one host', () => {
|
||||
it("routes the panel's plugin.request to the mounted worker, unless `requests` stubs it", async () => {
|
||||
const host = mockHost({ capabilities: [], requests: { stubbed: 'from the stub' } })
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { atom, read, set, update } from '../runtime/declarative-atoms'
|
||||
import { h } from '../runtime/declarative-elements'
|
||||
|
||||
import { mount, stored, type TestPanel } from './orca-testing'
|
||||
|
||||
let panel: TestPanel | null = null
|
||||
afterEach(async () => {
|
||||
await panel?.unmount()
|
||||
panel = null
|
||||
})
|
||||
|
||||
const count = atom('testing.count', 0, { persist: 'plugin' })
|
||||
const draft = atom('')
|
||||
const done = atom(false)
|
||||
|
||||
function Counter() {
|
||||
return h(
|
||||
'Stack',
|
||||
null,
|
||||
h('Heading', null, `Count ${read(count)}`),
|
||||
h('Button', { key: 'add', onPress: () => update(count, (n) => n + 1) }, 'Add'),
|
||||
h('Input', {
|
||||
label: 'Title',
|
||||
value: read(draft),
|
||||
onChange: (value: string) => set(draft, value),
|
||||
onSubmit: () => set(draft, '')
|
||||
}),
|
||||
h('Switch', {
|
||||
label: 'Done',
|
||||
checked: read(done),
|
||||
onChange: (value: boolean) => set(done, value)
|
||||
}),
|
||||
h('Select', {
|
||||
label: 'Size',
|
||||
defaultValue: 's',
|
||||
options: [
|
||||
{ value: 's', label: 'Small' },
|
||||
{ value: 'l', label: 'Large' },
|
||||
{ value: 'x', label: 'Huge', disabled: true }
|
||||
],
|
||||
onChange: () => undefined
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
describe('orca/testing', () => {
|
||||
it('starts each mount fresh and hydrates persisted values, migrating old versions', async () => {
|
||||
panel = await mount(Counter, { persisted: { plugin: { 'testing.count': 41 } } })
|
||||
expect(panel.find({ role: 'heading' })?.text).toBe('Count 41')
|
||||
await panel.unmount()
|
||||
panel = await mount(Counter)
|
||||
expect(panel.find({ role: 'heading' })?.text).toBe('Count 0')
|
||||
const legacy = atom('testing.legacy', 'new', {
|
||||
persist: 'plugin',
|
||||
version: 2,
|
||||
migrate: (old) => `migrated ${String(old)}`
|
||||
})
|
||||
await panel.unmount()
|
||||
panel = await mount(() => h('Text', null, read(legacy)), {
|
||||
persisted: { plugin: { 'testing.legacy': stored('v1', 1) } }
|
||||
})
|
||||
expect(panel.tree()).toEqual({ type: 'Text', children: ['migrated v1'] })
|
||||
})
|
||||
|
||||
it("reports a render Orca would refuse and the plugin's own errors", async () => {
|
||||
panel = await mount(() => h('List', null, h('Text', null, 'not an item')))
|
||||
expect(panel.errors).toEqual([
|
||||
expect.objectContaining({ kind: 'refused', message: expect.stringContaining('ListItem') })
|
||||
])
|
||||
await panel.unmount()
|
||||
panel = await mount(() =>
|
||||
h(
|
||||
'Button',
|
||||
{
|
||||
onPress: () => {
|
||||
throw new Error('boom')
|
||||
}
|
||||
},
|
||||
'x'
|
||||
)
|
||||
)
|
||||
await panel.press({ role: 'button' })
|
||||
expect(panel.errors).toEqual([
|
||||
{ kind: 'plugin', message: 'boom', stack: expect.stringContaining('orca-testing.test.ts') }
|
||||
])
|
||||
await panel.unmount()
|
||||
panel = await mount(() => h('Text', { color: 'red' }, 'x'))
|
||||
expect(panel.warnings).toEqual(['Text: ignored unknown prop "color"'])
|
||||
})
|
||||
|
||||
it('fails a test that never settles instead of hanging', async () => {
|
||||
const ticks = atom(0)
|
||||
const loop = () => {
|
||||
queueMicrotask(() => update(ticks, (n) => n + 1))
|
||||
return h('Text', null, String(read(ticks)))
|
||||
}
|
||||
await expect(mount(loop)).rejects.toThrow(/did not settle/)
|
||||
})
|
||||
})
|
||||
@@ -17,17 +17,6 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('mockEditorHost', () => {
|
||||
it('installs orca with the real document session over an in-memory file', async () => {
|
||||
host = mockEditorHost({ text: 'a' })
|
||||
const doc = await session()
|
||||
expect(doc.value).toBe('a')
|
||||
doc.change('ab')
|
||||
await host.flush()
|
||||
expect(host.text).toBe('ab')
|
||||
expect(host.edits).toEqual([{ baseVersion: 1, content: { kind: 'text', text: 'ab' } }])
|
||||
doc.dispose()
|
||||
})
|
||||
|
||||
it('sends outside changes and refuses the next edit on conflictNext', async () => {
|
||||
host = mockEditorHost({ text: 'a' })
|
||||
const replaced: unknown[] = []
|
||||
@@ -46,26 +35,6 @@ describe('mockEditorHost', () => {
|
||||
expect(replaced.at(-1)).toBe('agentoutside!')
|
||||
doc.dispose()
|
||||
})
|
||||
|
||||
it('backs a bytes editor, follows the theme, and removes orca on dispose', async () => {
|
||||
host = mockEditorHost({ bytes: new Uint8Array([1]) }, { fileType: 'bin', colorScheme: 'light' })
|
||||
const doc = await session({
|
||||
decode: (content: { bytes: ArrayBuffer }) => [...new Uint8Array(content.bytes)],
|
||||
encode: (value: number[]) => ({ kind: 'bytes', bytes: new Uint8Array(value).buffer })
|
||||
})
|
||||
expect(doc.value).toEqual([1])
|
||||
doc.change([2, 3])
|
||||
await host.flush()
|
||||
expect([...(host.bytes ?? [])]).toEqual([2, 3])
|
||||
const themes: unknown[] = []
|
||||
host.orca.on('theme', (theme) => themes.push(theme))
|
||||
host.setTheme('dark')
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
expect(themes).toEqual([{ colorScheme: 'dark' }])
|
||||
doc.dispose()
|
||||
host.dispose()
|
||||
expect('orca' in globalThis).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('mockEditorHost saves as Orca does', () => {
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { catalogEntryFixture, catalogFixture } from '../manifest/plugin-json-schema.test-fixture'
|
||||
import { validatePluginFile } from './plugin-file-validation'
|
||||
|
||||
const VALID_RELEASE = {
|
||||
version: '1.0.0',
|
||||
commit: 'a'.repeat(40),
|
||||
contentHash: 'b'.repeat(64),
|
||||
execution: 'data',
|
||||
minimumOrca: '1.4.0',
|
||||
types: ['syntax']
|
||||
}
|
||||
|
||||
describe('validatePluginFile', () => {
|
||||
it('turns every runtime repair of a catalog into an error', () => {
|
||||
const errors = validatePluginFile(
|
||||
'orca-catalog.json',
|
||||
catalogFixture([
|
||||
catalogEntryFixture({ categories: ['syntax', 'syntax'], description: 5 }),
|
||||
catalogEntryFixture(),
|
||||
catalogEntryFixture({
|
||||
id: 'acme.other',
|
||||
releases: [{ ...VALID_RELEASE, commit: 'v1.0.0' }, VALID_RELEASE]
|
||||
}),
|
||||
catalogEntryFixture({ id: 'acme.broken', releases: [] })
|
||||
])
|
||||
)
|
||||
expect(errors).toEqual([
|
||||
'plugins[0].categories: has invalid, repeated or extra categories',
|
||||
'plugins[0].description: must be text of 1 to 4096 characters',
|
||||
'plugins[1].id: duplicate plugin id acme.gleam-syntax',
|
||||
'plugins[2].releases[0]: commit: must be a full lowercase SHA-1 commit',
|
||||
'plugins[3]: releases: needs at least one release this Orca can read'
|
||||
])
|
||||
})
|
||||
|
||||
it('checks catalog images against the files in the catalog repository', () => {
|
||||
const be32 = (n: number) => [n >>> 24, (n >>> 16) & 255, (n >>> 8) & 255, n & 255]
|
||||
const png = (w: number, h: number) =>
|
||||
Uint8Array.from([
|
||||
0x89,
|
||||
0x50,
|
||||
0x4e,
|
||||
0x47,
|
||||
0x0d,
|
||||
0x0a,
|
||||
0x1a,
|
||||
0x0a,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
13,
|
||||
73,
|
||||
72,
|
||||
68,
|
||||
82,
|
||||
...be32(w),
|
||||
...be32(h),
|
||||
8,
|
||||
6,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
])
|
||||
const files: Record<string, { bytes: Uint8Array; sha256: string }> = {
|
||||
'assets/cover.png': { bytes: png(1600, 1000), sha256: 'c'.repeat(64) },
|
||||
'assets/icon.png': { bytes: png(512, 512), sha256: 'd'.repeat(64) }
|
||||
}
|
||||
const image = (path: string, sha256: string, width: number, height: number) => ({
|
||||
path,
|
||||
alt: 'An image',
|
||||
sha256,
|
||||
width,
|
||||
height
|
||||
})
|
||||
const catalog = catalogFixture([
|
||||
catalogEntryFixture(
|
||||
{},
|
||||
{
|
||||
images: {
|
||||
icon: image('assets/icon.png', 'd'.repeat(64), 256, 256),
|
||||
cover: image('assets/cover.png', 'e'.repeat(64), 1600, 1000),
|
||||
screenshots: [image('assets/missing.png', 'f'.repeat(64), 1600, 1000)]
|
||||
}
|
||||
}
|
||||
)
|
||||
])
|
||||
expect(validatePluginFile('orca-catalog.json', catalog, (path) => files[path] ?? null)).toEqual(
|
||||
[
|
||||
'plugins[0].releases[0].images.icon: is 512×512, not 256×256',
|
||||
'plugins[0].releases[0].images.cover: sha256 does not match assets/cover.png',
|
||||
'plugins[0].releases[0].images.screenshots[0]: assets/missing.png is missing from the catalog repository'
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user