Once clicking a download button, files will be downloaded. Before executing next code, it needs to wait until the download completes.
My code looks like this:
<This code will always work.. Try it out guys!
public void waitForFileDownloaded(String fileName, int timeoutSeconds) {
FluentWait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(timeoutSeconds))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
wait.until((x) -> {
File[] files = new File(downloadfolderPath).listFiles();
for (File file : files) {
if (file.getName().contains(fileName)) {
return true;
}
}
return false;
});
}
A little late but this question has a good number of views, I thought it would be worth the time to answer it in case you haven't moved on or someone else comes across it.
I too ran into the same problem and thought I'd share. I was developing in python at the time but the same concept applies. You don't have to do the actual download using selenium. Rather than clicking on the element to start the download, you should consider retrieving the link and using built in functions to proceed from there.
The element you would normally click to begin the download should have a 'href' attribute that you should be able to read using selenium. This is the url pointing to the actual file. In python, it looks something like this:
element = driver.find_element_by_id('dl_link')
url = element.get_attribute('href')
From here you can use an http library to call the url. The important part here is that you set 'stream' to true so you can begin writing the bytes to a file. Make sure the file path contains the correct file extension and another thing, most operating systems don't allow you to name files with certain characters such as back slashes or quotations so heads up on that.
def download_file(url, file_path):
from requests import get
reply = get(url, stream=True)
with open(file_path, 'wb') as file:
for chunk in reply.iter_content(chunk_size=1024):
if chunk:
file.write(chunk)
The program shouldn't continue until the download is complete making it no longer necessary to poll until it is complete.
I apologize for answering in a different language, in Java I believe you can use the HttpURLConnection API. Hope this helps!
A java adaptation of Alexander Arendar's idea :
(using Java 8 & the predicate version of until method of FluentWait)
private void waitForFileDownload(int totalTimeoutInMillis, String expectedFileName) throws IOException {
FluentWait<WebDriver> wait = new FluentWait(this.funcDriver.driver)
.withTimeout(totalTimeoutInMillis, TimeUnit.MILLISECONDS)
.pollingEvery(200, TimeUnit.MILLISECONDS);
File fileToCheck = getDownloadsDirectory()
.resolve(expectedFileName)
.toFile();
wait.until((WebDriver wd) -> fileToCheck.exists());
}
public synchronized Path getDownloadsDirectory(){
if(downloadsDirectory == null){
try {
downloadsDirectory = Files.createTempDirectory("selleniumdownloads_");
} catch (IOException ex) {
throw new RuntimeException("Failed to create temporary downloads directory");
}
}
return downloadsDirectory;
}
Note the use of createTempDirectory to avoid the caveats of recursively deleting more than intended as well as automatically safely disposing of the folder when we re done with it.
Well, your file is stored somewhere, right? So, check if it exists in file system
File f = new File(filePathString);
do {
Thread.sleep(3000);
} while (f.exists() && f.length() == expectedSizeInBytes)
I like awaitility
Path filePath = Paths.get(".", "filename");
await().atMost(1, MINUTES)
.ignoreExceptions()
.until(() -> filePath.toFile().exists());
More info : http://www.testautomationguru.com/selenium-webdriver-how-to-wait-for-expected-conditions-using-awaitility/
Here's one using just WebDriverWait:
new WebDriverWait(driver, 60).until(d -> Paths.get(downloadDir, downloadFileName).toFile().exists());