From e3b7b6a76d148d56d354ca54f14e96307868f400 Mon Sep 17 00:00:00 2001
From: latlon team <info@lat-lon.de>
Date: Mon, 5 Feb 2024 07:48:55 +0000
Subject: [PATCH] Code drop

- XPLANBOX-2327 - added arguments (edd757940)
- XPLANBOX-2327 - set TZ=Europe/Berlin (5d397604c)
- XPLANBOX-2327 - set default values of baseUrlValidatorWeb/BASE_URL_Validator_WEB (5e480940c)
- XPLANBOX-2327 - set maven.install.skip=true, maven.deploy.skip=true, enforcer.skip=true (d03ec5e18)
- XPLANBOX-2327 - fixed version of parent (726fd20d3)
- XPLANBOX-2327 ignore certificate errors (903950171)
- XPLANBOX-2327 first selenium test (cleaned) (cac5cbbab)

Co-authored-by: Lyn Elisa Goltz <goltz@lat-lon.de>
Co-authored-by: Marc Guillemot <guillemot@lat-lon.de>

Dropped from commit: d1cd6d515a6757d88a38a6f89c2a1120f04b09f3
---
 jenkinsfiles/test/Jenkinsfile                 |  21 +-
 xplan-tests/pom.xml                           |   1 +
 .../xplan-tests-selenium/.dockerignore        |   3 +
 xplan-tests/xplan-tests-selenium/Dockerfile   |  34 ++++
 xplan-tests/xplan-tests-selenium/README.md    |  43 ++++
 xplan-tests/xplan-tests-selenium/pom.xml      | 122 +++++++++++
 .../runAllSeleniumTests.sh                    |  49 +++++
 .../validatorweb/XPlanValidatorWebIT.java     | 189 ++++++++++++++++++
 .../src/test/resources/BPlan001_5-4.zip       | Bin 0 -> 2935 bytes
 9 files changed, 457 insertions(+), 5 deletions(-)
 create mode 100644 xplan-tests/xplan-tests-selenium/.dockerignore
 create mode 100644 xplan-tests/xplan-tests-selenium/Dockerfile
 create mode 100644 xplan-tests/xplan-tests-selenium/README.md
 create mode 100644 xplan-tests/xplan-tests-selenium/pom.xml
 create mode 100755 xplan-tests/xplan-tests-selenium/runAllSeleniumTests.sh
 create mode 100644 xplan-tests/xplan-tests-selenium/src/test/java/de/latlon/xplanbox/tests/selenium/validatorweb/XPlanValidatorWebIT.java
 create mode 100644 xplan-tests/xplan-tests-selenium/src/test/resources/BPlan001_5-4.zip

