Tests/Tests.ps1
|
<#
.SYNOPSIS Pester tests for M365PlannerPro module .DESCRIPTION Comprehensive test suite for M365PlannerPro module including: - Module structure validation - Function existence and parameter validation - Help content validation - CSV format validation .NOTES Author: Microsoft Planner Pro Team Version: 1.0.0 Requires: Pester module (Install-Module Pester -Force) Run tests: Invoke-Pester .\Tests.ps1 -Output Detailed #> BeforeAll { $ModulePath = Split-Path -Parent $PSCommandPath $ModuleName = 'M365PlannerPro' $ManifestPath = Join-Path $ModulePath "$ModuleName.psd1" if (Get-Module $ModuleName) { Remove-Module $ModuleName -Force } Import-Module $ManifestPath -Force } Describe "Module Structure Tests" { Context "Module Manifest" { It "Should have a valid module manifest" { $ManifestPath = Join-Path $ModulePath "$ModuleName.psd1" $ManifestPath | Should -Exist } It "Should have a valid module file" { $ModuleFile = Join-Path $ModulePath "$ModuleName.psm1" $ModuleFile | Should -Exist } It "Should import without errors" { { Import-Module $ManifestPath -Force -ErrorAction Stop } | Should -Not -Throw } It "Should have required module version" { $manifest = Test-ModuleManifest -Path $ManifestPath $manifest.Version | Should -BeOfType [version] $manifest.Version.Major | Should -BeGreaterOrEqual 1 } It "Should require PowerShell 7.0 or higher" { $manifest = Test-ModuleManifest -Path $ManifestPath $manifest.PowerShellVersion | Should -BeGreaterOrEqual ([version]'7.0') } It "Should have Microsoft.Graph.Planner as a required module" { $manifest = Test-ModuleManifest -Path $ManifestPath $manifest.RequiredModules.Name | Should -Contain 'Microsoft.Graph.Planner' } } Context "Public Folder" { It "Should have a Public folder" { $PublicFolder = Join-Path $ModulePath "Public" $PublicFolder | Should -Exist } It "Should contain .ps1 files in Public folder" { $PublicFiles = Get-ChildItem (Join-Path $ModulePath "Public") -Filter *.ps1 $PublicFiles.Count | Should -BeGreaterThan 0 } } Context "Documentation" { It "Should have README.md" { Join-Path $ModulePath "README.md" | Should -Exist } It "Should have CHANGELOG.md" { Join-Path $ModulePath "CHANGELOG.md" | Should -Exist } It "Should have example-tasks.csv" { Join-Path $ModulePath "example-tasks.csv" | Should -Exist } } } Describe "Function Export Tests" { Context "Exported Functions" { $ExportedFunctions = @( 'Copy-M365PPlan', 'Import-M365PTasksFromCsv', 'Get-M365PUserWorkload', 'Update-M365PTaskSmart' ) foreach ($FunctionName in $ExportedFunctions) { It "Should export function: $FunctionName" { $Module = Get-Module $ModuleName $Module.ExportedCommands.Keys | Should -Contain $FunctionName } It "Should have help content for: $FunctionName" { $Help = Get-Help $FunctionName $Help | Should -Not -BeNullOrEmpty $Help.Synopsis | Should -Not -BeNullOrEmpty } It "Should have examples for: $FunctionName" { $Help = Get-Help $FunctionName $Help.Examples | Should -Not -BeNullOrEmpty $Help.Examples.Example.Count | Should -BeGreaterThan 0 } } } } Describe "Copy-M365PPlan Function Tests" { Context "Parameters" { It "Should have SourceGroupId parameter" { (Get-Command Copy-M365PPlan).Parameters.Keys | Should -Contain 'SourceGroupId' } It "Should have SourcePlanId parameter" { (Get-Command Copy-M365PPlan).Parameters.Keys | Should -Contain 'SourcePlanId' } It "Should have DestinationGroupId parameter" { (Get-Command Copy-M365PPlan).Parameters.Keys | Should -Contain 'DestinationGroupId' } It "Should have optional NewPlanTitle parameter" { $Param = (Get-Command Copy-M365PPlan).Parameters['NewPlanTitle'] $Param | Should -Not -BeNullOrEmpty $Param.ParameterSets['__AllParameterSets'].IsMandatory | Should -Be $false } } Context "Help Content" { $Help = Get-Help Copy-M365PPlan It "Should have Synopsis" { $Help.Synopsis | Should -Not -BeNullOrEmpty } It "Should have Description" { $Help.Description | Should -Not -BeNullOrEmpty } It "Should have at least 2 examples" { $Help.Examples.Example.Count | Should -BeGreaterOrEqual 2 } } } Describe "Import-M365PTasksFromCsv Function Tests" { Context "Parameters" { It "Should have PlanId parameter" { (Get-Command Import-M365PTasksFromCsv).Parameters.Keys | Should -Contain 'PlanId' } It "Should have CsvPath parameter" { (Get-Command Import-M365PTasksFromCsv).Parameters.Keys | Should -Contain 'CsvPath' } It "Should have GroupId parameter" { (Get-Command Import-M365PTasksFromCsv).Parameters.Keys | Should -Contain 'GroupId' } } Context "CSV Validation" { It "Should have example CSV file" { $CsvPath = Join-Path $ModulePath "example-tasks.csv" $CsvPath | Should -Exist } It "Example CSV should have required columns" { $CsvPath = Join-Path $ModulePath "example-tasks.csv" $Csv = Import-Csv $CsvPath $RequiredColumns = @('Title', 'BucketName') foreach ($Column in $RequiredColumns) { $Csv[0].PSObject.Properties.Name | Should -Contain $Column } } It "Example CSV should have valid content" { $CsvPath = Join-Path $ModulePath "example-tasks.csv" $Csv = Import-Csv $CsvPath $Csv.Count | Should -BeGreaterThan 0 $Csv[0].Title | Should -Not -BeNullOrEmpty } } } Describe "Get-M365PUserWorkload Function Tests" { Context "Parameters" { It "Should have optional GroupId parameter" { $Param = (Get-Command Get-M365PUserWorkload).Parameters['GroupId'] $Param | Should -Not -BeNullOrEmpty $Param.ParameterSets.Values.IsMandatory | Should -Contain $false } It "Should have optional PlanId parameter" { (Get-Command Get-M365PUserWorkload).Parameters.Keys | Should -Contain 'PlanId' } It "Should have IncludeCompletedTasks switch" { $Param = (Get-Command Get-M365PUserWorkload).Parameters['IncludeCompletedTasks'] $Param.SwitchParameter | Should -Be $true } It "Should have Top parameter" { (Get-Command Get-M365PUserWorkload).Parameters.Keys | Should -Contain 'Top' } } } Describe "Update-M365PTaskSmart Function Tests" { Context "Parameters" { It "Should have TaskId parameter" { $Param = (Get-Command Update-M365PTaskSmart).Parameters['TaskId'] $Param | Should -Not -BeNullOrEmpty } It "TaskId should accept pipeline input" { $Param = (Get-Command Update-M365PTaskSmart).Parameters['TaskId'] $Param.Attributes.ValueFromPipeline | Should -Contain $true } It "Should have optional Title parameter" { (Get-Command Update-M365PTaskSmart).Parameters.Keys | Should -Contain 'Title' } It "Should have PercentComplete parameter" { (Get-Command Update-M365PTaskSmart).Parameters.Keys | Should -Contain 'PercentComplete' } It "Should have MaxRetries parameter" { (Get-Command Update-M365PTaskSmart).Parameters.Keys | Should -Contain 'MaxRetries' } It "Should support WhatIf" { (Get-Command Update-M365PTaskSmart).Parameters.Keys | Should -Contain 'WhatIf' } } Context "Parameter Validation" { It "PercentComplete should have range validation" { $Param = (Get-Command Update-M365PTaskSmart).Parameters['PercentComplete'] $ValidateRange = $Param.Attributes | Where-Object { $_ -is [System.Management.Automation.ValidateRangeAttribute] } $ValidateRange | Should -Not -BeNullOrEmpty $ValidateRange.MinRange | Should -Be 0 $ValidateRange.MaxRange | Should -Be 100 } It "Priority should have range validation" { $Param = (Get-Command Update-M365PTaskSmart).Parameters['Priority'] $ValidateRange = $Param.Attributes | Where-Object { $_ -is [System.Management.Automation.ValidateRangeAttribute] } $ValidateRange | Should -Not -BeNullOrEmpty $ValidateRange.MinRange | Should -Be 0 $ValidateRange.MaxRange | Should -Be 10 } } } Describe "PowerShell Best Practices" { Context "Function Naming" { $Functions = Get-Command -Module $ModuleName foreach ($Function in $Functions) { It "$($Function.Name) should follow Verb-Noun naming" { $Function.Name | Should -Match '^[A-Z][a-z]+-[A-Z][a-zA-Z0-9]*$' } It "$($Function.Name) should use approved verb" { $Verb = $Function.Name.Split('-')[0] $ApprovedVerbs = Get-Verb | Select-Object -ExpandProperty Verb $ApprovedVerbs | Should -Contain $Verb } } } Context "Comment-Based Help" { $Functions = Get-Command -Module $ModuleName foreach ($Function in $Functions) { $Help = Get-Help $Function.Name It "$($Function.Name) should have Synopsis" { $Help.Synopsis | Should -Not -BeNullOrEmpty $Help.Synopsis | Should -Not -Match $Function.Name # Should not be auto-generated } It "$($Function.Name) should have Description" { $Help.Description | Should -Not -BeNullOrEmpty } It "$($Function.Name) should have at least one Example" { $Help.Examples.Example.Count | Should -BeGreaterOrEqual 1 } It "$($Function.Name) should have parameter descriptions" { $Params = $Help.Parameters.Parameter foreach ($Param in $Params) { $Param.Description | Should -Not -BeNullOrEmpty } } } } } Describe "Integration Tests" -Tag "Integration" { Context "Module Load Performance" { It "Should load module in reasonable time" { $Stopwatch = [System.Diagnostics.Stopwatch]::StartNew() Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue Import-Module $ManifestPath -Force $Stopwatch.Stop() $Stopwatch.ElapsedMilliseconds | Should -BeLessThan 5000 # 5 seconds } } Context "Function Execution (Dry Run)" { It "Update-M365PTaskSmart should support WhatIf without errors" { { Update-M365PTaskSmart -TaskId "test-id" -Title "Test" -WhatIf } | Should -Not -Throw } } } AfterAll { Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue } |