json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Fri, 07 Feb 2014 07:44:34 +0100
changeset 551 7ca2253fa86d
parent 425 6729b08befde
child 569 245637e6d8db
permissions -rw-r--r--
Updating copyright headers to mention current year
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package net.java.html.json.tests;
    44 
    45 import java.util.List;
    46 import net.java.html.BrwsrCtx;
    47 import net.java.html.json.ComputedProperty;
    48 import net.java.html.json.Function;
    49 import net.java.html.json.Model;
    50 import net.java.html.json.Models;
    51 import net.java.html.json.Property;
    52 import org.apidesign.html.json.tck.KOTest;
    53 import org.apidesign.html.json.tck.KnockoutTCK;
    54 
    55 /**
    56  *
    57  * @author Jaroslav Tulach <jtulach@netbeans.org>
    58  */
    59 @Model(className="KnockoutModel", properties={
    60     @Property(name="name", type=String.class),
    61     @Property(name="results", type=String.class, array = true),
    62     @Property(name="callbackCount", type=int.class),
    63     @Property(name="people", type=PersonImpl.class, array = true),
    64     @Property(name="enabled", type=boolean.class),
    65     @Property(name="latitude", type=double.class)
    66 }) 
    67 public final class KnockoutTest {
    68     
    69     @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
    70         Object exp = Utils.exposeHTML(KnockoutTest.class, 
    71             "Latitude: <input id='input' data-bind=\"value: latitude\"></input>\n"
    72         );
    73         try {
    74 
    75             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
    76             m.setLatitude(50.5);
    77             m.applyBindings();
    78 
    79             String v = getSetInput(null);
    80             assert "50.5".equals(v) : "Value is really 50.5: " + v;
    81 
    82             getSetInput("49.5");
    83             triggerEvent("input", "change");
    84 
    85             assert 49.5 == m.getLatitude() : "Double property updated: " + m.getLatitude();
    86         } catch (Throwable t) {
    87             throw t;
    88         } finally {
    89             Utils.exposeHTML(KnockoutTest.class, "");
    90         }
    91     }
    92     
    93     @KOTest public void modifyValueAssertChangeInModelOnBoolean() throws Throwable {
    94         Object exp = Utils.exposeHTML(KnockoutTest.class, 
    95             "Latitude: <input id='input' data-bind=\"value: enabled\"></input>\n"
    96         );
    97         try {
    98 
    99             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   100             m.setEnabled(true);
   101             m.applyBindings();
   102 
   103             String v = getSetInput(null);
   104             assert "true".equals(v) : "Value is really true: " + v;
   105 
   106             getSetInput("false");
   107             triggerEvent("input", "change");
   108 
   109             assert false == m.isEnabled(): "Boolean property updated: " + m.isEnabled();
   110         } catch (Throwable t) {
   111             throw t;
   112         } finally {
   113             Utils.exposeHTML(KnockoutTest.class, "");
   114         }
   115     }
   116     
   117     @KOTest public void modifyValueAssertChangeInModel() throws Exception {
   118         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   119             "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
   120             "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
   121             "<button id=\"hello\">Say Hello!</button>\n"
   122         );
   123         try {
   124 
   125             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   126             m.setName("Kukuc");
   127             m.applyBindings();
   128 
   129             String v = getSetInput(null);
   130             assert "Kukuc".equals(v) : "Value is really kukuc: " + v;
   131 
   132             getSetInput("Jardo");
   133             triggerEvent("input", "change");
   134 
   135             assert "Jardo".equals(m.getName()) : "Name property updated: " + m.getName();
   136         } finally {
   137             Utils.exposeHTML(KnockoutTest.class, "");
   138         }
   139     }
   140     
   141     private static String getSetInput(String value) throws Exception {
   142         String s = "var value = arguments[0];\n"
   143         + "var n = window.document.getElementById('input'); \n "
   144         + "if (value != null) n['value'] = value; \n "
   145         + "return n['value'];";
   146         return (String)Utils.executeScript(
   147             KnockoutTest.class,
   148             s, value
   149         );
   150     }
   151     
   152     public static void triggerEvent(String id, String ev) throws Exception {
   153         Utils.executeScript(
   154             KnockoutTest.class,
   155             "ko.utils.triggerEvent(window.document.getElementById(arguments[0]), arguments[1]);",
   156             id, ev
   157         );
   158     }
   159     
   160     @KOTest public void displayContentOfArray() throws Exception {
   161         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   162             "<ul id='ul' data-bind='foreach: results'>\n"
   163             + "  <li data-bind='text: $data, click: $root.call'/>\n"
   164             + "</ul>\n"
   165         );
   166         try {
   167             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   168             m.getResults().add("Ahoj");
   169             m.applyBindings();
   170 
   171             int cnt = countChildren("ul");
   172             assert cnt == 1 : "One child, but was " + cnt;
   173 
   174             m.getResults().add("Hi");
   175 
   176             cnt = countChildren("ul");
   177             assert cnt == 2 : "Two children now, but was " + cnt;
   178 
   179             triggerChildClick("ul", 1);
   180 
   181             assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
   182             assert "Hi".equals(m.getName()) : "We got callback from 2nd child " + m.getName();
   183         } finally {
   184             Utils.exposeHTML(KnockoutTest.class, "");
   185         }
   186     }
   187     
   188     @KOTest public void displayContentOfComputedArray() throws Exception {
   189         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   190             "<ul id='ul' data-bind='foreach: bothNames'>\n"
   191             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   192             + "</ul>\n"
   193         );
   194         try {
   195             Pair m = Models.bind(new Pair("First", "Last", null), newContext());
   196             m.applyBindings();
   197 
   198             int cnt = countChildren("ul");
   199             assert cnt == 2 : "Two children now, but was " + cnt;
   200 
   201             triggerChildClick("ul", 1);
   202 
   203             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   204         } finally {
   205             Utils.exposeHTML(KnockoutTest.class, "");
   206         }
   207     }
   208     
   209     @KOTest public void displayContentOfComputedArrayOnASubpair() throws Exception {
   210         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   211               "<div data-bind='with: next'>\n"
   212             + "<ul id='ul' data-bind='foreach: bothNames'>\n"
   213             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   214             + "</ul>"
   215             + "</div>\n"
   216         );
   217         try {
   218             Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
   219             m.applyBindings();
   220 
   221             int cnt = countChildren("ul");
   222             assert cnt == 2 : "Two children now, but was " + cnt;
   223 
   224             triggerChildClick("ul", 1);
   225 
   226             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   227         } finally {
   228             Utils.exposeHTML(KnockoutTest.class, "");
   229         }
   230     }
   231     
   232     @KOTest public void displayContentOfComputedArrayOnComputedASubpair() throws Exception {
   233         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   234               "<div data-bind='with: nextOne'>\n"
   235             + "<ul id='ul' data-bind='foreach: bothNames'>\n"
   236             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   237             + "</ul>"
   238             + "</div>\n"
   239         );
   240         try {
   241             Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
   242             m.applyBindings();
   243 
   244             int cnt = countChildren("ul");
   245             assert cnt == 2 : "Two children now, but was " + cnt;
   246 
   247             triggerChildClick("ul", 1);
   248 
   249             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   250         } finally {
   251             Utils.exposeHTML(KnockoutTest.class, "");
   252         }
   253     }
   254 
   255     @KOTest public void checkBoxToBooleanBinding() throws Exception {
   256         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   257             "<input type='checkbox' id='b' data-bind='checked: enabled'></input>\n"
   258         );
   259         try {
   260             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   261             m.applyBindings();
   262 
   263             assert !m.isEnabled() : "Is disabled";
   264 
   265             triggerClick("b");
   266 
   267             assert m.isEnabled() : "Now the model is enabled";
   268         } finally {
   269             Utils.exposeHTML(KnockoutTest.class, "");
   270         }
   271     }
   272     
   273     
   274     
   275     @KOTest public void displayContentOfDerivedArray() throws Exception {
   276         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   277             "<ul id='ul' data-bind='foreach: cmpResults'>\n"
   278             + "  <li><b data-bind='text: $data'></b></li>\n"
   279             + "</ul>\n"
   280         );
   281         try {
   282             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   283             m.getResults().add("Ahoj");
   284             m.applyBindings();
   285 
   286             int cnt = countChildren("ul");
   287             assert cnt == 1 : "One child, but was " + cnt;
   288 
   289             m.getResults().add("hello");
   290 
   291             cnt = countChildren("ul");
   292             assert cnt == 2 : "Two children now, but was " + cnt;
   293         } finally {
   294             Utils.exposeHTML(KnockoutTest.class, "");
   295         }
   296     }
   297     
   298     @KOTest public void displayContentOfArrayOfPeople() throws Exception {
   299         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   300             "<ul id='ul' data-bind='foreach: people'>\n"
   301             + "  <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
   302             + "</ul>\n"
   303         );
   304         try {
   305             final BrwsrCtx c = newContext();
   306             KnockoutModel m = Models.bind(new KnockoutModel(), c);
   307 
   308             final Person first = Models.bind(new Person(), c);
   309             first.setFirstName("first");
   310             m.getPeople().add(first);
   311 
   312             m.applyBindings();
   313 
   314             int cnt = countChildren("ul");
   315             assert cnt == 1 : "One child, but was " + cnt;
   316 
   317             final Person second = Models.bind(new Person(), c);
   318             second.setFirstName("second");
   319             m.getPeople().add(second);
   320 
   321             cnt = countChildren("ul");
   322             assert cnt == 2 : "Two children now, but was " + cnt;
   323 
   324             triggerChildClick("ul", 1);
   325 
   326             assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
   327 
   328             cnt = countChildren("ul");
   329             assert cnt == 1 : "Again one child, but was " + cnt;
   330 
   331             String txt = childText("ul", 0);
   332             assert "first".equals(txt) : "Expecting 'first': " + txt;
   333 
   334             first.setFirstName("changed");
   335 
   336             txt = childText("ul", 0);
   337             assert "changed".equals(txt) : "Expecting 'changed': " + txt;
   338         } finally {
   339             Utils.exposeHTML(KnockoutTest.class, "");
   340         }
   341     }
   342     
   343     @ComputedProperty
   344     static Person firstPerson(List<Person> people) {
   345         return people.isEmpty() ? null : people.get(0);
   346     }
   347     
   348     @KOTest public void accessFirstPersonWithOnFunction() throws Exception {
   349         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   350             "<p id='ul' data-bind='with: firstPerson'>\n"
   351             + "  <span data-bind='text: firstName, click: changeSex'></span>\n"
   352             + "</p>\n"
   353         );
   354         try {
   355             trasfertToFemale();
   356         } finally {
   357             Utils.exposeHTML(KnockoutTest.class, "");
   358         }
   359     }
   360     
   361     @KOTest public void onPersonFunction() throws Exception {
   362         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   363             "<ul id='ul' data-bind='foreach: people'>\n"
   364             + "  <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
   365             + "</ul>\n"
   366         );
   367         try {
   368             trasfertToFemale();
   369         } finally {
   370             Utils.exposeHTML(KnockoutTest.class, "");
   371         }
   372     }
   373     
   374     private void trasfertToFemale() throws Exception {
   375         KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   376 
   377         final Person first = Models.bind(new Person(), newContext());
   378         first.setFirstName("first");
   379         first.setSex(Sex.MALE);
   380         m.getPeople().add(first);
   381 
   382 
   383         m.applyBindings();
   384 
   385         int cnt = countChildren("ul");
   386         assert cnt == 1 : "One child, but was " + cnt;
   387 
   388 
   389         triggerChildClick("ul", 0);
   390 
   391         assert first.getSex() == Sex.FEMALE : "Transverted to female: " + first.getSex();
   392     }
   393     
   394     @Function
   395     static void call(KnockoutModel m, String data) {
   396         m.setName(data);
   397         m.setCallbackCount(m.getCallbackCount() + 1);
   398     }
   399 
   400     @Function
   401     static void removePerson(KnockoutModel model, Person data) {
   402         model.setCallbackCount(model.getCallbackCount() + 1);
   403         model.getPeople().remove(data);
   404     }
   405     
   406     
   407     @ComputedProperty
   408     static String helloMessage(String name) {
   409         return "Hello " + name + "!";
   410     }
   411     
   412     @ComputedProperty
   413     static List<String> cmpResults(List<String> results) {
   414         return results;
   415     }
   416     
   417     private static int countChildren(String id) throws Exception {
   418         return ((Number)Utils.executeScript(
   419           KnockoutTest.class,
   420           "var e = window.document.getElementById(arguments[0]);\n "
   421         + "if (typeof e === 'undefined') return -2;\n "
   422         + "return e.children.length;", 
   423             id
   424         )).intValue();
   425     }
   426 
   427     private static void triggerClick(String id) throws Exception {
   428         String s = "var id = arguments[0];"
   429             + "var e = window.document.getElementById(id);\n "
   430             + "var ev = window.document.createEvent('MouseEvents');\n "
   431             + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
   432             + "e.dispatchEvent(ev);\n ";
   433         Utils.executeScript(
   434             KnockoutTest.class,
   435             s, id);
   436     }
   437     private static void triggerChildClick(String id, int pos) throws Exception {
   438         String s = "var id = arguments[0]; var pos = arguments[1];"
   439             + "var e = window.document.getElementById(id);\n "
   440             + "var ev = window.document.createEvent('MouseEvents');\n "
   441             + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
   442             + "e.children[pos].dispatchEvent(ev);\n ";
   443         Utils.executeScript(
   444             KnockoutTest.class,
   445             s, id, pos);
   446     }
   447 
   448     private static String childText(String id, int pos) throws Exception {
   449         String s = "var id = arguments[0]; var pos = arguments[1];"
   450         + "var e = window.document.getElementById(id);\n "
   451         + "var t = e.children[pos].innerHTML;\n "
   452         + "return t ? t : null;";
   453         return (String)Utils.executeScript(
   454             KnockoutTest.class,
   455             s, id, pos);
   456     }
   457 
   458     private static BrwsrCtx newContext() {
   459         return Utils.newContext(KnockoutTest.class);
   460     }
   461 }