Skip to content

Bump Node.js packages and update testing infrastructure #5188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 0 additions & 75 deletions .eslintrc.json

This file was deleted.

8 changes: 2 additions & 6 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
{
"require": "esbuild-register",
"color": true,
"enable-source-maps": true,
"extensions": [
".js",
".jsx"
],
"require": "source-map-support/register",
"timeout": 600000,
"slow": 2000,
"spec": "test/**/*.test.js"
"spec": "test/**/*.test.ts"
}
1 change: 0 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -2,6 +2,5 @@
save=true
; We use a public Azure Artifacts mirror
registry=https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/powershell/npm/registry/
always-auth=true
; But we don't want references to it in the lockfile
omit-lockfile-registry-resolved=true
Empty file added .prettierignore
Empty file.
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tabWidth": 2,
"plugins": ["prettier-plugin-organize-imports"]
}
15 changes: 15 additions & 0 deletions .vscode-test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import os from "os";
import path from "path";
import { defineConfig } from "@vscode/test-cli";

export default defineConfig({
files: "test/**/*.test.ts",
// The default user data directory had too many characters for the IPC connection on macOS in CI.
launchArgs: [ "--profile-temp", "--user-data-dir", path.join(os.tmpdir(), "vscode-user-data") ],
workspaceFolder: "test/TestEnvironment.code-workspace",
mocha: {
ui: "bdd", // describe, it, etc.
require: "esbuild-register",
timeout: 60 * 1000 // 10 minutes to allow for debugging
},
});
48 changes: 48 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import eslint from "@eslint/js";
import eslintConfigPrettier from "eslint-config-prettier/flat";
import tseslint from "typescript-eslint";

export default tseslint.config(
eslint.configs.recommended,
tseslint.configs.strictTypeChecked,
eslintConfigPrettier,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true,
},
],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: true,
ignoreMixedLogicalExpressions: true,
},
],
},
},
);
2,664 changes: 1,956 additions & 708 deletions package-lock.json

Large diffs are not rendered by default.

