I am writing a selenium test to verify a file being downloaded. It works fine in locally. And I can easily access the file both through the 'target' folder and inside the container /home/seluser/Downloads.
The test script is:
@BeforeMethod
public void setUp() throws MalformedURLException {
folder = new File("target");
for(File file : folder.listFiles()) {
file.delete();
}
System.setProperty("webdriver.chrome.driver", "chromedriver.exe");
ChromeOptions options = new ChromeOptions();
Map<String, Object> prefs = new HashMap<String, Object>();
prefs.put("profile.default_content_settings.popups", 0);
prefs.put("download.default_directory", folder.getAbsolutePath());
options.setExperimentalOption("prefs", prefs);
DesiredCapabilities cap = new DesiredCapabilities();
cap.setBrowserName("chrome");
cap.setCapability(ChromeOptions.CAPABILITY, options);
//driver = new ChromeDriver(cap);
//driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), cap);
driver = new RemoteWebDriver(new URL("http://docker:4444/wd/hub"), cap);
}
@AfterMethod
public void tearDown() {
driver.quit();
}
@Test
public void downloadFileTest() throws InterruptedException {
driver.get("http://the-internet.herokuapp.com/download");
driver.findElement(By.linkText("some-file.txt")).click();
Thread.sleep(2000);
File listOffFiles[] = folder.listFiles();
Assert.assertTrue(listOffFiles.length > 0);
for(File file : listOffFiles) {
Assert.assertTrue(file.length() > 0);
}
}
Let me explain a little. First I create a folder named "target" in the project root repository. Then I set the download path in the chrome docker comtainer via container volumes in docker-compose file.
version: "3"
services:
chrome:
image: selenium/node-chrome:4.0.0-20211013
container_name: chrome
shm_size: 2gb
depends_on:
- selenium-hub
volumes:
- ./target:/home/seluser/Downloads
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_GRID_URL=http://localhost:4444
ports:
- "6900:5900"
selenium-hub:
image: selenium/hub:4.0.0-20211013
container_name: selenium-hub
ports:
- "4444:4444"
This setting works fine locally. when I run it in the gitlab CI, i cannot push a empty fold to gitlab, so i have to create a file and store it in the folder and push it to gitlab. But it the test script, I delete this file in the setup stage in case it disturb the assertion. But the pipeline fails. The result does not give me more details , just said the assertionException. Here is the gitlab-ci.yml:
image: adoptopenjdk/openjdk11
stages:
- gradle-build
- docker-test
.gradle_template: &gradle_definition
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- export GRADLE_USER_HOME=${CI_PROJECT_DIR}/.gradle
gradle-build:
<<: *gradle_definition
stage: gradle-build
script:
- chmod x ./gradlew
- ./gradlew --build-cache assemble
cache:
key: "$CI_COMMIT_REF_NAME"
paths:
- build
- .gradle
artifacts:
paths:
- build/libs/*.jar
expire_in: 1 day
only:
- feature/multi-browsers
chrome-test:
stage: docker-test
image:
name: docker/compose:1.29.2
entrypoint: [ "/bin/sh", "-c" ]
services:
- docker:19.03.12-dind
variables:
DOCKER_TLS_CERTDIR: ""
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375/
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
paths:
- build
- .gradle
dependencies:
- gradle-build
before_script:
- docker info
- docker-compose --version
script:
- apk add --no-cache docker-compose
- apk add openjdk11
- docker-compose down
- docker-compose up --build --force-recreate --no-deps -d
- echo "Hello, chrome-test"
- chmod x ./gradlew
- ./gradlew :test --tests "LogInTest_chrome"
artifacts:
when: always
reports:
junit: build/test-results/test/**/TEST-*.xml
paths:
- build/reports/*
expire_in: 1 day
only:
- feature/multi-browsers
I wonder if someone has experience with this download test in gitlab CI. I think the download path I set maybe not work in gitlab CI. I even have no ideas how to check if a file is downloaded or not it gitlab CI.Thanks.
CodePudding user response:
I dont exactly know what you expect to run on http://docker:4444
, but that seems not correct at: driver = new RemoteWebDriver(new URL("http://docker:4444/wd/hub"), cap);
.
I geuss you want to connect with the selenium-hub instead. Personally I always prefer the use of GitLab services over running docker-compose
in your pipeline. Maybe this answer about running E2E tests with Docker in GitLab helps.
CodePudding user response:
- Statement : 'Let me explain a little. First I create a folder named "target" in the project root repository.' I assume that you are creating this by executing
folder = new File("target");
This actually will not create the directory, what you need to apply something like the following:
String directory = "/target";
directory.mkdir()
However, when this part of your code runs, this will not actually create the directory due to your docker-compose.yml where the volume mapping configuration from your chrome-node is mapped to the host /target directory.
volumes:
./target:/home/seluser/Downloads
This will already exist, as docker will create it, so the java code will return a boolean value of 'false' (as it does not need to create the directory) and will proceed to the next step.
docker-compose.yml: there is a mapping for your 'selenium/node-chrome' image where you have mapped /target to /home/seluser/Downloads. As this directory does not initially exist when 'docker-compose up' is run, docker will create the directory on the host, so it can be mapped to your desired volume. Here lies 2 problems, first of all docker runs as root and will create the new '/target' directory on the host, but only gives it linux permissions 'drwxr-xr-x' (755). This means that only root user can write to that directory. So even though the configuration has mapped the volume, when you download to the directory as 'seluser', it will not be able to write and the browser will be returned with a 'Permission denied' response.
The other issue is the java code declares to the RemoteWebDriver that the download will need to be saved to
prefs.put("download.default_directory", folder.getAbsolutePath());
, which has been declared as "target", this is an issue as the chrome-node where the browser resides does not have a directory called '/target', so will fail to download anyway. This is the cause of your 'assertion exception'
Propose that the following should be done for efficiency and stability:
- Update the gitlab-ci.yml prior to the 'docker-compose down & docker-compose up --build --force-recreate --no-deps -d' commands
mkdir /target
chmod -R 777 /target
This will ensure that the directory can be written to by 'seluser' on the node-chrome container
- Update the docker-compose.yml
volumes:
./target:/target
This will ensure that the Chrome browser can find a directory named '/target' and that the java test can see a file written to the host '/target' directory
Also your selenium-hub configuration needs to be updated, ports for publish events and subscribe events have not been mapped, update to the following:
selenium-hub:
image: selenium/hub:4.0.0-20211013
container_name: selenium-hub
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"