tests/winget.Tests.ps1
|
BeforeAll { $script:CompanionPath = Join-Path $PSScriptRoot '../Tools/winget.ps1' . "$PSScriptRoot/../Private/Invoke-DFFzf.ps1" . "$PSScriptRoot/../Public/Invoke-DFPicker.ps1" # A fzf stand-in: returns whatever lines the test sets in $script:FzfOut, after # recording the items the picker fed in. Mocked per-test via Set-Variable. function script:FakePkg ($Name, $Id, $Ver, [switch]$Update, $Avail, $Source = 'winget') { [pscustomobject]@{ Name = $Name; Id = $Id; Version = $Ver; InstalledVersion = $Ver IsUpdateAvailable = [bool]$Update; AvailableVersions = @($Avail, $Ver) Source = $Source } } } Describe 'winget companion' { BeforeEach { . $script:CompanionPath } AfterEach { 'Select-WingetPackage', 'Remove-WingetPackage', 'Invoke-WingetUpdate', 'Assert-DFWingetModule' | ForEach-Object { Remove-Item "function:global:$_" -ErrorAction Ignore } 'wins', 'wrm', 'wup' | ForEach-Object { Remove-Item "alias:global:$_" -ErrorAction Ignore } Remove-PSReadLineKeyHandler -Chord 'Ctrl+g,w' -ErrorAction Ignore } It 'defines wins/wrm/wup functions and aliases globally' { (Get-Command Select-WingetPackage -CommandType Function) | Should -Not -BeNullOrEmpty (Get-Command Remove-WingetPackage -CommandType Function) | Should -Not -BeNullOrEmpty (Get-Command Invoke-WingetUpdate -CommandType Function) | Should -Not -BeNullOrEmpty (Get-Alias wins).Definition | Should -Be 'Select-WingetPackage' (Get-Alias wrm).Definition | Should -Be 'Remove-WingetPackage' (Get-Alias wup).Definition | Should -Be 'Invoke-WingetUpdate' } It 'binds Ctrl+G,W to the install-command prefill when PSReadLine is present' { (Get-PSReadLineKeyHandler | Where-Object { $_.Key -eq 'Ctrl+g,w' }) | Should -Not -BeNullOrEmpty } It 'installs the pickers as GLOBAL functions that survive Register-DFTool''s scope' { # Register-DFTool dot-sources the companion INSIDE its own function scope; # `function global:` must make the pickers survive that scope's return. function Invoke-LikeRegisterDFTool { . $script:CompanionPath (Get-Command wins -ErrorAction Ignore) | Should -Not -BeNullOrEmpty } Invoke-LikeRegisterDFTool (Get-Command Select-WingetPackage -CommandType Function -ErrorAction Ignore) | Should -Not -BeNullOrEmpty } Context 'module guard' { It 'returns without invoking the picker when the module is absent' { Mock Assert-DFWingetModule { $false } Mock Invoke-DFPicker { throw 'picker should not run' } { Select-WingetPackage -Query 'x' } | Should -Not -Throw Should -Invoke Invoke-DFPicker -Times 0 } It 'reports available when Find-WinGetPackage resolves' { # The module is installed in this environment, so the real guard is true. Assert-DFWingetModule | Should -BeTrue } } Context 'search / install picker (wins)' { BeforeEach { Mock Find-WinGetPackage { FakePkg 'RipGrep' 'BurntSushi.ripgrep.MSVC' '15.2.0' } } It 'feeds fzf a tab-delimited "<display>`t<id>" line built from object properties' { $script:fed = $null Mock Invoke-DFFzf { $script:fed = $InputItems; '' ; @($InputItems)[0] } Select-WingetPackage -Query 'ripgrep' | Out-Null @($script:fed)[0] | Should -Match "`tBurntSushi\.ripgrep\.MSVC$" @($script:fed)[0] | Should -Match 'RipGrep' } It 'returns the install command string on Enter (empty key line)' { Mock Invoke-DFFzf { '' ; @($InputItems)[0] } $out = Select-WingetPackage -Query 'ripgrep' $out | Should -Be 'winget install --id BurntSushi.ripgrep.MSVC --exact' } It 'calls Install-WinGetPackage on Alt-R' { Mock Invoke-DFFzf { 'alt-r' ; @($InputItems)[0] } Mock Install-WinGetPackage { } Select-WingetPackage -Query 'ripgrep' | Out-Null Should -Invoke Install-WinGetPackage -ParameterFilter { $Id -eq 'BurntSushi.ripgrep.MSVC' } } It 'returns nothing when the user cancels' { Mock Invoke-DFFzf { } Select-WingetPackage -Query 'ripgrep' | Should -BeNullOrEmpty } } Context 'uninstall picker (wrm)' { BeforeEach { Mock Get-WinGetPackage { FakePkg 'draw.io' 'JGraph.Draw' '30.3.14' } } It 'calls Uninstall-WinGetPackage on Enter' { Mock Invoke-DFFzf { '' ; @($InputItems)[0] } Mock Uninstall-WinGetPackage { } Remove-WingetPackage | Out-Null Should -Invoke Uninstall-WinGetPackage -ParameterFilter { $Id -eq 'JGraph.Draw' } } It 'returns the uninstall command on Alt-C' { Mock Invoke-DFFzf { 'alt-c' ; @($InputItems)[0] } Remove-WingetPackage | Should -Be 'winget uninstall --id JGraph.Draw' } It 'filters the list to -Source, dropping other/ARP entries' { Mock Get-WinGetPackage { FakePkg 'draw.io' 'JGraph.Draw' '30.3.14' -Source winget FakePkg 'SomeArp' 'ARP\X\Y' '1.0' -Source '' FakePkg 'AStore' 'Store.App' '2.0' -Source msstore } $script:fed = $null Mock Invoke-DFFzf { $script:fed = $InputItems } Remove-WingetPackage -Source winget | Out-Null @($script:fed).Count | Should -Be 1 ($script:fed -join "`n") | Should -Match 'JGraph.Draw' ($script:fed -join "`n") | Should -Not -Match 'ARP' } It 'lists every source when -Source is omitted' { Mock Get-WinGetPackage { FakePkg 'draw.io' 'JGraph.Draw' '30.3.14' -Source winget FakePkg 'SomeArp' 'ARP\X\Y' '1.0' -Source '' } $script:fed = $null Mock Invoke-DFFzf { $script:fed = $InputItems } Remove-WingetPackage | Out-Null @($script:fed).Count | Should -Be 2 } } Context 'update picker (wup)' { BeforeEach { Mock Get-WinGetPackage { FakePkg 'Claude' 'Anthropic.Claude' '1.0' -Update -Avail '2.0' FakePkg 'Codex' 'OpenAI.Codex' '0.1' -Update -Avail '0.2' FakePkg 'Stable' 'Some.Stable' '9.0' -Avail '9.0' } } It 'lists only upgradable packages' { $script:fed = $null Mock Invoke-DFFzf { $script:fed = $InputItems; } Invoke-WingetUpdate | Out-Null @($script:fed).Count | Should -Be 2 ($script:fed -join "`n") | Should -Not -Match 'Some\.Stable' } It 'updates each selected package on Enter (multi-select)' { Mock Invoke-DFFzf { '' ; $InputItems } # Enter, both items selected Mock Update-WinGetPackage { } Invoke-WingetUpdate | Out-Null Should -Invoke Update-WinGetPackage -Times 2 } It 'runs winget upgrade --all on Alt-A' { Mock Invoke-DFFzf { 'alt-a' } Mock winget { } Invoke-WingetUpdate | Out-Null Should -Invoke winget -ParameterFilter { $args -contains 'upgrade' -and $args -contains '--all' } } } } |