tests/Invoke-Method.tests.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] Param() Import-Module "$PSScriptRoot/../PwshZendesk.psm1" -Force Describe 'Invoke-Method' -Tags 'internet' { InModuleScope PwshZendesk { $IRM = Get-Command -Name 'Invoke-RestMethod' -Module 'Microsoft.PowerShell.Utility' $context = @{ Organization = 'company' BaseUrl = 'https://company.testdesk.com' Credential = [System.Management.Automation.PSCredential]::New("email", ('api-key' | ConvertTo-SecureString -AsPlainText -Force)) } $context | Add-Member -TypeName 'ZendeskContext' Mock -ModuleName PwshZendesk Invoke-RestMethod { } It 'Uses the baseUrl' { Invoke-Method -Context $context -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -match 'https://company.testdesk.com' } -Scope It } It 'Uses the path' { Invoke-Method -Context $context -Path '/Thing' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -match '/Thing' } -Scope It } It 'Accepts JSON' { Invoke-Method -Context $context -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Headers.ContainsKey('Accept') -and $Headers.Accept -match 'application\/json' } -Scope It } It 'Cascades Verbose' { Invoke-Method -Context $context -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { -not $VerbosePreference } -Scope It Invoke-Method -Context $context -Path '/' -Verbose Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $VerbosePreference } -Scope It Invoke-Method -Context $context -Path '/' -Verbose:$false Assert-MockCalled Invoke-RestMethod -Exactly 2 -ParameterFilter { -not $VerbosePreference } -Scope It } It 'Default Method: Get' { Invoke-Method -Context $context -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Get' } -Scope It } It 'Explicit Method: Get' { Invoke-Method -Context $context -Method 'Get' -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Get' } -Scope It } It 'Explicit Method: Post' { Invoke-Method -Context $context -Method 'Post' -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Post' } -Scope It } It 'Explicit Method: Put' { Invoke-Method -Context $context -Method 'Put' -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Put' } -Scope It } It 'Explicit Method: Delete' { Invoke-Method -Context $context -Method 'Delete' -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Method -eq 'Delete' } -Scope It } It 'Throws with no connection' { { Invoke-Method -Path '/' } | Should -Throw } It 'Throws with no invalid connection type' { $block = { $context = [PSCustomObject]@{ Organization = 'company' BaseUrl = 'https://company.testdesk.com' Credential = $null } Invoke-Method -Path '/' -Context $context } $block | Should -Throw } It 'Converts Body to JSON by default' { Invoke-Method -Context $context -Method 'Post' -Path '/' -Body ([PSCustomObject]@{ A = 1; B = 2; C = 3 }) Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Body -eq '{"A":1,"B":2,"C":3}' } -Scope It Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $ContentType -eq 'application/json' } -Scope It } It 'Leaves Body alone with explicit ContentType' { Invoke-Method -Context $context -Method 'Post' -Path '/' -Body 'The Body' -ContentType 'text/plain' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Body -eq 'The Body' } -Scope It Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $ContentType -eq 'text/plain' } -Scope It } It 'Escapes non-ascii characters' { Invoke-Method -Context $context -Method 'Post' -Path '/' -Body ([PSCustomObject]@{ user = @{ name = '(╯°□°)╯︵ ┻━┻' } }) Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Body -eq '{"user":{"name":"(\u256f\u00b0\u25a1\u00b0\uff09\u256f\ufe35 \u253b\u2501\u253b"}}' } -Scope It } It 'Sorts by created_at by default' { Invoke-Method -Context $context -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -match 'sort_by=created_at' } -Scope It } It 'Sorts by any supplied property' { Invoke-Method -Context $context -Path '/' -SortBy 'name' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -match 'sort_by=name' } -Scope It } It 'Doesn;t sort when SortBy is set to $null' { Invoke-Method -Context $context -Path '/' -SortBy $null Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -notmatch 'sort_by' } -Scope It } It 'Can sort if path includes query variables' { Invoke-Method -Context $context -Path '/thing?name=jim' Assert-MockCalled Invoke-RestMethod -Exactly 1 -ParameterFilter { $Uri -match '\?name=jim&sort_by' } -Scope It } Mock -ModuleName PwshZendesk Invoke-RestMethod { & $IRM 'httpstat.us/404' } It 'Throws on a 404' { { Invoke-Method -Context $context -Path '/' } | Should -Throw } It 'Passes on 404 error message' { try { Invoke-Method -Context $context -Path '/' } catch { $E = $_ } $E | Should -Match '\(?404\)? \(?Not Found\)?' } Mock -ModuleName PwshZendesk Invoke-RestMethod { & $IRM 'httpstat.us/400' } It 'Passes on 400 error message' { try { Invoke-Method -Context $context -Path '/' } catch { $E = $_ } $E | Should -Match '\(?400\)? \(?Bad Request\)?' } Mock -ModuleName PwshZendesk Invoke-RestMethod { & $IRM 'httpstat.us/500' } It 'Passes on 500 error message' { try { Invoke-Method -Context $context -Path '/' } catch { $E = $_ } $E | Should -Match '\(?500\)? \(?Internal Server Error\)?' } It 'Passes on Calling function' { try { Invoke-Method -Context $context -Path '/' } catch { $E = $_ } $E | Should -Match '<ScriptBlock>: line 1\d\d' } Mock -ModuleName PwshZendesk Invoke-RestMethod { if ($Uri -match 'idx=([0-9])') { $idx = [int]$Matches[1] if ($idx -eq 5) { [PSCustomObject]@{ next_page = $null } } else { $idx += 1 [PSCustomObject]@{ next_page = $Uri -replace 'idx=[0-9]', "idx=$idx" } } } else { throw 'no idx' } } It 'Pages by default' { Invoke-Method -Context $context -Path '/Thing?idx=1' Assert-MockCalled Invoke-RestMethod -Exactly 5 -Scope It } It 'Pages explicitly' { Invoke-Method -Context $context -Path '/Thing?idx=1' -Pagination $true Assert-MockCalled Invoke-RestMethod -Exactly 5 -Scope It } It 'Does not page when asked not to' { Invoke-Method -Context $context -Path '/Thing?idx=1' -Pagination $false Assert-MockCalled Invoke-RestMethod -Exactly 1 -Scope It } $Script:attempts = 0 Mock -ModuleName PwshZendesk Invoke-RestMethod { $Script:attempts += 1 if ($Script:attempts -lt 3) { & $IRM 'httpstat.us/429' } } It 'Does not rety if requested not to' { $Script:attempts = 0 { Invoke-Method -Context $context -Path '/' -Retry $false } | Should -Throw Assert-MockCalled Invoke-RestMethod -Exactly 1 -Scope It } It 'Retries by default' { $Script:attempts = 0 Invoke-Method -Context $context -Path '/' 3>$null Assert-MockCalled Invoke-RestMethod -Exactly 3 -Scope It } It 'Retries explicitly' { $Script:attempts = 0 Invoke-Method -Context $context -Path '/' -Retry $true 3>$null Assert-MockCalled Invoke-RestMethod -Exactly 3 -Scope It } Mock -ModuleName PwshZendesk Invoke-RestMethod { } $Script:Context = $context It 'Uses the stored context' { Invoke-Method -Path '/' Assert-MockCalled Invoke-RestMethod -Exactly 1 -Scope It } } } |