Private/CuiTests/UxBrowserHelpers.ps1
|
# Copyright (c) 2026 Jeffrey Snover. All rights reserved. # Licensed under the MIT License. See LICENSE file in the project root. function Invoke-UxNavigate { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Url, [Parameter()][int]$TimeoutSec = 15 ) Invoke-CdpCommand -Session $Session -Method 'Page.navigate' -Params @{ url = $Url } -TimeoutSec $TimeoutSec Invoke-CdpCommand -Session $Session -Method 'Page.enable' -TimeoutSec 5 | Out-Null $sw = [System.Diagnostics.Stopwatch]::StartNew() while ($sw.ElapsedMilliseconds -lt ($TimeoutSec * 1000)) { $nav = Invoke-CdpCommand -Session $Session -Method 'Page.getNavigationHistory' -TimeoutSec 5 if ($null -ne $nav) { break } Start-Sleep -Milliseconds 200 } } function Invoke-UxClick { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter()][int]$TimeoutSec = 10 ) $escaped = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $js = @" (() => { const el = document.querySelector('$escaped'); if (!el) return { found: false }; el.scrollIntoView({ block: 'center' }); el.click(); return { found: true }; })() "@ $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = $js; returnByValue = $true } -TimeoutSec $TimeoutSec if ($result.result.value.found -ne $true) { throw "Element not found: $Selector" } } function Invoke-UxType { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter(Mandatory)][string]$Text, [Parameter()][switch]$Clear, [Parameter()][int]$TimeoutSec = 10 ) $escapedSel = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $escapedText = $Text -replace '\\', '\\\\' -replace "'", "\\\'" -replace "`n", "\\n" $clearJs = if ($Clear) { "el.value = '';" } else { '' } $js = @" (() => { const el = document.querySelector('$escapedSel'); if (!el) return { found: false }; el.focus(); $clearJs const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, 'value')?.set || Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set; if (nativeInputValueSetter) nativeInputValueSetter.call(el, '$escapedText'); else el.value = '$escapedText'; el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); return { found: true }; })() "@ $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = $js; returnByValue = $true } -TimeoutSec $TimeoutSec if ($result.result.value.found -ne $true) { throw "Input element not found: $Selector" } } function Invoke-UxWaitForSelector { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter()][int]$TimeoutMs = 5000, [Parameter()][int]$PollMs = 200, [Parameter()][switch]$Hidden ) $escaped = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $checkExpr = if ($Hidden) { "!document.querySelector('$escaped') || document.querySelector('$escaped').offsetParent === null" } else { "!!document.querySelector('$escaped')" } $sw = [System.Diagnostics.Stopwatch]::StartNew() while ($sw.ElapsedMilliseconds -lt $TimeoutMs) { $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = $checkExpr; returnByValue = $true } -TimeoutSec 5 if ($result.result.value -eq $true) { return $true } Start-Sleep -Milliseconds $PollMs } return $false } function Invoke-UxScreenshot { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Path, [Parameter()][int]$TimeoutSec = 10 ) $dir = [System.IO.Path]::GetDirectoryName($Path) if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } $result = Invoke-CdpCommand -Session $Session -Method 'Page.captureScreenshot' ` -Params @{ format = 'png' } -TimeoutSec $TimeoutSec $bytes = [System.Convert]::FromBase64String($result.data) [System.IO.File]::WriteAllBytes($Path, $bytes) $Path } function Invoke-UxGetText { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter()][int]$TimeoutSec = 10 ) $escaped = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = "document.querySelector('$escaped')?.textContent ?? ''"; returnByValue = $true } ` -TimeoutSec $TimeoutSec $result.result.value } function Invoke-UxEvaluate { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Expression, [Parameter()][int]$TimeoutSec = 10 ) $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = $Expression; returnByValue = $true } -TimeoutSec $TimeoutSec $result.result.value } function Invoke-UxSelectOption { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter(Mandatory)][string]$Value, [Parameter()][int]$TimeoutSec = 10 ) $escapedSel = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $escapedVal = $Value -replace '\\', '\\\\' -replace "'", "\\\'" $js = @" (() => { const el = document.querySelector('$escapedSel'); if (!el) return { found: false }; el.value = '$escapedVal'; el.dispatchEvent(new Event('change', { bubbles: true })); return { found: true }; })() "@ $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = $js; returnByValue = $true } -TimeoutSec $TimeoutSec if ($result.result.value.found -ne $true) { throw "Select element not found: $Selector" } } function Invoke-UxElementExists { [CmdletBinding()] param( [Parameter(Mandatory)][PSCustomObject]$Session, [Parameter(Mandatory)][string]$Selector, [Parameter()][int]$TimeoutSec = 5 ) $escaped = $Selector -replace '\\', '\\\\' -replace "'", "\\\'" $result = Invoke-CdpCommand -Session $Session -Method 'Runtime.evaluate' ` -Params @{ expression = "!!document.querySelector('$escaped')"; returnByValue = $true } ` -TimeoutSec $TimeoutSec $result.result.value -eq $true } function New-UxScreenshotDir { [CmdletBinding()] param( [Parameter(Mandatory)][string]$CuiId, [Parameter()][string]$BaseDir ) if (-not $BaseDir) { $BaseDir = Join-Path ([System.IO.Path]::GetTempPath()) 'cui-screenshots' } $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $dir = Join-Path $BaseDir "${CuiId}_${timestamp}" New-Item -ItemType Directory -Path $dir -Force | Out-Null $dir } |