From de837577546082a30b2d3cd57311bf2456b85768 Mon Sep 17 00:00:00 2001 From: BenStullsBets Date: Thu, 2 Jul 2026 06:45:59 -0700 Subject: [PATCH] test: cover syncContext context-key derivation + exit idempotency (CoeditingRegistry) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements comprehensive unit test coverage for CoeditingRegistry.syncContext, which derives context keys (cowriting.isCoediting, cowriting.baselineMode) via vscode.commands.executeCommand — previously untested. Added 8 new tests: - isCoediting: true for active editor with coediting doc - isCoediting: false for undefined editor or non-entered doc - baselineMode: uses hook result when set; defaults to "" otherwise - exit idempotency: double exit fires onDidChange only once All assertions inspect the mocked executeCommand call arguments directly. Co-Authored-By: Claude Fable 5 --- test/coeditingRegistry.test.ts | 106 +++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/test/coeditingRegistry.test.ts b/test/coeditingRegistry.test.ts index 05ff076..915cfc5 100644 --- a/test/coeditingRegistry.test.ts +++ b/test/coeditingRegistry.test.ts @@ -14,6 +14,7 @@ vi.mock("vscode", () => ({ commands: { executeCommand: vi.fn() }, window: { activeTextEditor: undefined }, })); +import * as vscode from "vscode"; import { CoeditingRegistry } from "../src/coeditingRegistry"; function memento(): { store: Map } & { get: any; update: any } { @@ -60,4 +61,109 @@ describe("CoeditingRegistry", () => { reg.enter(uri); expect(events).toHaveLength(1); }); + + it("exit is idempotent (no duplicate events on double exit)", () => { + const reg = new CoeditingRegistry(memento() as any); + const events: unknown[] = []; + reg.onDidChange((e) => events.push(e)); + const uri = { toString: () => "file:///a.md" } as any; + reg.enter(uri); + reg.exit(uri); + reg.exit(uri); + expect(events).toHaveLength(2); // enter, then exit (second exit fires nothing) + }); + + it("syncContext: active editor with coediting doc sets isCoediting=true", () => { + const reg = new CoeditingRegistry(memento() as any); + const uri = { toString: () => "file:///a.md" } as any; + reg.enter(uri); + + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.isCoediting", true); + }); + + it("syncContext: undefined editor sets isCoediting=false", () => { + const reg = new CoeditingRegistry(memento() as any); + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + reg.syncContext(undefined); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.isCoediting", false); + }); + + it("syncContext: non-coediting doc sets isCoediting=false", () => { + const reg = new CoeditingRegistry(memento() as any); + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const uri = { toString: () => "file:///nonexistent.md" } as any; + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.isCoediting", false); + }); + + it("syncContext: baselineMode defaults to empty string when not coediting", () => { + const reg = new CoeditingRegistry(memento() as any); + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const uri = { toString: () => "file:///a.md" } as any; + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.baselineMode", ""); + }); + + it("syncContext: baselineMode uses hook result when coediting and hook is set", () => { + const reg = new CoeditingRegistry(memento() as any); + const uri = { toString: () => "file:///a.md" } as any; + reg.enter(uri); + + reg.baselineModeOf = vi.fn((): "head" | "snapshot" | undefined => "snapshot"); + + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.baselineMode", "snapshot"); + }); + + it("syncContext: baselineMode defaults to empty string when hook returns undefined", () => { + const reg = new CoeditingRegistry(memento() as any); + const uri = { toString: () => "file:///a.md" } as any; + reg.enter(uri); + + reg.baselineModeOf = vi.fn((): "head" | "snapshot" | undefined => undefined); + + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledWith("setContext", "cowriting.baselineMode", ""); + }); + + it("syncContext: calls executeCommand twice (isCoediting and baselineMode)", () => { + const reg = new CoeditingRegistry(memento() as any); + const uri = { toString: () => "file:///a.md" } as any; + reg.enter(uri); + + const mockExecuteCommand = vscode.commands.executeCommand as any; + mockExecuteCommand.mockClear(); + + const editor = { document: { uri } } as any; + reg.syncContext(editor); + + expect(mockExecuteCommand).toHaveBeenCalledTimes(2); + }); });