Public/Show-PesterResult.ps1
function Show-PesterResult { <# .SYNOPSIS Open a TUI to explore the Pester result object. .DESCRIPTION Show a Pester result in a TUI (Text User Interface) using Spectre.Console. This function builds a layout with a header, a list of items, and a preview panel. .PARAMETER PesterResult The Pester result object to display. This should be a Pester Run object. .PARAMETER NoShortcutPanel If specified, the shortcut panel will not be displayed at the bottom of the TUI. .EXAMPLE $pesterResult = Invoke-Pester -Path "path\to\tests.ps1" -PassThru Show-PesterResult -PesterResult $pesterResult This example runs Pester tests and opens a TUI to explore the results. #> [CmdletBinding()] [OutputType([void])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSReviewUnusedParameter', 'PesterResult', Justification='This is actually used in the script block.' )] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Pester.Run] $PesterResult, [switch] $NoShortcutPanel ) # Build and show the TUI $rows = @( # Row 1 ( New-SpectreLayout -Name "header" -MinimumSize 5 -Ratio 1 -Data ("empty") ), # Row 2 ( New-SpectreLayout -Name "content" -Ratio 10 -Columns @( ( New-SpectreLayout -Name "list" -Ratio 1 -Data "empty" ), ( New-SpectreLayout -Name "preview" -Ratio 4 -Data "empty" ) ) ) ) if(-not $NoShortcutPanel) { $rows += ( # Row 3 ( New-SpectreLayout -Name "footer" -Ratio 1 -MinimumSize 1 -Data ( Get-ShortcutKeyPanel ) ) ) } $layout = New-SpectreLayout -Name "root" -Rows $rows # Start live rendering the layout Invoke-SpectreLive -Data $layout -ScriptBlock { param ( [Spectre.Console.LiveDisplayContext] $Context ) #region Initial State $items = Get-ListFromObject -Object $PesterResult Write-Debug "Items: $($items.Keys -join ', ')" $list = [array]$items.Keys $selectedItem = $list[0] $stack = [System.Collections.Stack]::new() $object = $PesterResult $selectedPane = 'list' $scrollPosition = 0 #endregion Initial State while ($true) { # Check the layout sizes $sizes = $layout | Get-SpectreLayoutSizes $previewHeight = $sizes["preview"].Height $previewWidth = $sizes["preview"].Width Write-Debug "Preview size: $previewWidth x $previewHeight" # Handle input $lastKeyPressed = Get-LastKeyPressed if ($null -ne $lastKeyPressed) { #region List Navigation if($selectedPane -eq 'list') { if ($lastKeyPressed.Key -in @("j", "DownArrow")) { $selectedItem = $list[($list.IndexOf($selectedItem) + 1) % $list.Count] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -in @("k", "UpArrow")) { $selectedItem = $list[($list.IndexOf($selectedItem) - 1 + $list.Count) % $list.Count] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -eq "PageDown") { $currentIndex = $list.IndexOf($selectedItem) $newIndex = [Math]::Min($currentIndex + 10, $list.Count - 1) $selectedItem = $list[$newIndex] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -eq "PageUp") { $currentIndex = $list.IndexOf($selectedItem) $newIndex = [Math]::Max($currentIndex - 10, $list.Count - 1) $selectedItem = $list[$newIndex] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -eq "Home") { $selectedItem = $list[0] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -eq "End") { $selectedItem = $list[-1] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -in @("Tab", "RightArrow", "l")) { $selectedPane = 'preview' } elseif ($lastKeyPressed.Key -eq "Enter") { <# Recurse into Pester Object #> if($items.Item($selectedItem).GetType().Name -eq "Test") { # This is a test. We don't want to go deeper. } if($selectedItem -like '*..*') { # Move up one via selecting .. $object = $stack.Pop() Write-Debug "Popped item from stack: $($object.Name)" } else { Write-Debug "Pushing item into stack: $($items.Item($selectedItem).Name)" $stack.Push($object) $object = $items.Item($selectedItem) } $items = Get-ListFromObject -Object $object $list = [array]$items.Keys $selectedItem = $list[0] $scrollPosition = 0 } elseif ($lastKeyPressed.Key -eq "Escape") { # Move up via Esc key if($stack.Count -eq 0) { # This is the top level. Exit the loop. return } $object = $stack.Pop() $items = Get-ListFromObject -Object $object $list = [array]$items.Keys $selectedItem = $list[0] $scrollPosition = 0 } } else { #region Preview Navigation if ($lastKeyPressed.Key -in "Escape", "Tab", "LeftArrow", "h") { $selectedPane = 'list' } elseif ($lastKeyPressed.Key -eq "Down") { # Scroll down in the preview panel $scrollPosition = $ScrollPosition + 1 } elseif ($lastKeyPressed.Key -eq "Up") { # Scroll up in the preview panel $scrollPosition = $ScrollPosition - 1 } elseif ($lastKeyPressed.Key -eq "PageDown") { # Scroll down by a page in the preview panel $scrollPosition = $ScrollPosition + 1 } elseif ($lastKeyPressed.Key -eq "PageUp") { # Scroll up by a page in the preview panel $scrollPosition = $ScrollPosition - 1 } #endregion Preview Navigation } } # Generate new data $titlePanel = Get-TitlePanel -Item $object $getListPanelSplat = @{ List = $list SelectedItem = $selectedItem SelectedPane = $selectedPane } $listPanel = Get-ListPanel @getListPanelSplat $getPreviewPanelSplat = @{ Items = $items SelectedItem = $selectedItem ScrollPosition = $scrollPosition PreviewHeight = $previewHeight PreviewWidth = $previewWidth SelectedPane = $selectedPane } $previewPanel = Get-PreviewPanel @getPreviewPanelSplat # Update layout $layout["header"].Update($titlePanel) | Out-Null $layout["list"].Update($listPanel) | Out-Null $layout["preview"].Update($previewPanel) | Out-Null # Draw changes $Context.Refresh() Start-Sleep -Milliseconds 100 } } } |