Open dkaszews opened 1 year ago
This could theoretically be done, but 1) we need a less generic name to be used in that hashtable to represent that scriptblock. 2) it is not very pleasant to provide that scriptblock for every expansion, and we don't have a more convenient place for it, unless we introduce additional parameter to It, Describe and Context, like --DisplayNameScriptblock.
There is an easy way to get this result, which is simply putting both Expected and AreEqual into the hashtable.
Just for the geeks out there, but I don't recommend using this:
You can also trick the code that does the re-evaluation of the string, by embedding a sub-expression, and have it evaluate any known function or your provided scripblock:
See if you can figure out why it works from the escaping code here: https://github.com/pester/Pester/blob/main/src/Pester.Runtime.ps1#L392-L405
The only downside there is that you get an extra `
before the expanding, but you can just backspace that 😁
Invoke-pester -container (new-pestercontainer -scriptblock {
BeforeDiscovery {
function Same ($Same){ $Same -eq "same" ? "`bTHE SAME" : "`bSOOO DIFFERENT" }
}
describe "a" {
It '<First> and <Second> return `$(Same <AreSame>) results' -ForEach @(
@{ First = 'Foo'; Second = 'Bar'; AreSame = 'same'; Eval = { param ($a) Write-Host -ForegroundColor Red "-$a-" } }
@{ First = 'Foo'; Second = 'Blergh'; AreSame = 'different' }
) {
# the test
}
It '<First> and <Second> return `$(& <Eval> <AreSame>) results' -ForEach @(
@{ First = 'Foo'; Second = 'Bar'; AreSame = 'same'; Eval = { param ($a) $a -eq "same" ? "`bTHE SAME" : "`bSOOO DIFFERENT" } }
@{ First = 'Foo'; Second = 'Blergh'; AreSame = 'different'; Eval = { param ($a) $a -eq "same" ? "`bTHE SAME" : "`bSOOO DIFFERENT" } }
) {
# the test
}
}
}) -Output Diagnostic
Running tests.
Describing a
[+] Foo and Bar return THE SAME results 6ms (3ms|4ms)
[+] Foo and Blergh return SOOO DIFFERENT results 2ms (1ms|1ms)
[+] Foo and Bar return THE SAME results 6ms (5ms|2ms)
[+] Foo and Blergh return SOOO DIFFERENT results 5ms (3ms|1ms)
Tests completed in 184ms
Tests Passed: 4, Failed: 0, Skipped: 0 NotRun: 0
I think you misunderstood, I am proposing to pass the scriptblock into the -Name
parameter, not the -ForEach
hashtable for every case. So the syntax is nearly identical as current templating, just wrapped into braces and double quotes instead of singles:
# Old style
It 'Tests with <First> and <Second>' ...
# New style
It {"Tests with $First and $Second"} ...
No new parameters are required, all Pester has to do is check the type of -Name
(example code, did not look into internals):
- $DisplayName = ProcessTemplate $Name $TestCase
+ if ($Name is [String]) {
+ $DisplayName = Process-Template $Name $TestCase
+ } else {
+ $Display Name = Invoke-Command $Name -ArgumentList $TestCase
+ }
Maybe some other PowerShell magic will be required to pass the arguments without having to create param()
, but you get the idea.
An alternative idea with similar syntax is to add a parameter which instead of processing the template will just call $ExecutionContext.InvokeCommand.ExpandString($Name)
. The examples above become then:
It -ExpandName 'Tests with $First and $Second' ...
I find it less elegant, as it requires extra parameter and use of single quotes to delay expansion, which may look weird and unintuitive.
I don't really understand why Pester did not go into one of those approaches in the first place. It limits the templating to just variables and their children, and the hack you have shown indicates that it is possible to break out of this "sandbox" anyways.
There is an easy way to get this result, which is simply putting both Expected and AreEqual into the hashtable.
By same argument, you could just write the entire test name into an argument and use -Name '<DisplayName>'
, but that kinda defeats the whole point of templating, doesn't it?
Checklist
Summary of the feature request
I often find myself compromising on the data I use with
-ForEach
/-TestCases
just to get more readable test names. For example:I would prefer to put into data just
Expected = $true
andExpected = $false
, but then I have no way of writing the test template to produce fully gramatical English sentence, as those do not support e.g. ternary operator. Trying to write something like'return <Expected ? "same" : "different">'
just fails to expand the template, or fails the discovery entirely.One idea I had to (hopefully) easily implement advanced templating without breaking changes is to allow the
Name
parameter to be a[ScriptBlock]
instead. If so, it can be called with all the parameters of the test case. Allowing the user to immediately return a string with full variable substitution should cover most of the cases in a compact way. For example, see below.How should it work?