Skip to content

Fix path regressions and cover with tests #3570

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

Merged
merged 13 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions .vsts-ci/templates/ci-general.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ steps:
inputs:
targetType: inline
script: |
Get-Module -ListAvailable Pester
Install-Module InvokeBuild -Scope CurrentUser -Force
Invoke-Build
Write-Host "##vso[task.setvariable variable=vsixPath]$(Resolve-Path powershell-*.vsix)"
Expand Down
13 changes: 7 additions & 6 deletions src/features/Examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
// Licensed under the MIT License.

import path = require("path");
import utils = require("../utils")
import vscode = require("vscode");

export class ExamplesFeature implements vscode.Disposable {
private command: vscode.Disposable;
private examplesPath: string;
private examplesPath: vscode.Uri;

constructor() {
this.examplesPath = path.resolve(__dirname, "../../examples");
this.examplesPath = vscode.Uri.file(path.resolve(__dirname, "../examples"));
this.command = vscode.commands.registerCommand("PowerShell.OpenExamplesFolder", () => {
vscode.commands.executeCommand(
"vscode.openFolder",
vscode.Uri.file(this.examplesPath),
true);
vscode.commands.executeCommand("vscode.openFolder", this.examplesPath, true);
// Return existence of the path for testing. The `vscode.openFolder`
// command should do this, but doesn't (yet).
return utils.fileExists(this.examplesPath);
});
}

Expand Down
29 changes: 18 additions & 11 deletions src/features/PesterTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,51 @@ export class PesterTestsFeature implements vscode.Disposable {
private invokePesterStubScriptPath: string;

constructor(private sessionManager: SessionManager) {
this.invokePesterStubScriptPath = path.resolve(__dirname, "../../modules/PowerShellEditorServices/InvokePesterStub.ps1");
this.invokePesterStubScriptPath = path.resolve(__dirname, "../modules/PowerShellEditorServices/InvokePesterStub.ps1");

// File context-menu command - Run Pester Tests
this.command = vscode.commands.registerCommand(
"PowerShell.RunPesterTestsFromFile",
(fileUri) => {
this.launchAllTestsInActiveEditor(LaunchType.Run, fileUri);
return this.launchAllTestsInActiveEditor(LaunchType.Run, fileUri);
});
// File context-menu command - Debug Pester Tests
this.command = vscode.commands.registerCommand(
"PowerShell.DebugPesterTestsFromFile",
(fileUri) => {
this.launchAllTestsInActiveEditor(LaunchType.Debug, fileUri);
return this.launchAllTestsInActiveEditor(LaunchType.Debug, fileUri);
});
// This command is provided for usage by PowerShellEditorServices (PSES) only
this.command = vscode.commands.registerCommand(
"PowerShell.RunPesterTests",
(uriString, runInDebugger, describeBlockName?, describeBlockLineNumber?, outputPath?) => {
this.launchTests(uriString, runInDebugger, describeBlockName, describeBlockLineNumber, outputPath);
return this.launchTests(uriString, runInDebugger, describeBlockName, describeBlockLineNumber, outputPath);
});
}

public dispose() {
this.command.dispose();
}

private launchAllTestsInActiveEditor(launchType: LaunchType, fileUri: vscode.Uri) {
private async launchAllTestsInActiveEditor(
launchType: LaunchType,
fileUri: vscode.Uri): Promise<boolean> {

const uriString = (fileUri || vscode.window.activeTextEditor.document.uri).toString();
const launchConfig = this.createLaunchConfig(uriString, launchType);
this.launch(launchConfig);
return this.launch(launchConfig);
}

private async launchTests(
uriString: string,
runInDebugger: boolean,
describeBlockName?: string,
describeBlockLineNumber?: number,
outputPath?: string) {
outputPath?: string): Promise<boolean> {

const launchType = runInDebugger ? LaunchType.Debug : LaunchType.Run;
const launchConfig = this.createLaunchConfig(uriString, launchType, describeBlockName, describeBlockLineNumber, outputPath);
this.launch(launchConfig);
return this.launch(launchConfig);
}

private createLaunchConfig(
Expand Down Expand Up @@ -126,9 +129,9 @@ export class PesterTestsFeature implements vscode.Disposable {
return launchConfig;
}

private launch(launchConfig) {
private async launch(launchConfig): Promise<boolean> {
// Create or show the interactive console
// TODO #367: Check if "newSession" mode is configured
// TODO: #367 Check if "newSession" mode is configured
vscode.commands.executeCommand("PowerShell.ShowSessionConsole", true);

// Write out temporary debug session file
Expand All @@ -137,6 +140,10 @@ export class PesterTestsFeature implements vscode.Disposable {
this.sessionManager.getSessionDetails());

// TODO: Update to handle multiple root workspaces.
vscode.debug.startDebugging(vscode.workspace.workspaceFolders[0], launchConfig);
//
// Ensure the necessary script exists (for testing). The debugger will
// start regardless, but we also pass its success along.
return utils.fileExists(this.invokePesterStubScriptPath)
&& vscode.debug.startDebugging(vscode.workspace.workspaceFolders[0], launchConfig);
}
}
4 changes: 3 additions & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export function load(): ISettings {

const defaultDeveloperSettings: IDeveloperSettings = {
featureFlags: [],
// From `<root>/out/main.js` we go to the directory before <root> and
// then into the other repo.
bundledModulesPath: "../../PowerShellEditorServices/module",
editorServicesLogLevel: "Normal",
editorServicesWaitForDebugger: false,
Expand Down Expand Up @@ -234,7 +236,7 @@ export function load(): ISettings {
promptToUpdatePackageManagement:
configuration.get<boolean>("promptToUpdatePackageManagement", true),
bundledModulesPath:
"../modules",
"../modules", // Because the extension is always at `<root>/out/main.js`
useX86Host:
configuration.get<boolean>("useX86Host", false),
enableProfileLoading:
Expand Down
23 changes: 21 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import fs = require("fs");
import os = require("os");
import path = require("path");
import vscode = require("vscode");

export const PowerShellLanguageId = "powershell";

export function ensurePathExists(targetPath: string) {
export function ensurePathExists(targetPath: string): void {
// Ensure that the path exists
try {
// TODO: Use vscode.workspace.fs
fs.mkdirSync(targetPath);
} catch (e) {
// If the exception isn't to indicate that the folder exists already, rethrow it.
Expand All @@ -21,6 +23,23 @@ export function ensurePathExists(targetPath: string) {
}
}

// Check that the file exists in an asynchronous manner that relies solely on the VS Code API, not Node's fs library.
export async function fileExists(targetPath: string | vscode.Uri): Promise<boolean> {
try {
await vscode.workspace.fs.stat(
targetPath instanceof vscode.Uri
? targetPath
: vscode.Uri.file(targetPath));
return true;
} catch (e) {
if (e instanceof vscode.FileSystemError.FileNotFound) {
return false;
}
throw e;
}

}

export function getPipePath(pipeName: string) {
if (os.platform() === "win32") {
return "\\\\.\\pipe\\" + pipeName;
Expand All @@ -45,7 +64,7 @@ export interface IEditorServicesSessionDetails {

export type IReadSessionFileCallback = (details: IEditorServicesSessionDetails) => void;

const sessionsFolder = path.resolve(__dirname, "..", "..", "sessions/");
const sessionsFolder = path.resolve(__dirname, "../sessions");
const sessionFilePathPrefix = path.resolve(sessionsFolder, "PSES-VSCode-" + process.env.VSCODE_PID);

// Create the sessions path if it doesn't exist already
Expand Down
28 changes: 28 additions & 0 deletions test/core/paths.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import * as assert from "assert";
import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";
import { suiteSetup } from "mocha";
import utils = require("../utils");

suite("Path assumptions", () => {
suiteSetup(utils.ensureExtensionIsActivated);

// TODO: This is skipped because it intereferes with other tests. Either
// need to find a way to close the opened folder via a Code API, or find
// another way to test this.
test.skip("The examples folder can be opened (and exists)", async () => {
assert(await vscode.commands.executeCommand("PowerShell.OpenExamplesFolder"));
});

test("The session folder is created in the right place", async () => {
assert(fs.existsSync(path.resolve(utils.rootPath, "sessions")));
});

test("The logs folder is created in the right place", async () => {
assert(fs.existsSync(path.resolve(utils.rootPath, "logs")));
});
});
6 changes: 3 additions & 3 deletions test/features/CustomViews.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ hello
content: "console.log('asdf');",
},
{
fileName: "../../testCustomViews.js",
fileName: "../testCustomViews.js",
content: "console.log('asdf');",
},
],
cssFiles: [],
expectedHtmlString: `<html><head></head><body>
hello
<script src="${convertToVSCodeResourceScheme(path.join(__dirname, "testCustomViews.js"))}"></script>
<script src="${convertToVSCodeResourceScheme(path.join(__dirname, "../../testCustomViews.js"))}"></script>
<script src="${convertToVSCodeResourceScheme(path.join(__dirname, "../testCustomViews.js"))}"></script>
</body></html>`,
},

Expand Down Expand Up @@ -129,7 +129,7 @@ hello
styleSheetPaths: cssPaths,
};
try {
assert.equal(htmlContentView.getContent(), testCase.expectedHtmlString);
assert.strictEqual(htmlContentView.getContent(), testCase.expectedHtmlString);
} finally {
jsPaths.forEach((jsPath) => fs.unlinkSync(vscode.Uri.parse(jsPath).fsPath));
cssPaths.forEach((cssPath) => fs.unlinkSync(vscode.Uri.parse(cssPath).fsPath));
Expand Down
42 changes: 15 additions & 27 deletions test/features/ExternalApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,19 @@
// Licensed under the MIT License.

import * as assert from "assert";
import * as vscode from "vscode";
import { before, beforeEach, afterEach } from "mocha";
import { suiteSetup, setup, teardown } from "mocha";
import utils = require("../utils");
import { IExternalPowerShellDetails, IPowerShellExtensionClient } from "../../src/features/ExternalApi";

// tslint:disable-next-line: no-var-requires
const PackageJSON: any = require("../../../package.json");
const testExtensionId = `${PackageJSON.publisher}.${PackageJSON.name}`;

suite("ExternalApi feature - Registration API", () => {
let powerShellExtensionClient: IPowerShellExtensionClient;
before(async () => {
const powershellExtension = vscode.extensions.getExtension<IPowerShellExtensionClient>(testExtensionId);
if (!powershellExtension.isActive) {
powerShellExtensionClient = await powershellExtension.activate();
return;
}
suiteSetup(async () => {
const powershellExtension = await utils.ensureExtensionIsActivated();
powerShellExtensionClient = powershellExtension!.exports as IPowerShellExtensionClient;
});

test("It can register and unregister an extension", () => {
const sessionId: string = powerShellExtensionClient.registerExternalExtension(testExtensionId);
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
assert.notStrictEqual(sessionId , "");
assert.notStrictEqual(sessionId , null);
assert.strictEqual(
Expand All @@ -31,7 +23,7 @@ suite("ExternalApi feature - Registration API", () => {
});

test("It can register and unregister an extension with a version", () => {
const sessionId: string = powerShellExtensionClient.registerExternalExtension(testExtensionId, "v2");
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId, "v2");
assert.notStrictEqual(sessionId , "");
assert.notStrictEqual(sessionId , null);
assert.strictEqual(
Expand All @@ -48,12 +40,12 @@ suite("ExternalApi feature - Registration API", () => {
});

test("It can't register the same extension twice", async () => {
const sessionId: string = powerShellExtensionClient.registerExternalExtension(testExtensionId);
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
try {
assert.throws(
() => powerShellExtensionClient.registerExternalExtension(testExtensionId),
() => powerShellExtensionClient.registerExternalExtension(utils.extensionId),
{
message: `The extension '${testExtensionId}' is already registered.`
message: `The extension '${utils.extensionId}' is already registered.`
});
} finally {
powerShellExtensionClient.unregisterExternalExtension(sessionId);
Expand All @@ -73,20 +65,16 @@ suite("ExternalApi feature - Other APIs", () => {
let sessionId: string;
let powerShellExtensionClient: IPowerShellExtensionClient;

before(async () => {
const powershellExtension = vscode.extensions.getExtension<IPowerShellExtensionClient>(testExtensionId);
if (!powershellExtension.isActive) {
powerShellExtensionClient = await powershellExtension.activate();
return;
}
suiteSetup(async () => {
const powershellExtension = await utils.ensureExtensionIsActivated();
powerShellExtensionClient = powershellExtension!.exports as IPowerShellExtensionClient;
});

beforeEach(() => {
sessionId = powerShellExtensionClient.registerExternalExtension(testExtensionId);
setup(() => {
sessionId = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
});

afterEach(() => {
teardown(() => {
powerShellExtensionClient.unregisterExternalExtension(sessionId);
});

Expand All @@ -105,6 +93,6 @@ suite("ExternalApi feature - Other APIs", () => {
assert.notStrictEqual(versionDetails.version, "");
assert.notStrictEqual(versionDetails.version, null);

// Start up can take some time... so set the time out to 30s
// Start up can take some time...so set the timeout to 30 seconds.
}).timeout(30000);
});
Loading