You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bo...@apache.org on 2021/01/11 21:09:35 UTC
[myfaces-tobago] 03/11: Integration tests with testcontainers
This is an automated email from the ASF dual-hosted git repository.
bommel pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit 9313c7f445f9453a781922dd7cdd352f888a3406
Author: Henning Nöth <hn...@apache.org>
AuthorDate: Tue Dec 15 20:59:28 2020 +0100
Integration tests with testcontainers
* update junit5; add testcontainers dependencies
* add TestRule fake class, which is needed for testcontainers
* better naming package, class, tests
* refactor integration tests to work with jasmine
---
pom.xml | 30 +-
tobago-example/tobago-example-demo/pom.xml | 2 +-
.../tobago-example-demo/src/main/webapp/test.xhtml | 2 +-
.../src/main/webapp/testAccessAllPages.xhtml | 4 +-
.../tobago/example/demo/integration/BasicTest.java | 161 ++++++++++
.../example/demo/integration/FrontendBase.java | 119 +++++++
.../example/demo/integration/FrontendTest.java | 93 ++++++
.../example/demo/qunit/AccessAllPagesTest.java | 158 ---------
.../tobago/example/demo/qunit/SeleniumBase.java | 354 ---------------------
.../tobago/example/demo/qunit/StandardTest.java | 81 -----
.../src/test/java/org/junit/rules/TestRule.java | 28 ++
11 files changed, 433 insertions(+), 599 deletions(-)
diff --git a/pom.xml b/pom.xml
index fbf27d2..79f749f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -448,13 +448,31 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
- <version>5.6.2</version>
+ <version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
- <version>5.6.2</version>
+ <version>5.7.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.7.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
+ <version>1.15.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <version>1.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -532,6 +550,14 @@
<artifactId>junit-jupiter-params</artifactId>
</dependency>
<dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ </dependency>
+ <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
diff --git a/tobago-example/tobago-example-demo/pom.xml b/tobago-example/tobago-example-demo/pom.xml
index 3f0d1dc..d9ab0c5 100644
--- a/tobago-example/tobago-example-demo/pom.xml
+++ b/tobago-example/tobago-example-demo/pom.xml
@@ -144,7 +144,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
- <exclude>qunit/*</exclude>
+ <exclude>integration/*</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/test.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/test.xhtml
index d06d97b..5b857f6 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/test.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/test.xhtml
@@ -28,7 +28,7 @@
<tc:script file="#{request.contextPath}/tobago/test/tobago-test-tool.js" type="module"/>
<tc:script file="#{request.contextPath}/script/tobago-test.js" type="module"/>
<tc:style file="#{request.contextPath}/style/jasmine-3.5.0.css"/>
- <tc:script file="#{request.contextPath}/#{param['accessTest'] ? 'error/error' : param['base']}.test.js"
+ <tc:script file="#{request.contextPath}/#{param['basicTest'] ? 'error/error' : param['base']}.test.js"
type="module"/>
<div id="jasmine-container"></div>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/testAccessAllPages.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/testAccessAllPages.xhtml
index 87e5511..7aa327d 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/testAccessAllPages.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/testAccessAllPages.xhtml
@@ -29,9 +29,9 @@
<c:forEach items="#{testController.allTestPages}" var="testPage">
<div class="testframe-wrapper">
<div>
- <tc:link label="open in new tab" link="test.xhtml?base=#{testPage.base}&accessTest=true" target="_blank"/>
+ <tc:link label="open in new tab" link="test.xhtml?base=#{testPage.base}&basicTest=true" target="_blank"/>
</div>
- <tc:object id="#{testPage.id}" name="test.xhtml?base=#{testPage.base}&accessTest=true">
+ <tc:object id="#{testPage.id}" name="test.xhtml?base=#{testPage.base}&basicTest=true">
<tc:style height="300px"/>
</tc:object>
</div>
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/BasicTest.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/BasicTest.java
new file mode 100644
index 0000000..7216c7b
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/BasicTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.example.demo.integration;
+
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.invoke.MethodHandles;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalTime;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Testcontainers
+class BasicTest extends FrontendBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ static LocalTime startTime;
+
+ @BeforeAll
+ public static void setup() {
+ startTime = LocalTime.now();
+ }
+
+ @Test
+ void verifyExceptionTest() throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
+ final String host = InetAddress.getLocalHost().getHostAddress();
+ final int tomcatPort = tomcat.getFirstMappedPort();
+ final String path = "error/exception.xhtml";
+
+ final String base = path.substring(0, path.length() - 6);
+ final String url = "http://" + host + ":" + tomcatPort + "/test.xhtml?base="
+ + URLEncoder.encode(base, "UTF-8") + "&basicTest=true";
+
+ WebDriver webDriver = getWebDriver(host, seleniumChrome.getFirstMappedPort());
+ webDriver.get(url);
+
+ List<WebElement> results = getJasmineResults(webDriver);
+ Assertions.assertTrue(results.size() > 0, "no results detected");
+ for (WebElement result : results) {
+ if ("has no exception".equals(result.getAttribute("title"))) {
+ Assertions.assertEquals("jasmine-failed", result.getAttribute("class"), result.getAttribute("title"));
+ } else {
+ Assertions.assertEquals("jasmine-passed", result.getAttribute("class"), result.getAttribute("title"));
+ }
+ }
+ }
+
+ @Test
+ void verify404Test() throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
+ final String host = InetAddress.getLocalHost().getHostAddress();
+ final int tomcatPort = tomcat.getFirstMappedPort();
+ final String path = "error/404.xhtml";
+
+ final String base = path.substring(0, path.length() - 6);
+ final String url = "http://" + host + ":" + tomcatPort + "/test.xhtml?base="
+ + URLEncoder.encode(base, "UTF-8") + "&basicTest=true";
+
+ WebDriver webDriver = getWebDriver(host, seleniumChrome.getFirstMappedPort());
+ webDriver.get(url);
+
+ List<WebElement> results = getJasmineResults(webDriver);
+ Assertions.assertTrue(results.size() > 0, "no results detected");
+ for (WebElement result : results) {
+ if ("has no 404".equals(result.getAttribute("title"))) {
+ Assertions.assertEquals("jasmine-failed", result.getAttribute("class"), result.getAttribute("title"));
+ } else {
+ Assertions.assertEquals("jasmine-passed", result.getAttribute("class"), result.getAttribute("title"));
+ }
+ }
+ }
+
+ /**
+ * Call every page without a specific *.test.js and run general tests (duplicated Ids, 404, exception, ...).
+ */
+ @ParameterizedTest
+ @MethodSource("basicTestProvider")
+ void basicTest(String path, int testNumber, int testSize)
+ throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
+
+ final String timeLeft = getTimeLeft(startTime, testSize, testNumber);
+ final String host = InetAddress.getLocalHost().getHostAddress();
+ final int tomcatPort = tomcat.getFirstMappedPort();
+
+ LOG.info("(" + testNumber + "/" + testSize + " | time left: " + timeLeft + ")"
+ + " - url: http://" + host + ":" + tomcatPort + "/" + path);
+
+ final String base = path.substring(0, path.length() - 6);
+ final String url = "http://" + host + ":" + tomcatPort + "/test.xhtml?base="
+ + URLEncoder.encode(base, "UTF-8") + "&basicTest=true";
+
+ WebDriver webDriver = getWebDriver(host, seleniumChrome.getFirstMappedPort());
+ webDriver.get(url);
+
+ List<WebElement> results = getJasmineResults(webDriver);
+ parseJasmineResults(results);
+ }
+
+ private static Stream<Arguments> basicTestProvider() throws IOException {
+ final List<String> paths = Files.walk(Paths.get("src/main/webapp/content/"))
+ .filter(Files::isRegularFile)
+ .map(Path::toString)
+ .filter(s -> s.endsWith(".xhtml"))
+ .filter(s -> !s.contains("/x-"))
+ .map(s -> s.substring("src/main/webapp/".length()))
+ .sorted()
+ .collect(Collectors.toList());
+
+ for (String standardTestPath : getStandardTestPaths()) {
+ paths.remove(standardTestPath); // already tested by standard test
+ }
+
+ final int testSize = paths.size();
+
+ int testNumber = 1;
+ List<Arguments> arguments = new LinkedList<>();
+ for (String path : paths) {
+ arguments.add(Arguments.of(path, testNumber, testSize));
+ testNumber++;
+ }
+ return arguments.stream();
+ }
+}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendBase.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendBase.java
new file mode 100644
index 0000000..a613c8e
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendBase.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.example.demo.integration;
+
+import org.apache.commons.lang3.time.DurationFormatUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.ui.FluentWait;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.utility.DockerImageName;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+abstract class FrontendBase {
+
+ @SuppressWarnings("rawtypes") // this is how to use testcontainers
+ @Container
+ public static GenericContainer seleniumChrome =
+ new GenericContainer<>(DockerImageName.parse("selenium/standalone-chrome")).withExposedPorts(4444);
+
+ @SuppressWarnings("rawtypes") // this is how to use testcontainers
+ @Container
+ public static GenericContainer tomcat =
+ new GenericContainer(DockerImageName.parse("myfaces/tobago-example-demo")).withExposedPorts(8080);
+
+ private static WebDriver chromeDriver;
+
+ @AfterAll
+ static void tearDown() {
+ if (chromeDriver != null) {
+ chromeDriver.quit();
+ }
+ }
+
+ static List<String> getStandardTestPaths() throws IOException {
+ return Files.walk(Paths.get("src/main/webapp/content/"))
+ .filter(Files::isRegularFile)
+ .map(Path::toString)
+ .filter(s -> s.endsWith(".test.js"))
+ .map(s -> s.substring("src/main/webapp/".length()))
+ .sorted()
+ .map(s -> s.substring(0, s.length() - 8) + ".xhtml")
+ .collect(Collectors.toList());
+ }
+
+ WebDriver getWebDriver(final String host, final Integer port) throws MalformedURLException {
+ if (chromeDriver == null || ((RemoteWebDriver) chromeDriver).getSessionId() == null) {
+ chromeDriver = new RemoteWebDriver(new URL("http://" + host + ":" + port + "/wd/hub"), new ChromeOptions());
+ }
+ return chromeDriver;
+ }
+
+ List<WebElement> getJasmineResults(WebDriver webDriver) {
+ final FluentWait<WebDriver> fluentWait = new FluentWait<>(webDriver)
+ .withTimeout(Duration.ofSeconds(60))
+ .pollingEvery(Duration.ofSeconds(1))
+ .ignoring(NoSuchElementException.class);
+ fluentWait.until(driver -> driver.findElement(By.className("jasmine-overall-result")));
+
+ return webDriver.findElements(By.cssSelector(".jasmine-symbol-summary li"));
+ }
+
+ void parseJasmineResults(List<WebElement> results) {
+ Assertions.assertTrue(results.size() > 0, "no results detected");
+ for (WebElement result : results) {
+ Assertions.assertEquals("jasmine-passed", result.getAttribute("class"), result.getAttribute("title"));
+ }
+ }
+
+ String getTimeLeft(final LocalTime startTime, final int testSize, final int testNo) {
+ final LocalTime now = LocalTime.now();
+ final Duration completeWaitTime = Duration.between(startTime, now).dividedBy(testNo).multipliedBy(testSize);
+ final LocalTime endTime = LocalTime.from(startTime).plus(completeWaitTime);
+ final Duration timeLeft = Duration.between(LocalTime.now(), endTime);
+
+ if (timeLeft.toHours() > 0) {
+ return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "H'h' m'm' s's'");
+ } else if (timeLeft.toMinutes() > 0) {
+ return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "m'm' s's'");
+ } else if (timeLeft.toMillis() >= 0) {
+ return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "s's'");
+ } else {
+ return "---";
+ }
+ }
+}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendTest.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendTest.java
new file mode 100644
index 0000000..db7d116
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/integration/FrontendTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.example.demo.integration;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.invoke.MethodHandles;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.time.LocalTime;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Stream;
+
+@Testcontainers
+class FrontendTest extends FrontendBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ static LocalTime startTime;
+
+ @BeforeAll
+ public static void setup() {
+ startTime = LocalTime.now();
+ }
+
+ /**
+ * Call every page with a specific *.test.js.
+ */
+ @ParameterizedTest
+ @MethodSource("standardTestProvider")
+ void frontendTest(String path, int testNumber, int testSize)
+ throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
+
+ final String timeLeft = getTimeLeft(FrontendTest.startTime, testSize, testNumber);
+ final String host = InetAddress.getLocalHost().getHostAddress();
+ final int tomcatPort = tomcat.getFirstMappedPort();
+
+ LOG.info("(" + testNumber + "/" + testSize + " | time left: " + timeLeft + ")"
+ + " - url: http://" + host + ":" + tomcatPort + "/" + path);
+
+ final String base = path.substring(0, path.length() - 6);
+ final String url = "http://" + host + ":" + tomcatPort + "/test.xhtml?base=" + URLEncoder.encode(base, "UTF-8");
+
+ WebDriver webDriver = getWebDriver(host, seleniumChrome.getFirstMappedPort());
+ webDriver.get(url);
+
+ List<WebElement> results = getJasmineResults(webDriver);
+ parseJasmineResults(results);
+ }
+
+ private static Stream<Arguments> standardTestProvider() throws IOException {
+ final List<String> paths = getStandardTestPaths();
+ final int testSize = paths.size();
+
+ int testNumber = 1;
+ List<Arguments> arguments = new LinkedList<>();
+ for (String path : paths) {
+ arguments.add(Arguments.of(path, testNumber, testSize));
+ testNumber++;
+ }
+ return arguments.stream();
+ }
+}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/AccessAllPagesTest.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/AccessAllPagesTest.java
deleted file mode 100644
index 8b610f2..0000000
--- a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/AccessAllPagesTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.example.demo.qunit;
-
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.lang.invoke.MethodHandles;
-import java.net.MalformedURLException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalTime;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-class AccessAllPagesTest extends SeleniumBase {
-
- private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- /**
- * Verify qunit test for "no exception".
- */
- @ParameterizedTest
- @MethodSource("verifyNoException404TestProvider")
- void verifyNoExceptionTest(Browser browser, String serverUrl)
- throws MalformedURLException, UnsupportedEncodingException {
- final String path = "error/exception.xhtml";
- LOG.info("browser: " + browser + " - url: " + serverUrl + "/" + path);
-
- if (isIgnored(serverUrl, path)) {
- logIgnoreMessage(serverUrl, path);
- } else {
- setupWebDriver(browser, serverUrl, path, true);
-
- final WebDriver webDriver = getWebDriver(browser);
- waitForQUnitBanner(webDriver);
- WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
-
- List<WebElement> results = qunitTests.findElements(By.xpath("li"));
- boolean testException = false;
- for (final WebElement result : results) {
- if ("has no exception".equals(result.findElement(By.className("test-name")).getText())) {
- Assertions.assertEquals(result.getAttribute("class"), "fail");
- testException = true;
- }
- }
- Assertions.assertTrue(testException, "Could not verify 'has no exception' test.");
- }
- }
-
- /**
- * Verify qunit test for "no 404".
- */
- @ParameterizedTest
- @MethodSource("verifyNoException404TestProvider")
- void verifyNo404Test(Browser browser, String serverUrl) throws MalformedURLException, UnsupportedEncodingException {
- final String path = "error/404.xhtml";
- LOG.info("browser: " + browser + " - url: " + serverUrl + "/" + path);
-
- if (isIgnored(serverUrl, path)) {
- logIgnoreMessage(serverUrl, path);
- } else {
- setupWebDriver(browser, serverUrl, path, true);
-
- final WebDriver webDriver = getWebDriver(browser);
- waitForQUnitBanner(webDriver);
- WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
-
- List<WebElement> results = qunitTests.findElements(By.xpath("li"));
- boolean test404 = false;
- for (final WebElement result : results) {
- if ("has no 404".equals(result.findElement(By.className("test-name")).getText())) {
- Assertions.assertEquals(result.getAttribute("class"), "fail");
- test404 = true;
- }
- }
- Assertions.assertTrue(test404, "Could not verify 'has no 404' test.");
- }
- }
-
- private static Stream<Arguments> verifyNoException404TestProvider() throws IOException {
- List<Arguments> arguments = new LinkedList<>();
-
- for (Browser browser : Browser.values()) {
- for (String serverUrl : getServerUrls()) {
- arguments.add(Arguments.of(browser, serverUrl));
- }
- }
-
- return arguments.stream();
- }
-
- @ParameterizedTest
- @MethodSource("accessAllPagesProvider")
- void testAccessAllPages(Browser browser, String serverUrl, String path, LocalTime startTime, int testSize, int testNo)
- throws MalformedURLException, UnsupportedEncodingException {
-
- double percent = 100 * (double) testNo / testSize;
- final String timeLeft = getTimeLeft(startTime, testSize, testNo);
-
- LOG.info("(" + String.format("%.2f", percent) + " % complete" + " | time left: " + timeLeft + ")"
- + " browser: " + browser + " - url: " + serverUrl + "/" + path);
-
- if (isIgnored(serverUrl, path)) {
- logIgnoreMessage(serverUrl, path);
- } else {
- setupWebDriver(browser, serverUrl, path, true);
- parseQUnitResults(browser, serverUrl, path);
- }
- }
-
- private static Stream<Arguments> accessAllPagesProvider() throws IOException {
- final List<String> paths = Files.walk(Paths.get("src/main/webapp/content/"))
- .filter(Files::isRegularFile)
- .map(Path::toString)
- .filter(s -> s.endsWith(".xhtml"))
- .filter(s -> !s.contains("/x-"))
- .map(s -> s.substring("src/main/webapp/".length()))
- .sorted()
- .collect(Collectors.toList());
-
- for (String standardTestPath : getStandardTestPaths()) {
- paths.remove(standardTestPath); // already tested by standard test
- }
-
- return getArguments(paths);
- }
-}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/SeleniumBase.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/SeleniumBase.java
deleted file mode 100644
index d025d93..0000000
--- a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/SeleniumBase.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.example.demo.qunit;
-
-import org.apache.commons.lang3.time.DurationFormatUtils;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.params.provider.Arguments;
-import org.openqa.selenium.By;
-import org.openqa.selenium.NoSuchElementException;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.chrome.ChromeOptions;
-import org.openqa.selenium.remote.RemoteWebDriver;
-import org.openqa.selenium.support.ui.ExpectedConditions;
-import org.openqa.selenium.support.ui.FluentWait;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.lang.invoke.MethodHandles;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.net.UnknownHostException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.Duration;
-import java.time.LocalTime;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-abstract class SeleniumBase {
-
- private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- private static WebDriver chromeDriver;
- private static List<String> serverUrls = new ArrayList<>();
- private static Map<String, String> ignores = new HashMap<>();
-
- @BeforeAll
- static void setUp() {
- ignores.put(":8083/tobago-example-demo-myfaces-2.3",
- "MyFaces 2.3 don't work with Tomcat 8.5 and openjdk10");
- ignores.put("tobago-example-demo-mojarra-2.0",
- "Ajax events don't work with Mojarra 2.0: https://issues.apache.org/jira/browse/TOBAGO-1589");
- ignores.put("tobago-example-demo-mojarra-2.3",
- "Currently Tobago demo don't run with Mojarra 2.3 on Tomcat 8.5");
-
- ignores.put("content/40-test/6000-event/event.xhtml",
- "Focus/blur event can only be fired if the browser window is in foreground."
- + " This cannot be guaranteed in selenium tests."
- + " event.test.js contain focus/blur events");
-
- final String tobago1910 = "TreeSelect: Single selection nodes are not deselected correctly with mojarra: "
- + "https://issues.apache.org/jira/browse/TOBAGO-1910";
- ignores.put("tobago-example-demo-mojarra-2.1/content/20-component/090-tree/01-select/tree-select.xhtml",
- tobago1910);
- ignores.put("tobago-example-demo-mojarra-2.2/content/20-component/090-tree/01-select/tree-select.xhtml",
- tobago1910);
- }
-
- @AfterAll
- static void tearDown() {
- if (chromeDriver != null) {
- chromeDriver.quit();
- }
- }
-
- enum Browser {
- chrome
- //, firefox // TODO implement firefox
- }
-
- static List<String> getServerUrls() throws UnknownHostException, MalformedURLException {
- if (serverUrls.size() <= 0) {
- final String hostAddress = InetAddress.getLocalHost().getHostAddress();
-
- List<String> ports = new ArrayList<>();
- ports.add("8082"); // Tomcat JRE 8
- ports.add("8083"); // Tomcat JRE 10
-
- List<String> contextPaths = new ArrayList<>();
- contextPaths.add("tobago-example-demo"); // MyFaces 2.0
- contextPaths.add("tobago-example-demo-myfaces-2.1");
- contextPaths.add("tobago-example-demo-myfaces-2.2");
- contextPaths.add("tobago-example-demo-myfaces-2.3");
- contextPaths.add("tobago-example-demo-mojarra-2.0");
- contextPaths.add("tobago-example-demo-mojarra-2.1");
- contextPaths.add("tobago-example-demo-mojarra-2.2");
- contextPaths.add("tobago-example-demo-mojarra-2.3");
-
- for (String port : ports) {
- for (String contextPath : contextPaths) {
- String url = "http://" + hostAddress + ":" + port + "/" + contextPath;
- final int status = getStatus(url);
- if (status == 200) {
- serverUrls.add(url);
- } else {
- LOG.warn("\n⚠️ IGNORED: Tests for " + url + ":\n Server status: " + status);
- }
- }
- }
- }
-
- return serverUrls;
- }
-
- private static int getStatus(String url) throws MalformedURLException {
- URL siteURL = new URL(url);
- try {
- HttpURLConnection connection = (HttpURLConnection) siteURL.openConnection();
- connection.setRequestMethod("GET");
- connection.connect();
- return connection.getResponseCode();
- } catch (IOException e) {
- return -1;
- }
- }
-
- static List<String> getStandardTestPaths() throws IOException {
- return Files.walk(Paths.get("src/main/webapp/content/"))
- .filter(Files::isRegularFile)
- .map(Path::toString)
- .filter(s -> s.endsWith(".test.js"))
- .map(s -> s.substring("src/main/webapp/".length()))
- .sorted()
- .map(s -> s.substring(0, s.length() - 8) + ".xhtml")
- .collect(Collectors.toList());
- }
-
- boolean isIgnored(final String serverUrl, final String path) {
- final String url = serverUrl + "/" + path;
- for (String key : ignores.keySet()) {
- if (url.contains(key)) {
- return true;
- }
- }
- return false;
- }
-
- void logIgnoreMessage(final String serverUrl, final String path) {
- final String url = serverUrl + "/" + path;
- for (final Map.Entry<String, String> ignore : ignores.entrySet()) {
- if (url.contains(ignore.getKey())) {
- final String message = ignore.getValue();
- LOG.info("\n⚠️ IGNORED: Test for " + url + ":\n" + message);
- return;
- }
- }
- }
-
- void setupWebDriver(final Browser browser, final String serverUrl, final String path, final boolean accessTest)
- throws MalformedURLException, UnsupportedEncodingException {
- if (Browser.chrome.equals(browser)
- && (chromeDriver == null) || ((RemoteWebDriver) chromeDriver).getSessionId() == null) {
- chromeDriver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), new ChromeOptions());
- }
-
- final String base = path.substring(0, path.length() - 6);
- final String url = serverUrl + "/test.xhtml?base="
- + URLEncoder.encode(base, "UTF-8") + (accessTest ? "&accessTest=true" : "");
- getWebDriver(browser).get(url);
- }
-
- WebDriver getWebDriver(Browser browser) {
- if (Browser.chrome.equals(browser)) {
- return chromeDriver;
- } else {
- return null;
- }
- }
-
- static Stream<Arguments> getArguments(final List<String> paths) throws MalformedURLException, UnknownHostException {
- final LocalTime startTime = LocalTime.now();
- final int testSize = Browser.values().length * getServerUrls().size() * paths.size();
-
- List<Arguments> arguments = new LinkedList<>();
-
- int testNo = 1;
- for (String serverUrl : getServerUrls()) {
- for (String path : paths) {
- for (Browser browser : Browser.values()) {
- arguments.add(Arguments.of(browser, serverUrl, path, startTime, testSize, testNo));
- testNo++;
- }
- }
- }
-
- return arguments.stream();
- }
-
- String getTimeLeft(final LocalTime startTime, final int testSize, final int testNo) {
- final LocalTime now = LocalTime.now();
- final Duration completeWaitTime = Duration.between(startTime, now).dividedBy(testNo).multipliedBy(testSize);
- final LocalTime endTime = LocalTime.from(startTime).plus(completeWaitTime);
- final Duration timeLeft = Duration.between(LocalTime.now(), endTime);
-
- if (timeLeft.toHours() > 0) {
- return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "H'h' m'm' s's'");
- } else if (timeLeft.toMinutes() > 0) {
- return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "m'm' s's'");
- } else if (timeLeft.toMillis() >= 0) {
- return DurationFormatUtils.formatDuration(timeLeft.toMillis(), "s's'");
- } else {
- return "---";
- }
- }
-
- /**
- * Wait for the qunit-banner web element and return it.
- * If the web element is available, the execution of qunit test should be done and it is safe to parse the results.
- *
- * @return qunit-banner web element
- */
- WebElement waitForQUnitBanner(final WebDriver webDriver) {
- final FluentWait<WebDriver> fluentWait = new FluentWait<>(webDriver)
- .withTimeout(Duration.ofSeconds(90))
- .pollingEvery(Duration.ofSeconds(1))
- .ignoring(NoSuchElementException.class);
-
- WebElement qunitBanner = fluentWait.until(driver -> driver.findElement(By.id("qunit-banner")));
- fluentWait.until(ExpectedConditions.attributeToBeNotEmpty(qunitBanner, "class"));
-
- return qunitBanner;
- }
-
- void parseQUnitResults(final Browser browser, final String serverUrl, final String path) {
- final WebDriver webDriver = getWebDriver(browser);
- WebElement qunitBanner;
- try {
- qunitBanner = waitForQUnitBanner(webDriver);
- } catch (Exception e) {
- qunitBanner = webDriver.findElement(By.id("qunit-banner"));
- }
-
- WebElement qunitTestResult = webDriver.findElement(By.id("qunit-testresult"));
- WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
-
- final List<WebElement> testCases = qunitTests.findElements(By.xpath("li"));
- Assertions.assertTrue(testCases.size() > 0, "There must be at least one test case.");
-
- final boolean testFailed = !qunitBanner.getAttribute("class").equals("qunit-pass");
-
- int testCaseCount = 1;
- final StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append(qunitTestResult.getAttribute("textContent"));
- stringBuilder.append("\n");
-
- if (testFailed) {
- for (final WebElement testCase : testCases) {
- final String testName = getText(testCase, "test-name");
- final String testStatus = testCase.getAttribute("class").toUpperCase();
-
- stringBuilder.append(testCaseCount++);
- stringBuilder.append(". ");
- stringBuilder.append(testStatus);
- stringBuilder.append(": ");
- stringBuilder.append(testName);
- stringBuilder.append(" (");
- stringBuilder.append(getText(testCase, "runtime"));
- stringBuilder.append(")\n");
-
- final WebElement assertList = testCase.findElement(By.className("qunit-assert-list"));
- final List<WebElement> asserts = assertList.findElements(By.tagName("li"));
- int assertCount = 1;
- for (final WebElement assertion : asserts) {
- final String assertStatus = assertion.getAttribute("class");
-
- stringBuilder.append("- ");
- if (assertCount <= 9) {
- stringBuilder.append("0");
- }
- stringBuilder.append(assertCount++);
- stringBuilder.append(". ");
- stringBuilder.append(assertStatus);
- stringBuilder.append(": ");
- stringBuilder.append(getText(assertion, "test-message"));
- stringBuilder.append(getText(assertion, "runtime"));
- stringBuilder.append("\n");
-
- final String assertExpected = getText(assertion, "test-expected");
- if (!"null".equals(assertExpected)) {
- stringBuilder.append("-- ");
- stringBuilder.append(assertExpected);
- stringBuilder.append("\n");
- }
- final String assertResult = getText(assertion, "test-actual");
- if (!"null".equals(assertResult)) {
- stringBuilder.append("-- ");
- stringBuilder.append(assertResult);
- stringBuilder.append("\n");
- }
- final String assertSource = getText(assertion, "test-source");
- if (!"null".equals(assertSource)) {
- stringBuilder.append("-- ");
- stringBuilder.append(assertSource);
- stringBuilder.append("\n");
- }
- }
-
- stringBuilder.append(getText(testCase, "qunit-source"));
- stringBuilder.append("\n\n");
- }
- }
-
- final String url = serverUrl + "/" + path;
- if (testFailed) {
- final String message = "\n❌ FAILED: Test with '" + browser + "' for " + url + "\n" + stringBuilder.toString();
- LOG.warn(message);
- Assertions.fail(message);
- } else {
- final String message = "\n✅ PASSED: Test with '" + browser + "' for " + url + "\n" + stringBuilder.toString();
- LOG.info(message);
- Assertions.assertTrue(true, message);
- }
- }
-
- private String getText(final WebElement webElement, final String className) {
- final List<WebElement> elements = webElement.findElements(By.className(className));
- if (elements.size() > 0) {
- return elements.get(0).getAttribute("textContent");
- } else {
- return "null";
- }
- }
-}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/StandardTest.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/StandardTest.java
deleted file mode 100644
index b174f0a..0000000
--- a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/StandardTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.example.demo.qunit;
-
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.lang.invoke.MethodHandles;
-import java.net.MalformedURLException;
-import java.net.UnknownHostException;
-import java.time.LocalTime;
-import java.util.List;
-import java.util.stream.Stream;
-
-class StandardTest extends SeleniumBase {
-
- private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- /**
- * To test only a singe page, just change browser setup, 'portContextPath' and/or 'path'.
- * Start the docker container with mvn -Pdocker-qunit-tests docker:start
- */
- @Test
- void testSinglePage() throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
- final Browser browser = Browser.chrome;
- final String serverUrl = getServerUrls().get(0);
- final String path = "content/10-intro/intro.xhtml";
-
- LOG.info("browser: " + browser + " - url: " + serverUrl + "/" + path);
-
- setupWebDriver(browser, serverUrl, path, false);
- parseQUnitResults(browser, serverUrl, path);
- }
-
- @ParameterizedTest
- @MethodSource("standardTestProvider")
- void testStandard(Browser browser, String serverUrl, String path, LocalTime startTime, int testSize, int testNo)
- throws MalformedURLException, UnsupportedEncodingException {
-
- double percent = 100 * (double) testNo / testSize;
- final String timeLeft = getTimeLeft(startTime, testSize, testNo);
-
- LOG.info("(" + String.format("%.2f", percent) + " % complete" + " | time left: " + timeLeft + ")"
- + " browser: " + browser + " - url: " + serverUrl + "/" + path);
-
- if (isIgnored(serverUrl, path)) {
- logIgnoreMessage(serverUrl, path);
- } else {
- setupWebDriver(browser, serverUrl, path, false);
- parseQUnitResults(browser, serverUrl, path);
- }
- }
-
- private static Stream<Arguments> standardTestProvider() throws IOException {
- final List<String> paths = getStandardTestPaths();
- return getArguments(paths);
- }
-}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/junit/rules/TestRule.java b/tobago-example/tobago-example-demo/src/test/java/org/junit/rules/TestRule.java
new file mode 100644
index 0000000..f0f6c69
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/junit/rules/TestRule.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.junit.rules;
+
+/*
+ * the fake class is needed for testcontainers, because of an dependency to junit4
+ * https://github.com/testcontainers/testcontainers-java/issues/970
+ */
+@SuppressWarnings("unused")
+public interface TestRule {
+}