diff --git a/src/Pester.RSpec.ps1 b/src/Pester.RSpec.ps1 index e15094b98..e9dd3c318 100644 --- a/src/Pester.RSpec.ps1 +++ b/src/Pester.RSpec.ps1 @@ -30,7 +30,8 @@ foreach ($item in $items) { if ($item.PSIsContainer) { # this is an existing directory search it for tests file - & $SafeCommands['Get-ChildItem'] -Recurse -Path $item -Filter "*$Extension" -File + # use -Force to include hidden items (e.g. dot-prefixed folders on Linux) + & $SafeCommands['Get-ChildItem'] -Recurse -Path $item -Filter "*$Extension" -File -Force } elseif ("FileSystem" -ne $item.PSProvider.Name) { # item is not a directory and exists but is not a file so we are not interested @@ -60,13 +61,30 @@ else { # this is a path that does not exist so let's hope it is # a wildcarded path that will resolve to some files - & $SafeCommands['Get-ChildItem'] -Recurse -Path $p -Filter "*$Extension" -File + # use -Force to include hidden items (e.g. dot-prefixed folders on Linux) + & $SafeCommands['Get-ChildItem'] -Recurse -Path $p -Filter "*$Extension" -File -Force } } + # Exclude files found inside version-control metadata directories. + # These are almost never wanted and .git in particular can contain many files. + $vcsDirectories = @('.git', '.svn', '.hg') + $filteredFiles = foreach ($f in $files) { + # normalize backslashes for cross-platform ease of use + $normalizedPath = $f.FullName -replace "/", "\" + $dominated = $false + foreach ($vcs in $vcsDirectories) { + if ($normalizedPath -like "*\${vcs}\*") { + $dominated = $true + break + } + } + if (-not $dominated) { $f } + } + # Deduplicate files if overlapping -Path values - $uniquePaths = [System.Collections.Generic.HashSet[string]]::new(@($files).Count) - $uniqueFiles = foreach ($f in $files) { if ($uniquePaths.Add($f.FullName)) { $f } } + $uniquePaths = [System.Collections.Generic.HashSet[string]]::new(@($filteredFiles).Count) + $uniqueFiles = foreach ($f in $filteredFiles) { if ($uniquePaths.Add($f.FullName)) { $f } } Filter-Excluded -Files $uniqueFiles -ExcludePath $ExcludePath | & $SafeCommands['Where-Object'] { $_ } } diff --git a/tst/Pester.RSpec.ts.ps1 b/tst/Pester.RSpec.ts.ps1 index c8847d604..0f6a32389 100644 --- a/tst/Pester.RSpec.ts.ps1 +++ b/tst/Pester.RSpec.ts.ps1 @@ -2966,4 +2966,66 @@ i -PassThru:$PassThru { $ex.Exception.Message | Verify-Like '*Unbound scriptblock*' } } + + # Regression test for https://github.com/pester/Pester/issues/2515 + # Find-File should discover test files inside hidden (dot-prefixed) directories. + # Without -Force on Get-ChildItem, hidden folders are silently skipped. + b "Find-File discovers hidden folders" { + t "discovers test files in dot-prefixed (hidden) subdirectories" { + $tempDir = Join-Path ([IO.Path]::GetTempPath()) "PesterHidden_$([IO.Path]::GetRandomFileName().Substring(0,4))" + $hiddenDir = Join-Path $tempDir '.hidden' + $null = New-Item -ItemType Directory -Path $hiddenDir -Force + $testFile = Join-Path $hiddenDir 'MyHidden.Tests.ps1' + Set-Content -Path $testFile -Value "Describe 'Hidden' { It 'works' { `$true | Should -Be `$true } }" + + try { + $found = & (Get-Module Pester) { Find-File -Path $args[0] -Extension '.Tests.ps1' } $tempDir + $found | Should -Not -BeNullOrEmpty + ($found | ForEach-Object { $_.FullName }) | Should -Contain $testFile + } + finally { + Remove-Item -Path $tempDir -Recurse -Force + } + } + + t "discovers test files in nested hidden directories" { + $tempDir = Join-Path ([IO.Path]::GetTempPath()) "PesterHidden2_$([IO.Path]::GetRandomFileName().Substring(0,4))" + $nestedHidden = Join-Path $tempDir '.config/tests' + $null = New-Item -ItemType Directory -Path $nestedHidden -Force + $testFile = Join-Path $nestedHidden 'Deep.Tests.ps1' + Set-Content -Path $testFile -Value "Describe 'Deep' { It 'works' { `$true | Should -Be `$true } }" + + try { + $found = & (Get-Module Pester) { Find-File -Path $args[0] -Extension '.Tests.ps1' } $tempDir + $found | Should -Not -BeNullOrEmpty + ($found | ForEach-Object { $_.FullName }) | Should -Contain $testFile + } + finally { + Remove-Item -Path $tempDir -Recurse -Force + } + } + + t "excludes test files inside .git directories" { + $tempDir = Join-Path ([IO.Path]::GetTempPath()) "PesterGitExclude_$([IO.Path]::GetRandomFileName().Substring(0,4))" + $gitDir = Join-Path $tempDir '.git' + $hiddenDir = Join-Path $tempDir '.hidden' + $null = New-Item -ItemType Directory -Path $gitDir -Force + $null = New-Item -ItemType Directory -Path $hiddenDir -Force + $gitTestFile = Join-Path $gitDir 'Something.Tests.ps1' + $hiddenTestFile = Join-Path $hiddenDir 'Real.Tests.ps1' + Set-Content -Path $gitTestFile -Value "Describe 'Git' { It 'works' { `$true | Should -Be `$true } }" + Set-Content -Path $hiddenTestFile -Value "Describe 'Hidden' { It 'works' { `$true | Should -Be `$true } }" + + try { + $found = & (Get-Module Pester) { Find-File -Path $args[0] -Extension '.Tests.ps1' } $tempDir + $found | Should -Not -BeNullOrEmpty + $foundPaths = $found | ForEach-Object { $_.FullName } + $foundPaths | Should -Contain $hiddenTestFile + $foundPaths | Should -Not -Contain $gitTestFile + } + finally { + Remove-Item -Path $tempDir -Recurse -Force + } + } + } }