diff --git a/jenkinsfiles/test/Jenkinsfile b/jenkinsfiles/test/Jenkinsfile
index 09a3939c37..c227917d2e 100644
--- a/jenkinsfiles/test/Jenkinsfile
+++ b/jenkinsfiles/test/Jenkinsfile
@@ -13,6 +13,7 @@ pipeline {
       string(name: 'BASE_URL_DIENSTE', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of XPlanDienste')
       string(name: 'BASE_URL_INSPIRE_PLU', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of INSPIRE PLU')
       string(name: 'BASE_URL_MANAGER_API', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of XPlanManagerAPI')
+      string(name: 'BASE_URL_Validator_WEB', defaultValue: "https://xplanbox.lat-lon.de/xplan-validator-web", description: 'Set base URL of XPlanValidatorWeb')
       string(name: 'BASE_URL_DOKUMENTEN_API', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of XPlanDokumentenAPI')
       string(name: 'BASE_URL_MAPSERVER', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of MapServer')
       string(name: 'BASE_URL_MAPPROXY', defaultValue: "https://xplanbox.lat-lon.de", description: 'Set base URL of MapProxy')
@@ -22,7 +23,7 @@ pipeline {
       string(name: 'SLACK_TOKEN_CREDENTIAL_ID', defaultValue: "slack-integration-id", description: 'Set slack token credential id')
    }
    stages {
-      stage('Test XPlanManagerAPI') {
+      stage('SoapUI-Test XPlanManagerAPI') {
          steps {
             withCredentials([
                usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
@@ -31,7 +32,7 @@ pipeline {
             }
          }
       }
-      stage('Test XPlanValidatorAPI') {
+      stage('SoapUI-Test XPlanValidatorAPI') {
          steps {
             withCredentials([
                usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
@@ -40,7 +41,7 @@ pipeline {
             }
          }
       }
-      stage('Test XPlanDokumentenAPI') {
+      stage('SoapUI-Test XPlanDokumentenAPI') {
          steps {
             withCredentials([
                usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
@@ -49,7 +50,7 @@ pipeline {
             }
          }
       }
-      stage('Test XPlanManagerWeb') {
+      stage('SoapUI-Test XPlanManagerWeb') {
          steps {
             withCredentials([
                usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
@@ -58,7 +59,7 @@ pipeline {
             }
          }
       }
-      stage('Test XPlanDienste') {
+      stage('SoapUI-Test XPlanDienste') {
          steps {
             withCredentials([
                usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
@@ -67,9 +68,19 @@ pipeline {
             }
          }
       }
+      stage('Selenium-Test XPlanValidatorWeb') {
+         steps {
+            withCredentials([
+               usernamePassword(credentialsId:"${CREDENTIALS_ID}", passwordVariable: 'Password', usernameVariable: 'Username')
+            ]) {
+               sh 'mvn integration-test -pl :xplan-tests-selenium -Psystem-tests -DbaseUrlValidatorWeb=${BASE_URL_Validator_WEB} -Dusername=$Username -Dpassword=$Password'
+            }
+         }
+      }
       stage('Results') {
          steps{
             junit '**/**/target/soapui/TEST-*.xml'
+            junit '**/**/target/failsafe-reports/TEST-*.xml'
          }
       }
    }
diff --git a/xplan-tests/pom.xml b/xplan-tests/pom.xml
index 0035579bb1..97e51a3824 100644
--- a/xplan-tests/pom.xml
+++ b/xplan-tests/pom.xml
@@ -19,6 +19,7 @@
   <modules>
     <module>xplan-tests-soapui</module>
     <module>xplan-tests-manual</module>
+    <module>xplan-tests-selenium</module>
   </modules>
 
 </project>
\ No newline at end of file
diff --git a/xplan-tests/xplan-tests-selenium/.dockerignore b/xplan-tests/xplan-tests-selenium/.dockerignore
new file mode 100644
index 0000000000..425b773149
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/.dockerignore
@@ -0,0 +1,3 @@
+target/**
+Dockerfile
+.settings/*
\ No newline at end of file
diff --git a/xplan-tests/xplan-tests-selenium/Dockerfile b/xplan-tests/xplan-tests-selenium/Dockerfile
new file mode 100644
index 0000000000..69d2336b13
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/Dockerfile
@@ -0,0 +1,34 @@
+FROM maven:3.9-eclipse-temurin-11-alpine
+ARG BUILD_DATE=?
+ARG DOCKER_IMAGE_NAME=?
+ARG GIT_REVISION=?
+ARG XPLANBOX_VERSION=latest
+
+# see https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
+LABEL "org.opencontainers.image.created"="$BUILD_DATE" \
+	"org.opencontainers.image.description"="ozgxplanung xPlanBox component" \
+	"org.opencontainers.image.licenses"="GNU Affero General Public License & others" \
+	"org.opencontainers.image.ref.name"="$DOCKER_IMAGE_NAME" \
+	"org.opencontainers.image.revision"="$GIT_REVISION" \
+	"org.opencontainers.image.title"="ozgxplanung - $DOCKER_IMAGE_NAME" \
+	"org.opencontainers.image.url"="https://gitlab.opencode.de/diplanung/ozgxplanung" \
+	"org.opencontainers.image.vendor"="lat/lon GmbH" \
+	"org.opencontainers.image.version"="$XPLANBOX_VERSION"
+
+RUN apk add py3-pip py3-pillow py3-cffi py3-brotli gcc musl-dev python3-dev pango pango-tools aws-cli chromium chromium-chromedriver xvfb
+RUN pip install weasyprint
+
+ADD . /xplanbox/xplan-tests/xplan-tests-selenium
+ADD maven/xplanbox-pom.xml /xplanbox/pom.xml
+ADD maven/xplan-tests-pom.xml /xplanbox/xplan-tests/pom.xml
+
+WORKDIR /xplanbox/xplan-tests/xplan-tests-selenium
+
+ENV TZ=Europe/Berlin
+
+# pre-fill local maven repo (including plugins)
+RUN mvn -B integration-test -Psystem-tests -Dtest=NotExistingOne -Dsurefire.failIfNoSpecifiedTests=false > /dev/null \
+	&& mvn -B surefire-report:report-only \
+	&& rm -rf target
+
+ENTRYPOINT ["/xplanbox/xplan-tests/xplan-tests-selenium/runAllSeleniumTests.sh"]
\ No newline at end of file
diff --git a/xplan-tests/xplan-tests-selenium/README.md b/xplan-tests/xplan-tests-selenium/README.md
new file mode 100644
index 0000000000..00054be033
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/README.md
@@ -0,0 +1,43 @@
+# Selenium Tests
+
+Die Tests in diesem Projekt sind nicht gedacht, um direkt als Teil vom Build ausgeführt zu werden sondern eher zu einem späteren Zeitpunkt, wenn die Anwendungen schon deployt worden sind.
+
+## Ausführung mit Maven
+
+```
+mvn clean integration-test -Psystem-tests -DbaseUrlValidatorWeb=https://xplanbox.lat-lon.de/xplan-validator-web -Dpassword='PWD' -Dusername=xplanbox
+```
+
+## Ausführung im Docker Container
+
+Die Selenium Tests können in einem Docker Container ausgeführt werden
+
+```
+docker run --env XPLAN_WEB_VALIDATOR_BASE_URL=... xplanbox/xplan-tests-selenium
+```
+
+### Umgebungsvariablen
+
+- `XPLAN_WEB_VALIDATOR_BASE_URL`
+- `XPLAN_WEB_VALIDATOR_USERNAME`
+- `XPLAN_WEB_VALIDATOR_PASSWORD`
+
+Der Report im PDF Format kann zu einem S3 Bucket hochgeladen werden, dafür müssen folgende Umgebungsvariablen gesetzt werden:
+
+- `XPLAN_UPLOAD_TEST_REPORT`: muss auf `true` gesetzt werden
+- `XPLAN_S3_ENDPOINT`: die S3 Url
+- `XPLAN_S3_REPORT_ID` (optional): ein Id, dass im S3-Objektname verwendet werden soll
+- `XPLAN_S3_REPORT_PATH`(optional): der Pfad im S3 Bucket (default: `test-reports`)
+- `XPLAN_S3_ACCESS_KEY`: der S3-Zugangschlüssel
+- `XPLAN_S3_SECRET_ACCESS_KEY`: der S3-Geheimzugangschlüssel
+- `XPLAN_S3_REGION`: die S3 Region
+- `XPLAN_S3_BUCKET_NAME`: der Name des Buckets
+
+Der Report kann aus S3 lokal kopiert werden, z,B. mit:
+
+	aws s3 cp s3://my-bucket/test-reports/report-2023-05-26T08:57:15.pdf report.pdf --endpoint-url https://the.s3.url
+
+Eine Notification kann nach der Ausführung der Tests zu einem Slack Chanel geschickt werden. Dafür müssen folgende Umgebungsvariablen gesetzt werden:
+
+- `XPLAN_NOTIFY_SLACK_CHANNEL`: der Slack Kanal
+- `XPLAN_NOTIFY_SLACK_TOKEN`: das Slack Authorisierungstoken
diff --git a/xplan-tests/xplan-tests-selenium/pom.xml b/xplan-tests/xplan-tests-selenium/pom.xml
new file mode 100644
index 0000000000..ea05632a98
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/pom.xml
@@ -0,0 +1,122 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>xplan-tests-selenium</artifactId>
+
+  <parent>
+    <groupId>de.latlon.product.xplanbox</groupId>
+    <artifactId>xplan-tests</artifactId>
+    <version>7.2-SNAPSHOT</version>
+  </parent>
+
+  <properties>
+    <maven.test.skip>true</maven.test.skip>
+    <maven.install.skip>true</maven.install.skip>
+    <maven.deploy.skip>true</maven.deploy.skip>
+    <enforcer.skip>true</enforcer.skip>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.seleniumhq.selenium</groupId>
+      <artifactId>selenium-remote-driver</artifactId>
+      <version>4.12.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.seleniumhq.selenium</groupId>
+      <artifactId>selenium-chrome-driver</artifactId>
+      <version>4.12.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <skipIfEmpty>true</skipIfEmpty>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>system-tests</id>
+      <properties>
+        <baseUrlValidatorWeb/>
+        <maven.test.skip>false</maven.test.skip>
+        <password/>
+        <username/>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.github.git-commit-id</groupId>
+            <artifactId>git-commit-id-maven-plugin</artifactId>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <systemPropertyVariables>
+                <baseUrlValidatorWeb>${baseUrlValidatorWeb}</baseUrlValidatorWeb>
+                <username>${username}</username>
+                <password>${password}</password>
+              </systemPropertyVariables>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <profile>
+      <id>docker</id>
+      <properties>
+        <docker-image.skip>false</docker-image.skip>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <build>
+                    <assembly>
+                      <inline>
+                        <files>
+                          <file>
+                            <source>../pom.xml</source>
+                            <destName>xplan-tests-pom.xml</destName>
+                          </file>
+                          <file>
+                            <source>../../pom.xml</source>
+                            <destName>xplanbox-pom.xml</destName>
+                          </file>
+                        </files>
+                      </inline>
+                    </assembly>
+                  </build>
+                </image>
+              </images>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
\ No newline at end of file
diff --git a/xplan-tests/xplan-tests-selenium/runAllSeleniumTests.sh b/xplan-tests/xplan-tests-selenium/runAllSeleniumTests.sh
new file mode 100755
index 0000000000..ea36420295
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/runAllSeleniumTests.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# start virtual buffer
+Xvfb :0 -screen 0 1024x768x24 &
+xvfbPid=$!
+
+echo "Executing tests..."
+DISPLAY=:0 mvn integration-test -Psystem-tests -DbaseUrlValidatorWeb=$XPLAN_WEB_VALIDATOR_BASE_URL -Dusername=$XPLAN_WEB_VALIDATOR_USERNAME -Dpassword=$XPLAN_WEB_VALIDATOR_PASSWORD -Dwebdriver.chrome.driver=/usr/bin/chromedriver
+kill -9 $xvfbPid
+
+echo "Generating html report..."
+mvn surefire-report:failsafe-report-only -q
+
+REPORT_PATH_PDF=target/test-report.pdf
+echo "Transforming to PDF $REPORT_PATH_PDF..."
+sed -i 's/display:none;//' target/site/failsafe-report.html
+weasyprint file://$PWD/target/site/failsafe-report.html $REPORT_PATH_PDF
+REPORT_PATH_TAR=target/test-report.tar.gz
+tar czf $REPORT_PATH_TAR -C target/site .
+
+if [ "$XPLAN_UPLOAD_TEST_REPORT" = "true" ];
+then
+	export AWS_ACCESS_KEY_ID="$XPLAN_S3_ACCESS_KEY"
+	export AWS_SECRET_ACCESS_KEY="$XPLAN_S3_SECRET_ACCESS_KEY"
+	export AWS_DEFAULT_REGION="$XPLAN_S3_REGION"
+	XPLAN_S3_REPORT_ID="${XPLAN_S3_REPORT_ID:-`date +%y-%m-%dT%H:%m:%S`}"
+	XPLAN_S3_REPORT_PATH="${XPLAN_S3_REPORT_PATH:-test-reports}"
+
+	S3_PATH_REPORT_PATH_TAR="s3://$XPLAN_S3_BUCKET_NAME/$XPLAN_S3_REPORT_PATH/report_selenium-$XPLAN_S3_REPORT_ID.tar.gz"
+	S3_PATH_PDF="s3://$XPLAN_S3_BUCKET_NAME/$XPLAN_S3_REPORT_PATH/report_selenium-$XPLAN_S3_REPORT_ID.pdf"
+	echo "Uploading report to $S3_PATH..."
+	aws --endpoint-url $XPLAN_S3_ENDPOINT s3 cp $REPORT_PATH_TAR $S3_PATH_REPORT_PATH_TAR
+	aws --endpoint-url $XPLAN_S3_ENDPOINT s3 cp $REPORT_PATH_PDF $S3_PATH_PDF
+else
+	echo "No upload to S3 configured"
+fi
+
+
+if [ -n "$XPLAN_NOTIFY_SLACK_CHANNEL" ] &&  [ -n "$XPLAN_NOTIFY_SLACK_TOKEN" ]; then
+	echo "Sending slack notification to $XPLAN_NOTIFY_SLACK_CHANNEL"
+	message="Finished Selenium tests for $XPLAN_WEB_VALIDATOR_BASE_URL and Co."
+	if [ -n "$S3_PATH" ]; then
+		echo "s3"
+		message="$message%0A%0ATest Report available at $S3_PATH"
+	fi
+	curl -d "text=$message" -d "channel=$XPLAN_NOTIFY_SLACK_CHANNEL" -H "Authorization: Bearer $XPLAN_NOTIFY_SLACK_TOKEN" -X POST https://slack.com/api/chat.postMessage
+fi
+
+echo "Ready"
diff --git a/xplan-tests/xplan-tests-selenium/src/test/java/de/latlon/xplanbox/tests/selenium/validatorweb/XPlanValidatorWebIT.java b/xplan-tests/xplan-tests-selenium/src/test/java/de/latlon/xplanbox/tests/selenium/validatorweb/XPlanValidatorWebIT.java
new file mode 100644
index 0000000000..26fe9f80d7
--- /dev/null
+++ b/xplan-tests/xplan-tests-selenium/src/test/java/de/latlon/xplanbox/tests/selenium/validatorweb/XPlanValidatorWebIT.java
@@ -0,0 +1,189 @@
+package de.latlon.xplanbox.tests.selenium.validatorweb;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.CleanupMode;
+import org.junit.jupiter.api.io.TempDir;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeOptions;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class XPlanValidatorWebIT {
+
+	private static final String NAMEBPLAN_TEST = "Selenium_Test";
+
+	private static final String NAMEBPLAN_ORIGINAL = "BPlan001_5-4";
+
+	private static String connectUrl;
+
+	@BeforeAll
+	static void readSystemProperties() {
+		String url = System.getProperty("baseUrlValidatorWeb", "https://xplanbox.lat-lon.de/xplan-validator-web");
+		String username = System.getProperty("username", null);
+		String password = System.getProperty("password", null);
+		connectUrl = createConnectUrl(url, username, password);
+	}
+
+	@Test
+	void test_XPlanValidatorWeb_withValidPlan(@TempDir(cleanup = CleanupMode.ON_SUCCESS) final Path tmpDir)
+			throws Exception {
+
+		Map<String, Object> chromePrefs = new HashMap<String, Object>();
+		// chromePrefs.put("profile.default_content_settings.popups", 0);
+		chromePrefs.put("download.default_directory", tmpDir.toString());
+		ChromeOptions options = new ChromeOptions();
+		options.setExperimentalOption("prefs", chromePrefs);
+
+		options.addArguments("--no-sandbox", "--ignore-certificate-errors", "--headless", "--disable-dev-shm-usage",
+				"--disable-gpu", "--disable-software-rasterizer");
+
+		// options.addArguments("--headless");
+		WebDriver driver = new ChromeDriver(options);
+		String myZIPFile = getClass().getResource("/" + NAMEBPLAN_ORIGINAL + ".zip").getFile().toString();
+
+		try {
+			driver.get(connectUrl);
+			assertEquals("XPlanValidatorWeb", driver.getTitle());
+
+			WebElement elemAdd = driver.findElement(By.name("uploadPlanItem"));
+			elemAdd.sendKeys(myZIPFile);
+
+			driver.findElement(By.xpath("//button[text()='Hochladen und Validierungsoptionen einstellen']")).click();
+			verifyByXPath(driver, "//*[@class='gwt-DialogBox']//*[@class='Caption']", "Plan hochgeladen");
+
+			// einmal abbrechen und neu validieren
+			driver.findElement(By.xpath("//button[text()='abbrechen']")).click();
+
+			driver.findElement(By.xpath("//button[text()='Hochladen und Validierungsoptionen einstellen']")).click();
+			verifyByXPath(driver, "//*[@class='gwt-DialogBox']//*[@class='Caption']", "Plan hochgeladen");
+
+			driver.findElement(By.xpath("//button[text()='zur Validierung']")).click();
+			verifyByXPath(driver, "//*[@class='valOptionTitle']", "Validierungsoptionen");
+
+			WebElement elemName = driver.findElement(By.xpath(
+					"//tr[td/div[@class='valOptionLabel']/text() = 'Bezeichnung für den Report']/following-sibling::tr[1]//input"));
+			elemName.clear();
+			elemName.sendKeys(NAMEBPLAN_TEST);
+
+			driver.findElement(By.xpath("//label[text() = 'semantisch']")).click();
+
+			// Hier kann theoretisch noch ein Schema ausgewählt werden
+			// try {
+			// driver.findElement(By.xpath("//tr[12]/td/span/input")).click();
+			// sleep();
+			// }
+			// catch (NoSuchElementException nSEE_Ex) {
+			// nSEE_Ex.printStackTrace();
+			// }
+
+			driver.findElement(By.xpath("//button[text()='Validierung starten']")).click();
+
+			verifyByXPath(driver, "//*[@class='gwt-DialogBox']//*[@class='Caption']", "Ergebnisse der Validierung", 30);
+
+			WebElement iframe = driver.findElement(
+					By.xpath("//html/body/div[4]/div/table/tbody/tr[2]/td[2]/div/table/tbody/tr/td[1]/iframe")); // Hier
+																													// iframeName
+																													// durch
+																													// den
+																													// tatsächlichen
+																													// Namen
+																													// des
+																													// iframes
+																													// ersetzen
+			driver.switchTo().frame(iframe);
+
+			String name = driver.findElement(By.xpath("//body/p[1]/b")).getText();
+			String valide = driver.findElement(By.xpath("//body/p[4]/b/font")).getText();
+			String planname = driver.findElement(By.xpath("//body/ul[1]/b/li[1]")).getText();
+
+			SoftAssertions softly = new SoftAssertions();
+			softly.assertThat(name).isEqualTo(NAMEBPLAN_TEST);
+			softly.assertThat(valide).isEqualTo("valide");
+			softly.assertThat(planname).isEqualTo(NAMEBPLAN_ORIGINAL);
+			softly.assertAll();
+
+			driver.switchTo().defaultContent();
+
+			driver.findElement(By.xpath("//label[text() = 'HTML Report']")).click();
+			driver.findElement(By.xpath("//label[text() = 'PDF Report']")).click();
+			driver.findElement(By.xpath("//label[text() = 'XML Report']")).click();
+			driver.findElement(By.xpath("//button[text() = 'Download']")).click();
+
+			String zipFileName = NAMEBPLAN_TEST + "-Report.zip";
+			withinSeconds(10, () -> assertThat(listFiles(tmpDir)).containsExactly(zipFileName));
+
+			Path zipFile = tmpDir.resolve(zipFileName);
+			try (FileSystem zipfs = FileSystems.newFileSystem(zipFile, null)) {
+				Path rootInZip = zipfs.getRootDirectories().iterator().next();
+
+				assertThat(listFiles(rootInZip)).describedAs("Content of " + zipFile)
+					.containsExactlyInAnyOrder(NAMEBPLAN_TEST + ".html", NAMEBPLAN_TEST + ".pdf",
+							NAMEBPLAN_TEST + ".xml");
+			}
+		}
+		finally {
+			// System.out.println("url: " + driver.getCurrentUrl());
+			driver.close();
+		}
+	}
+
+	private void withinSeconds(int nbSeconds, Callable<?> callable) throws Exception {
+		Instant timeout = Instant.now().plusSeconds(nbSeconds);
+
+		while (Instant.now().isBefore(timeout)) {
+			try {
+				callable.call();
+				return;
+			}
+			catch (Exception | org.opentest4j.AssertionFailedError e) {
+				Thread.sleep(1000);
+			}
+		}
+		callable.call();
+	}
+
+	private List<String> listFiles(Path tmpDir) throws IOException {
+		return Files.list(tmpDir).map((it) -> it.getFileName().toString()).collect(Collectors.toList());
+	}
+
+	private void verifyByXPath(WebDriver driver, String xpath, String expectedText) throws Exception {
+		verifyByXPath(driver, xpath, expectedText, 5);
+	}
+
+	private void verifyByXPath(WebDriver driver, String xpath, String expectedText, int maxWaitInSeconds)
+			throws Exception {
+		Callable<?> c = () -> {
+			WebElement elt = driver.findElement(By.xpath(xpath));
+			assertEquals(expectedText, elt.getText());
+			return null;
+		};
+		withinSeconds(maxWaitInSeconds, c);
+	}
+
+	private static String createConnectUrl(String url, String username, String password) {
+		if (username != null && !username.isEmpty()) {
+			String authentication = username + ":" + password + "@";
+			return url.replace("://", "://" + authentication);
+		}
+		return url;
+	}
+
+}
diff --git a/xplan-tests/xplan-tests-selenium/src/test/resources/BPlan001_5-4.zip b/xplan-tests/xplan-tests-selenium/src/test/resources/BPlan001_5-4.zip
new file mode 100644
index 0000000000000000000000000000000000000000..db9c96803f87ae159467ec89fbd9db8b548d46f7
GIT binary patch
literal 2935
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

literal 0
HcmV?d00001

-- 
GitLab