diff --git a/extensions/positron-python/src/test/common/process/pythonToolService.unit.test.ts b/extensions/positron-python/src/test/common/process/pythonToolService.unit.test.ts index 1765f35fb91..bef199ce223 100644 --- a/extensions/positron-python/src/test/common/process/pythonToolService.unit.test.ts +++ b/extensions/positron-python/src/test/common/process/pythonToolService.unit.test.ts @@ -53,10 +53,7 @@ suite('Process - Python tool execution service', () => { when(pythonService.execModule(anything(), anything(), anything())).thenResolve(executionResult); const pythonServiceInstance = instance(pythonService); - // --- Start Positron --- - // No longer needed and errors since we already set `.then` in positron/initialize/patchMockingLibs. - // (pythonServiceInstance as any).then = undefined; - // --- End Positron --- + (pythonServiceInstance as any).then = undefined; executionFactory = mock(PythonExecutionFactory); when(executionFactory.create(anything())).thenResolve(pythonServiceInstance); diff --git a/extensions/positron-python/src/test/common/serviceRegistry.unit.test.ts b/extensions/positron-python/src/test/common/serviceRegistry.unit.test.ts index 20ac22b1539..9a82681625d 100644 --- a/extensions/positron-python/src/test/common/serviceRegistry.unit.test.ts +++ b/extensions/positron-python/src/test/common/serviceRegistry.unit.test.ts @@ -125,10 +125,7 @@ suite('Common - Service Registry', () => { if (mapping.length === 2) { serviceManager .setup((s) => - // --- Start Positron --- - // Fix for Typescript v5 - s.addSingleton( - // --- End Positron --- + s.addSingleton( typemoq.It.isValue(mapping[0] as any), typemoq.It.is((value: any) => mapping[1] === value), ), diff --git a/extensions/positron-python/src/test/index.ts b/extensions/positron-python/src/test/index.ts index d67018e99ca..f528a755122 100644 --- a/extensions/positron-python/src/test/index.ts +++ b/extensions/positron-python/src/test/index.ts @@ -17,9 +17,6 @@ import { IS_CI_SERVER_TEST_DEBUGGER, MOCHA_REPORTER_JUNIT } from './ciConstants' import { IS_MULTI_ROOT_TEST, MAX_EXTENSION_ACTIVATION_TIME, TEST_RETRYCOUNT, TEST_TIMEOUT } from './constants'; import { initialize } from './initialize'; import { initializeLogger } from './testLogger'; -// --- Start Positron --- -import { patchMockingLibs } from './positron/initialize'; -// --- End Positron --- initializeLogger(); @@ -162,11 +159,6 @@ export async function run(): Promise { console.error('Failed to activate python extension without errors', ex); } - // --- Start Positron --- - // See patchMockingLibs docs for why this is necessary. - patchMockingLibs(); - // --- End Positron --- - // Run the tests. await new Promise((resolve, reject) => { mocha.run((failures) => { diff --git a/extensions/positron-python/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts b/extensions/positron-python/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts index faa95a08a3c..a8159f4d88d 100644 --- a/extensions/positron-python/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts +++ b/extensions/positron-python/src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts @@ -140,10 +140,6 @@ suite('Terminal Environment Variable Collection Service', () => { // --- End Positron --- reset(experimentService); - // --- Start Positron --- - // Use globalCollection instead of collection since we're using a later version of @types/vscode - when(context.environmentVariableCollection).thenReturn(instance(globalCollection)); - // --- End Positron --- when(experimentService.inExperimentSync(TerminalEnvVarActivation.experiment)).thenReturn(false); const applyCollectionStub = sinon.stub(terminalEnvVarCollectionService, '_applyCollection'); applyCollectionStub.resolves(); diff --git a/extensions/positron-python/src/test/mocks/helper.ts b/extensions/positron-python/src/test/mocks/helper.ts index d5206b7f66e..d61bf728a25 100644 --- a/extensions/positron-python/src/test/mocks/helper.ts +++ b/extensions/positron-python/src/test/mocks/helper.ts @@ -23,8 +23,6 @@ export function createTypeMoq( // Use typemoqs for those things that are resolved as promises. mockito doesn't allow nesting of mocks. ES6 Proxy class // is the problem. We still need to make it thenable though. See this issue: https://github.com/florinn/typemoq/issues/67 const result = TypeMoq.Mock.ofType(targetCtor, behavior, shouldOverrideTarget, ...targetCtorArgs); - // --- Start Positron --- - // result.setup((x: any) => x.then).returns(() => undefined); - // --- End Positron --- + result.setup((x: any) => x.then).returns(() => undefined); return result; } diff --git a/extensions/positron-python/src/test/positron/createEnvApi.unit.test.ts b/extensions/positron-python/src/test/positron/createEnvApi.unit.test.ts index 1340ac75d4f..5aec96cb7b8 100644 --- a/extensions/positron-python/src/test/positron/createEnvApi.unit.test.ts +++ b/extensions/positron-python/src/test/positron/createEnvApi.unit.test.ts @@ -25,6 +25,7 @@ import { CreateEnvironmentOptionsInternal } from '../../client/pythonEnvironment import { IPythonRuntimeManager } from '../../client/positron/manager'; import { IInterpreterQuickPick } from '../../client/interpreter/configuration/types'; import { createEnvironmentAndRegister } from '../../client/positron/createEnvApi'; +import { createTypeMoq } from '../mocks/helper'; chaiUse(chaiAsPromised.default); @@ -33,7 +34,7 @@ suite('Positron Create Environment APIs', () => { let handleCreateEnvironmentCommandStub: sinon.SinonStub; const disposables: IDisposableRegistry = []; - const mockProvider = typemoq.Mock.ofType(); + const mockProvider = createTypeMoq(); const mockProviders = [mockProvider.object]; let pythonRuntimeManager: typemoq.IMock; @@ -67,10 +68,10 @@ suite('Positron Create Environment APIs', () => { registerCommandStub = sinon.stub(commandApis, 'registerCommand'); handleCreateEnvironmentCommandStub = sinon.stub(createEnvironmentApis, 'handleCreateEnvironmentCommand'); - pythonRuntimeManager = typemoq.Mock.ofType(); - pathUtils = typemoq.Mock.ofType(); - interpreterQuickPick = typemoq.Mock.ofType(); - interpreterPathService = typemoq.Mock.ofType(); + pythonRuntimeManager = createTypeMoq(); + pathUtils = createTypeMoq(); + interpreterQuickPick = createTypeMoq(); + interpreterPathService = createTypeMoq(); registerCommandStub.callsFake((_command: string, _callback: (...args: any[]) => any) => ({ dispose: () => { @@ -98,7 +99,7 @@ suite('Positron Create Environment APIs', () => { const resultPath = '/path/to/created/env'; pythonRuntimeManager .setup((p) => p.registerLanguageRuntimeFromPath(resultPath)) - .returns(() => Promise.resolve(typemoq.Mock.ofType().object)) + .returns(() => Promise.resolve(createTypeMoq().object)) .verifiable(typemoq.Times.once()); handleCreateEnvironmentCommandStub.returns(Promise.resolve({ path: resultPath })); @@ -117,7 +118,7 @@ suite('Positron Create Environment APIs', () => { test(`Environment creation fails when options are missing: ${optionsName} `, async () => { pythonRuntimeManager .setup((p) => p.registerLanguageRuntimeFromPath(typemoq.It.isAny())) - .returns(() => Promise.resolve(typemoq.Mock.ofType().object)) + .returns(() => Promise.resolve(createTypeMoq().object)) .verifiable(typemoq.Times.never()); const result = await createEnvironmentAndRegister(mockProviders, pythonRuntimeManager.object, options); diff --git a/extensions/positron-python/src/test/positron/initialize.ts b/extensions/positron-python/src/test/positron/initialize.ts index 92debe0a985..dba08894368 100644 --- a/extensions/positron-python/src/test/positron/initialize.ts +++ b/extensions/positron-python/src/test/positron/initialize.ts @@ -3,10 +3,7 @@ * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. *--------------------------------------------------------------------------------------------*/ -import * as TypeMoq from 'typemoq'; -import * as tsMockito from 'ts-mockito'; - -// Initialize Positron for Python extension integration tests. +/** Initialize Positron for Python extension integration tests. */ export function initializePositron(): void { // Use a late import since this module may be imported without Positron being installed // e.g. in unit tests. @@ -18,47 +15,3 @@ export function initializePositron(): void { .getConfiguration('positron.interpreters') .update('automaticStartup', false, vscode.ConfigurationTarget.Global); } - -// Save a reference to the original patched objects. -const originalTypeMoqMockOfType = TypeMoq.Mock.ofType; -const originalTsMockitoMock = tsMockito.mock; - -/** - * InversifyJS v6 (required by TypeScript v5) tries to await bound objects if they - * look like promises. TypeMoq's dynamic mocks and ts-mockito instances unfortunately - * do look like promises by default (they are functions and their properties are functions, - * including `then`). This causes unexpected behavior in InversifyJS. - * - * Here, we patch `TypeMoq.Mock.ofType` and `tsMockito.mock` to setup the `then` property to return - * undefined to avoid the above behavior. - */ -export function patchMockingLibs(): void { - // Patch TypeMoq. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TypeMoq.Mock.ofType = function (targetConstructor?: any, behavior?: any, ...args: never[]): TypeMoq.IMock { - const mock = originalTypeMoqMockOfType(targetConstructor, behavior, ...args); - - // Only setup `then` if the target constructor is undefined, meaning the mock is dynamic - if (targetConstructor === undefined) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const returnsResult = mock.setup((x: any) => x.then).returns(() => undefined); - - // If a user configures 'strict' mock behavior, all setups are expected to be called - // once. Override this by allowing `then` to be called any number of times. - if (behavior === TypeMoq.MockBehavior.Strict) { - returnsResult.verifiable(TypeMoq.Times.atLeast(0)); - } - } - - return mock as TypeMoq.IMock; - }; - - // Patch ts-mockito. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (tsMockito as any).mock = function (...args: never[]): T { - const mocked = originalTsMockitoMock(...args); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - tsMockito.when((mocked as any).then).thenReturn(undefined); - return mocked as T; - }; -} diff --git a/extensions/positron-python/src/test/positron/manager.unit.test.ts b/extensions/positron-python/src/test/positron/manager.unit.test.ts index 19133e091fd..ea93000687a 100644 --- a/extensions/positron-python/src/test/positron/manager.unit.test.ts +++ b/extensions/positron-python/src/test/positron/manager.unit.test.ts @@ -20,6 +20,7 @@ import { PythonRuntimeManager } from '../../client/positron/manager'; import { IInterpreterService } from '../../client/interpreter/contracts'; import { PythonEnvironment } from '../../client/pythonEnvironments/info'; import { mockedPositronNamespaces } from '../vscode-mock'; +import { createTypeMoq } from '../mocks/helper'; suite('Python runtime manager', () => { const pythonPath = 'pythonPath'; @@ -34,12 +35,12 @@ suite('Python runtime manager', () => { let disposables: IDisposable[]; setup(() => { - runtimeMetadata = TypeMoq.Mock.ofType(); - interpreter = TypeMoq.Mock.ofType(); - configService = TypeMoq.Mock.ofType(); - envVarsProvider = TypeMoq.Mock.ofType(); - interpreterService = TypeMoq.Mock.ofType(); - serviceContainer = TypeMoq.Mock.ofType(); + runtimeMetadata = createTypeMoq(); + interpreter = createTypeMoq(); + configService = createTypeMoq(); + envVarsProvider = createTypeMoq(); + interpreterService = createTypeMoq(); + serviceContainer = createTypeMoq(); runtimeMetadata.setup((r) => r.runtimeId).returns(() => 'runtimeId'); runtimeMetadata @@ -99,7 +100,7 @@ suite('Python runtime manager', () => { // }); test('restoreSession: creates and returns a Python runtime session', async () => { - const sessionMetadata = TypeMoq.Mock.ofType(); + const sessionMetadata = createTypeMoq(); const pythonRuntimeSession = sinon.stub(session, 'PythonRuntimeSession'); const result = await pythonRuntimeManager.restoreSession(runtimeMetadata.object, sessionMetadata.object); @@ -130,7 +131,7 @@ suite('Python runtime manager', () => { pythonRuntimeManager.registeredPythonRuntimes.set(pythonPath, runtimeMetadata.object); // Create a metadata fragment (only contains extra data python path). - const runtimeMetadataFragment = TypeMoq.Mock.ofType(); + const runtimeMetadataFragment = createTypeMoq(); runtimeMetadataFragment.setup((r) => r.extraRuntimeData).returns(() => ({ pythonPath })); // Override the pathExists stub to return true and validate the metadata. @@ -142,7 +143,7 @@ suite('Python runtime manager', () => { }); test('validateMetadata: throws if extra data is missing', async () => { - const invalidRuntimeMetadata = TypeMoq.Mock.ofType(); + const invalidRuntimeMetadata = createTypeMoq(); assert.rejects(() => pythonRuntimeManager.validateMetadata(invalidRuntimeMetadata.object)); }); diff --git a/extensions/positron-python/src/test/terminals/serviceRegistry.unit.test.ts b/extensions/positron-python/src/test/terminals/serviceRegistry.unit.test.ts index 91d99ea1c8c..cb5b7715c4b 100644 --- a/extensions/positron-python/src/test/terminals/serviceRegistry.unit.test.ts +++ b/extensions/positron-python/src/test/terminals/serviceRegistry.unit.test.ts @@ -44,10 +44,7 @@ suite('Terminal - Service Registry', () => { if (args.length === 2) { services .setup((s) => - // --- Start Positron --- - // Fix for Typescript v5 - s.addSingleton( - // --- End Positron --- + s.addSingleton( typemoq.It.is((v: any) => args[0] === v), typemoq.It.is((value: any) => args[1] === value), ), @@ -56,10 +53,7 @@ suite('Terminal - Service Registry', () => { } else { services .setup((s) => - // --- Start Positron --- - // Fix for Typescript v5 - s.addSingleton( - // --- End Positron --- + s.addSingleton( typemoq.It.is((v: any) => args[0] === v), typemoq.It.is((value: any) => args[1] === value), @@ -71,10 +65,7 @@ suite('Terminal - Service Registry', () => { }); services .setup((s) => - // --- Start Positron --- - // Fix for Typescript v5 - s.addBinding( - // --- End Positron --- + s.addBinding( typemoq.It.is((v: any) => ITerminalEnvVarCollectionService === v), typemoq.It.is((value: any) => IExtensionActivationService === value), ), diff --git a/extensions/positron-python/src/test/vscode-mock.ts b/extensions/positron-python/src/test/vscode-mock.ts index b78cf71285a..da73fca98a2 100644 --- a/extensions/positron-python/src/test/vscode-mock.ts +++ b/extensions/positron-python/src/test/vscode-mock.ts @@ -28,10 +28,6 @@ type Positron = typeof positron; const mockedPositron: Partial = {}; export const mockedPositronNamespaces: { [P in keyof Positron]?: Positron[P] } = {}; -// TODO(seem): mockedPositron is currently empty. We can update it as needed as we add tests. - -import { patchMockingLibs } from './positron/initialize'; - function generatePositronMock(name: K): void { const mockedObj = mock(); (mockedPositron as any)[name] = instance(mockedObj); @@ -109,11 +105,6 @@ export function initialize() { } return originalLoad.apply(this, arguments); }; - - // --- Start Positron --- - // See patchMockingLibs docs for why this is necessary. - patchMockingLibs(); - // --- End Positron --- } mockedVSCode.ThemeIcon = vscodeMocks.ThemeIcon;