diff --git a/packages/ai/src/ai-actions/__tests__/editor/editor-adapter.test.ts b/packages/ai/src/ai-actions/__tests__/editor/editor-adapter.test.ts index eb20a47ddf..1255cf4bdc 100644 --- a/packages/ai/src/ai-actions/__tests__/editor/editor-adapter.test.ts +++ b/packages/ai/src/ai-actions/__tests__/editor/editor-adapter.test.ts @@ -203,6 +203,9 @@ describe('EditorAdapter', () => { editorState = newState; }, view, + dispatch: vi.fn((tr) => { + editorState = editorState.apply(tr); + }), exportDocx: vi.fn().mockResolvedValue({}), options: { documentId: 'doc-123', @@ -562,6 +565,41 @@ describe('EditorAdapter', () => { (mockAdapter as unknown as { applyPatch: () => void }).applyPatch = originalApply; }); + + it('applies tracked change in headless mode (no view)', () => { + let headlessState = createEditorState([{ text: 'original' }]); + const headlessEditor = { + get state() { + return headlessState; + }, + set state(newState) { + headlessState = newState; + }, + view: undefined, + dispatch: vi.fn((tr) => { + headlessState = headlessState.apply(tr); + }), + options: { + documentId: 'headless-doc', + user: { name: 'Test User', image: '' }, + }, + commands: { + enableTrackChanges: vi.fn(), + disableTrackChanges: vi.fn(), + }, + chain: vi.fn(), + } as unknown as Editor; + + const headlessAdapter = new EditorAdapter(headlessEditor); + const from = 1; + const to = headlessState.doc.content.size - 1; + + const changeId = headlessAdapter.createTrackedChange(from, to, 'tracked'); + + expect(changeId).toMatch(/^tracked-change-/); + expect(headlessEditor.dispatch).toHaveBeenCalled(); + expect(headlessState.doc.textContent).toBe('tracked'); + }); }); describe('createComment', () => { diff --git a/packages/ai/src/ai-actions/__tests__/services/ai-actions-service.test.ts b/packages/ai/src/ai-actions/__tests__/services/ai-actions-service.test.ts index 29cdd68696..07d30df74f 100644 --- a/packages/ai/src/ai-actions/__tests__/services/ai-actions-service.test.ts +++ b/packages/ai/src/ai-actions/__tests__/services/ai-actions-service.test.ts @@ -101,6 +101,7 @@ describe('AIActionsService', () => { }; }), }, + dispatch: vi.fn(), exportDocx: vi.fn(), options: { documentId: 'doc-123', @@ -267,7 +268,7 @@ describe('AIActionsService', () => { const result = await actions.replace('replace old with new'); expect(result.success).toBe(true); - expect(mockEditor.view?.dispatch).toHaveBeenCalled(); + expect(mockEditor.dispatch).toHaveBeenCalled(); }); it('should validate input', async () => { @@ -326,7 +327,7 @@ describe('AIActionsService', () => { expect(result.success).toBe(true); expect(result.results).toHaveLength(2); expect(result.results[0].originalText).toBe('A'); - expect(mockEditor.view?.dispatch).toHaveBeenCalled(); + expect(mockEditor.dispatch).toHaveBeenCalled(); expect(trackedSpy).not.toHaveBeenCalled(); }); @@ -658,7 +659,7 @@ describe('AIActionsService', () => { const result = await actions.insertContent('generate introduction'); expect(result.success).toBe(true); - expect(mockEditor.view?.dispatch).toHaveBeenCalled(); + expect(mockEditor.dispatch).toHaveBeenCalled(); }); it('should validate input', async () => { @@ -765,7 +766,7 @@ describe('AIActionsService', () => { const result = await actions.insertContent('generate introduction'); expect(result.success).toBe(true); - expect(mockEditor.view?.dispatch).toHaveBeenCalled(); + expect(mockEditor.dispatch).toHaveBeenCalled(); expect(onStreamChunk).toHaveBeenCalledWith('Generated content'); }); diff --git a/packages/ai/src/ai-actions/editor/editor-adapter.ts b/packages/ai/src/ai-actions/editor/editor-adapter.ts index 4f502b87c5..25c7fcbfb7 100644 --- a/packages/ai/src/ai-actions/editor/editor-adapter.ts +++ b/packages/ai/src/ai-actions/editor/editor-adapter.ts @@ -604,8 +604,8 @@ export class EditorAdapter { * @private */ private applyPatch(from: number, to: number, suggestedText: string): void { - const { state, view } = this.editor; - if (!state || !view) { + const { state } = this.editor; + if (!state) { return; } @@ -638,7 +638,8 @@ export class EditorAdapter { tr.insert(insertPos, node); insertPos += node.nodeSize; } - view.dispatch(tr); + + this.editor.dispatch(tr); } /** @@ -675,6 +676,7 @@ export class EditorAdapter { this.editor.commands.disableTrackChanges(); } } + return changeId; }