aerokube / selenoid

Selenium Hub successor running browsers within containers. Scalable, immutable, self hosted Selenium-Grid on any platform with single binary.
https://aerokube.com/selenoid/latest/
Apache License 2.0
2.57k stars 322 forks source link

How to upload files with current browsers? #76

Closed ghost closed 7 years ago

ghost commented 7 years ago

With docker service of browsers, it really eliminate a lot of processes issues. But how to upload files with browser? I don't know where to put my local files. How to map volumes in browser docker service?

ghost commented 7 years ago

Ref to #23 I know I can resolve it with profile. But how to upload files with profile? can you give me one example? Thanks!

I don't know which profile it is.

leonsabr commented 7 years ago

I have tested the following Java code in Selenoid remote browsers (Firefox and Chrome). It is supposed that the file you want to upload is located on a machine which runs your tests.

1) Find input element with type='file' attribute.

WebElement input = driver.findElement(By.cssSelector("input[type='file']"))

2) Make sure element is visible. You can't sendKeys into hidden elements.

((JavascriptExecutor) driver).executeScript("arguments[0].style.display = 'block';", input)

3) Set LocalFileDetector. The file will be base64 encoded and sent transparently through the JSON Wire Protocol.

driver.setFileDetector(new LocalFileDetector())

4) Perform sendKeys.

input.sendKeys("/path/to/file/on/machine/which/runs/tests")
aandryashin commented 7 years ago

I found this link, it may be helpful: http://seleniumguru.teachable.com/courses/selenium-webdriver/lectures/1714839

vania-pooh commented 7 years ago

@pdli did it help?

vania-pooh commented 7 years ago

@pdli closing because of inactivity. Feel free to reopen if having more questions.

Alek5andr commented 6 years ago

@leonsabr , I could not repeat success of your code.

I tried the following steps to upload the file being inside "selenoid" container:

  1. docker cp /home/usa/Documents/Upload/ selenoid:/home/selenium/ => copied host's "Upload/" directory and its content to containers "selenium/" one successfully.
  2. I run a test to upload "/home/selenium/Upload/test.txt" file. => No luck - file is not found.
  3. docker cp selenoid:/home/selenium/ /home/usa/Documents/Upload/ => "selenium/Upload/test.txt" was successfully copied from "selenoid" container.
  4. I run the test again in debug-mode using VNC and explored upload window on my own => there was no "/home/selenium/Upload/test.txt" file visible on UI, via VNC, in the container.

I'm in confusion: how to provide upload window with a file being inside a container? Could you suggest me, guys?

leonsabr commented 6 years ago

@Alek5andr, when you set driver.setFileDetector(new LocalFileDetector()) you don't need to copy (docker cp ...) files from your host machine to container. Selenium WebDriver does everything.

1) Put your test.txt in /home/usa/Documents/Upload/ directory (I guess it is machine where tests are run). 2) In test call input.sendKeys("/home/usa/Documents/Upload/test.txt") 3) Selenoid browser in container should find test.txt in some temporary directory where it was copied by Selenium WebDriver.

Alek5andr commented 6 years ago

@leonsabr, actually, I tried that way. My code snippet is:

((JavascriptExecutor) BrowserFactory.getFactory().getDriver()).executeScript("arguments[0].style.display = 'block';", fileUploadElement);

((RemoteWebDriver) BrowserFactory.getFactory().getDriver()).setFileDetector(new LocalFileDetector());

fileUploadElement.sendKeys(path);

where path = "/home/usa/Documents/Upload/test.txt"; It fails.

leonsabr commented 6 years ago

@Alek5andr could you provide exception message? What locator was used to find fileUploadElement?

Alek5andr commented 6 years ago

@leonsabr, there is no exception message in runtime. The path is successfully set to input of "fileUploadElement" and "submit" button on UI is clicked. After that opens page with the following messages (Google Chrome):

Your file was not found It may have been moved or deleted ERR_FILE_NOT_FOUND

CSS-locator of "fileUploadElement" is "input[type='file']".

Is there a way explicitly transfer files from host to container?

leonsabr commented 6 years ago

Yes, you can use docker-java client and method copyArchiveToContainerCmd to copy files into container (if you know its id).

You can also try the following check with Firefox: 1) right after fileUploadElement.sendKeys(path); go to Firefox container 2) in /tmp/ directory find subdirectory which name is equal to sessionId 3) your file should be there

I have just tested it:

# ls /tmp/07572a16-ef95-4750-9b49-1f2f599c4156/
test-keystore.p12
slothds commented 6 years ago

driver.setFileDetector(new LocalFileDetector()) works correctly, but it upload file into selenoid container, not browser. I'v solved this by mounting volume to selenoid container: -v /some/path/to/tmp:/tmp and setting arg in browsers.json:

"chrome": {
    "default": "62.0",
    "versions": {
        "62.0": {
            "image": "selenoid/vnc:chrome_62.0",
            "volumes": [ "/some/path/to/tmp:/tmp" ],
            "port": "4444",
            "path": "/"
        },
    }
}
Alek5andr commented 6 years ago

@leonsabr, indeed your solution worked with Firefox! I was amazed and glad. And, browsing through upload window, I managed to navigate to a file inside the container. WoW!

But still no luck with Google Chrome vers. 54 and 62, @slothds. I tried your suggestion: If I set "volumes" in "browsers.json", my test won't run due to failure to instantiate a class. Setting only a volume for the container does not succeed either =/

Why leonsabr's solution does not work with Chrome?

OK, update: I managed to upload a file in Chrome. The problem is due to "org.openqa.selenium.WebDriverException: invalid argument: File not found" exception. I debug on Windows 10. The path to necessary file is "C:\Users\usa\Documents\Upload\test.txt". I have such code snippet:

String path = "";
try {
 path = LOCATION_OF_UPLOAD_WINDOWS + keysToSend;
 fileUploadElement.sendKeys(path);
} catch (WebDriverException e) {
 path = LOCATION_OF_UPLOAD_LINUX + keysToSend;
}
((JavascriptExecutor) BrowserFactory.getFactory().getDriver()).executeScript("arguments[0].style.display = 'block';", fileUploadElement);
((RemoteWebDriver) BrowserFactory.getFactory().getDriver()).setFileDetector(new LocalFileDetector());
fileUploadElement.sendKeys(path);

Now I start to dig in the exception to solve it. Thank you, guys! You are the support >.<

Update 2: Damn it. I found the issue. I messed up with the try-catch statement XP The problem caused fileUploadElement.sendKeys(path); in try-block. Now everything works as a charm. Thank you one more time for the suggestions!

vania-pooh commented 6 years ago

@KathiresanRamkumar95 some example commands?

vania-pooh commented 6 years ago

@KathiresanRamkumar95 just do the following. 1) Manually edit browsers.json of working Selenoid and add "volumes": ["/home/app/uploadFiles:/home/app/uploadFiles"] as shown here: https://aerokube.com/selenoid/latest/#_browsers_configuration_file 2) Restart Selenoid container

vania-pooh commented 6 years ago

@KathiresanRamkumar95 should edit on host machine and not inside Docker container.

vania-pooh commented 6 years ago

@KathiresanRamkumar95 just edit this file with your preferred editor.

vania-pooh commented 6 years ago

@KathiresanRamkumar95 I would use selenium user inside container, e.g. /home/automation/uploadTesting:/home/selenium/uploadTesting.

vania-pooh commented 6 years ago

@KathiresanRamkumar95 just follow the docs: https://aerokube.com/selenoid/latest/#_option_2_start_selenoid_container and mount directory with browsers.json as /etc/selenoid.