To resolve the file download issue in Katalon where the PDF temporarily appears but fails to save properly, follow these steps:
1. Correct ChromeOptions Configuration
Ensure auto-download without the “Save As” dialog by setting download.prompt_for_download
to false
and specifying an absolute path:
import com.kms.katalon.core.webui.driver.DriverFactory
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.WebDriver
String downloadDir = "${RunConfiguration.getProjectDir()}/downloads".replace("/", File.separator) // Use OS-specific separators
new File(downloadDir).mkdirs() // Create directory if missing
ChromeOptions options = new ChromeOptions()
HashMap<String, Object> chromePrefs = new HashMap<>()
chromePrefs.put('download.prompt_for_download', false) // Disable dialog
chromePrefs.put('plugins.always_open_pdf_externally', true) // Force PDF download
chromePrefs.put('download.default_directory', downloadDir)
chromePrefs.put('download.directory_upgrade', true) // Overwrite existing files
options.setExperimentalOption('prefs', chromePrefs)
// Add arguments for stability (especially in headless/TestOps)
options.addArguments('--disable-gpu', '--no-sandbox', '--remote-allow-origins=*')
WebDriver driver = new ChromeDriver(options)
DriverFactory.changeWebDriver(driver)
2. Verify File Download with Dynamic Waits
After triggering the download, check for the file with a dynamic wait:
import java.nio.file.Files
import java.nio.file.Paths
String expectedFileName = "General_access_conditions.pdf"
String expectedFilePath = Paths.get(downloadDir, expectedFileName).toString()
int maxWait = 30 // Max wait in seconds
int interval = 1 // Check every 1 second
boolean fileFound = false
for (int elapsed = 0; elapsed < maxWait; elapsed += interval) {
File downloadedFile = new File(expectedFilePath)
if (downloadedFile.exists()) {
fileFound = true
break
}
WebUI.delay(interval)
}
assert fileFound : "File not found at ${expectedFilePath}"
3. Handle Temp Files and Partial Downloads
If files are saved as .tmp
and deleted:
- Add a post-download delay to allow Chrome to complete the download:
// After triggering download
WebUI.delay(5) // Adjust based on file size
- Check for
.tmp
files and rename them:
// After triggering download
File tmpFile = new File(Paths.get(downloadDir, "Unconfirmed_*.tmp").toString())
if (tmpFile.exists()) {
tmpFile.renameTo(new File(expectedFilePath))
}
4. Configure TestOps for File Access
- Specify Absolute Paths: Use
${RunConfiguration.getProjectDir()}
to avoid path ambiguity.
- Pre-Create Directories: Add a setup script to create
downloads
folder:
new File("${RunConfiguration.getProjectDir()}/downloads").mkdirs()
- Clean Up Files post-execution (in teardown script):
new File("${RunConfiguration.getProjectDir()}/downloads").deleteDir()
5. Handle Filename Conflicts
If the server appends timestamps to filenames (e.g., General_access_conditions(1).pdf
):
// Find the latest PDF in the download directory
File[] files = new File(downloadDir).listFiles({ file -> file.getName().endsWith('.pdf') } as FileFilter)
files.sort({ a, b -> Long.compare(b.lastModified(), a.lastModified()) }) // Sort by latest
String actualFilePath = files[0].getAbsolutePath()
// Rename to the desired filename
Files.move(Paths.get(actualFilePath), Paths.get(expectedFilePath))
6. Troubleshooting Tips
options.setCapability("goog:loggingPrefs", [performance: 'ALL', browser: 'ALL'])
Check logs via DriverFactory.getWebDriver().manage().logs().get('browser')
.
- Run in Non-Headless Mode (for local debugging):
options.addArguments('--headless=new') // Remove this line
- Verify Permissions: Ensure TestOps agent/user has write access to
downloadDir
.
By configuring Chrome to auto-download without dialogs, dynamically verifying file existence, and handling temp files, you can reliably save the PDF to your desired location with the correct name.