You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2018/05/24 17:15:12 UTC
[myfaces-tobago] branch master updated: QUnitTests reimplemented
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/master by this push:
new 9dcacb5 QUnitTests reimplemented
9dcacb5 is described below
commit 9dcacb5fca466a23b6073276a28626ffbed0558c
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Thu May 24 19:15:02 2018 +0200
QUnitTests reimplemented
* former qunit-integration-tests are reimplemented with junit5, selenium-grid and docker.
** to start the tests, docker is needed.
** to run the tests: mvn -Pdocker-qunit-tests
** to just start docker container: mvn -Pdocker-qunit-tests docker:start
** to stop docker container: mvn -Pdocker-qunit-tests docker:stop
* arquillian dependencies removed (including ArquillianTest example)
* simple test for intro.xhtml added
* 'wait for test' updated, so testing 'error/exception.xhtml' and 'error/404.xhtml' is possible
---
pom.xml | 22 +-
tobago-example/tobago-example-demo/pom.xml | 239 +++++---
.../src/main/webapp/content/10-intro/intro.test.js | 24 +
.../src/main/webapp/script/tobago-test.js | 3 +-
.../tobago/example/demo/ArquillianTest.java | 106 ----
.../myfaces/tobago/example/demo/QUnitTests.java | 600 ---------------------
.../example/demo/qunit/AccessAllPagesTest.java | 169 ++++++
.../tobago/example/demo/qunit/SeleniumBase.java | 188 +++++++
.../tobago/example/demo/qunit/StandardTest.java | 100 ++++
9 files changed, 656 insertions(+), 795 deletions(-)
diff --git a/pom.xml b/pom.xml
index 94252b0..c708d5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -438,6 +438,18 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.portals</groupId>
<artifactId>portlet-api_2.0_spec</artifactId>
<version>1.0</version>
@@ -500,6 +512,14 @@
<artifactId>junit</artifactId>
</dependency>
<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ </dependency>
+ <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
@@ -810,7 +830,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
- <version>2.20.1</version>
+ <version>2.21.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/tobago-example/tobago-example-demo/pom.xml b/tobago-example/tobago-example-demo/pom.xml
index 982fd2a..55f7fd1 100644
--- a/tobago-example/tobago-example-demo/pom.xml
+++ b/tobago-example/tobago-example-demo/pom.xml
@@ -34,10 +34,7 @@
<properties>
<openwebbeans.version>2.0.4</openwebbeans.version>
<deltaspike.version>1.8.1</deltaspike.version>
- <!--<arquillian.browser>firefox</arquillian.browser>-->
- <!-- phantomjs works not with CSP (report-only) -->
- <arquillian.browser>phantomjs</arquillian.browser>
- <selenium.version>3.7.1</selenium.version>
+ <selenium.version>3.12.0</selenium.version>
<tomee.version>7.0.4</tomee.version>
<meecrowave.version>1.2.1</meecrowave.version>
<tomcat.version>9.0.5</tomcat.version>
@@ -139,81 +136,20 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
- <excludes><!-- TODO define group for ArquillianTests and use excludeGroups -->
- <exclude>**/ArquillianTest.java</exclude>
+ <excludes>
+ <exclude>qunit/*</exclude>
</excludes>
</configuration>
</plugin>
- <plugin>
- <artifactId>maven-failsafe-plugin</artifactId>
- <configuration>
- <includes><!-- TODO define group for ArquillianTests or use convention *IT.java, *ITCase.java -->
- <include>**/ArquillianTest.java</include>
- </includes>
- </configuration>
- </plugin>
- <plugin>
- <groupId>io.fabric8</groupId>
- <artifactId>docker-maven-plugin</artifactId>
- <version>0.22.1</version>
- <configuration>
- <images>
- <image>
- <name>selenium/standalone-firefox:${selenium.version}</name>
- <run>
- <ports>
- <port>4444:4444</port>
- </ports>
- </run>
- </image>
- </images>
- </configuration>
- </plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
- <groupId>org.jboss.arquillian</groupId>
- <artifactId>arquillian-bom</artifactId>
- <version>1.1.15.Final</version>
- <scope>import</scope>
- <type>pom</type>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.selenium</groupId>
- <artifactId>selenium-bom</artifactId>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.extension</groupId>
- <artifactId>arquillian-drone-bom</artifactId>
- <version>2.4.5</version>
- <scope>import</scope>
- <type>pom</type>
- </dependency>
- <!-- this is needed for arquillian drone (QUnitTests) -->
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.11</version>
- <!-- scope must not be "test", because myfaces-impl also uses commons-codec -->
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.graphene</groupId>
- <artifactId>graphene-webdriver</artifactId>
- <version>2.3.2</version>
- <type>pom</type>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </exclusion>
- </exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -278,24 +214,8 @@
<version>4.4.8</version>
</dependency>
<dependency>
- <groupId>org.jboss.arquillian.junit</groupId>
- <artifactId>arquillian-junit-container</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.shrinkwrap.resolver</groupId>
- <artifactId>shrinkwrap-resolver-api-maven-archive</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.shrinkwrap.resolver</groupId>
- <artifactId>shrinkwrap-resolver-impl-maven-archive</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.arquillian.graphene</groupId>
- <artifactId>graphene-webdriver</artifactId>
- <type>pom</type>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-java</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@@ -865,6 +785,151 @@
</profile>
<profile>
+ <id>docker-qunit-tests</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <version>0.25.2</version>
+ <configuration>
+ <images>
+ <image>
+ <name>tomcat:8.5-jre8</name>
+ <run>
+ <ports>
+ <port>8081:8080</port>
+ </ports>
+ <volumes>
+ <bind>
+ <volume>
+ ${project.build.directory}/${project.artifactId}:/usr/local/tomcat/webapps/${project.artifactId}
+ </volume>
+ </bind>
+ </volumes>
+ <wait>
+ <http>
+ <url>http://localhost:8081/${project.artifactId}</url>
+ </http>
+ <time>60000</time>
+ </wait>
+ </run>
+ </image>
+ <image>
+ <alias>selenium-hub</alias>
+ <name>selenium/hub:${selenium.version}</name>
+ <run>
+ <ports>
+ <port>4444:4444</port>
+ </ports>
+ <wait>
+ <http>
+ <url>http://localhost:4444</url>
+ <status>200</status>
+ </http>
+ <time>20000</time>
+ </wait>
+ </run>
+ </image>
+ <image>
+ <name>selenium/node-chrome:${selenium.version}</name>
+ <run>
+ <dependsOn>
+ <container>selenium-hub</container>
+ </dependsOn>
+ <links>
+ <link>selenium-hub</link>
+ </links>
+ <env>
+ <HUB_HOST>selenium-hub</HUB_HOST>
+ <HOB_PORT>4444</HOB_PORT>
+ </env>
+ <ports>
+ <port>5556:5555</port>
+ </ports>
+ <wait>
+ <http>
+ <url>http://localhost:5556</url>
+ <status>200</status>
+ </http>
+ <time>20000</time>
+ </wait>
+ </run>
+ </image>
+ <image>
+ <name>selenium/node-firefox:${selenium.version}</name>
+ <run>
+ <dependsOn>
+ <container>selenium-hub</container>
+ </dependsOn>
+ <links>
+ <link>selenium-hub</link>
+ </links>
+ <env>
+ <HUB_HOST>selenium-hub</HUB_HOST>
+ <HOB_PORT>4444</HOB_PORT>
+ </env>
+ <ports>
+ <port>5557:5555</port>
+ </ports>
+ <wait>
+ <http>
+ <url>http://localhost:5557</url>
+ <status>200</status>
+ </http>
+ <time>20000</time>
+ </wait>
+ </run>
+ </image>
+ </images>
+ </configuration>
+ <executions>
+ <execution>
+ <id>start-container</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ <goal>build</goal>
+ <goal>start</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>stop-container</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-surefire-provider</artifactId>
+ <version>1.2.0</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <includes>
+ <include>qunit/*</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>integration-test</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
<id>qunit-integration-tests</id>
<build>
<plugins>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/intro.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/intro.test.js
new file mode 100644
index 0000000..d2e6110
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/10-intro/intro.test.js
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+QUnit.test("First section title is 'Intro'", function (assert) {
+ assert.expect(1);
+
+ var titleOfFirstSectionHeader = jQueryFrame(".tobago-section-header:first span").text();
+
+ assert.equal(titleOfFirstSectionHeader, "Intro");
+});
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js b/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
index 2829cf5..3974cfa 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/script/tobago-test.js
@@ -33,7 +33,8 @@ QUnit.test("wait for test", function (assert) {
var waitingDone = false;
var interval = setInterval(function () {
contentWindowName = document.getElementById("page:testframe").contentWindow.name;
- waitingDone = contentWindowName !== "page:testframe" && contentWindowName !== "ds-tempWindowId";
+ waitingDone = (contentWindowName !== "page:testframe" && contentWindowName !== "ds-tempWindowId")
+ || new RegExp('[\?&]base=([^&#]*)').exec(window.location.href)[1].indexOf("error%2F") === 0;
if (new Date().getTime() - startTime >= 20000 || waitingDone) {
clearInterval(interval);
assert.ok(waitingDone);
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/ArquillianTest.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/ArquillianTest.java
deleted file mode 100644
index 7f2a74c..0000000
--- a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/ArquillianTest.java
+++ /dev/null
@@ -1,106 +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;
-
-import org.jboss.arquillian.container.test.api.Deployment;
-import org.jboss.arquillian.container.test.api.RunAsClient;
-import org.jboss.arquillian.drone.api.annotation.Drone;
-import org.jboss.arquillian.graphene.findby.FindByJQuery;
-import org.jboss.arquillian.junit.Arquillian;
-import org.jboss.arquillian.test.api.ArquillianResource;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.jboss.shrinkwrap.resolver.api.maven.archive.importer.MavenImporter;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.support.FindBy;
-
-import java.io.File;
-import java.net.URL;
-
-/**
- * if PhantomJS is configured, ensure that content-security-policy mode="off" is in tobago-config.xml otherwise
- * it will result in "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed
- * source of script in the following Content Security Policy directive"
- * see: https://github.com/ariya/phantomjs/issues/13114
- */
-@RunWith(Arquillian.class)
-@RunAsClient
-public class ArquillianTest {
-
- @Drone
- private WebDriver browser;
-
- @ArquillianResource
- private URL contextPath;
-
- @FindBy(id = "page:iajax::field")
- private WebElement input;
-
- @FindBy(id = "page:oajax")
- private WebElement output;
-
- @FindByJQuery("#page\\:oajax > label")
- private WebElement outputLabel;
-
- @FindByJQuery("#page\\:oajax > span")
- private WebElement outputField;
-
- @Deployment(testable = false)
- public static WebArchive createDeployment() {
- final File pom = new File("tobago-example/tobago-example-demo/pom.xml");
- final WebArchive webArchive = ShrinkWrap.create(MavenImporter.class).
- loadPomFromFile(pom, "jsf-provided", "!myfaces-2.0").importBuildOutput()
- .as(WebArchive.class);
- // XXX there should be a proper profile in POM for that
- webArchive.delete("/WEB-INF/lib/hibernate-validator-4.3.2.Final.jar");
- return webArchive;
- }
-
- @Test
- public void ajaxOnChange() {
- browser.get(contextPath + "/content/20-component/010-input/10-in/in.xhtml");
-
- Assert.assertEquals("On Server", outputLabel.getText());
- Assert.assertEquals("", outputField.getText());
-
- final String text = "Testtext";
- input.sendKeys(text);
- output.click();
-// Graphene.waitAjax();
-/*
- try {
- Thread.sleep(30000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-*/
-
- Assert.assertEquals(text, outputField.getText());
-
-
-// JavascriptExecutor js = (JavascriptExecutor) browser;
-// js.executeScript("$(Tobago.Utils.escapeClientId('{}')).blur();", output.getAttribute("id"));
-
- }
-}
diff --git a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/QUnitTests.java b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/QUnitTests.java
deleted file mode 100644
index 5b8edf4..0000000
--- a/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/QUnitTests.java
+++ /dev/null
@@ -1,600 +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;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.jboss.arquillian.container.test.api.Deployment;
-import org.jboss.arquillian.container.test.api.RunAsClient;
-import org.jboss.arquillian.drone.api.annotation.Drone;
-import org.jboss.arquillian.graphene.findby.FindByJQuery;
-import org.jboss.arquillian.junit.Arquillian;
-import org.jboss.arquillian.test.api.ArquillianResource;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.jboss.shrinkwrap.resolver.api.maven.archive.importer.MavenImporter;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-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.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-@RunWith(Arquillian.class)
-@RunAsClient
-public class QUnitTests {
-
- private static final Logger LOG = LoggerFactory.getLogger(QUnitTests.class);
- private static List<String> testedPages = new LinkedList<>();
-
- @Drone
- private WebDriver browser;
- @ArquillianResource
- private URL contextPath;
- @FindByJQuery("#qunit-testresult")
- private WebElement qunitTestresult;
- @FindByJQuery("#qunit-tests")
- private WebElement qunitTests;
-
- @Deployment
- public static WebArchive createDeployment() {
- WebArchive webArchive;
- try {
- webArchive = createWebArchive(new File("tobago-example/tobago-example-demo/pom.xml"));
- } catch (final Exception e) {
- webArchive = createWebArchive(new File("pom.xml")); // Jenkins
- }
- return disableCSP(webArchive);
- }
-
- private static WebArchive createWebArchive(final File pom) {
- final WebArchive webArchive = ShrinkWrap.create(MavenImporter.class).
- loadPomFromFile(pom, "jsf-provided", "!myfaces-2.0").importBuildOutput()
- .as(WebArchive.class);
- // XXX there should be a proper profile in POM for that
- webArchive.delete("/WEB-INF/lib/hibernate-validator-4.3.2.Final.jar");
- return webArchive;
- }
-
- private static WebArchive disableCSP(final WebArchive webArchive) {
- try {
- final InputStream inputStream = webArchive.get("WEB-INF/tobago-config.xml").getAsset().openStream();
-
- final StringWriter stringWriter = new StringWriter();
- IOUtils.copy(inputStream, stringWriter, Charset.defaultCharset());
- final String modifiedTobagoConfig = stringWriter.toString()
- .replace("<content-security-policy mode=\"on\">", "<content-security-policy mode=\"off\">");
-
- final File tobagoConfigXml = new File("target/tobago-config.xml");
- FileUtils.writeStringToFile(tobagoConfigXml, modifiedTobagoConfig, Charset.defaultCharset());
- webArchive.addAsWebInfResource(tobagoConfigXml);
- } catch (final IOException e) {
- LOG.error("could not modify tobago-config.xml", e);
- }
- return webArchive;
- }
-
- private void setupBrowser(final String base, final boolean accessTest) throws UnsupportedEncodingException {
- LOG.info("setup browser for: " + base + ".xhtml | accessTest=" + accessTest);
- browser.get(contextPath + "test.xhtml?base=" + URLEncoder.encode(base, "UTF-8")
- + (accessTest ? "&accessTest=true" : ""));
- }
-
- private void runStandardTest(final String page) throws UnsupportedEncodingException, InterruptedException {
- testedPages.add(page);
-
- if (!ignorePages().contains(page)) {
- final String base = page.substring(0, page.length() - 6);
- setupBrowser(base, false);
-
- checkQUnitResults(page);
- }
- }
-
- private void checkQUnitResults(final String page) throws InterruptedException {
- final boolean timeout = waitForTest(page);
- final List<WebElement> testCases = qunitTests.findElements(By.xpath("li"));
- Assert.assertTrue("There must be at least one test case.", testCases.size() > 0);
-
- final String textContent = qunitTests.getAttribute("textContent");
-
- final boolean testFailed = timeout || (textContent != null
- && textContent.contains(" msfailed@ ") || textContent.contains("Expected:") || textContent.contains("Result:"));
-
- 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");
- }
- }
-
- if (testFailed) {
- final String message = "Tests for " + page + " FAILED:\n" + stringBuilder.toString();
- LOG.warn(message);
- Assert.fail(message);
- } else {
- final String message = "Tests for " + page + " PASSED:\n" + stringBuilder.toString();
- LOG.info(message);
- Assert.assertTrue(message, true);
- }
- }
-
- private boolean waitForTest(final String page) throws InterruptedException {
- final long endTime = System.currentTimeMillis() + 90000;
- String lastStatus = null;
- while (System.currentTimeMillis() < endTime) {
- try {
- final String status = qunitTestresult.getAttribute("textContent");
- if (status == null) {
- LOG.info(page + " status=null");
- } else if (!status.equals(lastStatus)) {
- lastStatus = status;
- LOG.info(page + " " + status + " (" + (endTime - System.currentTimeMillis()) + "ms left)");
- if (status.startsWith("Tests completed")) {
- return false;
- }
- }
- } catch (final Exception e) {
- Thread.sleep(200);
- }
- }
- LOG.warn(page + " timeout");
- return true;
- }
-
- 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";
- }
- }
-
- @AfterClass
- public static void checkMissingTests() {
- if (testedPages.size() > 1) {
- final List<String> pages = getXHTMLs();
- int testablePagesCount = 0;
-
- final StringBuilder stringBuilder = new StringBuilder();
- for (final String page : pages) {
- if (new File(page.substring(0, page.length() - 6) + ".test.js").exists()) {
- testablePagesCount++;
-
- final String pathForBrowser = page.substring(page.indexOf("src/main/webapp/") + "src/main/webapp/".length());
- if (!testedPages.contains(pathForBrowser)) {
- final String errorString = "missing testmethod for " + pathForBrowser;
- LOG.warn(errorString);
- stringBuilder.append("\n");
- stringBuilder.append(errorString);
- }
- }
- }
- Assert.assertEquals(stringBuilder.toString(), testablePagesCount, testedPages.size());
- }
- }
-
- @Test
- public void testAccessAllPages() throws UnsupportedEncodingException, InterruptedException {
- final List<String> pages = getXHTMLs();
- List<WebElement> results;
-
- // Test if 'has no exception' test is correct.
- setupBrowser("error/exception", true);
- final boolean timeoutException = waitForTest("error/exception");
- Assert.assertFalse("Could not verify 'has no exception' test: TIMEOUT", timeoutException);
- 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())) {
- Assert.assertEquals(result.getAttribute("class"), "fail");
- testException = true;
- }
- }
- Assert.assertTrue("Could not verify 'has no exception' test.", testException);
-
- // Test if 'has no 404' test is correct.
- setupBrowser("error/404", true);
- final boolean timeout404 = waitForTest("error/404");
- Assert.assertFalse("Could not verify 'has no 404' test. TIMEOUT", timeout404);
- boolean test404 = false;
- results = qunitTests.findElements(By.xpath("li"));
- for (final WebElement result : results) {
- if ("has no 404".equals(result.findElement(By.className("test-name")).getText())) {
- Assert.assertEquals(result.getAttribute("class"), "fail");
- test404 = true;
- }
- }
- Assert.assertTrue("Could not verify 'has no 404' test.", test404);
-
- for (final String page : pages) {
- final String pathForBrowser = page.substring(page.indexOf("src/main/webapp/") + "src/main/webapp/".length(),
- page.length() - 6);
-
- //TODO: reimplement/remove/cleanup attic tests - currently too much failed
- if (!pathForBrowser.contains("content/40-test/90000-attic/")) {
- setupBrowser(pathForBrowser, true);
- checkQUnitResults(page);
- }
- }
- }
-
- private static List<String> getXHTMLs() {
- File rootDir = new File("tobago-example/tobago-example-demo/src/main/webapp/content");
- if (!rootDir.exists()) {
- rootDir = new File("src/main/webapp/content"); // Jenkins.
- }
- return getXHTMLs(rootDir);
- }
-
- private static List<String> getXHTMLs(final File dir) {
- final List<String> xhtmls = new ArrayList<>();
- for (final File file : dir.listFiles()) {
- if (file.isDirectory()) {
- xhtmls.addAll(getXHTMLs(file));
- } else if (!file.getName().startsWith("x-") && file.getName().endsWith(".xhtml")) {
- xhtmls.add(file.getPath());
- }
- }
- return xhtmls;
- }
-
- private List<String> ignorePages() {
- final List<String> ignore = new ArrayList<>();
- //ajaxListener doesn't work for <tc:in> events: focus, blur, click, dblclick
- ignore.add("content/40-test/6000-event/event.xhtml");
- return ignore;
- }
-
- @Test
- public void in() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/010-input/10-in/in.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void suggest() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/010-input/20-suggest/suggest.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void date() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/010-input/40-date/date.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void group() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/010-input/50-input-group/group.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void selectBooleanCheckbox() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/030-select/10-selectBooleanCheckbox/selectBooleanCheckbox.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void selectOneChoice() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/030-select/20-selectOneChoice/selectOneChoice.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void selectOneRadio() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/030-select/30-selectOneRadio/selectOneRadio.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void selectOneListbox() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/030-select/40-selectOneListbox/selectOneListbox.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void selectManyCheckbox() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/030-select/50-selectManyCheckbox/selectManyCheckbox.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void buttons() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/040-command/20-buttons/buttons.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void box() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/050-container/10-box/box.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void section() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/050-container/40-section/section.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void popup() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/060-popup/popup.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void tab() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/070-tab/tab.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void sheetSorting() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/080-sheet/10-sort/sheet-sorting.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void sheetEvent() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/080-sheet/30-event/sheet-event.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void treeSelect() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/20-component/090-tree/01-select/tree-select.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void contentValidation() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/06-validation/00/content-validation.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void validationJsr303() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/06-validation/01/validation-jsr303.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void form() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/08-form/form.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void formRequired() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/08-form/10-required/form-required.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void formAjax() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/08-form/20-ajax/form-ajax.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void forEach() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/51-for-each/for-each.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void collapsibleBox() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/53-collapsible/00-collapsible-box/collapsible-box.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void collapsiblePopup() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/53-collapsible/10-collapsible-popup/collapsible-popup.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void collapsiblePanel() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/53-collapsible/20-collapsible-panel/collapsible-panel.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void collapsibleSection() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/30-concept/53-collapsible/30-collapsible-section/collapsible-section.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void suggestMethod() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/35-deprecated/15-suggest-method/suggest-method.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testSuggestQuotMark() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/1020-suggest-quotMark/suggest-quotMark.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testDate() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/1040-date/date.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testDatePattern() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/1041-date-pattern/date-pattern.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testTabgroupStyle() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/2500-tab/tabgroup-style.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testSheetTypes() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/3000-sheet/10-sheet-types/sheet-types.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testButtonLink() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/4000-button+link/button+link.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testAjaxDropdown() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/4000-button+link/4050-ajax-dropdown/ajax-dropdown.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testIdMarkup() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/4800-labelLayout/100-id-markup/id-markup.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testLabelLayoutTop() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/4810-labelLayoutTop/labelLayoutTop.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testEvent() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/6000-event/event.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testModeValueIfSet() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/9010-mode-valueIfSet/mode-valueIfSet.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testHeadings() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/40000-style/100-headings/headings.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void rendererBaseGetCurrentValue() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/50000-java/10-rendererBase-getCurrentValue/rendererBase-getCurrentValue.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void ajaxExecute() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/50000-java/20-ajax-execute/ajax-execute.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void ajaxSpecialCharacter() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/50000-java/30-ajax-special-character/ajax-special-character.xhtml";
- runStandardTest(page);
- }
-
- @Test
- public void testBehavior() throws UnsupportedEncodingException, InterruptedException {
- final String page = "content/40-test/6500-behavior/behavior.xhtml";
- runStandardTest(page);
- }
-}
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
new file mode 100644
index 0000000..9485052
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/AccessAllPagesTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.Assert;
+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.WebElement;
+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.net.MalformedURLException;
+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.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(AccessAllPagesTest.class);
+
+ /**
+ * Verify if qunit test for "no exception".
+ */
+ @ParameterizedTest
+ @MethodSource("verifyNoException404TestProvider")
+ void verifyNoExceptionTest(Browser browser, String portContextPath) throws MalformedURLException,
+ UnsupportedEncodingException, UnknownHostException {
+ LOG.info("browser: " + browser + " - port and context path: " + portContextPath);
+
+ setupBrowser(browser);
+
+ final String path = "error/exception.xhtml";
+ setupWebDriver(portContextPath, path, true);
+
+ WebElement qunitBanner = webDriver.findElement(By.id("qunit-banner"));
+ WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
+
+ new FluentWait(webDriver)
+ .withTimeout(Duration.ofSeconds(90))
+ .pollingEvery(Duration.ofSeconds(1))
+ .until(ExpectedConditions.attributeToBeNotEmpty(qunitBanner, "class"));
+
+ 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())) {
+ Assert.assertEquals(result.getAttribute("class"), "fail");
+ testException = true;
+ }
+ }
+ Assert.assertTrue("Could not verify 'has no exception' test.", testException);
+
+ webDriver.quit();
+ }
+
+ /**
+ * Verify if qunit test for "no 404".
+ */
+ @ParameterizedTest
+ @MethodSource("verifyNoException404TestProvider")
+ void verifyNo404Test(Browser browser, String portContextPath) throws MalformedURLException,
+ UnsupportedEncodingException, UnknownHostException {
+ LOG.info("browser: " + browser + " - port and context path: " + portContextPath);
+
+ setupBrowser(browser);
+
+ final String path = "error/404.xhtml";
+ setupWebDriver(portContextPath, path, true);
+
+ WebElement qunitBanner = webDriver.findElement(By.id("qunit-banner"));
+ WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
+
+ new FluentWait(webDriver)
+ .withTimeout(Duration.ofSeconds(90))
+ .pollingEvery(Duration.ofSeconds(1))
+ .until(ExpectedConditions.attributeToBeNotEmpty(qunitBanner, "class"));
+
+ 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())) {
+ Assert.assertEquals(result.getAttribute("class"), "fail");
+ test404 = true;
+ }
+ }
+ Assert.assertTrue("Could not verify 'has no 404' test.", test404);
+
+ webDriver.quit();
+ }
+
+ @ParameterizedTest
+ @MethodSource("accessAllPagesProvider")
+ void testAccessAllPages(Browser browser, String portContextPath, String path) throws MalformedURLException,
+ UnsupportedEncodingException, UnknownHostException {
+ LOG.info("browser: " + browser + " - port and context path: " + portContextPath + " - path: " + path);
+
+ setupBrowser(browser);
+ setupWebDriver(portContextPath, path, true);
+
+ parseQUnitResults(browser, portContextPath, path);
+
+ webDriver.quit();
+ }
+
+ private static Stream<Arguments> verifyNoException404TestProvider() throws IOException {
+ List<Arguments> arguments = new LinkedList<>();
+
+ for (Browser browser : Browser.values()) {
+ for (String portWithContextPath : serverPortWithContextPath) {
+ arguments.add(Arguments.of(browser, portWithContextPath));
+ }
+ }
+
+ return arguments.stream();
+ }
+
+ 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()))
+ .filter(s -> !s.startsWith("content/40-test/90000-attic")) // ignore 90000-attic
+ .sorted()
+ .collect(Collectors.toList());
+
+ List<Arguments> arguments = new LinkedList<>();
+
+ for (Browser browser : Browser.values()) {
+ for (String portWithContextPath : serverPortWithContextPath) {
+ for (String path : paths) {
+ arguments.add(Arguments.of(browser, portWithContextPath, path));
+ }
+ }
+ }
+
+ return arguments.stream();
+ }
+}
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
new file mode 100644
index 0000000..fa9224d
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/SeleniumBase.java
@@ -0,0 +1,188 @@
+/*
+ * 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.Assert;
+import org.junit.jupiter.api.AfterEach;
+import org.openqa.selenium.By;
+import org.openqa.selenium.MutableCapabilities;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+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.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.time.Duration;
+import java.util.List;
+
+abstract class SeleniumBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SeleniumBase.class);
+
+ WebDriver webDriver;
+
+ @AfterEach
+ void tearDown() {
+ if (webDriver != null) {
+ webDriver.quit();
+ }
+ }
+
+ enum Browser {
+ chrome, firefox
+ }
+
+ static String[] serverPortWithContextPath = {
+ "8081/tobago-example-demo"
+ };
+
+ void setupBrowser(final Browser browser) throws MalformedURLException {
+ MutableCapabilities options = null;
+ switch (browser) {
+ case chrome:
+ options = new ChromeOptions();
+ break;
+ case firefox:
+ options = new FirefoxOptions();
+ break;
+ }
+
+ webDriver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), new DesiredCapabilities(options));
+ }
+
+ void setupWebDriver(final String portContextPath, final String path, final boolean accessTest)
+ throws UnknownHostException, UnsupportedEncodingException {
+ final String hostAddress = InetAddress.getLocalHost().getHostAddress();
+ final String base = path.substring(0, path.length() - 6);
+ final String url = "http://" + hostAddress + ":" + portContextPath + "/test.xhtml?base="
+ + URLEncoder.encode(base, "UTF-8") + (accessTest ? "&accessTest=true" : "");
+ webDriver.get(url);
+ }
+
+ void parseQUnitResults(final Browser browser, final String portContextPath, final String path) throws UnknownHostException {
+ WebElement qunitBanner = webDriver.findElement(By.id("qunit-banner"));
+ WebElement qunitTestResult = webDriver.findElement(By.id("qunit-testresult"));
+ WebElement qunitTests = webDriver.findElement(By.id("qunit-tests"));
+
+ new FluentWait(webDriver)
+ .withTimeout(Duration.ofSeconds(90))
+ .pollingEvery(Duration.ofSeconds(1))
+ .until(ExpectedConditions.attributeToBeNotEmpty(qunitBanner, "class"));
+
+ final List<WebElement> testCases = qunitTests.findElements(By.xpath("li"));
+ Assert.assertTrue("There must be at least one test case.", testCases.size() > 0);
+
+ final boolean testFailed = qunitBanner.getAttribute("class").equals("qunit-fail");
+
+ 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 hostAddress = InetAddress.getLocalHost().getHostAddress();
+ final String url = "http://" + hostAddress + ":" + portContextPath + "/" + path;
+ if (testFailed) {
+ final String message = "\n❌ FAILED: Tests with '" + browser + "' for " + url + "\n" + stringBuilder.toString();
+ LOG.warn(message);
+ Assert.fail(message);
+ } else {
+ final String message = "\n✅ PASSED: Tests with '" + browser + "' for " + url + "\n" + stringBuilder.toString();
+ LOG.info(message);
+ Assert.assertTrue(message, true);
+ }
+ }
+
+ 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
new file mode 100644
index 0000000..370429e
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/test/java/org/apache/myfaces/tobago/example/demo/qunit/StandardTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+class StandardTest extends SeleniumBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(StandardTest.class);
+
+ /**
+ * To test only a singe page, just change browser setup, 'portContextPath' and/or 'path'.
+ */
+ @Test
+ void testSinglePage() throws MalformedURLException, UnknownHostException, UnsupportedEncodingException {
+ final Browser browser = Browser.chrome;
+ final String portContextPath = serverPortWithContextPath[0];
+ final String path = "content/10-intro/intro.xhtml";
+
+ LOG.info("browser: " + browser + " - port and context path: " + portContextPath + " - path: " + path);
+
+ setupBrowser(browser);
+ setupWebDriver(portContextPath, path, false);
+
+ parseQUnitResults(browser, portContextPath, path);
+
+ webDriver.quit();
+ }
+
+ @ParameterizedTest
+ @MethodSource("standardTestProvider")
+ void testStandard(Browser browser, String portContextPath, String path) throws MalformedURLException,
+ UnknownHostException, UnsupportedEncodingException {
+ LOG.info("browser: " + browser + " - port and context path: " + portContextPath + " - path: " + path);
+
+ setupBrowser(browser);
+ setupWebDriver(portContextPath, path, false);
+
+ parseQUnitResults(browser, portContextPath, path);
+
+ webDriver.quit();
+ }
+
+ private static Stream<Arguments> standardTestProvider() throws IOException {
+ final List<String> paths = 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());
+
+ List<Arguments> arguments = new LinkedList<>();
+
+ for (Browser browser : Browser.values()) {
+ for (String portWithContextPath : serverPortWithContextPath) {
+ for (String path : paths) {
+ arguments.add(Arguments.of(browser, portWithContextPath, path));
+ }
+ }
+ }
+
+ return arguments.stream();
+ }
+}
--
To stop receiving notification emails like this one, please contact
hnoeth@apache.org.