_csharp
TL;DR - Show Me The Code
using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
namespace csharp
{
[TestClass]
public class FileDownloadTest
{
IWebDriver _driver;
string _folderPath;
[TestInitialize]
public void SetUp()
{
_folderPath = System.Environment.CurrentDirectory + $"/../../../{System.Guid.NewGuid().ToString()}";
Directory.CreateDirectory(_folderPath);
FirefoxOptions Options = new FirefoxOptions();
Options.SetPreference("browser.download.dir", _folderPath);
Options.SetPreference("browser.download.folderList", 2);
Options.SetPreference("browser.helperApps.neverAsk.saveToDisk",
"image/jpeg, application/pdf, application/octet-stream");
Options.SetPreference("pdfjs.disabled", true);
_driver = new FirefoxDriver(Options);
}
[TestCleanup]
public void TearDown()
{
_driver.Quit();
Directory.Delete(_folderPath, true);
}
[TestMethod]
public void DownloadFileToDisk()
{
_driver.Url = "https://the-internet.herokuapp.com/download";
_driver.FindElement(By.CssSelector(".example a")).Click();
// Waiting up to 5 seconds for the file to be downloaded
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(5));
wait.Until(driver =>
{
DirectoryInfo downloadFolder = new DirectoryInfo(_folderPath);
return downloadFolder.GetFiles().Length > 0;
});
DirectoryInfo DownloadFolder = new DirectoryInfo(_folderPath);
Assert.IsTrue(DownloadFolder.GetFiles().Length > 0, "File not downloaded");
foreach(FileInfo file in DownloadFolder.GetFiles())
{
Assert.IsTrue(file.Length > 0, "File empty");
}
}
}
}
Code Walkthrough
Importing Libraries
Lines 1 to 6 are pulling in our requisite classes for interacting with the operating system (e.g., using System.IO;
),
our testing framework (e.g., using Microsoft.VisualStudio.TestTools.UnitTesting;
), driving the browser with
Selenium (e.g., using OpenQA.Selenium;
), launching an instance of Firefox
(e.g., using OpenQA.Selenium.Firefox;
), and Selenium's wait functions (e.g., using OpenQA.Selenium.Support.UI;
).
Setup and Teardown
After specifying the namespace and the class (e.g., public class FileDownloadTest
), lines 17 to 35 are setting up and
tearing down the browser instance.
First we create a field variable (e.g., IWebDriver _driver;
) to store our WebDriver instance for reuse throughout
the class.
We then create a SetUp()
method with a [TestInitialize]
attribute, so it runs before our test. This is where the
magic is happening in this example. In it, we're creating a uniquely named temp directory
(e.g., System.Guid.NewGuid().ToString();
), configuring a browser options object (for Firefox in this case), and
plying it with the necessary configuration parameters to make it automatically download the file where we want
(e.g., in the newly created temp directory).
Here's a breakdown of each of the browser preferences being set:
browser.download.dir
accepts a string. This is how we set the custom download path. It needs to be an absolute path.browser.download.folderList
takes a number. It tells Firefox which download directory to use.2
tells it to use a custom download path, whereas1
would use the browser's default path, and0
would place them on the Desktop.browser.helperApps.neverAsk.saveToDisk
tells Firefox when not to prompt for a file download. It accepts a string of the file's MIME type. If you want to specify more than one, you do it with a comma-separated string (which we've done).pdfjs.disabled
is for when downloading PDFs. This overrides the sensible default in Firefox that previews PDFs in the browser. It accepts a boolean.
The options are then passed into our instance of Selenium (e.g., _driver = new FirefoxDriver(Options);
).
After our test executes, the TearDown()
method will run thanks to the [TestCleanup]
attribute. This
calls _driver?.Quit();
which will close the browser instance. Then, it will clean up the temp directory by deleting
it. Specifying true
as a second parameter for Directory.Delete()
will recursively delete the files in the folder
before deleting it.
The Test
Lines 38 to 56 are the test itself.
We create an DownloadFileToDisk()
method and add a [TestMethod]
attribute, so it is run as a test. In it, we visit
the page we find the first download link and click it. The click triggers an automatic download to the temp directory
created in SetUp()
. We need to wait for the download to finish, so we leverage the WebDriverWait
class to wait for
the file to exist in the directory. After the file downloads, we perform some rudimentary checks to make sure the
unique temp directory isn't empty and then check the file (or files) to see that they aren't empty either.
Executing the Test
Before executing the test, we need to make sure the required dependencies are declared on the project file (e.g.,
csharp.csproj
in this case).
Toggle to see the csharp.csproj
file.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.5.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.5.2" />
<PackageReference Include="Selenium.Support" Version="4.24.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.24.0" />
</ItemGroup>
</Project>
Finally, we can run the test by executing dotnet test
from the command-line.