Skip to content
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

Migrate Pester version detection into an InovkePester stub script #1776

Merged
merged 6 commits into from
Mar 5, 2019
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
82 changes: 82 additions & 0 deletions InvokePesterStub.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env pwsh

<#
.SYNOPSIS
Stub around Invoke-Pester command used by VSCode PowerShell extension.
.DESCRIPTION
The stub checks the version of Pester and if >= 4.6.0, invokes Pester
using the LineNumber parameter (if specified). Otherwise, it invokes
using the TestName parameter (if specified). If the All parameter
is specified, then all the tests are invoked in the specifed file.
Finally, if none of these three parameters are specified, all tests
are invoked and a warning is issued indicating what the user can do
to allow invocation of individual Describe blocks.
.EXAMPLE
PS C:\> .\InvokePesterStub.ps1 ~\project\test\foo.tests.ps1 -LineNumber 14
Invokes a specific test by line number in the specified file.
.EXAMPLE
PS C:\> .\InvokePesterStub.ps1 ~\project\test\foo.tests.ps1 -TestName 'Foo Tests'
Invokes a specific test by test name in the specified file.
.EXAMPLE
PS C:\> .\InvokePesterStub.ps1 ~\project\test\foo.tests.ps1 -All
Invokes all tests in the specified file.
.INPUTS
None
.OUTPUTS
None
#>
param(
# Specifies the path to the test script.
[Parameter(Position=0, Mandatory)]
[ValidateNotNullOrEmpty()]
[string]
$ScriptPath,

# Specifies the name of the test taken from the Describe block's name.
[Parameter()]
[string]
$TestName,

# Specifies the starting line number of the DescribeBlock. This feature requires
# Pester 4.6.0 or higher.
[Parameter()]
[ValidatePattern('\d*')]
[string]
$LineNumber,

# If specified, executes all the tests in the specified test script.
[Parameter()]
[switch]
$All
)

$pesterModule = Microsoft.PowerShell.Core\Get-Module Pester
rkeithhill marked this conversation as resolved.
Show resolved Hide resolved
if (!$pesterModule) {
Write-Output "Importing Pester module..."
$pesterModule = Microsoft.PowerShell.Core\Import-Module Pester -ErrorAction Ignore -PassThru
if (!$pesterModule) {
# If we still don't have an imported Pester module, that is (most likely) because Pester is not installed.
Write-Warning "Failed to import the Pester module. You must install Pester to run or debug Pester tests."
Write-Warning "You can install Pester by executing: Install-Module Pester -Scope CurrentUser -Force"
return
}
}

if ($All) {
Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true}
}
elseif ($TestName) {
Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} -TestName $TestName
}
elseif (($LineNumber -match '\d+') -and ($pesterModule.Version -ge '4.6.0')) {
rkeithhill marked this conversation as resolved.
Show resolved Hide resolved
Pester\Invoke-Pester -Script $ScriptPath -PesterOption (New-PesterOption -ScriptBlockFilter @{
IncludeVSCodeMarker=$true; Line=$LineNumber; Path=$ScriptPath})
}
else {
# We get here when the TestName expression is of type ExpandableStringExpressionAst.
# PSES will not attempt to "evaluate" the expression so it returns null for the TestName.
Write-Warning "The Describe block's TestName cannot be evaluated. EXECUTING ALL TESTS instead."
Write-Warning "To avoid this, install Pester >= 4.6.0 or remove any expressions in the TestName."

Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true}
}
58 changes: 28 additions & 30 deletions src/features/PesterTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ export class PesterTestsFeature implements IFeature {

private command: vscode.Disposable;
private languageClient: LanguageClient;
private invokePesterStubScriptPath: string;

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

// File context-menu command - Run Pester Tests
this.command = vscode.commands.registerCommand(
"PowerShell.RunPesterTestsFromFile",
Expand All @@ -35,8 +38,8 @@ export class PesterTestsFeature implements IFeature {
// This command is provided for usage by PowerShellEditorServices (PSES) only
this.command = vscode.commands.registerCommand(
"PowerShell.RunPesterTests",
(uriString, runInDebugger, describeBlockName?) => {
this.launchTests(uriString, runInDebugger, describeBlockName);
(uriString, runInDebugger, describeBlockName?, describeBlockLineNumber?) => {
this.launchTests(uriString, runInDebugger, describeBlockName, describeBlockLineNumber);
});
}

Expand All @@ -51,38 +54,22 @@ export class PesterTestsFeature implements IFeature {
private launchAllTestsInActiveEditor(launchType: LaunchType) {
const uriString = vscode.window.activeTextEditor.document.uri.toString();
const launchConfig = this.createLaunchConfig(uriString, launchType);
launchConfig.args.push("-All");
this.launch(launchConfig);
}

private async launchTests(uriString: string, runInDebugger: boolean, describeBlockName?: string) {
// PSES passes null for the describeBlockName to signal that it can't evaluate the TestName.
if (!describeBlockName) {
const answer = await vscode.window.showErrorMessage(
"This Describe block's TestName parameter cannot be evaluated. " +
`Would you like to ${runInDebugger ? "debug" : "run"} all the tests in this file?`,
"Yes", "No");

if (answer !== "Yes") {
return;
}
}
private async launchTests(
uriString: string,
runInDebugger: boolean,
describeBlockName?: string,
describeBlockLineNumber?: number) {

const launchType = runInDebugger ? LaunchType.Debug : LaunchType.Run;
const launchConfig = this.createLaunchConfig(uriString, launchType);

if (describeBlockName) {
launchConfig.args.push("-TestName");
// Escape single quotes inside double quotes by doubling them up
if (describeBlockName.includes("'")) {
describeBlockName = describeBlockName.replace(/'/g, "''");
}
launchConfig.args.push(`'${describeBlockName}'`);
}

const launchConfig = this.createLaunchConfig(uriString, launchType, describeBlockName, describeBlockLineNumber);
this.launch(launchConfig);
}

private createLaunchConfig(uriString: string, launchType: LaunchType) {
private createLaunchConfig(uriString: string, launchType: LaunchType, testName?: string, lineNum?: number) {
const uri = vscode.Uri.parse(uriString);
const currentDocument = vscode.window.activeTextEditor.document;
const settings = Settings.load();
Expand All @@ -95,12 +82,10 @@ export class PesterTestsFeature implements IFeature {
request: "launch",
type: "PowerShell",
name: "PowerShell Launch Pester Tests",
script: "Invoke-Pester",
script: this.invokePesterStubScriptPath,
args: [
"-Script",
"-ScriptPath",
`'${scriptPath}'`,
"-PesterOption",
"@{IncludeVSCodeMarker=$true}",
],
internalConsoleOptions: "neverOpen",
noDebug: (launchType === LaunchType.Run),
Expand All @@ -111,6 +96,19 @@ export class PesterTestsFeature implements IFeature {
: path.dirname(currentDocument.fileName),
};

if (lineNum) {
launchConfig.args.push("-LineNumber", `${lineNum}`);
}

if (testName) {
// Escape single quotes inside double quotes by doubling them up
if (testName.includes("'")) {
testName = testName.replace(/'/g, "''");
}

launchConfig.args.push("-TestName", `'${testName}'`);
}

return launchConfig;
}

Expand Down