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:
But when I use jquery to find it, everything returns null (probably because it's behind shadow-root
)
Here's a big picture of all the information I have including showing that "#file-link" totally exists:
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
- Selenium webdriver can't find elements at chrome://downloads (This is the same problem I am having but in python)
Links
- Selenium Javascript API: /
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:
But when I use jquery to find it, everything returns null (probably because it's behind shadow-root
)
Here's a big picture of all the information I have including showing that "#file-link" totally exists:
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
- Selenium webdriver can't find elements at chrome://downloads (This is the same problem I am having but in python)
Links
- Selenium Javascript API: https://seleniumhq.github.io/selenium/docs/api/javascript/
3 Answers
Reset to default 5The $
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/' binator.
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]")
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.
I think this should work with the current version Chrome:
document.getElementsByTagName("downloads-manager")[0]
.shadowRoot.children["mainContainer"]
.getElementsByTagName("downloads-item")[0]
.shadowRoot.getElementById("file-link")
.getAttribute("href")