kazurayam / selenium-webdriver-java

Examples of the O'Reilly book "Hands-On Selenium WebDriver with Java"
https://oreil.ly/1E7CX
Apache License 2.0
0 stars 0 forks source link

Sample test classes write files into the subproject's root directory so that the file trees get dirty #8

Open kazurayam opened 1 year ago

kazurayam commented 1 year ago

The following graph shows the tree of a project root directory which contains multiple subprojects:

:~/github/selenium-webdriver-java (kazurayam8)
$ tree -L 2 .
.

├── selenium-ide
│   └── hello-selenium-ide.side
├── selenium-webdriver-junit4
│   ├── build
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── pom.xml
│   ├── src
│   └── target
├── selenium-webdriver-junit5
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── pom.xml
│   └── src
├── selenium-webdriver-junit5-seljup
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── pom.xml
│   └── src
├── selenium-webdriver-testng
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── pom.xml
│   └── src
├── settings.gradle

Then I executed all tests of the subprojects.

$ ./gradlew clean test

When all tests finished, I viewed the directory tree under a subproject selenium-webdriver-junit4

.
├── 2023.10.24_22.07.27.742-7440524241d0dbd63ca5eec377b6455c.png    --- x
├── 2023.10.24_22.07.29.333-7440524241d0dbd63ca5eec377b6455c.png    --- x
├── build
│   ├── allure-results
│   ├── classes
│   ├── downloads
│   ├── generated
│   ├── reports
│   ├── resources
│   ├── test-results
│   └── tmp
├── build.gradle
├── extentReport.html    --- x
├── fullpage-screenshot-chrome.png    --- x
├── gradle
│   └── wrapper
├── gradlew
├── gradlew.bat
├── login.har    --- x
├── my-pdf.pdf    --- x
├── pom.xml
├── screenshot.png    --- x
├── src
│   ├── main
│   └── test
├── target
│   ├── classes
│   ├── generated-sources
│   ├── generated-test-sources
│   ├── maven-status
│   └── test-classes
├── testAccessibility.json    --- x
├── webdrivermanager.pdf    --- x
├── webdrivermanager.png    --- x
└── webelement-screenshot.png    --- x

20 directories, 15 files

I found a lot of new files under the subproject's root directory. I executed git status command to find the new files:

$ git status
On branch kazurayam8
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        2023.10.24_22.07.27.742-7440524241d0dbd63ca5eec377b6455c.png
        2023.10.24_22.07.29.333-7440524241d0dbd63ca5eec377b6455c.png
        extentReport.html
        fullpage-screenshot-chrome.png
        login.har
        my-pdf.pdf
        screenshot.png
        testAccessibility.json
        webdrivermanager.pdf
        webdrivermanager.png
        webelement-screenshot.png

These new files are not gitignored. Therefore if I carelessly do the following operation:

$ git add .
$ git commit -m "save changes"

then the newl files will be commited into the project tree. A disastrous plution of the project tree!

The sample tests in the book should not write files into the project's root directory. The tests should write files into a particular directory in the project's root directory.

And I want to list the directroy in the .gitignore file so that Git ignores all the test outputs silently.

kazurayam commented 1 year ago

At first, I needed to identify which test classes wrote which files in the project's root directory.

I had to read the source codes in the selenium-webdriver-junit4 subproject .

  1. Created file

    • Test source which reads or writes the file
  2. 2023.10.24_22.07.27.742-7440524241d0dbd63ca5eec377b6455c.png

  3. 2023.10.24_22.07.29.333-7440524241d0dbd63ca5eec377b6455c.png

  4. extentReport.html

  5. fullpage-screenshot-chrome.png

  6. fullpage-screenshot-firefox.png

6. login.har

  1. my-pdf.pdf     - https://github.com/kazurayam/selenium-webdriver-java/blob/master/selenium-webdriver-junit4/src/test/java/io/github/bonigarcia/webdriver/junit4/ch05/print/PrintChromeJUnit4Test.java     - https://github.com/kazurayam/selenium-webdriver-java/blob/master/selenium-webdriver-junit4/src/test/java/io/github/bonigarcia/webdriver/junit4/ch05/print/PrintEdgeJUnit4Test.java     - https://github.com/kazurayam/selenium-webdriver-java/blob/master/selenium-webdriver-junit4/src/test/java/io/github/bonigarcia/webdriver/junit4/ch05/print/PrintFirefoxJUnit4Test.java

  2. screenshot.png

  3. testAccessibility.json

  4. webdrivermanager.pdf

  5. webdrivermanager.png

  6. webelement-screenshot.png

The other subprojects (-junit4seljp, -junit5, -testng) also have the ducplicating source codes.

