From 91bb63653044c0b78256da7d147e14956b76225c Mon Sep 17 00:00:00 2001 From: Neil Date: Mon, 5 Oct 2026 05:09:46 -0700 Subject: [PATCH] test(editor): align model and cursor custody fixtures with owner-close policy --- .../closed-editor-model-lifetime.test.ts | 3 ++- .../editor/editor-model-host-isolation.test.ts | 18 ++++++++++++++---- .../editor/monaco-cursor-line-lifetime.test.ts | 8 ++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts b/src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts index e3e904643a9..c1d65f92274 100644 --- a/src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts +++ b/src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts @@ -38,10 +38,11 @@ it('keeps a live model and releases only its closed sibling', async () => { it('preserves a shared URI until its final file owner closes', async () => { const { store, attach, add } = createModelLifetimeFixture() const { file, model } = add('shared-a') - store.setState({ openFiles: [file, { ...file, id: 'shared-b' }] }) + store.setState({ openFiles: [file, { ...file, id: 'shared-b', readOnly: true }] }) attach() store.getState().closeFile(file.id) await Promise.resolve() + expect(store.getState().openFiles.map((openFile) => openFile.id)).toEqual(['shared-b']) expect(model.isDisposed()).toBe(false) store.getState().closeFile('shared-b') await Promise.resolve() diff --git a/src/renderer/src/components/editor/editor-model-host-isolation.test.ts b/src/renderer/src/components/editor/editor-model-host-isolation.test.ts index c37491b0836..6fa6f5d829e 100644 --- a/src/renderer/src/components/editor/editor-model-host-isolation.test.ts +++ b/src/renderer/src/components/editor/editor-model-host-isolation.test.ts @@ -1,7 +1,7 @@ // @vitest-environment happy-dom import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js' import { afterEach, describe, expect, it, vi } from 'vitest' -import type { OpenFile } from '@/store/slices/editor' +import { buildOwnedEditorFileId, type OpenFile } from '@/store/slices/editor' import type { WorktreeOperationRoute } from '@/lib/worktree-operation-route' import { attachModelLifetimeView, @@ -35,6 +35,7 @@ function file(id: string, route: WorktreeOperationRoute, filePath = FILE_PATH): ...modelLifetimeFile(id), filePath, relativePath: 'same-path.txt', + runtimeEnvironmentId: route.runtimeEnvironmentId, operationProvenance: { ownershipProjection: 'explicit', generation: { @@ -249,6 +250,12 @@ describe('same-path models on different execution hosts', () => { const { owners, store, attach } = createHostModels() const local = owners[0]! const runtime = owners[2]! + const migratedFile: OpenFile = { + ...local.file, + id: buildOwnedEditorFileId(FILE_PATH, local.file.worktreeId, 'hub-a'), + runtimeEnvironmentId: 'hub-a', + operationProvenance: runtime.file.operationProvenance + } const detach = attachModelLifetimeView(local.model) edit(runtime.model, 'runtime independent edit') attach() @@ -257,8 +264,10 @@ describe('same-path models on different execution hosts', () => { .getState() .openFiles.map((opened) => opened.id === local.file.id - ? { ...opened, operationProvenance: runtime.file.operationProvenance } - : opened + ? migratedFile + : opened.id === runtime.file.id + ? { ...opened, readOnly: true } + : opened ) }) await Promise.resolve() @@ -268,8 +277,9 @@ describe('same-path models on different execution hosts', () => { expect(local.model.isDisposed()).toBe(true) expect(runtime.model.isDisposed()).toBe(false) expect(runtime.model.getValue()).toBe('runtime independent edit') - store.getState().closeFile(local.file.id) + store.getState().closeFile(migratedFile.id) await Promise.resolve() + expect(store.getState().openFiles.some((opened) => opened.id === runtime.file.id)).toBe(true) expect(runtime.model.isDisposed()).toBe(false) await runtime.model.undo() expect(runtime.model.getValue()).toBe(runtime.initial) diff --git a/src/renderer/src/components/editor/monaco-cursor-line-lifetime.test.ts b/src/renderer/src/components/editor/monaco-cursor-line-lifetime.test.ts index 3c7baa5bf2c..c4ec59c1311 100644 --- a/src/renderer/src/components/editor/monaco-cursor-line-lifetime.test.ts +++ b/src/renderer/src/components/editor/monaco-cursor-line-lifetime.test.ts @@ -41,6 +41,7 @@ function startTracking( describe('Monaco cursor-line ownership lifetime', () => { it('releases positions after 250 distinct owned editor tabs close', () => { const store = createEditorStore() + store.setState({ unifiedTabsByWorktree: {} }) for (let index = 0; index < 250; index += 1) { const file = makeFile(`editor:wt-1:local:file-${index}`, `/repo/file-${index}.ts`) store.setState({ openFiles: [file] }) @@ -57,8 +58,11 @@ describe('Monaco cursor-line ownership lifetime', () => { it('isolates same-path positions and closes only the selected file identity', () => { const store = createEditorStore() const local = makeFile('editor:wt-1:local:file.ts', '/repo/file.ts') - const remote = makeFile('editor:wt-1:remote-a:file.ts', '/repo/file.ts') - store.setState({ openFiles: [local, remote] }) + const remote = { + ...makeFile('editor:wt-1:remote-a:file.ts', '/repo/file.ts'), + runtimeEnvironmentId: 'remote-a' + } + store.setState({ openFiles: [local, remote], unifiedTabsByWorktree: {} }) const localTracking = startTracking(store, local, 12) const remoteTracking = startTracking(store, remote, 35)