Private/TestCaseManagement/ConvertFrom-TcmWorkItemToTestCase.ps1

function ConvertFrom-TcmWorkItemToTestCase {
    <#
        .SYNOPSIS
            Converts an Azure DevOps work item to test case format.

        .PARAMETER WorkItem
            The work item object from Azure DevOps.

        .OUTPUTS
            Hashtable representing the test case data structure.
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        $WorkItem
    )

    try {
        $fields = $WorkItem.fields

        # Extract test steps if present
        $steps = @()
        if ($fields.'Microsoft.VSTS.TCM.Steps') {
            # Parse XML test steps
            [xml]$stepsXml = $fields.'Microsoft.VSTS.TCM.Steps'
            $stepNumber = 1

            foreach ($step in $stepsXml.steps.step) {
                # Process both ActionStep and ValidateStep (portal creates ValidateStep)
                if ($step.type -eq 'ActionStep' -or $step.type -eq 'ValidateStep') {
                    # Build step with explicit order: stepNumber, attachments, action, expectedResult
                    $orderedStep = [ordered]@{}
                    $orderedStep['stepNumber'] = $stepNumber
                    $orderedStep['attachments'] = @()

                    # CDATA sections use '#cdata-section' property, not '#text'
                    # Portal-edited steps use '#text' with HTML entities, API-created steps use '#cdata-section'
                    $actionRaw = ($step.parameterizedString[0].'#cdata-section' ?? $step.parameterizedString[0].'#text' ?? '')
                    $expectedResultRaw = ($step.parameterizedString[1].'#cdata-section' ?? $step.parameterizedString[1].'#text' ?? '')

                    # Strip HTML tags from the content (portal adds <DIV>, <P> tags)
                    $orderedStep['action'] = ($actionRaw -replace '<[^>]+>', '').Trim()
                    $orderedStep['expectedResult'] = ($expectedResultRaw -replace '<[^>]+>', '').Trim()

                    $steps += $orderedStep
                    $stepNumber++
                }
            }
        }

        # If no steps were parsed, ensure there is at least one empty default step
        if (-not $steps -or $steps.Count -eq 0) {
            # Default empty step with explicit ordering
            $defaultStep = [ordered]@{}
            $defaultStep['stepNumber'] = 1
            $defaultStep['attachments'] = @()
            $defaultStep['action'] = ""
            $defaultStep['expectedResult'] = ""
            $steps = @($defaultStep)
        }

        # Build test case data structure
        $testCaseData = [ordered]@{
            id = $WorkItem.id
            title = $fields.'System.Title'
            areaPath = $fields.'System.AreaPath'
            iterationPath = $fields.'System.IterationPath'
            state = $fields.'System.State'
            priority = [int]($fields.'Microsoft.VSTS.Common.Priority' ?? 2)
            assignedTo = $fields.'System.AssignedTo'.displayName ?? ""
            tags = ($fields.'System.Tags' -split ';' | Where-Object { $_ }) ?? @()
            description = $fields.'System.Description' ?? ""
            preconditions = $fields.'Microsoft.VSTS.TCM.LocalDataSource' ?? ""
            steps = $steps
            automationStatus = $fields.'Microsoft.VSTS.TCM.AutomationStatus' ?? "Not Automated"
            customFields = @{}
        }

        # Extract custom fields (any field not in the standard set)
        $standardFields = @(
            'System.Id', 'System.Title', 'System.AreaPath', 'System.IterationPath',
            'System.State', 'System.AssignedTo', 'System.Tags', 'System.Description',
            'System.CreatedDate', 'System.CreatedBy', 'System.ChangedDate', 'System.ChangedBy',
            'Microsoft.VSTS.Common.Priority', 'Microsoft.VSTS.TCM.Steps',
            'Microsoft.VSTS.TCM.LocalDataSource', 'Microsoft.VSTS.TCM.AutomationStatus'
        )

        foreach ($fieldName in $fields.Keys) {
            if ($fieldName -notin $standardFields) {
                $testCaseData.customFields[$fieldName] = $fields[$fieldName]
            }
        }

        return $testCaseData
    }
    catch {
        throw "Failed to convert work item to test case format: $($_.Exception.Message)"
    }
}