How do I automate file selecting when the input is created by Javascript on click and never attached to the HTML document using Selenium? How do I automate file selecting when the input is created by Javascript on click and never attached to the HTML document using Selenium? selenium selenium

How do I automate file selecting when the input is created by Javascript on click and never attached to the HTML document using Selenium?


If your input were added to the DOM this would be a simple question, as I'm sure you're aware. The normal process looks something like this:

<input type="file" id="uploadhere" />
IWebElement element = driver.FindElement(By.Id("uploadhere"));element.SendKeys("C:\\Some_Folder\\MyFile.txt");

SendKeys handles the magic of the actual upload but it does so not by accessing the file upload menu, but by interacting with the input element directly.

Your problem is that the input element isn't in the DOM and isn't visible. The WebDriver API is designed to work with dynamic changing DOM elements that are visible to the user, mimicing the interactions with the UI. It can click on your button because it's visible, but it doesn't see the input element because it is not in the DOM or visible.

You're going to hit a hard wall here and be unable to solve this with Selenium directly, but there may be a workaround. The Automation API provided by .Net can provide you with a way to monitor the FileDialog itself.

Something like this may provide a path:

System.Windows.Forms.SendKeys.SendWait("pathToFile")

Or even a direct action, but this is fragile:

Actions action = new Actions(driver);action.SendKeys(pObjElement, Keys.Space).Build().Perform();Thread.Sleep(TimeSpan.FromSeconds(2));var dialogHWnd = FindWindow(null, "Select a file to upload..."); // Here goes the title of the dialog windowvar setFocus = SetForegroundWindow(dialogHWnd);if (setFocus){    Thread.Sleep(TimeSpan.FromSeconds(2));    System.Windows.Forms.SendKeys.SendWait(pFile);    System.Windows.Forms.SendKeys.SendWait("{DOWN}");    System.Windows.Forms.SendKeys.SendWait("{TAB}");    System.Windows.Forms.SendKeys.SendWait("{TAB}");    System.Windows.Forms.SendKeys.SendWait("{ENTER}");}


Suppress the click beforehand with a script injection. The file input will still be created on click but the modal file dialog won't appear. You'll also have to insert the input in the DOM for it to be retrieved via Selenium:

string JS_PREP_FILE_INPUT = @"HTMLInputElement.prototype.click = function () {    if (!this.parentNode) {        this.style.display = 'none';        document.documentElement.appendChild(this);        this.addEventListener('change', () => this.remove());    }}";driver.ExecuteScript(JS_PREP_FILE_INPUT);driver.FindElement(By.CssSelector("button"))    .Click();driver.FindElement(By.CssSelector("input[type=file]"))    .SendKeys("C:\\myfile.txt");


As per the script you have shared:

<body>    <button>Click me!</button>    <script>        document.querySelector("button").addEventListener("click", () => {            const txt = document.createElement("input");            txt.type = "file";            txt.addEventListener("change", () => {                console.log(txt.files[0]);            });            txt.click();        });    </script></body>

Will add an WebElement of type <input> with value of the type attribute as file within the DOM Tree as follows:

<input type="file" ...>

However, I don't see any issue in locating the same <input> tag once it is added within the HTML DOM. Ideally, you should be able to locate the element inducing WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using CssSelector considering the element is the only <input> element in the DOM Tree:

    new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("input[type='file']"))).SendKeys("/filename/with/absolute/path");
  • Using XPath considering the element is the only <input> element in the DOM Tree:

    new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//input[@type='file']"))).SendKeys("/filename/with/absolute/path");
  • Using XPath considering multiple <input> element exists within the DOM Tree:

    new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//button[text()='Click me!']//following::input[@type='file']"))).SendKeys("/filename/with/absolute/path");

Using SeleniumExtras.WaitHelpers

Incase you need SeleniumExtras.WaitHelpers:

new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.XPath("//input[@type='file']"))).SendKeys("/filename/with/absolute/path");