tests/AppModule/AppComponent.Tests.ps1
|
<#! Integration Test: AppComponent cmdlets Validates add / get / remove app module components, before publishing (Get-XrmAppComponents -Unpublished) and after. #> . "$PSScriptRoot\..\_TestConfig.ps1"; $suffix = Get-Random -Minimum 10000 -Maximum 99999; Write-Section "Create App Module and SiteMap"; $iconQuery = New-XrmQueryExpression -LogicalName "webresource" -Columns "name" -TopCount 1; $iconQuery = $iconQuery | Add-XrmQueryCondition -Field "webresourcetype" -Condition Equal -Values 11; $icon = $Global:XrmClient | Get-XrmMultipleRecords -Query $iconQuery | Select-Object -First 1; $defaultSolution = $Global:XrmClient | Get-XrmSolution -SolutionUniqueName "Default" -Columns "publisherid"; $appRef = $Global:XrmClient | Add-XrmAppModule -Name "PDO App Components $suffix" -UniqueName "pdoappcomp$suffix" -WebResourceId $icon.Id -PublisherReference $defaultSolution.publisherid_Value; Assert-Test "AppModule created" { $null -ne $appRef -and $appRef.Id -ne [Guid]::Empty }; $siteMapRef = $Global:XrmClient | Add-XrmSiteMap -Name "PDO App Components $suffix" -SiteMapXml '<SiteMap><Area Id="A1"><Group Id="G1"><SubArea Id="S1" Entity="account" /></Group></Area></SiteMap>'; Assert-Test "SiteMap created" { $null -ne $siteMapRef }; $view = @($Global:XrmClient | Get-XrmViews -EntityLogicalName "account" -Columns "name")[0]; Write-Section "Add components to the unpublished app"; $components = @( (New-XrmEntityReference -LogicalName "sitemap" -Id $siteMapRef.Id), (New-XrmEntityReference -LogicalName "savedquery" -Id $view.Id) ); $Global:XrmClient | Add-XrmAppComponents -AppModuleId $appRef.Id -Components $components | Out-Null; $unpublishedComponents = $Global:XrmClient | Get-XrmAppComponents -AppModuleId $appRef.Id -Unpublished; $unpublishedTypes = @($unpublishedComponents.Entities | ForEach-Object { $_["componenttype"].Value }); Assert-Test "-Unpublished returns an EntityCollection" { $unpublishedComponents -is [Microsoft.Xrm.Sdk.EntityCollection] }; Assert-Test "-Unpublished returns the sitemap (62) and the view (26) before publishing" { $unpublishedTypes -contains 62 -and $unpublishedTypes -contains 26; }; $publishedError = $null; try { $Global:XrmClient | Get-XrmAppComponents -AppModuleId $appRef.Id -ErrorAction Stop | Out-Null; } catch { $publishedError = $_.Exception.Message; } Assert-Test "Without -Unpublished, RetrieveAppComponents fails on a never published app" { $null -ne $publishedError }; Write-Section "Publish"; $Global:XrmClient | Publish-XrmComponent -ComponentName "appmodule" -ComponentId $appRef.Id | Out-Null; $publishedComponents = $Global:XrmClient | Get-XrmAppComponents -AppModuleId $appRef.Id; $publishedTypes = @($publishedComponents.Entities | ForEach-Object { $_["componenttype"].Value }); Assert-Test "After publish, RetrieveAppComponents returns the sitemap and the view" { $publishedTypes -contains 62 -and $publishedTypes -contains 26; }; Write-Section "Remove Component"; $Global:XrmClient | Remove-XrmAppComponents -AppModuleId $appRef.Id -Components @((New-XrmEntityReference -LogicalName "savedquery" -Id $view.Id)) | Out-Null; $afterRemove = $Global:XrmClient | Get-XrmAppComponents -AppModuleId $appRef.Id -Unpublished; $afterRemoveTypes = @($afterRemove.Entities | ForEach-Object { $_["componenttype"].Value }); Assert-Test "Component removed (view gone, sitemap kept)" { $afterRemoveTypes -notcontains 26 -and $afterRemoveTypes -contains 62; }; Write-Section "Cleanup"; # Publishing added Dataverse search rows (dvtablesearch) for the app, one of which blocks a plain delete: Remove-XrmAppModule deletes them first $searchQuery = New-XrmQueryExpression -LogicalName "dvtablesearch" -Columns "name"; $searchQuery.Criteria.FilterOperator = [Microsoft.Xrm.Sdk.Query.LogicalOperator]::Or; $searchQuery = $searchQuery | Add-XrmQueryCondition -Field "m365appmoduleid" -Condition Equal -Values $appRef.Id; $searchQuery = $searchQuery | Add-XrmQueryCondition -Field "appmoduleid" -Condition Equal -Values $appRef.Id; # The published app's row is written after PublishXml returns: wait for it, or the app delete races with its creation $searchRows = @(); for ($attempt = 0; $attempt -lt 12; $attempt++) { $searchRows = Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $searchQuery -AsArray; if (@($searchRows | Where-Object { $_.name -like "M365_Primary_*" }).Count -gt 0) { break; } Start-Sleep -Seconds 5; } Write-Host " dvtablesearch rows of the app: $(($searchRows | ForEach-Object { $_.name }) -join ', ')" -ForegroundColor DarkGray; $cleanupErrors = [System.Collections.Generic.List[string]]::new(); try { $Global:XrmClient | Remove-XrmAppModule -AppModuleReference $appRef -ErrorAction Stop; } catch { $cleanupErrors.Add("app: $($_.Exception.Message)"); } try { $Global:XrmClient | Remove-XrmRecord -LogicalName "sitemap" -Id $siteMapRef.Id -ErrorAction Stop; } catch { $cleanupErrors.Add("sitemap: $($_.Exception.Message)"); } Assert-Test "Cleanup complete (app and sitemap deleted) $($cleanupErrors -join ' | ')" { $cleanupErrors.Count -eq 0 -and @(Get-XrmAppModules -XrmClient $Global:XrmClient -Id $appRef.Id -Unpublished -Columns "name").Count -eq 0; }; Assert-Test "Remove-XrmAppModule deleted the dvtablesearch rows of the app" { (Get-XrmMultipleRecords -XrmClient $Global:XrmClient -Query $searchQuery -AsArray).Count -eq 0; }; Write-TestSummary; |