Solution 1: Refactor Tests to Remove Robot Dependency (Recommended)
Replace Robot-based interactions with WebDriver native solutions:
1. For browser dialogs (download prompts/alerts):
groovy
// Instead of Robot for download confirmations
driver.switchTo().alert().accept() // For JS alerts
// For Chrome download preferences
ChromeOptions options = new ChromeOptions()
options.addArguments("--safebrowsing-disable-download-protection")
options.addArguments("--disable-popup-blocking")
Map<String, Object> prefs = new HashMap<>()
prefs.put("download.prompt_for_download", false)
prefs.put("download.default_directory", "C:\\downloads\\path")
options.setExperimentalOption("prefs", prefs)
2. For plugin permissions (like camera/microphone):
groovy
ChromeOptions options = new ChromeOptions()
options.addArguments("--use-fake-ui-for-media-stream")
options.addArguments("--use-fake-device-for-media-stream")
Solution 2: Enable GUI on Windows Agent
Configure your self-hosted agent to run with GUI access:
- Reconfigure agent service:
powershell
Stop-Service "Azure Pipelines Agent"
cd C:\agent\bin
.\config remove
.\config --unattended --runAsService --windowsLogonAccount "YOUR_DOMAIN\username" --windowsLogonPassword "password"
Check “Allow service to interact with desktop” in Windows Services
2. Add agent capabilities:
In C:\agent\.agent
:
json
"capabilities": {
"GUI": "true"
}
Solution 3: Virtual Display (Alternative)
If GUI isn’t possible, use headless-compatible tools:
groovy
import org.openqa.selenium.Keys
// For keyboard interactions
WebElement element = driver.findElement(By.id("target"))
element.sendKeys(Keys.TAB)
element.sendKeys(Keys.ENTER)
// For complex interactions
Actions actions = new Actions(driver)
actions.sendKeys(Keys.TAB).sendKeys(Keys.ENTER).build().perform()
Pipeline Configuration Update
Add browser flags to suppress UI elements:
text
- task: KatalonStudio@2
inputs:
command: '-noSplash -runMode=console -browserType=Chrome -executionProfile=UAT -webui.autoUpdateDrivers=true --config -proxy.auth.option=NO_PROXY -chromeOptions="args=--headless,--disable-gpu,--disable-dev-shm-usage,--no-sandbox,--use-fake-ui-for-media-stream,--safebrowsing-disable-download-protection"'
Key Fixes:
- Remove Robot Class: Refactor all
java.awt.Robot
usage
- Browser Options: Configure Chrome/Firefox to avoid permission dialogs
- Agent Configuration: Enable desktop interaction for agent service
- Headless Mode: Use WebDriver-compatible interactions
Verification Steps:
- Test locally in headless mode:
bash
katalonc -runMode=console -browserType=Chrome -headless
- Add debug logging:
groovy
println "Current context: " + driver.switchTo().activeElement().getAttribute("id")
- Check browser logs in pipeline:
text
command: '... -logLevel=DEBUG -consoleLog'
Example Refactored Code:
groovy
// Before
Robot robot = new Robot()
robot.keyPress(KeyEvent.VK_TAB)
// After
driver.switchTo().activeElement().sendKeys(Keys.TAB)
// For file downloads
driver.findElement(By.linkText("Download")).click()
Thread.sleep(2000) // Allow download to complete
This eliminates the headless environment error by either enabling GUI access or removing GUI-dependent operations. Start with browser option configurations (Solution 1), as it’s the most pipeline-compatible approach