Skip to main content

_csharp

TL;DR - Show Me The Code

2-download-a-file/code/csharp/FileDownloadTest.cs
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, whereas 1 would use the browser's default path, and 0 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.
2-download-a-file/code/csharp/csharp.csproj
<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.6.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.3" />
<PackageReference Include="Selenium.Support" Version="4.26.1" />
<PackageReference Include="Selenium.WebDriver" Version="4.26.1" />
</ItemGroup>

</Project>

Finally, we can run the test by executing dotnet test from the command-line.