Skip to content

Import Pester via its manifest in parallel workers#2819

Merged
nohwnd merged 2 commits into
mainfrom
nohwnd-fix-parallel-worker-pester-manifest
Jun 30, 2026
Merged

Import Pester via its manifest in parallel workers#2819
nohwnd merged 2 commits into
mainfrom
nohwnd-fix-parallel-worker-pester-manifest

Conversation

@nohwnd

@nohwnd nohwnd commented Jun 30, 2026

Copy link
Copy Markdown
Member

Problem

Under Run.Parallel, a test that imports a module whose manifest lists Pester in RequiredModules fails, e.g.:

RequiredModules = @( @{ ModuleName = 'Pester'; ModuleVersion = '5.7.1' } )
Expected no exception to be thrown, but an exception "The required module 'Pester' was not
loaded because no valid module file was found in any module directory." was thrown ...

The same test passes in a sequential run.

Root cause

Invoke-TestInParallel handed each worker $ExecutionContext.SessionState.Module.Path, which is the root module (Pester.psm1), not the manifest (Pester.psd1). Each worker does Import-Module <that path>, and importing the bare .psm1 loads Pester without its manifest metadata, so the worker's Pester reports ModuleVersion 0.0.0.0.

When a test then imports a third‑party module that requires Pester >= 5.7.1, the loaded 0.0.0.0 Pester does not satisfy the requirement, so PowerShell tries to load Pester from disk — throwing either "no valid module file was found in any module directory" (reporter's environment) or "Could not load file or assembly 'Pester … already loaded" (when a real Pester is installed). Sequential runs are unaffected because the parent imported Pester through its manifest, so the version is correct.

Fix

Resolve the manifest (<ModuleBase>/<Name>.psd1) and import that in the worker, falling back to the root‑module path when no manifest is present. Workers now load Pester with its real version, so RequiredModules = Pester resolves against the already‑loaded module.

Test

Adds a regression test in tst/Pester.RSpec.Parallel.ts.ps1 that runs a module declaring RequiredModules = @{ ModuleName = 'Pester'; … } under Run.Parallel. It fails before the fix (worker Pester is 0.0.0.0) and passes after. Verified the full parallel suite stays green and the custom build analyzer is clean.

Fix #2816

Invoke-TestInParallel handed each worker $ExecutionContext.SessionState.Module.Path,
which is the root module (Pester.psm1), not the manifest (Pester.psd1). Importing the
bare .psm1 loads Pester without its manifest metadata, so the worker's Pester reports
ModuleVersion 0.0.0.0.

A test that imports a module whose manifest lists Pester in RequiredModules (e.g.
@{ ModuleName = 'Pester'; ModuleVersion = '5.7.1' }) then fails under Run.Parallel,
because the loaded 0.0.0.0 Pester does not satisfy the required version and PowerShell
tries to load Pester from disk instead - throwing either "no valid module file was
found in any module directory" or an assembly-already-loaded conflict.

Resolve the manifest (.psd1) next to the module and import that, falling back to the
root module path when no manifest is present, so workers load Pester with its real
version.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nohwnd nohwnd added this to the 6.0.0 milestone Jun 30, 2026
@fflaten

fflaten commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Of course! That's why the formatview tests failed when I tested parallel in this repo. 💡

The regression test imports a RequiresPester module whose manifest lists
Pester in RequiredModules. When Run.Parallel falls back to sequential (e.g.
Windows PowerShell 5.1, which has no ForEach-Object -Parallel) that import
runs in the current process, so the module leaks into the shared P-test
session. The next *.ts.ps1 file's `Get-Module Pester | Remove-Module` then
fails with "Unable to remove the module 'Pester' because it is required by
'RequiresPester'".

Remove the module in the test's finally block before deleting its folder.
Unloading first also releases the lock on its .psm1 so the folder removal
cannot fail on Windows. The cleanup is a harmless no-op on the true-parallel
path, where the import stays in the worker runspace.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nohwnd nohwnd merged commit b85be7b into main Jun 30, 2026
13 checks passed
@nohwnd nohwnd deleted the nohwnd-fix-parallel-worker-pester-manifest branch June 30, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parallell bug

2 participants