Write-Error in classes does not work with Should -Throw (in Codespaces)
Checklist
- [x] Issue has a meaningful title
- [x] I have searched the existing issues. See all issues
- [x] I have tested using the latest version of Pester. See Installation and update guide.
What is the issue?
when running:
{ $ErrorActionPreference = "stop"; [notion_parent]::ConvertFromObject($obj) } | Should -Throw
in a codespace
and providing input that should lead to an error, I would suspect the test to pass, unfortunately it claims "no error thrown":
[-] Creates an error for unknown type 27ms (26ms|1ms) at { $ErrorActionPreference = "stop"; [notion_parent]::ConvertFromObject($obj) } | Should -Throw, /workspaces/Notion/tests/Unit/Classes/Parent/parent.Tests.ps1:89 at <ScriptBlock>, /workspaces/Notion/tests/Unit/Classes/Parent/parent.Tests.ps1:89 Expected an exception to be thrown, but no exception was thrown.
When catching it in try catch directly, it executes the catch block + if I set the erroraction to stop in the function of the class, the test passes (but we want the user to decide, if it should be terminating or not)
on windows in powershell 7 it leads to the desired result:
Expected Behavior
The test should work in the Codespace (Linux) the same way as they do on windows.
Steps To Reproduce
In a codespace:
Define a class with a function, that uses write error (minified):
enum notion_parent_type
# https://developers.notion.com/reference/parent-object
{
database_id
page_id
workspace
block_id
}
class notion_parent
{
#https://developers.notion.com/reference/parent-object
[notion_parent_type]$type
notion_parent()
{
}
notion_parent([notion_parent_type]$type)
{
$this.type = $type
}
static [notion_parent] ConvertFromObject($Value)
{
$parent_obj = $null
switch ($Value.type)
{
"database_id"
{
Write-Hot "database_id"
}
"page_id"
{
Write-Hot "page_id"
}
"workspace"
{
Write-Hot "workspace"
}
"block_id"
{
Write-Hot "block_id"
}
default
{
Write-Error "Unknown parent type: $($Value.type)" -Category InvalidData -RecommendedAction "Check the parent type and try again. Supported types are: database, page, workspace, block"
}
}
return $parent_obj
}
}
Write a test for the class
{ $ErrorActionPreference = "stop"; [notion_parent]::ConvertFromObject($obj) } | Should -Throw
Describe your environment
Codespace:
Pester version : 6.0.0-alpha5 /workspaces/Notion/output/RequiredModules/Pester/6.0.0/Pester.psm1
PowerShell version : 7.5.1
OS version : Unix 6.8.0.1027
Local Dev: Pester version : 6.0.0-alpha5 C:\Users\fasteiner\OneDrive - TTTECH COMPUTERTECHNIK AG\Documents\PowerShell\Modules\Pester\6.0.0\Pester.psm1 PowerShell version : 7.5.1 OS version : Microsoft Windows NT 10.0.26100.0
Possible Solution?
No response
Thank you for the discussion at PSConfEU, issue and repro. This looks like a module scoping issue. Try setting a breakpoint inside your test and inside the class method.
Checking inside the It-block:
Breakpoint in the class method:
Modules have a separate session state for it's own variables, functions etc, so the value set outside is not inherited internally where Write-Error is called.
You can solve this by using a scriptblock that is bound to (executes in) the module's session state, meaning it can update the module-internal $ErrorActionPreference. E.g.:
$sb = InModuleScope -ModuleName Notion -ScriptBlock {
# Just outputting a scriptblock so it originates from the module = is module bound
{ $ErrorActionPreference = "stop"; [notion_parent]::ConvertFromObject($obj) }
}
$sb | Should -Throw
I'm not sure how it worked on Windows vs devcontainer, but that may be a different reason. I was not able to reproduce the success in Windows. Maybe you loaded the class manually (not by module import) in the Windows session?
I'm not sure how it worked on Windows vs devcontainer, but that may be a different reason. I was not able to reproduce the success in Windows. Maybe you loaded the class manually (not by module import) in the Windows session?
Yes I indeed loaded the class manually, as I wanted to make a quick repro on Windows, to see if it was a general issue.
You can solve this by using a scriptblock that is bound to (executes in) the module's session state, meaning it can update the module-internal
$ErrorActionPreference. E.g.:$sb = InModuleScope -ModuleName Notion -ScriptBlock { # Just outputting a scriptblock so it originates from the module = is module bound { $ErrorActionPreference = "stop"; [notion_parent]::ConvertFromObject($obj) } } $sb | Should -Throw
Yeah that works, thanks! Is there a particular reason this is needed only for classes?
Modules have a separate session state for it's own variables, functions etc, so the value set outside is not inherited internally where Write-Error is called.
But for functions it works? As soon as you loaded the module (and the classes from the module through accelerators), shouldn't be all in the same context?