diff --git a/InvokePesterStub.ps1 b/InvokePesterStub.ps1 index 8b6f204cce..d9aa31a132 100755 --- a/InvokePesterStub.ps1 +++ b/InvokePesterStub.ps1 @@ -47,36 +47,100 @@ param( # If specified, executes all the tests in the specified test script. [Parameter()] [switch] - $All + $All, + + [Parameter()] + [switch] $MinimumVersion5, + + [Parameter(Mandatory)] + [string] $Output ) $pesterModule = Microsoft.PowerShell.Core\Get-Module Pester +# add one line, so the subsequent output is not shifted to the side +Write-Output '' if (!$pesterModule) { Write-Output "Importing Pester module..." - $pesterModule = Microsoft.PowerShell.Core\Import-Module Pester -ErrorAction Ignore -PassThru + $minimumVersion = if ($MinimumVersion5) { "5.0.0" } else { "0.0.0" } + $versionMessage = " version $minimumVersion" + $pesterModule = Microsoft.PowerShell.Core\Import-Module Pester -ErrorAction Ignore -PassThru -MinimumVersion $minimumVersion 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" + Write-Warning "Failed to import Pester$(if ($MinimumVersion5){ $versionMessage }). You must install Pester module to run or debug Pester tests." + Write-Warning "You can install Pester by executing: Install-Module Pester $(if ($MinimumVersion5) {"-MinimumVersion 5.0.0" }) -Scope CurrentUser -Force" return } } -if ($All) { - Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} +$pester4Output = switch ($Output) { + "None" { "None" } + "Minimal" { "Fails" } + default { "All" } } -elseif ($TestName) { - Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} -TestName $TestName + +if ($MinimumVersion5 -and $pesterModule.Version -lt "5.0.0") { + Write-Warning "Pester 5.0.0 or newer is required because setting PowerShell > Pester: Enable Legacy Code Lens is disabled, but Pester $($pesterModule.Version) is loaded. Some of the code lense features might not work as expected." +} + + +if ($All) { + if ($pesterModule.Version -ge '5.0.0') { + $configuration = @{ + Run = @{ + Path = $ScriptPath + } + } + # only override this if user asks us to do it, to allow Pester to pick up + # $PesterPreference from caller context and merge it with the configuration + # we provide below, this way user can specify his output (and other) settings + # using the standard [PesterConfiguration] object, and we can avoid providing + # settings for everything + if ("FromPreference" -ne $Output) { + $configuration.Add('Output', @{ Verbosity = $Output }) + } + Pester\Invoke-Pester -Configuration $configuration | Out-Null + } + else { + Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} -Show $pester4Output + } } elseif (($LineNumber -match '\d+') -and ($pesterModule.Version -ge '4.6.0')) { - Pester\Invoke-Pester -Script $ScriptPath -PesterOption (New-PesterOption -ScriptBlockFilter @{ - IncludeVSCodeMarker=$true; Line=$LineNumber; Path=$ScriptPath}) + if ($pesterModule.Version -ge '5.0.0') { + $configuration = @{ + Run = @{ + Path = $ScriptPath + } + Filter = @{ + Line = "${ScriptPath}:$LineNumber" + } + } + if ("FromPreference" -ne $Output) { + $configuration.Add('Output', @{ Verbosity = $Output }) + } + Pester\Invoke-Pester -Configuration $configuration | Out-Null + } + else { + Pester\Invoke-Pester -Script $ScriptPath -PesterOption (New-PesterOption -ScriptBlockFilter @{ + IncludeVSCodeMarker=$true; Line=$LineNumber; Path=$ScriptPath}) -Show $pester4Output + } +} +elseif ($TestName) { + if ($pesterModule.Version -ge '5.0.0') { + throw "Running tests by test name is unsafe. This should not trigger for Pester 5." + } + else { + Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} -TestName $TestName -Show $pester4Output + } } else { + if ($pesterModule.Version -ge '5.0.0') { + throw "Running tests by expandable string is unsafe. This should not trigger for Pester 5." + } + # 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} + Pester\Invoke-Pester -Script $ScriptPath -PesterOption @{IncludeVSCodeMarker=$true} -Show $pester4Output } diff --git a/package.json b/package.json index ad2840184b..e7d2e90bad 100644 --- a/package.json +++ b/package.json @@ -750,6 +750,21 @@ "type": "array", "default": null, "description": "An array of strings that enable experimental features in the PowerShell extension." + }, + "powershell.pester.enableLegacyCodeLens": { + "type": "boolean", + "default": true, + "description": "Enable code lense that is compatible with Pester 4. Disabling this will show 'Run Tests' on all It, Describe and Context blocks, and will correctly work only with Pester 5 and newer." + }, + "powershell.pester.outputVerbosity": { + "type": "string", + "enum": [ + "FromPreference", + "Normal", + "Minimal" + ], + "default": "FromPreference", + "description": "Defines the verbosity of output to be used. For Pester 5 and newer the default value FromPreference, will use the Output settings from the $PesterPreference defined in the caller context, and will default to Normal if there is none. For Pester 4 the FromPreference and Normal options map to All, and Minimal option maps to Fails." } } }, diff --git a/src/features/PesterTests.ts b/src/features/PesterTests.ts index ea2c5fea9f..87872a13ca 100644 --- a/src/features/PesterTests.ts +++ b/src/features/PesterTests.ts @@ -109,6 +109,12 @@ export class PesterTestsFeature implements IFeature { launchConfig.args.push("-TestName", `'${testName}'`); } + if (!settings.pester.useLegacyCodeLens) { + launchConfig.args.push("-MinimumVersion5"); + } + + launchConfig.args.push("-Output", `'${settings.pester.outputVerbosity}'`); + return launchConfig; } diff --git a/src/settings.ts b/src/settings.ts index a8e931aaf8..34ce5c356c 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -94,6 +94,7 @@ export interface ISettings { integratedConsole?: IIntegratedConsoleSettings; bugReporting?: IBugReportingSettings; sideBar?: ISideBarSettings; + pester?: IPesterSettings; } export interface IStartAsLoginShellSettings { @@ -113,6 +114,11 @@ export interface ISideBarSettings { CommandExplorerVisibility?: boolean; } +export interface IPesterSettings { + useLegacyCodeLens?: boolean; + outputVerbosity?: string; +} + export function load(): ISettings { const configuration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration( @@ -177,6 +183,11 @@ export function load(): ISettings { CommandExplorerVisibility: true, }; + const defaultPesterSettings: IPesterSettings = { + useLegacyCodeLens: true, + outputVerbosity: "FromPreference", + }; + return { startAutomatically: configuration.get("startAutomatically", true), @@ -212,6 +223,8 @@ export function load(): ISettings { configuration.get("bugReporting", defaultBugReportingSettings), sideBar: configuration.get("sideBar", defaultSideBarSettings), + pester: + configuration.get("pester", defaultPesterSettings), startAsLoginShell: // tslint:disable-next-line // We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107