TeamsFunctions.Tests.ps1
# Module: TeamsFunctions # Function: Test # Author: David Eberhardt # Updated: 11-OCT-2020 Describe -Tags ('Unit', 'Acceptance') -Name 'TeamsFunctions Module Tests' { BeforeAll { $ModuleName = 'TeamsFunctions' Write-Host "Testing '$ModuleName' in path '$PsScriptRoot'" } #region Module Test Context 'Module' { It "has the root module '$ModuleName.psm1'" { "$PsScriptRoot\$ModuleName.psm1" | Should -Exist } -TestCases { Module = $module } It "has the a manifest file of '$ModuleName.psd1'" { "$PsScriptRoot\$ModuleName.psd1" | Should -Exist } -TestCases { Module = $module } It "$module has folder for Functions" { "$PSScriptRoot\Public" | Should -Exist "$PSScriptRoot\Private" | Should -Exist } It "$module has folder for Tests" { "$PSScriptRoot\Tests\Public" | Should -Exist "$PSScriptRoot\Tests\Private" | Should -Exist } It "$module is valid PowerShell code" { $psFile = Get-Content -Path "$PSScriptRoot\$ModuleName.psm1" -ErrorAction Stop $errors = $null $null = [System.Management.Automation.PSParser]::Tokenize($psFile, [ref]$errors) $errors.Count | Should -Be 0 } } # Context 'Module Setup' #endregion #region Function Testing $Allfunctions = Get-ChildItem "$PSScriptRoot\Public", "$PSScriptRoot\Private" -Include '*.ps1' -Exclude '*.Tests.ps1' -Recurse $PublicFunctions = Get-ChildItem "$PSScriptRoot\Public" -Include '*.ps1' -Exclude '*.Tests.ps1' -Recurse $PrivateFunctions = Get-ChildItem "$PSScriptRoot\Private" -Include '*.ps1' -Exclude '*.Tests.ps1' -Recurse $PublicDocs = Get-ChildItem "$PSScriptRoot\docs" -Include '*.md' -Recurse Context 'Testing Module ALL Functions' -ForEach $AllFunctions { It "'$($_.BaseName)' should exist" { "$($_.FullName)" | Should -Exist } It "'$_' should have a valid header" { "$($_.FullName)" | Should -FileContentMatch 'Module:' "$($_.FullName)" | Should -FileContentMatch 'Function:' "$($_.FullName)" | Should -FileContentMatch 'Author:' "$($_.FullName)" | Should -FileContentMatch 'Updated:' "$($_.FullName)" | Should -FileContentMatch 'Status:' } It "'$($_.BaseName)' should have a function" { "$($_.FullName)" | Should -FileContentMatch 'function' } It "'$($_.BaseName)' is valid PowerShell code" { $psFile = Get-Content -Path $_.FullName -ErrorAction Stop $errors = $null $null = [System.Management.Automation.PSParser]::Tokenize($psFile, [ref]$errors) $errors.Count | Should -Be 0 } } # Context "Testing Module ALL Functions" Context 'Testing Module PUBLIC Functions' -Foreach $PublicFunctions { It "'$($_.BaseName)' should have a SYNOPSIS section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.SYNOPSIS' } It "'$($_.BaseName)' should have a DESCRIPTION section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.DESCRIPTION' } It "'$($_.BaseName)' should have a EXAMPLE section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.EXAMPLE' } It "'$($_.BaseName)' should have a NOTES section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.NOTES' } It "'$($_.BaseName)' should have a INPUTS section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.INPUTS' } It "'$($_.BaseName)' should have a OUTPUTS section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.OUTPUTS' } It "'$($_.BaseName)' should have a COMPONENT section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.COMPONENT' } It "'$($_.BaseName)' should have a FUNCTIONALITY section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.FUNCTIONALITY' } It "'$($_.BaseName)' should have a LINK section in the help block" { "$($_.FullName)" | Should -FileContentMatch '.LINK' } It "'$($_.BaseName)' should have the HELP URL linked in the LINK section in the help block" { "$($_.FullName)" | Should -FileContentMatch "https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/$($_.BaseName).md" "$($_.FullName)" | Should -FileContentMatch 'https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/about_' "$($_.FullName)" | Should -FileContentMatch 'https://github.com/DEberhardt/TeamsFunctions/tree/main/docs/' } It "'$($_.BaseName)' should have an ABOUT topic linked in the LINK section in the help block" { "$($_.FullName)" | Should -FileContentMatch 'about_' } # not all will have the full begin, process, end model It "'$($_.BaseName)' should have a BEGIN, PROCESS and END block" { "$($_.FullName)" | Should -FileContentMatch 'begin {' "$($_.FullName)" | Should -FileContentMatch 'process {' "$($_.FullName)" | Should -FileContentMatch 'end {' } # not all will have advanced functions It "'$($_.BaseName)' should be an advanced function" { "$($_.FullName)" | Should -FileContentMatch 'cmdletbinding' "$($_.FullName)" | Should -FileContentMatch 'param' } It "'$($_.BaseName)' should have an OUTPUTTYPE set" { "$($_.FullName)" | Should -FileContentMatch '[OutputType([*)]' } It "'$($_.BaseName)' should contain Write-Verbose blocks" { "$($_.FullName)" | Should -FileContentMatch 'Write-Verbose' } } # Context "Testing Module PUBLIC Functions" Context 'Testing Module PRIVATE Functions' -ForEach $PrivateFunctions { # currently no special tests for private functions } # Context "Testing Module PRIVATE Functions" #endregion <# Commenting out as there aren't any tests files for individual files yet. Context "Testing FUNCTION has tests" -ForEach $AllFunctions { #$functionTests = Get-ChildItem "$($_.BaseName).Tests.ps1" -Recurse It "'$($_.BaseName).Tests.ps1' should exist" { "$($_.BaseName).Tests.ps1" | Should -Exist } } #> Context 'Testing Module PUBLIC Documentation' -Foreach $PublicDocs { It "'$_' should NOT have empty documentation in the MD file" { "$($_.FullName)" | Should -Not -FileContentMatch ([regex]::Escape('{{')) } } # Context "Testing Module DOCS" } <# # Code from F-X Cat https://vexx32.github.io/2020/07/08/Verify-Module-Help-Pester/ #region Discovery $ModuleName = 'TeamsFunctions' #endregion Discovery BeforeAll { $ModuleName = 'TeamsFunctions' #Import-Module $ModuleName swop 1 #Add-Type -Name Microsoft.Rtc.Management.Hosted.Online.Models.AudioFile # Doesn't work... } Describe "$ModuleName Sanity Tests - Help Content" -Tags 'Module' { #region Discovery # The module will need to be imported during Discovery since we're using it to generate test cases / Context blocks #Import-Module $ModuleName swop 1 $ShouldProcessParameters = 'WhatIf', 'Confirm' # Generate command list for generating Context / TestCases $Module = Get-Module $ModuleName $CommandList = @( $Module.ExportedFunctions.Keys $Module.ExportedCmdlets.Keys ) #endregion Discovery r}ach ($Command in $CommandList) { } Context "$Command - Help Content" { #region Discovery $Help = @{ Help = Get-Help -Name $Command -Full | Select-Object -Property * } $Parameters = Get-Help -Name $Command -Parameter * -ErrorAction Ignore | Where-Object { $_.Name -and $_.Name -notin $ShouldProcessParameters } | ForEach-Object { @{ Name = $_.name Description = $_.Description.Text } } $Ast = @{ # Ast will be $null if the command is a compiled cmdlet Ast = (Get-Content -Path "function:/$Command" -ErrorAction Ignore).Ast Parameters = $Parameters } $Examples = $Help.Help.Examples.Example | ForEach-Object { @{ Example = $_ } } #endregion Discovery It "has help content for $Command" -TestCases $Help { $Help | Should -Not -BeNullOrEmpty } It "contains a synopsis for $Command" -TestCases $Help { $Help.Synopsis | Should -Not -BeNullOrEmpty } It "contains a description for $Command" -TestCases $Help { $Help.Description | Should -Not -BeNullOrEmpty } It "lists the function author in the Notes section for $Command" -TestCases $Help { $Notes = $Help.AlertSet.Alert.Text -split '\n' $Notes[0].Trim() | Should -BeLike "Author: *" } # This will be skipped for compiled commands ($Ast.Ast will be $null) It "has a help entry for all parameters of $Command" -TestCases $Ast -Skip:(-not ($Parameters -and $Ast.Ast)) { @($Parameters).Count | Should -Be $Ast.Body.ParamBlock.Parameters.Count -Because 'the number of parameters in the help should match the number in the function script' } It "has a description for $Command parameter -<Name>" -TestCases $Parameters -Skip:(-not $Parameters) { $Description | Should -Not -BeNullOrEmpty -Because "parameter $Name should have a description" } It "has at least one usage example for $Command" -TestCases $Help { $Help.Examples.Example.Code.Count | Should -BeGreaterOrEqual 1 } It "lists a description for $Command example: <Title>" -TestCases $Examples { $Example.Remarks | Should -Not -BeNullOrEmpty -Because "example $($Example.Title) should have a description!" } } } } #> |