4

I am trying to get the name of the last downloaded file in my selenium javascript application.

I have my selenium driver navigating to the chrome downloads page using: driver.get('chrome://downloads'); , but when I get there, selenium is not able to find ANY elements on the download page.

The chrome downloads page 'chrome://downloads' has a bunch of shadow-root elements that I don't know how to get underneath in order to access the id's that I want. How do I access identifiers beneath shadow-root items?

I want to get $("#file-link") as shown here:

showing file link id

But when I use jquery to find it, everything returns null (probably because it's behind shadow-root)

jquery actions return null jquery actions return null 2

Here's a big picture of all the information I have including showing that "#file-link" totally exists:

html structure of chrome download page

The code I am using to wait for the element to exist is the same that I use for all elements in my application, so I think this is already working:

driver.wait(until.elementLocated(By.id('downloads-manager')), 120000).then(function(){
    console.log("#downloads-manager shows");
    driver.findElement(By.id('downloads-manager')).then(function(dwMan){
        //How do I "open" #shadow-root now? :(
    });
});

Here is my version information:

  • Chromium v54.0.2840.71
  • Node v6.5.0
  • ChromeDriver v2.27.440175
  • selenium-webdriver v3.4.0

Similar Question

Links

Katie
  • 45,622
  • 19
  • 93
  • 125

2 Answers2

4

The $ from your example is not a shorthand for JQuery. It's function overridden by the page to locate an element by id only:

function $(id){var el=document.getElementById(id);return el?assertInstanceof(el,HTMLElement):null}

To select through the shadow DOM, you need to use the '/deep/' combinator.

So to get all the links in the download page:

document.querySelectorAll("downloads-manager /deep/ downloads-item /deep/ [id=file-link]")

And with Selenium:

By.css("downloads-manager /deep/ downloads-item /deep/ [id=file-link]")
Florent B.
  • 41,537
  • 7
  • 86
  • 101
1

Why not check the downloads folder directly? I do this for downloading Excel files. I first clear the downloads folder, click the button to download the file, wait ~5 sec (varies by file size, internet speed, etc.), and then looking in the folder for a "*.xlsx" file. This also has the benefit of working with any browser.

C# Examples:

/// <summary>
/// Deletes the contents of the current user's "Downloads" folder
/// </summary>
public static void DeleteDownloads()
{
    // Get the default downloads folder for the current user
    string downloadFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads";
    // Delete all existing files
    DirectoryInfo di = new DirectoryInfo(directoryPath);
    foreach (FileInfo file in di.GetFiles())
    {
        file.Delete();
    }
    foreach (DirectoryInfo dir in di.GetDirectories())
    {
        dir.Delete(true);
    }
}

/// <summary>
/// Looks for a file with the given extension (Example: "*.xlsx") in the current user's "Download" folder.
/// </summary>
/// <returns>Empty string if files are found</returns>
public static string LocateDownloadedFile(string fileExtension)
{
    // Get the default downloads folder for the current user
    string downloadFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads";
    DirectoryInfo di = new DirectoryInfo(downloadFolderPath);
    FileInfo[] filesFound = di.GetFiles(fileExtension);
    if (filesFound.Length == 0)
    {
        return "No files present";
    }
    else
    {
        return "";
    }
}

And then in my Test I can Assert.IsEmpty(LocateDownloadedFile); This way if the assert fails, the error message if printed.

Expected: String.Empty. Actual: No files present.

Timothy Cope
  • 482
  • 2
  • 11
  • Thanks! Yeah that might be a better approach. I think there is a variable for where chrome downloads all the user's files, so I could just check to see if there was a file downloaded there recently. I'll try this method and see if it's easier to get working :) – Katie Jun 06 '17 at 22:31