kazurayam commented 1 year ago

In which directory under the project root should I house the output files from tests?

As for Maven, https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html writes

The target directory is used to house all output of the build.

As for Gradle, https://docs.gradle.org/current/userguide/directory_layout.html#dir:project_root writes

The build directory of this project into which Gradle generates all build artifacts.

My question: target directory or build directory, which directory to choose?

... Neither. I do not want any test case source dependent on which build tool to be used.

kazurayam commented 1 year ago

I looked at https://github.com/kazurayam/selenium-webdriver-java/blob/master/.gitignore

It contains a line

test-output

I believe that @bonigarcia had an intention to create the test-output directory.

However, the current test classes are written so that they write the files into the project's root directory, rather than the test-output directory.

Then, I would modify the test class so that they write files into the test-output directory.

kazurayam commented 1 year ago

How should I change the existing sources so that they write files into the new test-output directory?

At first I should study the existing code. For example, https://github.com/kazurayam/selenium-webdriver-java/blob/master/selenium-webdriver-junit4/src/test/java/io/github/bonigarcia/webdriver/junit4/ch04/event_listeners/MyEventListener.java has the following fragment, which decides the path to write the file into

        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "yyyy.MM.dd_HH.mm.ss.SSS");
        String screenshotFileName = String.format("%s-%s.png",
                dateFormat.format(today), sessionId.toString());
        Path destination = Paths.get(screenshotFileName);

I want the change to be minimum and clean:

So, how about adding a helper class: com.kazurayam.unittest.TestHelper. Provided that I have it, I would modify the above code as follows:

import com.kazurayam.unittest.TestHelper;
...
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "yyyy.MM.dd_HH.mm.ss.SSS");
        String screenshotFileName = String.format("%s-%s.png",
                dateFormat.format(today), sessionId.toString());
        Path destination = TestHelper.resolveOutput(screenshotFileName);

The package name is arguable. The candidates include:

Well, I must not pretend to be @bonigarcia myself. So I would call my class as com.kazurayam something.

kazurayam commented 1 year ago

In the selenium-webdriver-junit5 subproject, I executed

$ mvn test

that is, I executed full set of tests by Maven build. The result was as follows:

Screenshot 2023-10-25 at 19 36 25

Just similar set of output files were created in the project root dir as the selenium-webdriver-junit4 subproject. I expected this. Fine.

kazurayam commented 1 year ago

I would create several branches: kazurayam8a, kazurayam8b, etc. In each branches, I would work modifying the source code. In each branch, I would work for a single output file to be moved into the test-output directory. In each brach, I would modify the codes of 4 subprojects -junit4, -junit5, -junit5seljup and -testng

The plan is as follows:

branch output file code to change
kazurayam8a add com.kazurayam.unittest.TestHelper class https://github.com/kazurayam/unittest-helper
kazurayam8b inherits kazurayam8a 2023.10.24_22.07.27.742-7440524241d0dbd63ca5eec377b6455c.png and 2023.10.24_22.07.29.333-7440524241d0dbd63ca5eec377b6455c.png junit4/ch04/event_listeners/
kazurayam8c extentReport.html junit4/ch09/reporting
kazurayam8d fullpage-screenshot-chrome.png junit4/ch05/cdp/FullPageScreenshotChrome... and Firefox etc
kazurayam8e login.har junit4/ch09/performance
kazurayam8f my-pdf.pdf junit4/ch05/print and Firefox etc
kazurayam8g screenshot.png junit4/ch04/screenshots/
kazurayam8g webelement-screenshot.png junit4/ch04/screenshots/
kazurayam8h testAccessibility.json junit4/ch09/accessibility/
kazurayam8i webdrivermanager.pdf and webdrivermanager.png junit4/ch09/download/
kazurayam commented 1 year ago

I need to be careful about the "Current Working Directory". Now I have a statement in my test class source:

    Path static testOutputDir = Paths.get("test-output");

This assumes that the "Current Working Directory" is given with a value equal to the directory selenium-webdriver-java/selenium-webdriver-junit4.

However, this assumption is too fragile according to the runtime environment. In https://discuss.gradle.org/t/how-do-i-set-the-working-directory-for-testng-in-a-multi-project-gradle-build/7379/7,

luke_daley Gradle Employee Nov '13 Loading from the filesystem using relative paths during unit tests is problematic because different environments will set a different working directory for the test process. For example, Gradle uses the projects directory while IntelliJ uses the directory of the root project. The only really safe way to solve this problem is to load via the classpath.


A case

:~/github/selenium-webdriver-java (kazurayam8a *+)
$ gradle :selenium-webdriver-junit4:test -q --tests com.kazurayam.unittest.TestHelper

