myfaces-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hno...@apache.org
Subject [myfaces-tobago] branch master updated: improve jasmine test tools
Date Tue, 28 Apr 2020 18:20:37 GMT
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 fa9a8a5  improve jasmine test tools
fa9a8a5 is described below

commit fa9a8a53a0e837c396f1d75da3a9335e47877753
Author: Henning Nöth <hnoeth@apache.org>
AuthorDate: Tue Apr 28 20:15:18 2020 +0200

    improve jasmine test tools
    
    * add a "event" method for safer execute of dispatchEvent()
    * add logging
    * add a elementByIdFn to select elements within the testframe
    * rewrite tests
    * fix a bug in the sheet sorting demo where the custom filter was filtering the results of the first table.
      This bug only occurs in jasmine tests when submits are executed quickly one after another.
---
 .../example/demo/SheetSortingController.java       |  33 ++++-
 .../20-component/010-input/10-in/In.test.js        |   4 +-
 .../030-select/30-selectOneRadio/Radio.test.js     |  57 ++++----
 .../080-sheet/10-sort/Sheet_Sorting.test.js        | 146 +++++++++------------
 .../080-sheet/10-sort/Sheet_Sorting.xhtml          |   4 +-
 .../00-collapsible-box/Collapsible_Box.test.js     |  53 ++++----
 .../src/main/webapp/script/tobago-test.js          |   8 +-
 .../resources/tobago/test/tobago-test-tool.js      |  26 ++++
 8 files changed, 180 insertions(+), 151 deletions(-)

diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetSortingController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetSortingController.java
index 3e2a9f8..29ab595 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetSortingController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetSortingController.java
@@ -25,22 +25,37 @@ import org.apache.myfaces.tobago.model.SheetState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.PostConstruct;
 import javax.enterprise.context.SessionScoped;
 import javax.faces.context.FacesContext;
 import javax.faces.event.ActionEvent;
+import javax.inject.Inject;
 import javax.inject.Named;
 import java.io.Serializable;
 import java.lang.invoke.MethodHandles;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @SessionScoped
 @Named
