Tests/Start-ElmProgram.Tests.ps1
|
BeforeAll { function Enable-VirtualTerminal { return $true } function New-ElmTerminalDriver { param([switch]$AltScreen) return [PSCustomObject]@{ InputQueue = [System.Collections.Concurrent.ConcurrentQueue[object]]::new() Stop = {} } } function Invoke-ElmEventLoop { param($InitialModel, $UpdateFn, $ViewFn, $InputQueue, $TerminalWidth, $TerminalHeight) $script:lastEventLoopWidth = $TerminalWidth $script:lastEventLoopHeight = $TerminalHeight return $InitialModel } . $PSScriptRoot/../Public/Runtime/Start-ElmProgram.ps1 } Describe 'Start-ElmProgram' { It 'Should call InitFn and pass its model to Invoke-ElmEventLoop' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{ Count = 7 }; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } $result = Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn $result.Count | Should -Be 7 } It 'Should return the final model from Invoke-ElmEventLoop' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{ Status = 'done' }; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } $result = Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn $result.Status | Should -Be 'done' } It 'Should stop the terminal driver when the event loop completes' { $capture = @{ StopCalled = $false } $stopFn = { $capture.StopCalled = $true }.GetNewClosure() function New-ElmTerminalDriver { param([switch]$AltScreen) return [PSCustomObject]@{ InputQueue = [System.Collections.Concurrent.ConcurrentQueue[object]]::new() Stop = $stopFn } } $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn ($capture.StopCalled -eq $true) | Should -Be $true } It 'Should stop the terminal driver even if Invoke-ElmEventLoop throws' { $capture = @{ StopCalled = $false } $stopFn = { $capture.StopCalled = $true }.GetNewClosure() function New-ElmTerminalDriver { param([switch]$AltScreen) return [PSCustomObject]@{ InputQueue = [System.Collections.Concurrent.ConcurrentQueue[object]]::new() Stop = $stopFn } } function Invoke-ElmEventLoop { param($InitialModel, $UpdateFn, $ViewFn, $InputQueue, $TerminalWidth, $TerminalHeight) throw 'simulated loop error' } $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } { Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn } | Should -Throw ($capture.StopCalled -eq $true) | Should -Be $true } It 'Should accept optional Width and Height parameters within terminal bounds' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } $termW = if ([Console]::WindowWidth -gt 0) { [Console]::WindowWidth } else { 80 } $termH = if ([Console]::WindowHeight -gt 0) { [Console]::WindowHeight } else { 24 } { Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn -Width $termW -Height $termH } | Should -Not -Throw } It 'Should default Width and Height to console dimensions' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn $expectedWidth = if ([Console]::WindowWidth -gt 0) { [Console]::WindowWidth } else { 80 } $expectedHeight = if ([Console]::WindowHeight -gt 0) { [Console]::WindowHeight } else { 24 } $script:lastEventLoopWidth | Should -Be $expectedWidth $script:lastEventLoopHeight | Should -Be $expectedHeight } It 'Should throw a terminating error when Width exceeds terminal width' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } { Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn -Width 999999 } | Should -Throw } It 'Should throw a terminating error when Height exceeds terminal height' { $initFn = { [PSCustomObject]@{ Model = [PSCustomObject]@{}; Cmd = $null } } $updateFn = { param($msg, $model) [PSCustomObject]@{ Model = $model; Cmd = $null } } $viewFn = { param($model) [PSCustomObject]@{ Type = 'Text'; Content = 'x' } } { Start-ElmProgram -InitFn $initFn -UpdateFn $updateFn -ViewFn $viewFn -Height 999999 } | Should -Throw } } |