From 26817f74325b8a96dc76dcd8fd2b0b120ec90ce1 Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:37:58 +0100 Subject: [PATCH 1/2] Add `vscodeApi` for mocking --- .../src/constructTestHelpers.ts | 6 ++++-- packages/cursorless-vscode/src/extension.ts | 8 +++---- packages/cursorless-vscode/src/vscodeApi.ts | 19 +++++++++++++++++ packages/vscode-common/src/VscodeApi.ts | 21 +++++++++++++++++++ packages/vscode-common/src/getExtensionApi.ts | 6 ++++++ packages/vscode-common/src/index.ts | 1 + 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 packages/cursorless-vscode/src/vscodeApi.ts create mode 100644 packages/vscode-common/src/VscodeApi.ts diff --git a/packages/cursorless-vscode/src/constructTestHelpers.ts b/packages/cursorless-vscode/src/constructTestHelpers.ts index 3d2941dd2a..bb00ca3b8b 100644 --- a/packages/cursorless-vscode/src/constructTestHelpers.ts +++ b/packages/cursorless-vscode/src/constructTestHelpers.ts @@ -17,9 +17,10 @@ import { takeSnapshot, } from "@cursorless/cursorless-engine"; import { TestHelpers } from "@cursorless/vscode-common"; -import * as vscode from "vscode"; +import type { TextEditor as VscodeTextEditor } from "vscode"; import { VscodeIDE } from "./ide/vscode/VscodeIDE"; import { toVscodeEditor } from "./ide/vscode/toVscodeEditor"; +import { vscodeApi } from "./vscodeApi"; export function constructTestHelpers( commandServerApi: CommandServerApi | null, @@ -61,7 +62,7 @@ export function constructTestHelpers( }, setStoredTarget( - editor: vscode.TextEditor, + editor: VscodeTextEditor, key: StoredTargetKey, targets: TargetPlainObject[] | undefined, ): void { @@ -74,5 +75,6 @@ export function constructTestHelpers( }, hatTokenMap, runIntegrationTests, + vscodeApi, }; } diff --git a/packages/cursorless-vscode/src/extension.ts b/packages/cursorless-vscode/src/extension.ts index 21ce44432f..6c7164ea92 100644 --- a/packages/cursorless-vscode/src/extension.ts +++ b/packages/cursorless-vscode/src/extension.ts @@ -17,7 +17,6 @@ import { ParseTreeApi, toVscodeRange, } from "@cursorless/vscode-common"; -import * as vscode from "vscode"; import { constructTestHelpers } from "./constructTestHelpers"; import { FakeFontMeasurements } from "./ide/vscode/hats/FakeFontMeasurements"; import { FontMeasurementsImpl } from "./ide/vscode/hats/FontMeasurementsImpl"; @@ -26,6 +25,7 @@ import { VscodeIDE } from "./ide/vscode/VscodeIDE"; import { KeyboardCommands } from "./keyboard/KeyboardCommands"; import { registerCommands } from "./registerCommands"; import { StatusBarItem } from "./StatusBarItem"; +import { ExtensionContext, Location } from "vscode"; /** * Extension entrypoint called by VSCode on Cursorless startup. @@ -36,7 +36,7 @@ import { StatusBarItem } from "./StatusBarItem"; * - Creates an entrypoint for running commands {@link CommandRunner}. */ export async function activate( - context: vscode.ExtensionContext, + context: ExtensionContext, ): Promise { const parseTreeApi = await getParseTreeApi(); @@ -104,7 +104,7 @@ export async function activate( }; } -async function createVscodeIde(context: vscode.ExtensionContext) { +async function createVscodeIde(context: ExtensionContext) { const vscodeIDE = new VscodeIDE(context); const hats = new VscodeHats( @@ -123,7 +123,7 @@ function createTreeSitter(parseTreeApi: ParseTreeApi): TreeSitter { return { getNodeAtLocation(document: TextDocument, range: Range) { return parseTreeApi.getNodeAtLocation( - new vscode.Location(document.uri, toVscodeRange(range)), + new Location(document.uri, toVscodeRange(range)), ); }, diff --git a/packages/cursorless-vscode/src/vscodeApi.ts b/packages/cursorless-vscode/src/vscodeApi.ts new file mode 100644 index 0000000000..8275a485c3 --- /dev/null +++ b/packages/cursorless-vscode/src/vscodeApi.ts @@ -0,0 +1,19 @@ +import { workspace, window } from "vscode"; +import { VscodeApi } from "@cursorless/vscode-common"; + +/** + * A very thin wrapper around the VSCode API that allows us to mock it for + * testing. This is necessary because the test harness gets bundled separately + * from the extension code, so if we just import the VSCode API directly from + * the extension code, and from the test harness, we'll end up with two copies + * of the VSCode API, so the mocks won't work. + */ +export const vscodeApi: VscodeApi = { + workspace, + window, + editor: { + setDecorations(editor, ...args) { + return editor.setDecorations(...args); + }, + }, +}; diff --git a/packages/vscode-common/src/VscodeApi.ts b/packages/vscode-common/src/VscodeApi.ts new file mode 100644 index 0000000000..34048bb2b0 --- /dev/null +++ b/packages/vscode-common/src/VscodeApi.ts @@ -0,0 +1,21 @@ +import { workspace, window, TextEditor } from "vscode"; + +/** + * Subset of VSCode api that we need to be able to mock for testing + */ +export interface VscodeApi { + workspace: typeof workspace; + window: typeof window; + + /** + * Wrapper around editor api for easy mocking. Provides various + * {@link TextEditor} methods as static functions which take a text editor as + * their first argument. + */ + editor: { + setDecorations( + editor: TextEditor, + ...args: Parameters + ): ReturnType; + }; +} diff --git a/packages/vscode-common/src/getExtensionApi.ts b/packages/vscode-common/src/getExtensionApi.ts index 6c083ed85b..079f85b704 100644 --- a/packages/vscode-common/src/getExtensionApi.ts +++ b/packages/vscode-common/src/getExtensionApi.ts @@ -13,6 +13,7 @@ import type { } from "@cursorless/common"; import * as vscode from "vscode"; import type { Language, SyntaxNode, Tree } from "web-tree-sitter"; +import { VscodeApi } from "./VscodeApi"; export interface TestHelpers { ide: NormalizedIDE; @@ -42,6 +43,11 @@ export interface TestHelpers { ): Promise; runIntegrationTests(): Promise; + + /** + * A thin wrapper around the VSCode API that allows us to mock it for testing. + */ + vscodeApi: VscodeApi; } export interface CursorlessApi { diff --git a/packages/vscode-common/src/index.ts b/packages/vscode-common/src/index.ts index 15435d5cc6..de3a299986 100644 --- a/packages/vscode-common/src/index.ts +++ b/packages/vscode-common/src/index.ts @@ -3,3 +3,4 @@ export * from "./notebook"; export * from "./testUtil/openNewEditor"; export * from "./vscodeUtil"; export * from "./runCommand"; +export * from "./VscodeApi"; From 3d29ac4007ba49a481a5a3836641acc6ae03da2c Mon Sep 17 00:00:00 2001 From: Pokey Rule <755842+pokey@users.noreply.github.com> Date: Tue, 18 Jul 2023 11:17:33 +0100 Subject: [PATCH 2/2] Rollback vscode import changes --- packages/cursorless-vscode/src/constructTestHelpers.ts | 4 ++-- packages/cursorless-vscode/src/extension.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cursorless-vscode/src/constructTestHelpers.ts b/packages/cursorless-vscode/src/constructTestHelpers.ts index bb00ca3b8b..a68539edb0 100644 --- a/packages/cursorless-vscode/src/constructTestHelpers.ts +++ b/packages/cursorless-vscode/src/constructTestHelpers.ts @@ -17,7 +17,7 @@ import { takeSnapshot, } from "@cursorless/cursorless-engine"; import { TestHelpers } from "@cursorless/vscode-common"; -import type { TextEditor as VscodeTextEditor } from "vscode"; +import * as vscode from "vscode"; import { VscodeIDE } from "./ide/vscode/VscodeIDE"; import { toVscodeEditor } from "./ide/vscode/toVscodeEditor"; import { vscodeApi } from "./vscodeApi"; @@ -62,7 +62,7 @@ export function constructTestHelpers( }, setStoredTarget( - editor: VscodeTextEditor, + editor: vscode.TextEditor, key: StoredTargetKey, targets: TargetPlainObject[] | undefined, ): void { diff --git a/packages/cursorless-vscode/src/extension.ts b/packages/cursorless-vscode/src/extension.ts index 6c7164ea92..21ce44432f 100644 --- a/packages/cursorless-vscode/src/extension.ts +++ b/packages/cursorless-vscode/src/extension.ts @@ -17,6 +17,7 @@ import { ParseTreeApi, toVscodeRange, } from "@cursorless/vscode-common"; +import * as vscode from "vscode"; import { constructTestHelpers } from "./constructTestHelpers"; import { FakeFontMeasurements } from "./ide/vscode/hats/FakeFontMeasurements"; import { FontMeasurementsImpl } from "./ide/vscode/hats/FontMeasurementsImpl"; @@ -25,7 +26,6 @@ import { VscodeIDE } from "./ide/vscode/VscodeIDE"; import { KeyboardCommands } from "./keyboard/KeyboardCommands"; import { registerCommands } from "./registerCommands"; import { StatusBarItem } from "./StatusBarItem"; -import { ExtensionContext, Location } from "vscode"; /** * Extension entrypoint called by VSCode on Cursorless startup. @@ -36,7 +36,7 @@ import { ExtensionContext, Location } from "vscode"; * - Creates an entrypoint for running commands {@link CommandRunner}. */ export async function activate( - context: ExtensionContext, + context: vscode.ExtensionContext, ): Promise { const parseTreeApi = await getParseTreeApi(); @@ -104,7 +104,7 @@ export async function activate( }; } -async function createVscodeIde(context: ExtensionContext) { +async function createVscodeIde(context: vscode.ExtensionContext) { const vscodeIDE = new VscodeIDE(context); const hats = new VscodeHats( @@ -123,7 +123,7 @@ function createTreeSitter(parseTreeApi: ParseTreeApi): TreeSitter { return { getNodeAtLocation(document: TextDocument, range: Range) { return parseTreeApi.getNodeAtLocation( - new Location(document.uri, toVscodeRange(range)), + new vscode.Location(document.uri, toVscodeRange(range)), ); },