-public class SheetSortingController extends SheetController implements Serializable {
+public class SheetSortingController implements Serializable {
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
+  @Inject
+  private AstroData astroData;
+
+  private List<SolarObject> solarList1;
+  private List<SolarObject> solarList2;
+
+  @PostConstruct
+  private void init() {
+    solarList1 = astroData.findAll().collect(Collectors.toList());
+    solarList2 = astroData.findAll().collect(Collectors.toList());
+  }
+
   public void sheetSorter(final ActionEvent event) {
     if (event instanceof SortActionEvent) {
       final SortActionEvent sortEvent = (SortActionEvent) event;
@@ -68,4 +83,20 @@ public class SheetSortingController extends SheetController implements Serializa
       Collections.reverse(list);
     }
   }
+
+  public List<SolarObject> getSolarList1() {
+    return solarList1;
+  }
+
+  public void setSolarList1(List<SolarObject> solarList1) {
+    this.solarList1 = solarList1;
+  }
+
+  public List<SolarObject> getSolarList2() {
+    return solarList2;
+  }
+
+  public void setSolarList2(List<SolarObject> solarList2) {
+    this.solarList2 = solarList2;
+  }
 }
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/10-in/In.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/10-in/In.test.js
index d551113..fca385e 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/10-in/In.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/10-in/In.test.js
@@ -36,8 +36,8 @@ it("ajax change event", function (done) {
 
   const test = new JasmineTestTool(done);
   test.do(() => inputFieldFn().value = "some input text");
-  test.do(() => inputFieldFn().dispatchEvent(new Event("change", {bubbles: true})));
-  test.wait(() => outputFieldFn() && outputFieldFn().textContent === "some input text");
+  test.event("change", inputFieldFn,
+      () => outputFieldFn() && outputFieldFn().textContent === "some input text");
   test.do(() => expect(outputFieldFn().textContent).toBe("some input text"));
   test.start();
 });
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.test.js
index 891b604..a16f422 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/030-select/30-selectOneRadio/Radio.test.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
+import {elementByIdFn, querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
 import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
 
 it("submit: Addition (2 + 4)", function (done) {
@@ -31,8 +31,7 @@ it("submit: Addition (2 + 4)", function (done) {
   test.do(() => number2Fn().item(0).checked = false);
   test.do(() => number2Fn().item(1).checked = false);
   test.do(() => number2Fn().item(2).checked = true); // Select 4
-  test.do(() => submitAddFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => outputFn() && outputFn().textContent === "6");
+  test.event("click", submitAddFn, () => outputFn() && outputFn().textContent === "6");
   test.do(() => expect(outputFn().textContent).toBe("6"));
   test.start();
 });
@@ -50,46 +49,40 @@ it("submit: Subtraction (4 - 1)", function (done) {
   test.do(() => number2Fn().item(0).checked = true); // Select 1
   test.do(() => number2Fn().item(1).checked = false);
   test.do(() => number2Fn().item(2).checked = false);
-  test.do(() => submitSubFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => outputFn() && outputFn().textContent === "3");
+  test.event("click", submitSubFn, () => outputFn() && outputFn().textContent === "3");
   test.do(() => expect(outputFn().textContent).toBe("3"));
   test.start();
 });
-
 it("ajax: select Mars", function (done) {
-  let planetFn = querySelectorAllFn("#page\\:mainForm\\:selectPlanet input");
-  let moonsFn = querySelectorAllFn("#page\\:mainForm\\:moonradio label.form-check-label");
+  const earthFn = elementByIdFn("page:mainForm:selectPlanet::0");
+  const marsFn = elementByIdFn("page:mainForm:selectPlanet::1");
+  const jupiterFn = elementByIdFn("page:mainForm:selectPlanet::2");
+  const moonsFn = querySelectorAllFn("#page\\:mainForm\\:moonradio .custom-control-label");
 
   const test = new JasmineTestTool(done);
-  test.do(() => planetFn().item(0).checked = false);
-  test.do(() => planetFn().item(2).checked = false);
-  test.do(() => planetFn().item(1).checked = true); // Mars.
-  test.do(() => planetFn().item(1).dispatchEvent(new Event("change", {bubbles: true})));
-  test.wait(() => moonsFn()
-      && moonsFn().item(0).textContent === "Phobos" && moonsFn().item(1).textContent === "Deimos");
-  test.do(() => expect(moonsFn().item(0).textContent).toBe("Phobos"));
-  test.do(() => expect(moonsFn().item(1).textContent).toBe("Deimos"));
+  test.do(() => earthFn().checked = false);
+  test.do(() => marsFn().checked = true);
+  test.do(() => jupiterFn().checked = false);
+  test.event("change", marsFn, () => moonsFn() && moonsFn()[0].textContent === "Phobos");
+  test.do(() => expect(moonsFn()[0].textContent).toBe("Phobos"));
+  test.do(() => expect(moonsFn()[1].textContent).toBe("Deimos"));
   test.start();
 });
 
 it("ajax: select Jupiter", function (done) {
-  let planetFn = querySelectorAllFn("#page\\:mainForm\\:selectPlanet input");
-  let moonsFn = querySelectorAllFn("#page\\:mainForm\\:moonradio label.form-check-label");
+  const earthFn = elementByIdFn("page:mainForm:selectPlanet::0");
+  const marsFn = elementByIdFn("page:mainForm:selectPlanet::1");
+  const jupiterFn = elementByIdFn("page:mainForm:selectPlanet::2");
+  const moonsFn = querySelectorAllFn("#page\\:mainForm\\:moonradio .custom-control-label");
 
   const test = new JasmineTestTool(done);
-  test.do(() => planetFn().item(0).checked = false);
-  test.do(() => planetFn().item(1).checked = false);
-  test.do(() => planetFn().item(2).checked = true); // Jupiter.
-  test.do(() => planetFn().item(2).dispatchEvent(new Event("change", {bubbles: true})));
-  test.wait(() => moonsFn() &&
-      moonsFn().item(0).textContent === "Europa"
-      && moonsFn().item(1).textContent === "Ganymed"
-      && moonsFn().item(2).textContent === "Io"
-      && moonsFn().item(3).textContent === "Kallisto"
-  );
-  test.do(() => expect(moonsFn().item(0).textContent).toBe("Europa"));
-  test.do(() => expect(moonsFn().item(1).textContent).toBe("Ganymed"));
-  test.do(() => expect(moonsFn().item(2).textContent).toBe("Io"));
-  test.do(() => expect(moonsFn().item(3).textContent).toBe("Kallisto"));
+  test.do(() => earthFn().checked = false);
+  test.do(() => marsFn().checked = false);
+  test.do(() => jupiterFn().checked = true);
+  test.event("change", jupiterFn, () => moonsFn() && moonsFn()[0].textContent === "Europa");
+  test.do(() => expect(moonsFn()[0].textContent).toBe("Europa"));
+  test.do(() => expect(moonsFn()[1].textContent).toBe("Ganymed"));
+  test.do(() => expect(moonsFn()[2].textContent).toBe("Io"));
+  test.do(() => expect(moonsFn()[3].textContent).toBe("Kallisto"));
   test.start()
 });
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.test.js
index 4677fe1..7afdb69 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.test.js
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import {querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
+import {elementByIdFn, querySelectorAllFn, querySelectorFn} from "/script/tobago-test.js";
 import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
 
 it("Basics: Name", function (done) {
@@ -36,8 +36,7 @@ it("Basics: Name", function (done) {
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colNameFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colNameFn, () => waitForBodyTable(rowsFn(),
       "Proteus", "1.12", "1989",
       "Prospero", "-1962.95", "1999",
       "Prometheus", "0.61", "1980",
@@ -47,8 +46,7 @@ it("Basics: Name", function (done) {
       "Prospero", "-1962.95", "1999",
       "Prometheus", "0.61", "1980",
       "Praxidike", "625.3", "2000"));
-  test.do(() => colNameFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colNameFn, () => waitForBodyTable(rowsFn(),
       "Earth", "365.26", "",
       "Elara", "259.65", "1905",
       "Enceladus", "1.37", "1789",
@@ -74,13 +72,12 @@ it("Basics: Period", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Rosalind",
       () => {
         leftPagingFn().value = "29";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colPeriodFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colPeriodFn, () => waitForBodyTable(rowsFn(),
       "Callisto", "16.69", "1610",
       "Titan", "15.95", "1655",
       "Oberon", "13.46", "1787",
@@ -90,8 +87,7 @@ it("Basics: Period", function (done) {
       "Titan", "15.95", "1655",
       "Oberon", "13.46", "1787",
       "Titania", "8.71", "1787"));
-  test.do(() => colPeriodFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colPeriodFn, () => waitForBodyTable(rowsFn(),
       "Rosalind", "0.56", "1986",
       "Pan", "0.58", "1990",
       "Atlas", "0.6", "1980",
@@ -117,19 +113,19 @@ it("Basics: Year", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Amalthea",
       () => {
         leftPagingFn().value = "22";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colYearFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1999");
+  test.event("click", colYearFn,
+      () => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1999");
   test.do(() => expect(rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent).toBe("1999"));
   test.do(() => expect(rowsFn()[1].querySelectorAll(".tobago-out")[2].textContent).toBe("1999"));
   test.do(() => expect(rowsFn()[2].querySelectorAll(".tobago-out")[2].textContent).toBe("1997"));
   test.do(() => expect(rowsFn()[3].querySelectorAll(".tobago-out")[2].textContent).toBe("1997"));
-  test.do(() => colYearFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1892");
+  test.event("click", colYearFn,
+      () => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1892");
   test.do(() => expect(rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent).toBe("1892"));
   test.do(() => expect(rowsFn()[1].querySelectorAll(".tobago-out")[2].textContent).toBe("1898"));
   test.do(() => expect(rowsFn()[2].querySelectorAll(".tobago-out")[2].textContent).toBe("1904"));
@@ -154,14 +150,13 @@ it("Basics: left paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "1986U10",
       () => {
         leftPagingFn().value = "1";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
   test.do(() => leftPagingFn().value = "8");
-  test.do(() => leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("blur", leftPagingFn, () => waitForBodyTable(rowsFn(),
       "Bianca", "0.43", "1986",
       "Caliban", "-579.39", "1997",
       "Callirrhoe", "758.8", "2000",
@@ -172,8 +167,7 @@ it("Basics: left paging", function (done) {
       "Callirrhoe", "758.8", "2000",
       "Callisto", "16.69", "1610"));
   test.do(() => leftPagingFn().value = "9");
-  test.do(() => leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("blur", leftPagingFn, () => waitForBodyTable(rowsFn(),
       "Caliban", "-579.39", "1997",
       "Callirrhoe", "758.8", "2000",
       "Callisto", "16.69", "1610",
@@ -195,7 +189,9 @@ it("Basics: center paging", function (done) {
   let colNameFn = querySelectorFn("#page\\:mainForm\\:s1\\:columnName_sorter");
   let rowsFn = querySelectorAllFn("#page\\:mainForm\\:s1 .tobago-sheet-bodyTable tbody .tobago-sheet-row");
   let leftPagingFn = querySelectorFn("#page\\:mainForm\\:s1 .tobago-sheet-paging-markup-left input");
-  let centerPagingFn = querySelectorAllFn("#page\\:mainForm\\:s1 .tobago-sheet-paging-markup-center li .page-link");
+  let centerPaging7Fn = elementByIdFn("page:mainForm:s1:pageActiontoPage-7");
+  let centerPaging14Fn = elementByIdFn("page:mainForm:s1:pageActiontoPage-14");
+  let centerPaging16Fn = elementByIdFn("page:mainForm:s1:pageActiontoPage-16");
 
   let test = new JasmineTestTool(done);
   test.setup(
@@ -205,13 +201,12 @@ it("Basics: center paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "1986U10",
       () => {
         leftPagingFn().value = "1";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => centerPagingFn().item(6).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging7Fn, () => waitForBodyTable(rowsFn(),
       "Epimetheus", "0.69", "1980",
       "Erinome", "728.3", "2000",
       "Europa", "3.55", "1610",
@@ -221,8 +216,7 @@ it("Basics: center paging", function (done) {
       "Erinome", "728.3", "2000",
       "Europa", "3.55", "1610",
       "Galatea", "0.43", "1989"));
-  test.do(() => centerPagingFn().item(10).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging16Fn, () => waitForBodyTable(rowsFn(),
       "Phoebe", "-550.48", "1898",
       "Pluto", "90800.0", "1930",
       "Portia", "0.51", "1986",
@@ -232,8 +226,7 @@ it("Basics: center paging", function (done) {
       "Pluto", "90800.0", "1930",
       "Portia", "0.51", "1986",
       "Praxidike", "625.3", "2000"));
-  test.do(() => centerPagingFn().item(3).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging14Fn, () => waitForBodyTable(rowsFn(),
       "Neptune", "60190.0", "1846",
       "Nereid", "360.13", "1949",
       "Oberon", "13.46", "1787",
@@ -257,7 +250,10 @@ it("Basics: right paging", function (done) {
   let colNameFn = querySelectorFn("#page\\:mainForm\\:s1\\:columnName_sorter");
   let rowsFn = querySelectorAllFn("#page\\:mainForm\\:s1 .tobago-sheet-bodyTable tbody .tobago-sheet-row");
   let leftPagingFn = querySelectorFn("#page\\:mainForm\\:s1 .tobago-sheet-paging-markup-left input");
-  let rightPagingFn = querySelectorAllFn("#page\\:mainForm\\:s1 .tobago-sheet-paging-markup-right .page-link");
+  let rightPagingFirstFn = elementByIdFn("page:mainForm:s1:pageActionfirst");
+  let rightPagingPrevFn = elementByIdFn("page:mainForm:s1:pageActionprev");
+  let rightPagingNextFn = elementByIdFn("page:mainForm:s1:pageActionnext");
+  let rightPagingLastFn = elementByIdFn("page:mainForm:s1:pageActionlast");
   let jumpToPageFn = querySelectorFn("#page\\:mainForm\\:s1 .tobago-sheet-paging-markup-right .page-link input");
 
   let test = new JasmineTestTool(done);
@@ -268,13 +264,12 @@ it("Basics: right paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Earth",
       () => {
         leftPagingFn().value = "22";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => rightPagingFn().item(0).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingFirstFn, () => waitForBodyTable(rowsFn(),
       "1986U10", "0.64", "1999",
       "Adrastea", "0.3", "1979",
       "Amalthea", "0.5", "1892",
@@ -284,8 +279,7 @@ it("Basics: right paging", function (done) {
       "Adrastea", "0.3", "1979",
       "Amalthea", "0.5", "1892",
       "Ananke", "-629.77", "1951"));
-  test.do(() => rightPagingFn().item(3).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingNextFn, () => waitForBodyTable(rowsFn(),
       "Ariel", "2.52", "1851",
       "Atlas", "0.6", "1980",
       "Belinda", "0.62", "1986",
@@ -295,8 +289,7 @@ it("Basics: right paging", function (done) {
       "Atlas", "0.6", "1980",
       "Belinda", "0.62", "1986",
       "Bianca", "0.43", "1986"));
-  test.do(() => rightPagingFn().item(4).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingLastFn, () => waitForBodyTable(rowsFn(),
       "Triton", "-5.88", "1846",
       "Umbriel", "4.14", "1851",
       "Uranus", "30685.0", "1781",
@@ -306,8 +299,7 @@ it("Basics: right paging", function (done) {
       "Umbriel", "4.14", "1851",
       "Uranus", "30685.0", "1781",
       "Venus", "224.7", ""));
-  test.do(() => rightPagingFn().item(1).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingPrevFn, () => waitForBodyTable(rowsFn(),
       "Thebe", "0.67", "1979",
       "Themisto", "130.02", "2000",
       "Titan", "15.95", "1655",
@@ -318,8 +310,7 @@ it("Basics: right paging", function (done) {
       "Titan", "15.95", "1655",
       "Titania", "8.71", "1787"));
   test.do(() => jumpToPageFn().value = "14");
-  test.do(() => jumpToPageFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("blur", jumpToPageFn, () => waitForBodyTable(rowsFn(),
       "Neptune", "60190.0", "1846",
       "Nereid", "360.13", "1949",
       "Oberon", "13.46", "1787",
@@ -345,13 +336,12 @@ it("Custom Sorting: Name", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Earth",
       () => {
         leftPagingFn().value = "22";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colNameFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colNameFn, () => waitForBodyTable(rowsFn(),
       "Proteus", "1.12", "1989",
       "Prospero", "-1962.95", "1999",
       "Prometheus", "0.61", "1980",
@@ -361,8 +351,7 @@ it("Custom Sorting: Name", function (done) {
       "Prospero", "-1962.95", "1999",
       "Prometheus", "0.61", "1980",
       "Praxidike", "625.3", "2000"));
-  test.do(() => colNameFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colNameFn, () => waitForBodyTable(rowsFn(),
       "Earth", "365.26", "",
       "Elara", "259.65", "1905",
       "Enceladus", "1.37", "1789",
@@ -388,13 +377,12 @@ it("Custom Sorting: Period", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Mimas",
       () => {
         leftPagingFn().value = "29";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colPeriodFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colPeriodFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colPeriodFn, () => waitForBodyTable(rowsFn(),
       "Elara", "259.65", "1905",
       "Lysithea", "259.22", "1938",
       "Himalia", "250.57", "1904",
@@ -404,8 +392,7 @@ it("Custom Sorting: Period", function (done) {
       "Lysithea", "259.22", "1938",
       "Himalia", "250.57", "1904",
       "Leda", "238.72", "1974"));
-  test.do(() => colPeriodFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", colPeriodFn, () => waitForBodyTable(rowsFn(),
       "Mimas", "0.94", "1789",
       "Proteus", "1.12", "1989",
       "Deimos", "1.26", "1877",
@@ -431,19 +418,19 @@ it("Custom Sorting: Year", function (done) {
       () => rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1789",
       () => {
         leftPagingFn().value = "22";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colYearFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => colYearFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1989");
+  test.event("click", colYearFn,
+      () => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1989");
   test.do(() => expect(rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent).toBe("1989"));
   test.do(() => expect(rowsFn()[1].querySelectorAll(".tobago-out")[2].textContent).toBe("1989"));
   test.do(() => expect(rowsFn()[2].querySelectorAll(".tobago-out")[2].textContent).toBe("1989"));
   test.do(() => expect(rowsFn()[3].querySelectorAll(".tobago-out")[2].textContent).toBe("1986"));
-  test.do(() => colYearFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1789");
+  test.event("click", colYearFn,
+      () => rowsFn() && rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent === "1789");
   test.do(() => expect(rowsFn()[0].querySelectorAll(".tobago-out")[2].textContent).toBe("1789"));
   test.do(() => expect(rowsFn()[1].querySelectorAll(".tobago-out")[2].textContent).toBe("1846"));
   test.do(() => expect(rowsFn()[2].querySelectorAll(".tobago-out")[2].textContent).toBe("1846"));
@@ -468,14 +455,13 @@ it("Custom Sorting: left paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "1986U10",
       () => {
         leftPagingFn().value = "1";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
   test.do(() => leftPagingFn().value = "8");
-  test.do(() => leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("blur", leftPagingFn, () => waitForBodyTable(rowsFn(),
       "Bianca", "0.43", "1986",
       "Caliban", "-579.39", "1997",
       "Callirrhoe", "758.8", "2000",
@@ -486,8 +472,7 @@ it("Custom Sorting: left paging", function (done) {
       "Callirrhoe", "758.8", "2000",
       "Callisto", "16.69", "1610"));
   test.do(() => leftPagingFn().value = "9");
-  test.do(() => leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("blur", leftPagingFn, () => waitForBodyTable(rowsFn(),
       "Caliban", "-579.39", "1997",
       "Callirrhoe", "758.8", "2000",
       "Callisto", "16.69", "1610",
@@ -509,7 +494,9 @@ it("Custom Sorting: center paging", function (done) {
   let colNameFn = querySelectorFn("#page\\:mainForm\\:s2\\:customColumnName_sorter");
   let rowsFn = querySelectorAllFn("#page\\:mainForm\\:s2 .tobago-sheet-bodyTable tbody .tobago-sheet-row");
   let leftPagingFn = querySelectorFn("#page\\:mainForm\\:s2 .tobago-sheet-paging-markup-left input");
-  let centerPagingFn = querySelectorAllFn("#page\\:mainForm\\:s2 .tobago-sheet-paging-markup-center li .page-link");
+  let centerPaging7Fn = elementByIdFn("page:mainForm:s2:pageActiontoPage-7");
+  let centerPaging14Fn = elementByIdFn("page:mainForm:s2:pageActiontoPage-14");
+  let centerPaging16Fn = elementByIdFn("page:mainForm:s2:pageActiontoPage-16");
 
   let test = new JasmineTestTool(done);
   test.setup(
@@ -519,13 +506,12 @@ it("Custom Sorting: center paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "1986U10",
       () => {
         leftPagingFn().value = "1";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => centerPagingFn().item(6).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging7Fn, () => waitForBodyTable(rowsFn(),
       "Epimetheus", "0.69", "1980",
       "Erinome", "728.3", "2000",
       "Europa", "3.55", "1610",
@@ -535,8 +521,7 @@ it("Custom Sorting: center paging", function (done) {
       "Erinome", "728.3", "2000",
       "Europa", "3.55", "1610",
       "Galatea", "0.43", "1989"));
-  test.do(() => centerPagingFn().item(10).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging16Fn, () => waitForBodyTable(rowsFn(),
       "Phoebe", "-550.48", "1898",
       "Pluto", "90800.0", "1930",
       "Portia", "0.51", "1986",
@@ -546,8 +531,7 @@ it("Custom Sorting: center paging", function (done) {
       "Pluto", "90800.0", "1930",
       "Portia", "0.51", "1986",
       "Praxidike", "625.3", "2000"));
-  test.do(() => centerPagingFn().item(3).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", centerPaging14Fn, () => waitForBodyTable(rowsFn(),
       "Neptune", "60190.0", "1846",
       "Nereid", "360.13", "1949",
       "Oberon", "13.46", "1787",
@@ -571,8 +555,11 @@ it("Custom Sorting: right paging", function (done) {
   let colNameFn = querySelectorFn("#page\\:mainForm\\:s2\\:customColumnName_sorter");
   let rowsFn = querySelectorAllFn("#page\\:mainForm\\:s2 .tobago-sheet-bodyTable tbody .tobago-sheet-row");
   let leftPagingFn = querySelectorFn("#page\\:mainForm\\:s2 .tobago-sheet-paging-markup-left input");
-  let rightPagingFn = querySelectorAllFn("#page\\:mainForm\\:s2 .tobago-sheet-paging-markup-right .page-link");
-  let rightPagingInputFn = querySelectorFn("#page\\:mainForm\\:s2 .tobago-sheet-paging-markup-right .page-link input");
+  let rightPagingFirstFn = elementByIdFn("page:mainForm:s2:pageActionfirst");
+  let rightPagingPrevFn = elementByIdFn("page:mainForm:s2:pageActionprev");
+  let rightPagingNextFn = elementByIdFn("page:mainForm:s2:pageActionnext");
+  let rightPagingLastFn = elementByIdFn("page:mainForm:s2:pageActionlast");
+  let rightPagingToPageFn = elementByIdFn("page:mainForm:s2:pageActiontoPage");
 
   let test = new JasmineTestTool(done);
   test.setup(
@@ -582,13 +569,12 @@ it("Custom Sorting: right paging", function (done) {
       () => rowsFn()[0].querySelector(".tobago-out").textContent === "Earth",
       () => {
         leftPagingFn().value = "22";
-        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}))
+        leftPagingFn().dispatchEvent(new Event("blur", {bubbles: true}));
       });
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-sortable")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-ascending")).toBe(true));
   test.do(() => expect(colNameFn().classList.contains("tobago-sheet-header-markup-descending")).not.toBe(true));
-  test.do(() => rightPagingFn().item(0).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingFirstFn, () => waitForBodyTable(rowsFn(),
       "1986U10", "0.64", "1999",
       "Adrastea", "0.3", "1979",
       "Amalthea", "0.5", "1892",
@@ -598,8 +584,7 @@ it("Custom Sorting: right paging", function (done) {
       "Adrastea", "0.3", "1979",
       "Amalthea", "0.5", "1892",
       "Ananke", "-629.77", "1951"));
-  test.do(() => rightPagingFn().item(3).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingNextFn, () => waitForBodyTable(rowsFn(),
       "Ariel", "2.52", "1851",
       "Atlas", "0.6", "1980",
       "Belinda", "0.62", "1986",
@@ -609,8 +594,7 @@ it("Custom Sorting: right paging", function (done) {
       "Atlas", "0.6", "1980",
       "Belinda", "0.62", "1986",
       "Bianca", "0.43", "1986"));
-  test.do(() => rightPagingFn().item(4).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingLastFn, () => waitForBodyTable(rowsFn(),
       "Triton", "-5.88", "1846",
       "Umbriel", "4.14", "1851",
       "Uranus", "30685.0", "1781",
@@ -620,8 +604,7 @@ it("Custom Sorting: right paging", function (done) {
       "Umbriel", "4.14", "1851",
       "Uranus", "30685.0", "1781",
       "Venus", "224.7", ""));
-  test.do(() => rightPagingFn().item(1).dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.event("click", rightPagingPrevFn, () => waitForBodyTable(rowsFn(),
       "Thebe", "0.67", "1979",
       "Themisto", "130.02", "2000",
       "Titan", "15.95", "1655",
@@ -631,9 +614,8 @@ it("Custom Sorting: right paging", function (done) {
       "Themisto", "130.02", "2000",
       "Titan", "15.95", "1655",
       "Titania", "8.71", "1787"));
-  test.do(() => rightPagingInputFn().value = "14");
-  test.do(() => rightPagingInputFn().dispatchEvent(new Event("blur", {bubbles: true})));
-  test.wait(() => waitForBodyTable(rowsFn(),
+  test.do(() => rightPagingToPageFn().value = "14");
+  test.event("blur", rightPagingToPageFn, () => waitForBodyTable(rowsFn(),
       "Neptune", "60190.0", "1846",
       "Nereid", "360.13", "1949",
       "Oberon", "13.46", "1787",
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.xhtml
index 7ee3c25..56f3b1b 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/080-sheet/10-sort/Sheet_Sorting.xhtml
@@ -41,7 +41,7 @@
     <p>In this example, the <code>sortable</code> attribute is 'true' for all columns.
       Notice, that there are negative periods.</p>
     <pre><code class="language-markup">&lt;tc:column label="Name" sortable="true"></code></pre>
-    <tc:sheet id="s1" value="#{sheetSortingController.solarList}" var="object" rows="4" markup="small">
+    <tc:sheet id="s1" value="#{sheetSortingController.solarList1}" var="object" rows="4" markup="small">
       <tc:column id="columnName" label="Name" sortable="true">
         <tc:out value="#{object.name}" labelLayout="skip"/>
       </tc:column>
@@ -68,7 +68,7 @@
       ...
     </code></pre>
 
-    <tc:sheet id="s2" value="#{sheetSortingController.solarList}" var="object" rows="4"
+    <tc:sheet id="s2" value="#{sheetSortingController.solarList2}" var="object" rows="4"
               sortActionListener="#{sheetSortingController.sheetSorter}" markup="small">
       <tc:column id="customColumnName" label="Name" sortable="true">
         <tc:out value="#{object.name}" labelLayout="skip"/>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/53-collapsible/00-collapsible-box/Collapsible_Box.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/53-collapsible/00-collapsible-box/Collapsible_Box.test.js
index 9c56a8d..47a7864 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/53-collapsible/00-collapsible-box/Collapsible_Box.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/53-collapsible/00-collapsible-box/Collapsible_Box.test.js
@@ -28,8 +28,7 @@ it("Simple Collapsible Box: show -> hide transition", function (done) {
       () => contentFn(),
       () => showFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(contentFn() !== null).toBe(true));
-  test.do(() => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !contentFn());
+  test.event("click", hideFn, () => !contentFn());
   test.do(() => expect(contentFn() !== null).toBe(false));
   test.start();
 });
@@ -44,8 +43,7 @@ it("Simple Collapsible Box: hide -> show transition", function (done) {
       () => !contentFn(),
       () => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(contentFn() !== null).toBe(false));
-  test.do(() => showFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => contentFn());
+  test.event("click", showFn, () => contentFn());
   test.do(() => expect(contentFn() !== null).toBe(true));
   test.start();
 });
@@ -67,12 +65,10 @@ it("Full Server Request: open both boxes", function (done) {
       () => hide2Fn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(content1Fn() !== null).toBe(false));
   test.do(() => expect(content2Fn() !== null).toBe(false));
-  test.do(() => show1Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => content1Fn());
+  test.event("click", show1Fn, () => content1Fn());
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(false));
-  test.do(() => show2Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => content2Fn());
+  test.event("click", show2Fn, () => content2Fn());
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(true));
   test.start();
@@ -95,12 +91,10 @@ it("Full Server Request: open box 1, close box 2", function (done) {
       () => show2Fn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(content1Fn() !== null).toBe(false));
   test.do(() => expect(content2Fn() !== null).toBe(true));
-  test.do(() => show1Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => content1Fn());
+  test.event("click", show1Fn, () => content1Fn());
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(true));
-  test.do(() => hide2Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !content2Fn());
+  test.event("click", hide2Fn, () => !content2Fn());
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(false));
   test.start();
@@ -123,12 +117,10 @@ it("Full Server Request: close box 1, open box 2", function (done) {
       () => hide2Fn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(false));
-  test.do(() => hide1Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !content1Fn());
+  test.event("click", hide1Fn, () => !content1Fn());
   test.do(() => expect(content1Fn() !== null).toBe(false))
   test.do(() => expect(content2Fn() !== null).toBe(false));
-  test.do(() => show2Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => content2Fn());
+  test.event("click", show2Fn, () => content2Fn());
   test.do(() => expect(content1Fn() !== null).toBe(false));
   test.do(() => expect(content2Fn() !== null).toBe(true));
   test.start();
@@ -151,12 +143,10 @@ it("Full Server Request: close both boxes", function (done) {
       () => show2Fn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(content1Fn() !== null).toBe(true));
   test.do(() => expect(content2Fn() !== null).toBe(true));
-  test.do(() => hide1Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !content1Fn());
+  test.event("click", hide1Fn, () => !content1Fn());
   test.do(() => expect(content1Fn() !== null).toBe(false));
   test.do(() => expect(content2Fn() !== null).toBe(true));
-  test.do(() => hide2Fn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !content2Fn());
+  test.event("click", hide2Fn, () => !content2Fn());
   test.do(() => expect(content1Fn() !== null).toBe(false));
   test.do(() => expect(content2Fn() !== null).toBe(false));
   test.start();
@@ -205,8 +195,7 @@ it("Client Side: hide content and submit empty string", function (done) {
   test.do(() => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(boxFn().classList.contains("tobago-collapsed")).toBe(true));
   test.do(() => inFn().value = "");
-  test.do(() => submitFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => messagesFn() && messagesFn().length === 1);
+  test.event("click", submitFn, () => messagesFn() && messagesFn().length === 1);
   test.do(() => expect(messagesFn().length).toBe(1));
   test.start();
 });
@@ -221,8 +210,7 @@ it("Ajax: show -> hide transition", function (done) {
       () => inFn(),
       () => showFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(inFn() !== null).toBe(true));
-  test.do(() => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !inFn());
+  test.event("click", hideFn, () => !inFn());
   test.do(() => expect(inFn() !== null).toBe(false));
   test.start();
 });
@@ -237,13 +225,13 @@ it("Ajax: hide -> show transition", function (done) {
       () => !inFn(),
       () => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(inFn() !== null).toBe(false));
-  test.do(() => showFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => inFn());
+  test.event("click", showFn, () => inFn());
   test.do(() => expect(inFn() !== null).toBe(true));
   test.start();
 });
 
-it("Ajax: hide content and submit empty string", function (done) {
+it("Ajax: submit empty string with shown and hidden content", function (done) {
+  let hide1FullReqFn = querySelectorFn("#page\\:mainForm\\:server\\:hide1");
   let messagesFn = querySelectorAllFn("#page\\:messages.tobago-messages .alert");
   let showFn = querySelectorFn("#page\\:mainForm\\:ajax\\:showAjaxBox");
   let hideFn = querySelectorFn("#page\\:mainForm\\:ajax\\:hideAjaxBox");
@@ -254,13 +242,16 @@ it("Ajax: hide content and submit empty string", function (done) {
   test.setup(
       () => inFn(),
       () => showFn().dispatchEvent(new Event("click", {bubbles: true})));
+  test.setup(
+      () => messagesFn() && messagesFn().length === 0,
+      () => hide1FullReqFn().dispatchEvent(new Event("click", {bubbles: true})));
   test.do(() => expect(inFn() !== null).toBe(true));
   test.do(() => inFn().value = "");
-  test.do(() => hideFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => !inFn());
+  test.event("click", submitFn, () => messagesFn() && messagesFn().length === 1);
+  test.do(() => expect(messagesFn().length).toBe(1));
+  test.event("click", hideFn, () => !inFn());
   test.do(() => expect(inFn() !== null).toBe(false));
-  test.do(() => submitFn().dispatchEvent(new Event("click", {bubbles: true})));
-  test.wait(() => messagesFn() && messagesFn().length === 0);
+  test.event("click", submitFn, () => messagesFn() && messagesFn().length === 0);
   test.do(() => expect(messagesFn().length).toBe(0));
   test.start();
 });
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 7441b5c..b22460e 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
@@ -17,6 +17,12 @@
 
 import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
 
+function elementByIdFn(expression) {
+  return function () {
+    return document.getElementById("page:testframe").contentWindow.document.getElementById(expression);
+  }
+}
+
 function querySelectorFn(expression) {
   return function () {
     return document.getElementById("page:testframe").contentWindow.document.querySelector(expression);
@@ -41,7 +47,7 @@ function testFrameQuerySelectorAllFn(expression) {
   }
 }
 
-export {querySelectorFn, querySelectorAllFn, testFrameQuerySelectorFn, testFrameQuerySelectorAllFn};
+export {elementByIdFn, querySelectorFn, querySelectorAllFn, testFrameQuerySelectorFn, testFrameQuerySelectorAllFn};
 
 QUnit.test("wait for test", function (assert) {
   let done = assert.async();
diff --git a/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js b/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
index 47cb35c..19131ac 100644
--- a/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
+++ b/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
@@ -258,12 +258,32 @@ class JasmineTestTool {
   setup(fn1, fn2) {
     this.do(() => {
       if (!fn1()) {
+        console.debug("[JasmineTestTool] fn1() returns false, execute fn2()");
         fn2();
       }
     })
     this.wait(fn1);
   }
 
+  /**
+   * Execute dispatchEvent() on the given element. The result function must return false before dispatch.
+   * After the dispatch
+   * @param type of the event
+   * @param element function
+   * @param result function
+   */
+  event(type, element, result) {
+    this.do(() => {
+      if (result()) {
+        fail("The result function (" + result + ") returns true BEFORE the '" + type + "' event is dispatched."
+            + " Please define a result function that return false before dispatch event and return true after dispatch"
+            + " event.");
+      }
+    });
+    this.do(() => element().dispatchEvent(new Event(type, {bubbles: true})));
+    this.wait(result);
+  }
+
   do(fn) {
     this.steps.push({
       type: "do",
@@ -281,6 +301,7 @@ class JasmineTestTool {
   }
 
   start() {
+    console.debug("[JasmineTestTool] start");
     this.resetTimeout();
     this.cycle();
   }
@@ -296,14 +317,18 @@ class JasmineTestTool {
       this.resetTimeout();
       window.setTimeout(this.cycle.bind(this), 0);
     } else if (!this.isDocumentReady() || !this.isAjaxReady()) {
+      console.debug("[JasmineTestTool] documentReady: " + this.isDocumentReady()
+          + " - ajaxReady: " + this.isAjaxReady());
       window.setTimeout(this.cycle.bind(this), 50);
     } else if (nextStep.type === "do") {
+      console.debug("[JasmineTestTool] do-step: " + nextStep.func);
       this.registerCustomXmlHttpRequest();
       nextStep.func();
       nextStep.done = true;
       this.resetTimeout();
       window.setTimeout(this.cycle.bind(this), 0);
     } else if (nextStep.type === "wait") {
+      console.debug("[JasmineTestTool] wait-step: " + nextStep.func);
       if (nextStep.func()) {
         nextStep.done = true;
         this.resetTimeout();
@@ -336,6 +361,7 @@ class JasmineTestTool {
 
   static changeAjaxReadyState(event) {
     JasmineTestTool.ajaxReadyState = event.detail.readyState;
+    console.debug("[JasmineTestTool] ajaxReadyState: " + JasmineTestTool.ajaxReadyState);
   }
 
   registerCustomXmlHttpRequest() {


Mime
View raw message