Tests/PSFloRecruit.Tests.ps1
|
#Requires -Modules Pester BeforeAll { $ModulePath = Split-Path -Parent $PSScriptRoot Import-Module $ModulePath -Force } Describe 'PSFloRecruit Module' { Context 'Module Structure' { It 'Should have a valid manifest' { $manifestPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'PSFloRecruit.psd1' Test-Path $manifestPath | Should -Be $true $manifest = Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue $manifest | Should -Not -BeNullOrEmpty } It 'Should export Connect-FloRecruit' { Get-Command Connect-FloRecruit -Module PSFloRecruit -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty } It 'Should export Disconnect-FloRecruit' { Get-Command Disconnect-FloRecruit -Module PSFloRecruit -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty } It 'Should export Get-FloRecruitSession' { Get-Command Get-FloRecruitSession -Module PSFloRecruit -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty } It 'Should export Get-FloRecruitJobApplication' { Get-Command Get-FloRecruitJobApplication -Module PSFloRecruit -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty } } } Describe 'Connect-FloRecruit' { BeforeAll { Mock Invoke-WebRequest { param($Uri, $Method, $Body, $ContentType, $SessionVariable) # Create a mock response with proper headers $response = [PSCustomObject]@{ StatusCode = 200 Headers = @{ 'Set-Cookie' = 'auth_token=mock-token-12345; Path=/; HttpOnly' } Content = '{}' } return $response } -ModuleName PSFloRecruit } AfterEach { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should connect with SecureString password' { $password = ConvertTo-SecureString 'TestPassword123!' -AsPlainText -Force $result = Connect-FloRecruit -OrganizationName 'testorg' -Email 'admin@test.com' -Password $password $result | Should -Not -BeNullOrEmpty $result.OrganizationName | Should -Be 'testorg' $result.Email | Should -Be 'admin@test.com' } It 'Should create a session object' { $password = ConvertTo-SecureString 'TestPassword123!' -AsPlainText -Force Connect-FloRecruit -OrganizationName 'testorg' -Email 'admin@test.com' -Password $password InModuleScope PSFloRecruit { $Script:FloRecruitSession | Should -Not -BeNullOrEmpty $Script:FloRecruitSession.OrganizationName | Should -Be 'testorg' $Script:FloRecruitSession.Email | Should -Be 'admin@test.com' $Script:FloRecruitSession.AuthToken | Should -Not -BeNullOrEmpty } } It 'Should accept plain text password' { $result = Connect-FloRecruit -OrganizationName 'testorg' -Email 'admin@test.com' -PasswordPlainText 'TestPassword123!' $result | Should -Not -BeNullOrEmpty } } Describe 'Disconnect-FloRecruit' { BeforeEach { InModuleScope PSFloRecruit { $Script:FloRecruitSession = [PSCustomObject]@{ Email = 'test@test.com' } } } It 'Should clear the session' { Disconnect-FloRecruit InModuleScope PSFloRecruit { $Script:FloRecruitSession | Should -BeNullOrEmpty } } It 'Should not error when no session exists' { Disconnect-FloRecruit { Disconnect-FloRecruit } | Should -Not -Throw } } Describe 'Get-FloRecruitSession' { Context 'When connected' { BeforeAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = [PSCustomObject]@{ OrganizationName = 'testorg' Email = 'admin@test.com' BaseUrl = 'https://florecruit.com/app/testorg/api' ConnectedAt = Get-Date TokenExpiry = (Get-Date).AddHours(1) RequestCount = 5 RateLimitWindowStart = Get-Date } } } AfterAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should return session information' { $session = Get-FloRecruitSession $session | Should -Not -BeNullOrEmpty $session.OrganizationName | Should -Be 'testorg' $session.Email | Should -Be 'admin@test.com' } It 'Should not include credentials' { $session = Get-FloRecruitSession $session.Password | Should -BeNullOrEmpty $session.MFASecret | Should -BeNullOrEmpty } It 'Should include rate limit information' { $session = Get-FloRecruitSession $session.RequestsInWindow | Should -Be 5 $session.RequestsRemaining | Should -BeGreaterThan 0 } } Context 'When not connected' { BeforeAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should return null' { $session = Get-FloRecruitSession $session | Should -BeNullOrEmpty } } } Describe 'Get-FloRecruitJobApplication' { BeforeAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = [PSCustomObject]@{ OrganizationName = 'testorg' Email = 'admin@test.com' BaseUrl = 'https://florecruit.com/app/testorg/api' AuthToken = 'mock-token' TokenExpiry = (Get-Date).AddHours(1) RequestCount = 0 RateLimitWindowStart = Get-Date } } $mockJobApp1 = @{ applicationId = 'app123' candidateId = 'cand456' firstName = 'John' lastName = 'Doe' email = 'john.doe@example.com' jobTitle = 'Software Engineer' status = 'Hired' } $mockJobApp2 = @{ applicationId = 'app124' candidateId = 'cand457' firstName = 'Jane' lastName = 'Smith' email = 'jane.smith@example.com' jobTitle = 'Product Manager' status = 'Offered' } Mock Invoke-WebRequest { return [PSCustomObject]@{ Content = (ConvertTo-Json @($mockJobApp1, $mockJobApp2)) StatusCode = 200 Headers = @{} } } -ModuleName PSFloRecruit } AfterAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should retrieve job applications' { $result = Get-FloRecruitJobApplication $result | Should -Not -BeNullOrEmpty $result.Count | Should -BeGreaterThan 0 } It 'Should have correct type name' { $result = Get-FloRecruitJobApplication $result[0].PSObject.TypeNames | Should -Contain 'FloRecruit.JobApplication' } It 'Should accept status parameter' { { Get-FloRecruitJobApplication -Status "Hired" } | Should -Not -Throw } It 'Should accept status bucket parameter' { { Get-FloRecruitJobApplication -StatusBucket "Hired" } | Should -Not -Throw } It 'Should accept date range parameters' { $start = Get-Date "2026-01-01" $end = Get-Date "2026-01-31" { Get-FloRecruitJobApplication -StatusStart $start -StatusEnd $end } | Should -Not -Throw } It 'Should accept limit parameter' { { Get-FloRecruitJobApplication -Limit 100 } | Should -Not -Throw } } Describe 'Error Handling' { Context 'When not connected' { BeforeAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should throw error when calling Get-FloRecruitJobApplication' { { Get-FloRecruitJobApplication } | Should -Throw "*Not connected*" } } Context 'When API returns error' { BeforeAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = [PSCustomObject]@{ OrganizationName = 'testorg' BaseUrl = 'https://florecruit.com/app/testorg/api' AuthToken = 'mock-token' TokenExpiry = (Get-Date).AddHours(1) RequestCount = 0 RateLimitWindowStart = Get-Date } } Mock Invoke-WebRequest { $response = New-Object System.Net.Http.HttpResponseMessage $response.StatusCode = [System.Net.HttpStatusCode]::Unauthorized throw [Microsoft.PowerShell.Commands.HttpResponseException]::new("Unauthorized", $response) } -ModuleName PSFloRecruit } AfterAll { InModuleScope PSFloRecruit { $Script:FloRecruitSession = $null } } It 'Should handle 401 error' { { Get-FloRecruitJobApplication } | Should -Throw } } } Describe 'ConvertTo-FloRecruitError' { BeforeAll { InModuleScope PSFloRecruit { # Function is private, so we need to test it in module scope } } It 'Should create error record for 401' { InModuleScope PSFloRecruit { $exception = New-Object System.Exception "Unauthorized" $errorRecord = ConvertTo-FloRecruitError -Exception $exception -StatusCode 401 $errorRecord | Should -Not -BeNullOrEmpty $errorRecord.CategoryInfo.Category | Should -Be 'AuthenticationError' } } It 'Should create error record for 429' { InModuleScope PSFloRecruit { $exception = New-Object System.Exception "Rate limit exceeded" $errorRecord = ConvertTo-FloRecruitError -Exception $exception -StatusCode 429 $errorRecord | Should -Not -BeNullOrEmpty $errorRecord.CategoryInfo.Category | Should -Be 'LimitsExceeded' } } } AfterAll { Remove-Module PSFloRecruit -Force -ErrorAction SilentlyContinue } |