41 changes: 20 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -60,46 +60,46 @@
"onCommand:PowerShell.SpecifyScriptArgs"
],
"dependencies": {
"@vscode/extension-telemetry": "^0.9.8",
"@vscode/extension-telemetry": "^0.9.9",
"node-fetch": "^2.7.0",
"semver": "^7.7.1",
"semver": "^7.7.2",
"untildify": "^4.0.0",
"uuid": "^9.0.1",
"vscode-languageclient": "^9.0.1",
"vscode-languageserver-protocol": "^3.17.5"
},
"devDependencies": {
"@vscode/vsce": "^3.3.0",
"esbuild": "^0.25.1"
"@vscode/vsce": "^3.3.2",
"esbuild": "^0.25.4"
},
"optionalDependencies": {
"@tsconfig/node20": "^20.1.4",
"@eslint/js": "^9.26.0",
"@types/mocha": "^10.0.10",
"@types/mock-fs": "^4.13.4",
"@types/node": "^20.17.24",
"@types/node": "^20.17.47",
"@types/node-fetch": "^2.6.12",
"@types/rewire": "^2.5.30",
"@types/semver": "^7.5.8",
"@types/semver": "^7.7.0",
"@types/sinon": "^17.0.4",
"@types/ungap__structured-clone": "^1.2.0",
"@types/uuid": "^9.0.8",
"@types/vscode": "~1.96.0",
"@typescript-eslint/eslint-plugin": "^8.26.1",
"@typescript-eslint/parser": "^8.26.1",
"@ungap/structured-clone": "^1.3.0",
"@vscode/debugprotocol": "^1.68.0",
"@vscode/test-electron": "^2.4.1",
"eslint": "^8.57.0",
"eslint-plugin-header": "^3.1.1",
"glob": "^11.0.1",
"mocha": "^11.1.0",
"@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.5.2",
"esbuild-register": "^3.6.0",
"eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.5",
"mocha": "^11.2.2",
"mocha-explorer-launcher-scripts": "^0.4.0",
"mocha-multi-reporters": "^1.5.1",
"mock-fs": "^5.5.0",
"rewire": "^7.0.0",
"sinon": "^19.0.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"sinon": "^19.0.5",
"source-map-support": "^0.5.21",
"typescript": "^5.8.2"
"typescript": "^5.8.3",
"typescript-eslint": "^8.32.1"
},
"extensionDependencies": [
"vscode.powershell"
@@ -111,9 +111,8 @@
"lint": "eslint src test --ext .ts",
"package": "vsce package --out out/ --no-gitHubIssueLinking",
"publish": "vsce publish",
"compile-test": "npm run compile && tsc --incremental",
"watch-tests": "npm run compile-test -- --watch",
"test": "npm run compile-test && node ./test/runTests.js"
"pretest": "npm run compile",
"test": "vscode-test"
},
"contributes": {
"breakpoints": [
9 changes: 6 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -10,7 +10,10 @@ import { DebugSessionFeature } from "./features/DebugSession";
import { ExamplesFeature } from "./features/Examples";
import { ExpandAliasFeature } from "./features/ExpandAlias";
import { ExtensionCommandsFeature } from "./features/ExtensionCommands";
import { ExternalApiFeature, IPowerShellExtensionClient } from "./features/ExternalApi";
import {
ExternalApiFeature,
type IPowerShellExtensionClient,
} from "./features/ExternalApi";
import { GenerateBugReportFeature } from "./features/GenerateBugReport";
import { GetCommandsFeature } from "./features/GetCommands";
import { HelpCompletionFeature } from "./features/HelpCompletion";
@@ -82,7 +85,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IPower
// e.g. /** | */
// eslint-disable-next-line no-useless-escape
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
// eslint-disable-next-line no-useless-escape

afterText: /^\s*\*\/$/,
action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: " * " },
},
@@ -201,7 +204,7 @@ function registerWaitForPsesActivationCommand(context: vscode.ExtensionContext):
const pidFile = vscode.Uri.joinPath(context.globalStorageUri, "sessions", pidFileName);
const fs = vscode.workspace.fs;
// Wait for the file to be created
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, no-constant-condition
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while (true) {
try {
const pidContent = await fs.readFile(pidFile);
2 changes: 1 addition & 1 deletion src/features/CodeActions.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
// Licensed under the MIT License.

import vscode = require("vscode");
import { ILogger } from "../logging";
import type { ILogger } from "../logging";

export class CodeActionsFeature implements vscode.Disposable {
private command: vscode.Disposable;
7 changes: 5 additions & 2 deletions src/features/Console.ts
Original file line number Diff line number Diff line change
@@ -4,8 +4,11 @@
import vscode = require("vscode");
import { NotificationType, RequestType } from "vscode-languageclient";
import { LanguageClient } from "vscode-languageclient/node";
import { ICheckboxQuickPickItem, showCheckboxQuickPick } from "../controls/checkboxQuickPick";
import { ILogger } from "../logging";
import {
type ICheckboxQuickPickItem,
showCheckboxQuickPick,
} from "../controls/checkboxQuickPick";
import type { ILogger } from "../logging";
import { getSettings } from "../settings";
import { LanguageClientConsumer } from "../languageClientConsumer";

1,405 changes: 779 additions & 626 deletions src/features/DebugSession.ts

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/features/ExpandAlias.ts
Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@ import { RequestType } from "vscode-languageclient";
import { LanguageClientConsumer } from "../languageClientConsumer";
import type { LanguageClient } from "vscode-languageclient/node";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IExpandAliasRequestArguments {
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IExpandAliasRequestResponse {
text: string
}
@@ -52,7 +52,7 @@ export class ExpandAliasFeature extends LanguageClientConsumer {
});
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
public override onLanguageClientSet(_languageClient: LanguageClient): void {}

public dispose(): void {
4 changes: 2 additions & 2 deletions src/features/ExtensionCommands.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import {
Position, Range, RequestType
} from "vscode-languageclient";
import { LanguageClient } from "vscode-languageclient/node";
import { ILogger } from "../logging";
import type { ILogger } from "../logging";
import { getSettings, validateCwdSetting } from "../settings";
import { LanguageClientConsumer } from "../languageClientConsumer";
import { DebugConfig, DebugConfigurations } from "./DebugSession";
@@ -64,7 +64,7 @@ export const GetEditorContextRequestType =
new RequestType<IGetEditorContextRequestArguments, IEditorContext, void>(
"editor/getEditorContext");

// eslint-disable-next-line @typescript-eslint/no-empty-interface

export interface IGetEditorContextRequestArguments {
}

2 changes: 1 addition & 1 deletion src/features/ExternalApi.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

import * as vscode from "vscode";
import { v4 as uuidv4 } from "uuid";
import { ILogger } from "../logging";
import type { ILogger } from "../logging";
import { SessionManager } from "../session";

export interface IExternalPowerShellDetails {
12 changes: 6 additions & 6 deletions src/features/HelpCompletion.ts
Original file line number Diff line number Diff line change
@@ -3,18 +3,18 @@

import {
Disposable, EndOfLine, Range, SnippetString,
TextDocument, TextDocumentChangeEvent, window, workspace
type TextDocument, type TextDocumentChangeEvent, window, workspace
} from "vscode";
import { RequestType } from "vscode-languageclient";
import { LanguageClient } from "vscode-languageclient/node";
import { Settings, CommentType, getSettings } from "../settings";
import { LanguageClientConsumer } from "../languageClientConsumer";

// eslint-disable-next-line @typescript-eslint/no-empty-interface

interface ICommentHelpRequestArguments {
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface

interface ICommentHelpRequestResponse {
content: string[]
}
@@ -88,7 +88,7 @@ class TriggerFinder {
public updateState(document: TextDocument, changeText: string): void {
switch (this.state) {
case SearchState.Searching:
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with

if (changeText.length === 1 && changeText[0] === this.triggerCharacters[this.count]) {
this.state = SearchState.Locked;
this.document = document;
@@ -97,7 +97,7 @@ class TriggerFinder {
break;

case SearchState.Locked:
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with

if (document === this.document && changeText.length === 1 && changeText[0] === this.triggerCharacters[this.count]) {
this.count++;
if (this.count === this.triggerCharacters.length) {
@@ -136,7 +136,7 @@ class HelpCompletionProvider extends LanguageClientConsumer {
return this.triggerFinderHelpComment.found;
}

// eslint-disable-next-line @typescript-eslint/no-empty-function

public override onLanguageClientSet(_languageClient: LanguageClient): void {}

public updateState(document: TextDocument, changeText: string, changeRange: Range): void {
6 changes: 2 additions & 4 deletions src/features/PesterTests.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

import * as path from "path";
import vscode = require("vscode");
import { ILogger } from "../logging";
import type { ILogger } from "../logging";
import { SessionManager } from "../session";
import { getSettings, getChosenWorkspace } from "../settings";
import utils = require("../utils");
@@ -53,9 +53,7 @@ export class PesterTestsFeature implements vscode.Disposable {
launchType: LaunchType,
fileUri?: vscode.Uri): Promise<boolean> {

if (fileUri === undefined) {
fileUri = vscode.window.activeTextEditor?.document.uri;
}
fileUri ??= vscode.window.activeTextEditor?.document.uri;

if (fileUri === undefined) {
return false;
2 changes: 1 addition & 1 deletion src/features/RemoteFiles.ts
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ export class RemoteFilesFeature extends LanguageClientConsumer {
});
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
public override onLanguageClientSet(_languageClient: LanguageClient): void {}

public dispose(): void {
4 changes: 2 additions & 2 deletions src/features/ShowHelp.ts
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import { NotificationType } from "vscode-languageclient";
import { LanguageClientConsumer } from "../languageClientConsumer";
import type { LanguageClient } from "vscode-languageclient/node";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IShowHelpNotificationArguments {
}

@@ -40,7 +40,7 @@ export class ShowHelpFeature extends LanguageClientConsumer {
});
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
public override onLanguageClientSet(_languageClient: LanguageClient): void {}

public dispose(): void {
4 changes: 2 additions & 2 deletions src/features/UpdatePowerShell.ts
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@ import fetch from "node-fetch";
import { SemVer } from "semver";
import vscode = require("vscode");

import { ILogger } from "../logging";
import { IPowerShellVersionDetails } from "../session";
import type { ILogger } from "../logging";
import type { IPowerShellVersionDetails } from "../session";
import { changeSetting, Settings } from "../settings";

interface IUpdateMessageItem extends vscode.MessageItem {
6 changes: 2 additions & 4 deletions src/logging.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { LogOutputChannel, LogLevel, window, Event } from "vscode";
import { type LogOutputChannel, LogLevel, window, type Event } from "vscode";

/** Interface for logging operations. New features should use this interface for the "type" of logger.
* This will allow for easy mocking of the logger during unit tests.
@@ -140,9 +140,7 @@ export class Logger implements ILogger {
export class LanguageClientOutputChannelAdapter implements LogOutputChannel {
private _channel: LogOutputChannel | undefined;
private get channel(): LogOutputChannel {
if (!this._channel) {
this._channel = window.createOutputChannel(this.channelName, {log: true});
}
this._channel ??= window.createOutputChannel(this.channelName, {log: true});
return this._channel;
}

15 changes: 6 additions & 9 deletions src/platform.ts
Original file line number Diff line number Diff line change
@@ -6,12 +6,11 @@ import * as path from "path";
import * as process from "process";
import vscode = require("vscode");
import { integer } from "vscode-languageserver-protocol";
import { ILogger } from "./logging";
import { changeSetting, getSettings, PowerShellAdditionalExePathSettings } from "./settings";
import type { ILogger } from "./logging";
import { changeSetting, getSettings, type PowerShellAdditionalExePathSettings } from "./settings";
import untildify from "untildify";

// This uses require so we can rewire it in unit tests!
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
const utils = require("./utils");

const WindowsPowerShell64BitLabel = "Windows PowerShell (x64)";
@@ -92,7 +91,7 @@ export class PowerShellExeFinder {
private platformDetails: IPlatformDetails,
// Additional configured PowerShells
private additionalPowerShellExes: PowerShellAdditionalExePathSettings,
private logger: ILogger) { }
private logger?: ILogger) { }

/**
* Returns the first available PowerShell executable found in the search order.
@@ -157,7 +156,7 @@ export class PowerShellExeFinder {
yield additionalPwsh;
} else if (!additionalPwsh.suppressWarning) {
const message = `Additional PowerShell '${additionalPwsh.displayName}' not found at '${additionalPwsh.exePath}'!`;
this.logger.writeWarning(message);
this.logger?.writeWarning(message);

if (!getSettings().suppressAdditionalExeNotFoundWarning) {
const selection = await vscode.window.showWarningMessage(message, "Don't Show Again");
@@ -244,7 +243,7 @@ export class PowerShellExeFinder {
* Iterates through the configured additional PowerShell executable locations,
* without checking for their existence.
*/
private async *enumerateAdditionalPowerShellInstallations(): AsyncIterable<IPossiblePowerShellExe> {
public async *enumerateAdditionalPowerShellInstallations(): AsyncIterable<IPossiblePowerShellExe> {
for (const versionName in this.additionalPowerShellExes) {
if (Object.prototype.hasOwnProperty.call(this.additionalPowerShellExes, versionName)) {
let exePath: string | undefined = utils.stripQuotePair(this.additionalPowerShellExes[versionName]);
@@ -631,9 +630,7 @@ class PossiblePowerShellExe implements IPossiblePowerShellExe {
public readonly suppressWarning = false) { }

public async exists(): Promise<boolean> {
if (this.knownToExist === undefined) {
this.knownToExist = await utils.checkIfFileExists(this.exePath);
}
this.knownToExist ??= await utils.checkIfFileExists(this.exePath);
return this.knownToExist ?? false;
}
}
4 changes: 2 additions & 2 deletions src/process.ts
Original file line number Diff line number Diff line change
@@ -4,10 +4,10 @@
import cp = require("child_process");
import path = require("path");
import vscode = require("vscode");
import { ILogger } from "./logging";
import type { ILogger } from "./logging";
import { Settings, validateCwdSetting } from "./settings";
import utils = require("./utils");
import { IEditorServicesSessionDetails } from "./session";
import type { IEditorServicesSessionDetails } from "./session";
import { promisify } from "util";

export class PowerShellProcess {
46 changes: 35 additions & 11 deletions src/session.ts
Original file line number Diff line number Diff line change
@@ -4,25 +4,49 @@
import net = require("net");
import path = require("path");
import vscode = require("vscode");
import TelemetryReporter, { TelemetryEventProperties, TelemetryEventMeasurements } from "@vscode/extension-telemetry";
import TelemetryReporter, {
type TelemetryEventProperties,
type TelemetryEventMeasurements,
} from "@vscode/extension-telemetry";
import { Message } from "vscode-jsonrpc";
import { ILogger, LanguageClientOutputChannelAdapter, LspTraceParser, PsesParser } from "./logging";
import {
type ILogger,
LanguageClientOutputChannelAdapter,
LspTraceParser,
PsesParser,
} from "./logging";
import { PowerShellProcess } from "./process";
import { Settings, changeSetting, getSettings, getEffectiveConfigurationTarget, validateCwdSetting } from "./settings";
import {
Settings,
changeSetting,
getSettings,
getEffectiveConfigurationTarget,
validateCwdSetting,
} from "./settings";
import utils = require("./utils");

import {
CloseAction, CloseHandlerResult, DocumentSelector, ErrorAction, ErrorHandlerResult,
LanguageClientOptions, Middleware, NotificationType,
RequestType0, ResolveCodeLensSignature,
RevealOutputChannelOn,
CloseAction,
type CloseHandlerResult,
DocumentSelector,
ErrorAction,
type ErrorHandlerResult,
type LanguageClientOptions,
type Middleware,
NotificationType,
RequestType0,
type ResolveCodeLensSignature,
RevealOutputChannelOn,
} from "vscode-languageclient";
import { LanguageClient, StreamInfo } from "vscode-languageclient/node";
import { LanguageClient, type StreamInfo } from "vscode-languageclient/node";

import { UpdatePowerShell } from "./features/UpdatePowerShell";
import {
getPlatformDetails, IPlatformDetails, IPowerShellExeDetails,
OperatingSystem, PowerShellExeFinder
getPlatformDetails,
type IPlatformDetails,
type IPowerShellExeDetails,
OperatingSystem,
PowerShellExeFinder,
} from "./platform";
import { LanguageClientConsumer } from "./languageClientConsumer";
import { SemVer, satisfies } from "semver";
@@ -1067,7 +1091,7 @@ class SessionMenuItem implements vscode.QuickPickItem {

constructor(
public readonly label: string,
// eslint-disable-next-line @typescript-eslint/no-empty-function

public readonly callback = async (): Promise<void> => { }) {
}
}
2 changes: 1 addition & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
import vscode = require("vscode");
import utils = require("./utils");
import os = require("os");
import { ILogger } from "./logging";
import type { ILogger } from "./logging";
import untildify from "untildify";
import path = require("path");

2 changes: 1 addition & 1 deletion test/core/paths.test.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

import assert from "assert";
import * as vscode from "vscode";
import { IPowerShellExtensionClient } from "../../src/features/ExternalApi";
import type { IPowerShellExtensionClient } from "../../src/features/ExternalApi";
import utils = require("../utils");
import { checkIfDirectoryExists, checkIfFileExists, ShellIntegrationScript } from "../../src/utils";

76 changes: 28 additions & 48 deletions test/core/platform.test.ts
Original file line number Diff line number Diff line change
@@ -6,16 +6,11 @@ import mockFS = require("mock-fs");
import FileSystem = require("mock-fs/lib/filesystem");
import * as os from "os";
import * as path from "path";
import rewire = require("rewire");
import * as sinon from "sinon";
import * as platform from "../../src/platform";
import * as utils from "../../src/utils";
import * as fs from "fs"; // NOTE: Necessary for mock-fs.
import * as vscode from "vscode";
import { stripQuotePair } from "../../src/utils";

// We have to rewire the platform module so that mock-fs can be used, as it
// overrides the fs module but not the vscode.workspace.fs module.
const platformMock = rewire("../../src/platform");

// eslint-disable-next-line @typescript-eslint/require-await
async function fakeCheckIfFileExists(targetPath: string | vscode.Uri): Promise<boolean> {
@@ -42,15 +37,6 @@ async function fakeReadDirectory(targetPath: string | vscode.Uri): Promise<strin
return fs.readdirSync(targetPath instanceof vscode.Uri ? targetPath.fsPath : targetPath);
}

const utilsMock = {
checkIfFileExists: fakeCheckIfFileExists,
checkIfDirectoryExists: fakeCheckIfDirectoryExists,
readDirectory: fakeReadDirectory,
stripQuotePair: stripQuotePair
};

platformMock.__set__("utils", utilsMock);

/**
* Describes a platform on which the PowerShell extension should work,
* including the test conditions (filesystem, environment variables).
@@ -847,8 +833,22 @@ function setupTestEnvironment(testPlatform: ITestPlatform): void {
}

describe("Platform module", function () {
before(function () {
sinon.stub(utils, "checkIfFileExists").callsFake(fakeCheckIfFileExists);
sinon.stub(utils, "checkIfDirectoryExists").callsFake(fakeCheckIfDirectoryExists);
sinon.stub(utils, "readDirectory").callsFake(fakeReadDirectory);
});

after(function () {
sinon.restore();
})

afterEach(function () {
mockFS.restore();
});

it("Gets the correct platform details", function () {
const platformDetails: platform.IPlatformDetails = platformMock.getPlatformDetails();
const platformDetails: platform.IPlatformDetails = platform.getPlatformDetails();
switch (process.platform) {
case "darwin":
assert.strictEqual(
@@ -901,31 +901,26 @@ describe("Platform module", function () {
});

describe("Default PowerShell installation", function () {
afterEach(function () {
sinon.restore();
mockFS.restore();
});

for (const testPlatform of successTestCases) {
it(`Finds it on ${testPlatform.name}`, async function () {
setupTestEnvironment(testPlatform);

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, {});

const defaultPowerShell = await powerShellExeFinder.getFirstAvailablePowerShellInstallation();
const expectedPowerShell = testPlatform.expectedPowerShellSequence[0];

assert.strictEqual(defaultPowerShell.exePath, expectedPowerShell.exePath);
assert.strictEqual(defaultPowerShell.displayName, expectedPowerShell.displayName);
assert.strictEqual(defaultPowerShell.supportsProperArguments, expectedPowerShell.supportsProperArguments);
assert.strictEqual(defaultPowerShell!.exePath, expectedPowerShell.exePath);
assert.strictEqual(defaultPowerShell!.displayName, expectedPowerShell.displayName);
assert.strictEqual(defaultPowerShell!.supportsProperArguments, expectedPowerShell.supportsProperArguments);
});
}

for (const testPlatform of errorTestCases) {
it(`Fails gracefully on ${testPlatform.name}`, async function () {
setupTestEnvironment(testPlatform);

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, {});

const defaultPowerShell = await powerShellExeFinder.getFirstAvailablePowerShellInstallation();
assert.strictEqual(defaultPowerShell, undefined);
@@ -934,26 +929,21 @@ describe("Platform module", function () {
});

describe("Expected PowerShell installation list", function () {
afterEach(function () {
sinon.restore();
mockFS.restore();
});

for (const testPlatform of successTestCases) {
it(`Finds them on ${testPlatform.name}`, async function () {
setupTestEnvironment(testPlatform);

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, {});

const foundPowerShells = await powerShellExeFinder.getAllAvailablePowerShellInstallations();

for (let i = 0; i < testPlatform.expectedPowerShellSequence.length; i++) {
const foundPowerShell = foundPowerShells[i];
const expectedPowerShell = testPlatform.expectedPowerShellSequence[i];

assert.strictEqual(foundPowerShell?.exePath, expectedPowerShell.exePath);
assert.strictEqual(foundPowerShell?.displayName, expectedPowerShell.displayName);
assert.strictEqual(foundPowerShell?.supportsProperArguments, expectedPowerShell.supportsProperArguments);
assert.strictEqual(foundPowerShell.exePath, expectedPowerShell.exePath);
assert.strictEqual(foundPowerShell.displayName, expectedPowerShell.displayName);
assert.strictEqual(foundPowerShell.supportsProperArguments, expectedPowerShell.supportsProperArguments);
}

assert.strictEqual(
@@ -967,7 +957,7 @@ describe("Platform module", function () {
it(`Fails gracefully on ${testPlatform.name}`, async function () {
setupTestEnvironment(testPlatform);

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, {});

const foundPowerShells = await powerShellExeFinder.getAllAvailablePowerShellInstallations();
assert.strictEqual(foundPowerShells.length, 0);
@@ -976,11 +966,6 @@ describe("Platform module", function () {
});

describe("Windows PowerShell path fix", function () {
afterEach(function () {
sinon.restore();
mockFS.restore();
});

for (const testPlatform of successTestCases
.filter((tp) => tp.platformDetails.operatingSystem === platform.OperatingSystem.Windows)) {

@@ -1007,7 +992,7 @@ describe("Platform module", function () {
altWinPSPath = null;
}

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, {});

assert.strictEqual(powerShellExeFinder.fixWindowsPowerShellPath(winPSPath), winPSPath);

@@ -1019,16 +1004,11 @@ describe("Platform module", function () {
});

describe("PowerShell executables from 'powerShellAdditionalExePaths' are found", function () {
afterEach(function () {
sinon.restore();
mockFS.restore();
});

for (const testPlatform of successAdditionalTestCases) {
it(`Guesses for ${testPlatform.name}`, async function () {
setupTestEnvironment(testPlatform);

const powerShellExeFinder = new platformMock.PowerShellExeFinder(testPlatform.platformDetails, additionalPowerShellExes);
const powerShellExeFinder = new platform.PowerShellExeFinder(testPlatform.platformDetails, additionalPowerShellExes);

let i = 0;
for await (const additionalPwsh of powerShellExeFinder.enumerateAdditionalPowerShellInstallations()) {
35 changes: 30 additions & 5 deletions test/features/DebugSession.test.ts
Original file line number Diff line number Diff line change
@@ -4,13 +4,37 @@
import structuredClone from "@ungap/structured-clone"; //Polyfill for structuredClone which will be present in Node 17.
import * as assert from "assert";
import Sinon from "sinon";
import { DebugAdapterNamedPipeServer, DebugConfiguration, DebugSession, Extension, ExtensionContext, Range, SourceBreakpoint, TextDocument, TextEditor, Uri, commands, debug, extensions, window, workspace } from "vscode";
import {
DebugAdapterNamedPipeServer,
type DebugConfiguration,
type DebugSession,
type Extension,
type ExtensionContext,
Range,
SourceBreakpoint,
type TextDocument,
type TextEditor,
Uri,
commands,
debug,
extensions,
window,
workspace,
} from "vscode";
import { Disposable } from "vscode-languageserver-protocol";
import { DebugConfig, DebugSessionFeature, DebugConfigurations } from "../../src/features/DebugSession";
import { IPowerShellExtensionClient } from "../../src/features/ExternalApi";
import {
DebugConfig,
DebugSessionFeature,
DebugConfigurations,
} from "../../src/features/DebugSession";
import type { IPowerShellExtensionClient } from "../../src/features/ExternalApi";
import * as platform from "../../src/platform";
import { IPlatformDetails } from "../../src/platform";
import { IEditorServicesSessionDetails, IPowerShellVersionDetails, SessionManager } from "../../src/session";
import type { IPlatformDetails } from "../../src/platform";
import {
type IEditorServicesSessionDetails,
type IPowerShellVersionDetails,
SessionManager,
} from "../../src/session";
import * as utils from "../../src/utils";
import { BuildBinaryModuleMock, WaitEvent, ensureEditorServicesIsConnected, stubInterface, testLogger } from "../utils";

@@ -167,6 +191,7 @@ describe("DebugSessionFeature", () => {

assert.equal(actual, undefined);
assert.match(logger.writeAndShowError.firstCall.args[0], /debugging this file type/);
Sinon.restore();
});

it("Prevents debugging untitled files in a temp console", async () => {
2 changes: 1 addition & 1 deletion test/features/ExternalApi.test.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

import * as assert from "assert";
import utils = require("../utils");
import { IExternalPowerShellDetails, IPowerShellExtensionClient } from "../../src/features/ExternalApi";
import type { IExternalPowerShellDetails, IPowerShellExtensionClient } from "../../src/features/ExternalApi";

describe("ExternalApi feature", function () {
describe("External extension registration", function () {
2 changes: 1 addition & 1 deletion test/features/UpdatePowerShell.test.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
import assert from "assert";
import { UpdatePowerShell } from "../../src/features/UpdatePowerShell";
import { Settings } from "../../src/settings";
import { IPowerShellVersionDetails } from "../../src/session";
import type { IPowerShellVersionDetails } from "../../src/session";
import { testLogger } from "../utils";

describe("UpdatePowerShell feature", function () {
115 changes: 0 additions & 115 deletions test/runTests.ts

This file was deleted.

71 changes: 0 additions & 71 deletions test/runTestsInner.ts

This file was deleted.

6 changes: 3 additions & 3 deletions test/utils.ts
Original file line number Diff line number Diff line change
@@ -3,14 +3,14 @@

import * as path from "path";
import * as vscode from "vscode";
import { ILogger } from "../src/logging";
import { IPowerShellExtensionClient } from "../src/features/ExternalApi";
import type { ILogger } from "../src/logging";
import type { IPowerShellExtensionClient } from "../src/features/ExternalApi";
import { execSync } from "child_process";

// This lets us test the rest of our path assumptions against the baseline of
// this test file existing at `<root>/test/utils.js`.
export const rootPath = path.resolve(__dirname, "../");
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const packageJSON: any = require(path.resolve(rootPath, "package.json"));
export const extensionId = `${packageJSON.publisher}.${packageJSON.name}`;

26 changes: 12 additions & 14 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
// NOTE: The TypeScript compiler is only used for building the tests (and
// the sources which the tests need). The extension is built with `esbuild`.
{
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"sourceMap": true,
"rootDir": ".",
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"useUnknownInCatchVariables": true
"target": "ESNext",
"esModuleInterop": true,
"skipLibCheck": true,
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"verbatimModuleSyntax": true,
"strict": true,
"noEmit": true,
"module": "Preserve"
},
"include": [ "src", "test" ],
"exclude": [ "node_modules/@ungap/structured-clone" ]
"include": ["src/**/*.ts", "test/**/*.ts", "*.mjs"],
"exclude": ["node_modules"]
}
4 changes: 2 additions & 2 deletions vscode-powershell.build.ps1
Original file line number Diff line number Diff line change
@@ -24,12 +24,12 @@ function Get-EditorServicesPath {

task RestoreNode -If { !(Test-Path ./node_modules/esbuild) } {
Write-Build DarkGreen "Restoring build dependencies"
Invoke-BuildExec { & npm ci --omit=optional }
Invoke-BuildExec { & npm ci --omit optional }
}

task RestoreNodeOptional -If { !(Test-Path ./node_modules/eslint) } {
Write-Build DarkMagenta "Restoring build, test, and lint dependencies"
Invoke-BuildExec { & npm ci --include=optional }
Invoke-BuildExec { & npm ci --include optional }
}

task RestoreEditorServices -If (Get-EditorServicesPath) {