import { afterEach, describe, expect, it } from 'vitest' import { mockEditorHost, type MockEditorHost } from './testing-editor-host' import type { MockEditorSession, MockEditorSessionOptions } from './testing-editor-frame-api' /** `orca.document.session(options)` on the installed host, as an editor would call it. */ function session(options: MockEditorSessionOptions = {}): Promise { if (!host) { throw new Error('no mockEditorHost') } return host.orca.document.session({ debounceMs: 0, ...options }) } let host: MockEditorHost | null = null afterEach(() => { host?.dispose() host = null }) 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[] = [] const doc = await session({ merge: (_base: string, outside: string, mine: string) => outside + mine }) doc.onReplace((value) => replaced.push(value)) host.replace('outside') await new Promise((resolve) => setTimeout(resolve, 0)) expect(replaced).toEqual(['outside']) host.conflictNext('agent') doc.change('outside!') await doc.flush() expect(host.edits.map((edit) => edit.refused ?? 'applied')).toEqual(['conflict', 'applied']) expect(host.text).toBe('agentoutside!') 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', () => { it('blocks a save after an oversized edit until a later edit lands', async () => { host = mockEditorHost({ text: 'a' }) const { document } = host.orca const send = (text: string): Promise => document.applyEdit({ baseVersion: 1, content: { kind: 'text', text } }) await session() await expect(send('x'.repeat(64 * 1024 * 1024 + 1))).rejects.toMatchObject({ code: 'too_large' }) await expect(host.flush()).rejects.toThrow(/too large/) await send('fits') await expect(host.flush()).resolves.toBeUndefined() expect(host.text).toBe('fits') }) })