java.awt.AWTException: headless environment lors de l'exécution de tests Katalon dans une pipeline CI/CD (agent Windows)

Lorsque j’exécute mes tests Katalon localement avec la commande suivante, tout fonctionne correctement : le navigateur s’ouvre et les tests s’exécutent comme prévu.

Mais lorsque j’exécute la même commande via une pipeline (YAML) sur un agent Windows, j’obtiens l’erreur suivante :

java.awt.AWTException: headless environment

// Utiliser Robot pour simuler les interactions avec le plugin
Robot robot = new Robot()

	// Simuler la pression de la touche "Tab" pour naviguer dans la fenêtre
	robot.keyPress(KeyEvent.VK_TAB)
	robot.keyRelease(KeyEvent.VK_TAB)

	// Simuler la pression de la touche "Enter" pour cocher "Always allow..."
	robot.keyPress(KeyEvent.VK_ENTER)
	robot.keyRelease(KeyEvent.VK_ENTER)

	// Simuler plusieurs pressions de la touche "Tab" pour atteindre le bouton "OK"
	for (int i = 0; i < 1; i++) {
		// Ajustez le nombre de pressions de "Tab" selon vos besoins
		robot.keyPress(KeyEvent.VK_TAB)
		robot.keyRelease(KeyEvent.VK_TAB)
		Thread.sleep(500) // Pause entre chaque pression de "Tab"
	}

	// Simuler la pression de la touche "Enter" pour cliquer sur le bouton "OK"
	robot.keyPress(KeyEvent.VK_ENTER)
	robot.keyRelease(KeyEvent.VK_ENTER)
1 Like

Goggle Translate:
When I (@asma.gaies.external) run my Katalon tests locally with the following command, everything works fine: the browser opens and the tests run as expected.

But when I run the same command via a pipeline (YAML) on a Windows agent, I get the following error:

java.awt.AWTException: headless environment

    // Use Robot to simulate interactions with the plugin
    Robot robot = new Robot()

    // Simulate pressing the "Tab" key to navigate the window
    robot.keyPress(KeyEvent.VK_TAB)
    robot.keyRelease(KeyEvent.VK_TAB)

	// Simulate pressing the "Enter" key to check "Always allow..."
	robot.keyPress(KeyEvent.VK_ENTER)
	robot.keyRelease(KeyEvent.VK_ENTER)

	// Simulate multiple presses of the "Tab" key to reach the "OK" button
	for (int i = 0; i < 1; i++) {
		// Adjust the number of "Tab" presses as needed
		robot.keyPress(KeyEvent.VK_TAB)
		robot.keyRelease(KeyEvent.VK_TAB)
		Thread.sleep(500) // Pause entre chaque pression de "Tab"
	}

	// Simulate pressing the "Enter" key to click the "OK" button
	robot.keyPress(KeyEvent.VK_ENTER)
	robot.keyRelease(KeyEvent.VK_ENTER)

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:

  1. 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:

  1. Remove Robot Class: Refactor all java.awt.Robot usage
  2. Browser Options: Configure Chrome/Firefox to avoid permission dialogs
  3. Agent Configuration: Enable desktop interaction for agent service
  4. Headless Mode: Use WebDriver-compatible interactions

Verification Steps:

  1. Test locally in headless mode:

bash

katalonc -runMode=console -browserType=Chrome -headless
  1. Add debug logging:

groovy

println "Current context: " + driver.switchTo().activeElement().getAttribute("id")
  1. 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

Bonjour
Merci pour votre réponse.
j’ai essayé tout, aucune n’a fonctionné

voilà comment le popup est généré :

« Voilà la ligne de code JS (enfin TS, mais c’est converti en JS) qui est appelée :

$("form").append("<iframe id='ifrCustomProtocol' style='display:none;' src='" + this._options.CustomProtocolUrl + "' />");

On ajoute une IFrame qui appelle le CustomProtocol qui est configuré dans les paramètres du PluginManager. Et l’appel d’un customProtocol provoque l’ouverture de la popup par le navigateur (la première fois seulement, si on coche “toujours autoriser”, et à chaque fois si on ne coche pas la case “toujours autoriser”) »

je ne peux intéragir que niveau script test auto ou configuration pipeline ni niveau application ni création d’agent GUI

In English, please. You can use Google to translte your francais to English before posting.

Hello,
Thank you for your response.
I’ve tried everything, and nothing worked.

Here’s how the popup is generated:

“Here’s the line of JS code (actually TypeScript, but it gets compiled to JS) that is called:

$("form").append("<iframe id='ifrCustomProtocol' style='display:none;' src='" + this._options.CustomProtocolUrl + "' />");

An iframe is added that calls the CustomProtocol configured in the PluginManager settings.
And calling a customProtocol triggers the popup in the browser (only the first time, if you check ‘always allow’, and every time if you don’t check that box).”

I can only interact at the level of automated test scripts or pipeline configuration — not at the application level or by creating a GUI agent