This command passed and it created a directory selenium-webdriver-java/selenium-webdriver-junit4/test-output. This is what I expected. Fine. Very Good.

However, in IntelliJ IDEA, in the Java editor, I opend the com.kazurayam.unittest.TestHelper source, and right-click to choose "Run TestHelper.test_resolveOutput()"

Screenshot 2023-10-25 at 21 59 18

It ran passed, but it created a directory selenium-webdriver-java/test-output. This is NOT what I expected.

IntelliJ run the test with "Current Working Directory" = selenium-webdriver-java, not = selenium-webdriver-java/selenium-webdirver-junit4.

This IntelliJ's behavior confuses me.

I should find out how to configure IntelliJ IDEA so that it works just like Gradle. However, is it possible? ---- I am not sure.

kazurayam commented 1 year ago

I have developed a new class test/java/com.kazurayam.unittest.TestHelper with a method Path resolveOutput(String fileName).

I will commit this in the kazurayam8a branch.

A call to TestHelper.resolveOutput("extentReport.html") will return a Path selenium-webdriver-java/selenium-webdriver-junit4/test-output/extentReport.html. This is good.

The TestHelper.resolveOutput("foo") will NOT return a Path selenium-webdriver-java/test-output/foo. Rather it will return selenium-webdriver-java/selenium-webdriver-junit4/test-outpu/foo. This subtle difference matters.

kazurayam commented 1 year ago

As you see in

kazurayam developed a package of classes: com.kazurayam.unittest.TestHelper, ProjectDirectoryResolver and StringSequence. This package resolves this #8 issue.

However there is a problem. The package com.kazurayam.unittest is contained in the selenium-webdriver-java/selenium-webdriver-junit4 project. On the other hand, the other projects *-junit5, *-junit5seljup and *-testng will also require this package.

I do not like to duplicate the source code of the com.kazurayam.unittest package. Therefore I will move this package into a new independent project. The project name will be unittest-helper-x.x.x.jar.

I will publish the jar of unittesthelper-x.x.x.jar to the Maven Central repository. Therefore the jar will be available to any Gradle build.gradle and Maven pom.xml.

kazurayam commented 1 year ago

I have created a project "com.kazrurayam:unittest-helper:0.1.0"

https://github.com/kazurayam/unittest-helper

I have published the jar to the Maven Central repository, which will become available for download in a few days.

kazurayam commented 1 year ago

I will modify the branches kazurayam8, kazurayam8a, kazurayam8b, kazurayam8c, kazurayam8d so that the use the "com.kazrurayam:unittest-helper:0.1.0" as one of their dependencies downloaded from the maven repositories.

kazurayam commented 1 year ago

https://github.com/kazurayam/selenium-webdriver-java/issues/21

I found that the sample codes of the Chapter 9 "File Download" section are sensitive. There are 3 tests which write into output files.

One writes a file into the "Downloads" dir under the System.getProperty("user.home") = OS User Directory.

One writes a file into the dir as new File(".")

One writes a file into the file as new File("", fileName)

It seems that the book author, @bonigarcia, had a specific intention to show the ways how to locate the output files, but I am not sure.


We would need a sample code that writes a file into the "Downloads" directory of a user.

Should I modify the samples that uses new File(".") ? ------- I wondered a while ----- Yes, I would propose to do so.

kazurayam commented 1 year ago

All the works required for the issue #8 have been done. The tag issue8_done was created.

https://github.com/kazurayam/selenium-webdriver-java/tree/issue8_done

See the project's file tree:

Screenshot 2023-11-01 at 21 30 30

All files generated by the tests are written into a single directory test-output under the project's root directory. The test-output directory is gitignored.

This file tree looks clean to me. I like this.

kazurayam commented 1 year ago

I have got an additional requirement. I want to create subdirectory under the output dir.

The subdirectory could be any string. For example, I can set the Fully Qualified Class Name of the test case class as the subDir. Once implemented then the paths of output would look like this:

The path becomes rich. The path tells us which test class created the file.

kazurayam commented 1 year ago

With the unittest-helper-0.2.0.jar, I have managed to make the following test-output. Please note that

  1. all output files created by test class are written into a single dedicated directory test-output. No file is written in the project's root directory

  2. Under the test-output directory, we have a layer of directories which represents the Fully Qualified Class Name of the test classes.

Screenshot 2023-11-03 at 14 23 54

I think that this file organization is nice.

kazurayam commented 1 year ago

The unittest-helper project published a new version v0.3.0

https://github.com/kazurayam/unittest-helper/releases/tag/0.3.0

The API has been changed. The selenium-webdriver-java project should use the unittest-helper v0.3.0.

I will update the kazurayam8consolidated branch.