json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Mon, 16 Dec 2013 17:39:56 +0100
changeset 365 5c93ad8c7a15
parent 358 80702021b851
child 393 8b025bcde7bb
permissions -rw-r--r--
The work on this project started in 2013
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2013 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-2013 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 
    54 /**
    55  *
    56  * @author Jaroslav Tulach <jtulach@netbeans.org>
    57  */
    58 @Model(className="KnockoutModel", properties={
    59     @Property(name="name", type=String.class),
    60     @Property(name="results", type=String.class, array = true),
    61     @Property(name="callbackCount", type=int.class),
    62     @Property(name="people", type=PersonImpl.class, array = true),
    63     @Property(name="enabled", type=boolean.class),
    64     @Property(name="latitude", type=double.class)
    65 }) 
    66 public final class KnockoutTest {
    67     
    68     @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
    69         Object exp = Utils.exposeHTML(KnockoutTest.class, 
    70             "Latitude: <input id='input' data-bind=\"value: latitude\"></input>\n"
    71         );
    72         try {
    73 
    74             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
    75             m.setLatitude(50.5);
    76             m.applyBindings();
    77 
    78             String v = getSetInput(null);
    79             assert "50.5".equals(v) : "Value is really 50.5: " + v;
    80 
    81             getSetInput("49.5");
    82             triggerEvent("input", "change");
    83 
    84             assert 49.5 == m.getLatitude() : "Double property updated: " + m.getLatitude();
    85         } catch (Throwable t) {
    86             throw t;
    87         } finally {
    88             Utils.exposeHTML(KnockoutTest.class, "");
    89         }
    90     }
    91     
    92     @KOTest public void modifyValueAssertChangeInModelOnBoolean() throws Throwable {
    93         Object exp = Utils.exposeHTML(KnockoutTest.class, 
    94             "Latitude: <input id='input' data-bind=\"value: enabled\"></input>\n"
    95         );
    96         try {
    97 
    98             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
    99             m.setEnabled(true);
   100             m.applyBindings();
   101 
   102             String v = getSetInput(null);
   103             assert "true".equals(v) : "Value is really true: " + v;
   104 
   105             getSetInput("false");
   106             triggerEvent("input", "change");
   107 
   108             assert false == m.isEnabled(): "Boolean property updated: " + m.isEnabled();
   109         } catch (Throwable t) {
   110             throw t;
   111         } finally {
   112             Utils.exposeHTML(KnockoutTest.class, "");
   113         }
   114     }
   115     
   116     @KOTest public void modifyValueAssertChangeInModel() throws Exception {
   117         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   118             "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
   119             "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
   120             "<button id=\"hello\">Say Hello!</button>\n"
   121         );
   122         try {
   123 
   124             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   125             m.setName("Kukuc");
   126             m.applyBindings();
   127 
   128             String v = getSetInput(null);
   129             assert "Kukuc".equals(v) : "Value is really kukuc: " + v;
   130 
   131             getSetInput("Jardo");
   132             triggerEvent("input", "change");
   133 
   134             assert "Jardo".equals(m.getName()) : "Name property updated: " + m.getName();
   135         } finally {
   136             Utils.exposeHTML(KnockoutTest.class, "");
   137         }
   138     }
   139     
   140     private static String getSetInput(String value) throws Exception {
   141         String s = "var value = arguments[0];\n"
   142         + "var n = window.document.getElementById('input'); \n "
   143         + "if (value != null) n['value'] = value; \n "
   144         + "return n['value'];";
   145         return (String)Utils.executeScript(
   146             KnockoutTest.class,
   147             s, value
   148         );
   149     }
   150     
   151     public static void triggerEvent(String id, String ev) throws Exception {
   152         Utils.executeScript(
   153             KnockoutTest.class,
   154             "ko.utils.triggerEvent(window.document.getElementById(arguments[0]), arguments[1]);",
   155             id, ev
   156         );
   157     }
   158     
   159     @KOTest public void displayContentOfArray() throws Exception {
   160         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   161             "<ul id='ul' data-bind='foreach: results'>\n"
   162             + "  <li data-bind='text: $data, click: $root.call'/>\n"
   163             + "</ul>\n"
   164         );
   165         try {
   166             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   167             m.getResults().add("Ahoj");
   168             m.applyBindings();
   169 
   170             int cnt = countChildren("ul");
   171             assert cnt == 1 : "One child, but was " + cnt;
   172 
   173             m.getResults().add("Hi");
   174 
   175             cnt = countChildren("ul");
   176             assert cnt == 2 : "Two children now, but was " + cnt;
   177 
   178             triggerChildClick("ul", 1);
   179 
   180             assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
   181             assert "Hi".equals(m.getName()) : "We got callback from 2nd child " + m.getName();
   182         } finally {
   183             Utils.exposeHTML(KnockoutTest.class, "");
   184         }
   185     }
   186     
   187     @KOTest public void displayContentOfComputedArray() throws Exception {
   188         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   189             "<ul id='ul' data-bind='foreach: bothNames'>\n"
   190             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   191             + "</ul>\n"
   192         );
   193         try {
   194             Pair m = Models.bind(new Pair("First", "Last", null), newContext());
   195             m.applyBindings();
   196 
   197             int cnt = countChildren("ul");
   198             assert cnt == 2 : "Two children now, but was " + cnt;
   199 
   200             triggerChildClick("ul", 1);
   201 
   202             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   203         } finally {
   204             Utils.exposeHTML(KnockoutTest.class, "");
   205         }
   206     }
   207     
   208     @KOTest public void displayContentOfComputedArrayOnASubpair() throws Exception {
   209         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   210               "<div data-bind='with: next'>\n"
   211             + "<ul id='ul' data-bind='foreach: bothNames'>\n"
   212             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   213             + "</ul>"
   214             + "</div>\n"
   215         );
   216         try {
   217             Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
   218             m.applyBindings();
   219 
   220             int cnt = countChildren("ul");
   221             assert cnt == 2 : "Two children now, but was " + cnt;
   222 
   223             triggerChildClick("ul", 1);
   224 
   225             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   226         } finally {
   227             Utils.exposeHTML(KnockoutTest.class, "");
   228         }
   229     }
   230     
   231     @KOTest public void displayContentOfComputedArrayOnComputedASubpair() throws Exception {
   232         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   233               "<div data-bind='with: nextOne'>\n"
   234             + "<ul id='ul' data-bind='foreach: bothNames'>\n"
   235             + "  <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
   236             + "</ul>"
   237             + "</div>\n"
   238         );
   239         try {
   240             Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
   241             m.applyBindings();
   242 
   243             int cnt = countChildren("ul");
   244             assert cnt == 2 : "Two children now, but was " + cnt;
   245 
   246             triggerChildClick("ul", 1);
   247 
   248             assert "Last".equals(m.getFirstName()) : "We got callback from 2nd child " + m.getFirstName();
   249         } finally {
   250             Utils.exposeHTML(KnockoutTest.class, "");
   251         }
   252     }
   253 
   254     @KOTest public void checkBoxToBooleanBinding() throws Exception {
   255         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   256             "<input type='checkbox' id='b' data-bind='checked: enabled'></input>\n"
   257         );
   258         try {
   259             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   260             m.applyBindings();
   261 
   262             assert !m.isEnabled() : "Is disabled";
   263 
   264             triggerClick("b");
   265 
   266             assert m.isEnabled() : "Now the model is enabled";
   267         } finally {
   268             Utils.exposeHTML(KnockoutTest.class, "");
   269         }
   270     }
   271     
   272     
   273     
   274     @KOTest public void displayContentOfDerivedArray() throws Exception {
   275         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   276             "<ul id='ul' data-bind='foreach: cmpResults'>\n"
   277             + "  <li><b data-bind='text: $data'></b></li>\n"
   278             + "</ul>\n"
   279         );
   280         try {
   281             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   282             m.getResults().add("Ahoj");
   283             m.applyBindings();
   284 
   285             int cnt = countChildren("ul");
   286             assert cnt == 1 : "One child, but was " + cnt;
   287 
   288             m.getResults().add("hello");
   289 
   290             cnt = countChildren("ul");
   291             assert cnt == 2 : "Two children now, but was " + cnt;
   292         } finally {
   293             Utils.exposeHTML(KnockoutTest.class, "");
   294         }
   295     }
   296     
   297     @KOTest public void displayContentOfArrayOfPeople() throws Exception {
   298         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   299             "<ul id='ul' data-bind='foreach: people'>\n"
   300             + "  <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
   301             + "</ul>\n"
   302         );
   303         try {
   304             KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   305 
   306             final Person first = Models.bind(new Person(), newContext());
   307             first.setFirstName("first");
   308             m.getPeople().add(first);
   309 
   310             m.applyBindings();
   311 
   312             int cnt = countChildren("ul");
   313             assert cnt == 1 : "One child, but was " + cnt;
   314 
   315             final Person second = Models.bind(new Person(), newContext());
   316             second.setFirstName("second");
   317             m.getPeople().add(second);
   318 
   319             cnt = countChildren("ul");
   320             assert cnt == 2 : "Two children now, but was " + cnt;
   321 
   322             triggerChildClick("ul", 1);
   323 
   324             assert 1 == m.getCallbackCount() : "One callback " + m.getCallbackCount();
   325 
   326             cnt = countChildren("ul");
   327             assert cnt == 1 : "Again one child, but was " + cnt;
   328 
   329             String txt = childText("ul", 0);
   330             assert "first".equals(txt) : "Expecting 'first': " + txt;
   331 
   332             first.setFirstName("changed");
   333 
   334             txt = childText("ul", 0);
   335             assert "changed".equals(txt) : "Expecting 'changed': " + txt;
   336         } finally {
   337             Utils.exposeHTML(KnockoutTest.class, "");
   338         }
   339     }
   340     
   341     @ComputedProperty
   342     static Person firstPerson(List<Person> people) {
   343         return people.isEmpty() ? null : people.get(0);
   344     }
   345     
   346     @KOTest public void accessFirstPersonWithOnFunction() throws Exception {
   347         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   348             "<p id='ul' data-bind='with: firstPerson'>\n"
   349             + "  <span data-bind='text: firstName, click: changeSex'></span>\n"
   350             + "</p>\n"
   351         );
   352         try {
   353             trasfertToFemale();
   354         } finally {
   355             Utils.exposeHTML(KnockoutTest.class, "");
   356         }
   357     }
   358     
   359     @KOTest public void onPersonFunction() throws Exception {
   360         Object exp = Utils.exposeHTML(KnockoutTest.class, 
   361             "<ul id='ul' data-bind='foreach: people'>\n"
   362             + "  <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
   363             + "</ul>\n"
   364         );
   365         try {
   366             trasfertToFemale();
   367         } finally {
   368             Utils.exposeHTML(KnockoutTest.class, "");
   369         }
   370     }
   371     
   372     private void trasfertToFemale() throws Exception {
   373         KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
   374 
   375         final Person first = Models.bind(new Person(), newContext());
   376         first.setFirstName("first");
   377         first.setSex(Sex.MALE);
   378         m.getPeople().add(first);
   379 
   380 
   381         m.applyBindings();
   382 
   383         int cnt = countChildren("ul");
   384         assert cnt == 1 : "One child, but was " + cnt;
   385 
   386 
   387         triggerChildClick("ul", 0);
   388 
   389         assert first.getSex() == Sex.FEMALE : "Transverted to female: " + first.getSex();
   390     }
   391     
   392     @Function
   393     static void call(KnockoutModel m, String data) {
   394         m.setName(data);
   395         m.setCallbackCount(m.getCallbackCount() + 1);
   396     }
   397 
   398     @Function
   399     static void removePerson(KnockoutModel model, Person data) {
   400         model.setCallbackCount(model.getCallbackCount() + 1);
   401         model.getPeople().remove(data);
   402     }
   403     
   404     
   405     @ComputedProperty
   406     static String helloMessage(String name) {
   407         return "Hello " + name + "!";
   408     }
   409     
   410     @ComputedProperty
   411     static List<String> cmpResults(List<String> results) {
   412         return results;
   413     }
   414     
   415     private static int countChildren(String id) throws Exception {
   416         return ((Number)Utils.executeScript(
   417           KnockoutTest.class,
   418           "var e = window.document.getElementById(arguments[0]);\n "
   419         + "if (typeof e === 'undefined') return -2;\n "
   420         + "return e.children.length;", 
   421             id
   422         )).intValue();
   423     }
   424 
   425     private static void triggerClick(String id) throws Exception {
   426         String s = "var id = arguments[0];"
   427             + "var e = window.document.getElementById(id);\n "
   428             + "var ev = window.document.createEvent('MouseEvents');\n "
   429             + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
   430             + "e.dispatchEvent(ev);\n ";
   431         Utils.executeScript(
   432             KnockoutTest.class,
   433             s, id);
   434     }
   435     private static void triggerChildClick(String id, int pos) throws Exception {
   436         String s = "var id = arguments[0]; var pos = arguments[1];"
   437             + "var e = window.document.getElementById(id);\n "
   438             + "var ev = window.document.createEvent('MouseEvents');\n "
   439             + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
   440             + "e.children[pos].dispatchEvent(ev);\n ";
   441         Utils.executeScript(
   442             KnockoutTest.class,
   443             s, id, pos);
   444     }
   445 
   446     private static String childText(String id, int pos) throws Exception {
   447         String s = "var id = arguments[0]; var pos = arguments[1];"
   448         + "var e = window.document.getElementById(id);\n "
   449         + "var t = e.children[pos].innerHTML;\n "
   450         + "return t ? t : null;";
   451         return (String)Utils.executeScript(
   452             KnockoutTest.class,
   453             s, id, pos);
   454     }
   455 
   456     private static BrwsrCtx newContext() {
   457         return Utils.newContext(KnockoutTest.class);
   458     }
   459 }