Modules/businessdev.ALbuild.Containers/Private/Test-BcContainerAppPresence.ps1

function Test-BcContainerAppPresence {
    <#
    .SYNOPSIS
        Decides whether the app a capture run is meant to show is actually installed in the container.
 
    .DESCRIPTION
        The most expensive screenshot failure is not an error. It is a run that SUCCEEDS and produces
        pictures of standard Business Central without the feature in them - nobody notices until
        review, and by then the work item has been closed on the evidence.
 
        So the app under test is resolved before the browser starts:
 
            1. -AppId / -AppName, when the caller named one
            2. the app.json under -ProjectFolder
 
        and checked against what the container reports. INSTALLED, not merely published: a published
        app contributes no pages.
 
        When nothing identifies an app, this returns Known = $false rather than guessing. That case is
        legitimate (capturing standard BC on purpose) and is recorded in the manifest instead of being
        turned into a failure.
 
    .PARAMETER ContainerName
        The container to look in.
 
    .PARAMETER AppId
        App id to require.
 
    .PARAMETER AppName
        App name to require, when no id is available.
 
    .PARAMETER ProjectFolder
        An AL project folder; its app.json supplies id and name when neither was passed.
 
    .OUTPUTS
        PSCustomObject with Known, Installed, Name, Id, Version and Published.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ContainerName,
        [string] $AppId,
        [string] $AppName,
        [string] $ProjectFolder
    )

    if ((-not $AppId) -and (-not $AppName) -and $ProjectFolder) {
        $appJson = Join-Path -Path $ProjectFolder -ChildPath 'app.json'
        if (Test-Path -LiteralPath $appJson) {
            try {
                $manifest = Get-Content -LiteralPath $appJson -Raw | ConvertFrom-Json
                if ($manifest.PSObject.Properties['id']) { $AppId = "$($manifest.id)" }
                if ($manifest.PSObject.Properties['name']) { $AppName = "$($manifest.name)" }
            }
            catch {
                Write-ALbuildLog -Level Warning "Could not read '$appJson': $($_.Exception.Message)"
            }
        }
    }

    if ((-not $AppId) -and (-not $AppName)) {
        return [PSCustomObject]@{
            Known = $false; Installed = $null; Name = $null; Id = $null; Version = $null; Published = $false
        }
    }

    $installed = @()
    try { $installed = @(Get-BcContainerAppInfo -Name $ContainerName) }
    catch {
        # A container that cannot be asked is not evidence that the app is missing. The web client
        # check that follows will fail with something far more useful than a guess made here.
        Write-ALbuildLog -Level Warning "Could not read the app list of '$ContainerName': $($_.Exception.Message)"
        return [PSCustomObject]@{
            Known = $false; Installed = $null; Name = $AppName; Id = $AppId; Version = $null; Published = $false
        }
    }

    $found = @($installed | Where-Object {
            ($AppId -and "$($_.AppId)".Trim('{', '}') -eq "$AppId".Trim('{', '}')) -or
            ((-not $AppId) -and $AppName -and "$($_.Name)" -eq "$AppName")
        })

    $running = @($found | Where-Object { [bool] $_.IsInstalled })

    [PSCustomObject]@{
        Known     = $true
        Installed = ($running.Count -gt 0)
        Name      = $(if ($found.Count) { "$($found[0].Name)" } else { $AppName })
        Id        = $(if ($found.Count) { "$($found[0].AppId)" } else { $AppId })
        Version   = $(if ($running.Count) { "$($running[0].Version)" } elseif ($found.Count) { "$($found[0].Version)" } else { $null })
        Published = ($found.Count -gt 0)
    }
}