#258088: Non-mutable values aren't wrapped into ko.observable, but rather stored as primitive values
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
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]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
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.
43 package net.java.html.json.tests;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.Timer;
48 import java.util.TimerTask;
49 import net.java.html.BrwsrCtx;
50 import net.java.html.json.ComputedProperty;
51 import net.java.html.json.Function;
52 import net.java.html.json.Model;
53 import net.java.html.json.Models;
54 import net.java.html.json.Property;
55 import org.netbeans.html.json.tck.KOTest;
56 import static net.java.html.json.tests.Utils.assertEquals;
57 import static net.java.html.json.tests.Utils.assertNotNull;
58 import static net.java.html.json.tests.Utils.assertTrue;
59 import static net.java.html.json.tests.Utils.assertFalse;
63 * @author Jaroslav Tulach
65 @Model(className="KnockoutModel", targetId = "", properties={
66 @Property(name="name", type=String.class),
67 @Property(name="results", type=String.class, array = true),
68 @Property(name="numbers", type=int.class, array = true),
69 @Property(name="callbackCount", type=int.class),
70 @Property(name="people", type=PersonImpl.class, array = true),
71 @Property(name="enabled", type=boolean.class),
72 @Property(name="latitude", type=double.class),
73 @Property(name="choice", type=KnockoutTest.Choice.class),
74 @Property(name="archetype", type=ArchetypeData.class),
75 @Property(name="archetypes", type=ArchetypeData.class, array = true),
77 public final class KnockoutTest {
78 private KnockoutModel js;
84 @ComputedProperty static List<Integer> resultLengths(List<String> results) {
85 Integer[] arr = new Integer[results.size()];
86 for (int i = 0; i < arr.length; i++) {
87 arr[i] = results.get(i).length();
89 return Arrays.asList(arr);
92 @KOTest public void modifyValueAssertChangeInModelOnEnum() throws Throwable {
93 Object exp = Utils.exposeHTML(KnockoutTest.class,
94 "Latitude: <input id='input' data-bind=\"value: choice\"></input>\n"
98 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
99 m.setChoice(Choice.A);
102 String v = getSetInput("input", null);
103 assertEquals("A", v, "Value is really A: " + v);
105 getSetInput("input", "B");
106 triggerEvent("input", "change");
108 assertEquals(Choice.B, m.getChoice(), "Enum property updated: " + m.getChoice());
109 } catch (Throwable t) {
112 Utils.exposeHTML(KnockoutTest.class, "");
117 @KOTest public void modifyRadioValueOnEnum() throws Throwable {
118 Object exp = Utils.exposeHTML(KnockoutTest.class,
119 "<input id='i1' type=\"radio\" name=\"choice\" value=\"A\" data-bind=\"checked: choice\"></input>Right\n" +
120 "<input id='input' type=\"radio\" name=\"choice\" value=\"B\" data-bind=\"checked: choice\"></input>Never\n" +
125 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
126 m.setChoice(Choice.B);
129 assertFalse(isChecked("i1"), "B should be checked now");
130 assertTrue(isChecked("input"), "B should be checked now");
132 triggerEvent("i1", "click");
133 assertEquals(Choice.A, m.getChoice(), "Switched to A");
134 assertTrue(isChecked("i1"), "A should be checked now");
135 assertFalse(isChecked("input"), "A should be checked now");
137 triggerEvent("input", "click");
139 assertEquals(Choice.B, m.getChoice(), "Enum property updated: " + m.getChoice());
140 } catch (Throwable t) {
143 Utils.exposeHTML(KnockoutTest.class, "");
147 @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
148 Object exp = Utils.exposeHTML(KnockoutTest.class,
149 "Latitude: <input id='input' data-bind=\"value: latitude\"></input>\n"
153 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
157 String v = getSetInput("input", null);
158 assertEquals("50.5", v, "Value is really 50.5: " + v);
160 getSetInput("input", "49.5");
161 triggerEvent("input", "change");
163 assertEquals(49.5, m.getLatitude(), "Double property updated: " + m.getLatitude());
164 } catch (Throwable t) {
167 Utils.exposeHTML(KnockoutTest.class, "");
171 @KOTest public void rawObject() throws Exception {
173 final BrwsrCtx ctx = newContext();
174 Person p1 = Models.bind(new Person(), ctx);
175 p1.setFirstName("Jarda");
176 p1.setLastName("Tulach");
177 Object raw = Models.toRaw(p1);
178 Person p2 = Models.fromRaw(ctx, Person.class, raw);
180 assertEquals(p2.getFirstName(), "Jarda", "First name");
181 assertEquals(p2.getLastName(), "Tulach", "Last name");
183 p2.setFirstName("Jirka");
184 assertEquals(p2.getFirstName(), "Jirka", "First name updated");
186 js = new KnockoutModel();
187 js.getPeople().add(p1);
188 js.getPeople().add(p2);
191 Person p1 = js.getPeople().get(0);
192 Person p2 = js.getPeople().get(1);
194 if (js.getPeople().size() == 2) {
195 if (!"Jirka".equals(p1.getFirstName())) {
196 throw new InterruptedException();
199 assertEquals(p1.getFirstName(), "Jirka", "First name updated in original object");
201 p1.setFirstName("Ondra");
202 assertEquals(p1.getFirstName(), "Ondra", "1st name updated in original object");
204 js.getPeople().add(p1);
207 if (!"Ondra".equals(p2.getFirstName())) {
208 throw new InterruptedException();
210 assertEquals(p2.getFirstName(), "Ondra", "1st name updated in copied object");
213 @KOTest public void modifyComputedProperty() throws Throwable {
214 Object exp = Utils.exposeHTML(KnockoutTest.class,
215 "Full name: <div data-bind='with:firstPerson'>\n"
216 + "<input id='input' data-bind=\"value: fullName\"></input>\n"
220 KnockoutModel m = new KnockoutModel();
221 m.getPeople().add(new Person());
223 m = Models.bind(m, newContext());
224 m.getFirstPerson().setFirstName("Jarda");
225 m.getFirstPerson().setLastName("Tulach");
228 String v = getSetInput("input", null);
229 assertEquals("Jarda Tulach", v, "Value: " + v);
231 getSetInput("input", "Mickey Mouse");
232 triggerEvent("input", "change");
234 assertEquals("Mickey", m.getFirstPerson().getFirstName(), "First name updated");
235 assertEquals("Mouse", m.getFirstPerson().getLastName(), "Last name updated");
236 } catch (Throwable t) {
239 Utils.exposeHTML(KnockoutTest.class, "");
243 @KOTest public void modifyValueAssertChangeInModelOnBoolean() throws Throwable {
244 Object exp = Utils.exposeHTML(KnockoutTest.class,
245 "Latitude: <input id='input' data-bind=\"value: enabled\"></input>\n"
249 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
253 String v = getSetInput("input", null);
254 assertEquals("true", v, "Value is really true: " + v);
256 getSetInput("input", "false");
257 triggerEvent("input", "change");
259 assertFalse(m.isEnabled(), "Boolean property updated: " + m.isEnabled());
260 } catch (Throwable t) {
263 Utils.exposeHTML(KnockoutTest.class, "");
267 @KOTest public void modifyValueAssertChangeInModel() throws Exception {
268 Object exp = Utils.exposeHTML(KnockoutTest.class,
269 "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
270 "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
271 "<button id=\"hello\">Say Hello!</button>\n"
275 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
279 String v = getSetInput("input", null);
280 assertEquals("Kukuc", v, "Value is really kukuc: " + v);
282 getSetInput("input", "Jardo");
283 triggerEvent("input", "change");
285 assertEquals("Jardo", m.getName(), "Name property updated: " + m.getName());
287 Utils.exposeHTML(KnockoutTest.class, "");
291 private static String getSetSelected(int index, Object value) throws Exception {
292 String s = "var index = arguments[0];\n"
293 + "var value = arguments[1];\n"
294 + "var n = window.document.getElementById('input'); \n "
295 + "if (value != null) {\n"
296 + " n.options[index].value = 'me'; \n"
297 + " n.value = 'me'; \n"
298 + " ko.dataFor(n.options[index]).archetype(value); // haven't found better way to trigger ko change yet \n"
300 + "var op = n.options[n.selectedIndex]; \n"
301 + "return op ? op.text : n.selectedIndex;\n";
302 Object ret = Utils.executeScript(
306 return ret == null ? null : ret.toString();
309 @Model(className = "ArchetypeData", properties = {
310 @Property(name = "artifactId", type = String.class),
311 @Property(name = "groupId", type = String.class),
312 @Property(name = "version", type = String.class),
313 @Property(name = "name", type = String.class),
314 @Property(name = "description", type = String.class),
315 @Property(name = "url", type = String.class),
317 static class ArchModel {
320 @KOTest public void selectWorksOnModels() throws Exception {
322 Utils.exposeHTML(KnockoutTest.class,
323 "<select id='input' data-bind=\"options: archetypes,\n" +
324 " optionsText: 'name',\n" +
325 " value: archetype\">\n" +
330 js = Models.bind(new KnockoutModel(), newContext());
331 js.getArchetypes().add(new ArchetypeData("ko4j", "org.netbeans.html", "0.8.3", "ko4j", "ko4j", null));
332 js.getArchetypes().add(new ArchetypeData("crud", "org.netbeans.html", "0.8.3", "crud", "crud", null));
333 js.getArchetypes().add(new ArchetypeData("3rd", "org.netbeans.html", "0.8.3", "3rd", "3rd", null));
334 js.setArchetype(js.getArchetypes().get(1));
337 String v = getSetSelected(0, null);
338 assertEquals("crud", v, "Second index (e.g. crud) is selected: " + v);
340 String sel = getSetSelected(2, Models.toRaw(js.getArchetypes().get(2)));
341 assertEquals("3rd", sel, "3rd is selected now: " + sel);
344 if (js.getArchetype() != js.getArchetypes().get(2)) {
345 throw new InterruptedException();
348 Utils.exposeHTML(KnockoutTest.class, "");
351 @KOTest public void nestedObjectEqualsChange() throws Exception {
352 nestedObjectEqualsChange(true);
355 @KOTest public void nestedObjectChange() throws Exception {
356 nestedObjectEqualsChange(false);
358 private void nestedObjectEqualsChange(boolean preApply) throws Exception {
359 Utils.exposeHTML(KnockoutTest.class,
360 " <div data-bind='with: archetype'>\n" +
361 " <input id='input' data-bind='value: groupId'></input>\n" +
365 js = Models.bind(new KnockoutModel(), newContext());
369 js.setArchetype(new ArchetypeData());
370 js.getArchetype().setGroupId("org.netbeans.html");
373 String v = getSetInput("input", null);
374 assertEquals("org.netbeans.html", v, "groupId has been changed");
375 Utils.exposeHTML(KnockoutTest.class, "");
378 @KOTest public void modifyValueAssertAsyncChangeInModel() throws Exception {
380 Utils.exposeHTML(KnockoutTest.class,
381 "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
382 "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
383 "<button id=\"hello\">Say Hello!</button>\n"
386 js = Models.bind(new KnockoutModel(), newContext());
390 String v = getSetInput("input", null);
391 assertEquals("Kukuc", v, "Value is really kukuc: " + v);
393 Timer t = new Timer("Set to Jardo");
394 t.schedule(new TimerTask() {
402 String v = getSetInput("input", null);
403 if (!"Jardo".equals(v)) {
404 throw new InterruptedException();
407 Utils.exposeHTML(KnockoutTest.class, "");
410 @Model(className = "ConstantModel", targetId = "", builder = "assign", properties = {
411 @Property(name = "doubleValue", mutable = false, type = double.class),
412 @Property(name = "longValue", mutable = false, type = long.class),
413 @Property(name = "stringValue", mutable = false, type = String.class),
414 @Property(name = "boolValue", mutable = false, type = boolean.class),
415 @Property(name = "intArray", mutable = false, type = int.class, array = true),
417 static class ConstantCntrl {
420 @KOTest public void nonMutableDouble() throws Exception {
421 Utils.exposeHTML(KnockoutTest.class,
422 "Type: <input id='input' data-bind=\"value: typeof doubleValue\"></input>\n"
425 ConstantModel model = Models.bind(new ConstantModel(), newContext());
426 model.assignStringValue("Hello").assignDoubleValue(10.0);
427 model.applyBindings();
429 String v = getSetInput("input", null);
430 assertEquals(v, "number", "Right type found: " + v);
432 Utils.exposeHTML(KnockoutTest.class, "");
435 @KOTest public void nonMutableString() throws Exception {
436 Utils.exposeHTML(KnockoutTest.class,
437 "Type: <input id='input' data-bind=\"value: typeof stringValue\"></input>\n"
440 ConstantModel model = Models.bind(new ConstantModel(), newContext());
441 model.assignStringValue("Hello").assignDoubleValue(10.0);
442 model.applyBindings();
444 String v = getSetInput("input", null);
445 assertEquals(v, "string", "Right type found: " + v);
447 Utils.exposeHTML(KnockoutTest.class, "");
450 @KOTest public void nonMutableBoolean() throws Exception {
451 Utils.exposeHTML(KnockoutTest.class,
452 "Type: <input id='input' data-bind=\"value: typeof boolValue\"></input>\n"
455 ConstantModel model = Models.bind(new ConstantModel(), newContext());
456 model.assignStringValue("Hello").assignBoolValue(true);
457 model.applyBindings();
459 String v = getSetInput("input", null);
460 assertEquals(v, "boolean", "Right type found: " + v);
462 Utils.exposeHTML(KnockoutTest.class, "");
465 @KOTest public void nonMutableLong() throws Exception {
466 Utils.exposeHTML(KnockoutTest.class,
467 "Type: <input id='input' data-bind=\"value: typeof longValue\"></input>\n"
470 ConstantModel model = Models.bind(new ConstantModel(), newContext());
471 model.assignStringValue("Hello").assignLongValue(Long.MAX_VALUE);
472 model.applyBindings();
474 String v = getSetInput("input", null);
475 assertEquals(v, "number", "Right type found: " + v);
477 Utils.exposeHTML(KnockoutTest.class, "");
480 @KOTest public void nonMutableIntArray() throws Exception {
481 Utils.exposeHTML(KnockoutTest.class,
482 "Type: <input id='input' data-bind=\"value: typeof intArray\"></input>\n"
485 ConstantModel model = Models.bind(new ConstantModel(), newContext());
486 model.assignStringValue("Hello").assignLongValue(Long.MAX_VALUE).assignIntArray(1, 2, 3, 4);
487 model.applyBindings();
489 String v = getSetInput("input", null);
490 assertEquals(v, "object", "Right type found: " + v);
492 Utils.exposeHTML(KnockoutTest.class, "");
495 private static String getSetInput(String id, String value) throws Exception {
496 String s = "var value = arguments[0];\n"
497 + "var n = window.document.getElementById(arguments[1]); \n "
498 + "if (value != null) n['value'] = value; \n "
499 + "return n['value'];";
500 Object ret = Utils.executeScript(
504 return ret == null ? null : ret.toString();
507 private static boolean isChecked(String id) throws Exception {
509 + "var n = window.document.getElementById(arguments[0]); \n "
510 + "return n['checked'];";
511 Object ret = Utils.executeScript(
515 return Boolean.TRUE.equals(ret);
518 public static void triggerEvent(String id, String ev) throws Exception {
521 "ko.utils.triggerEvent(window.document.getElementById(arguments[0]), arguments[1]);",
526 @KOTest public void displayContentOfArray() throws Exception {
527 Object exp = Utils.exposeHTML(KnockoutTest.class,
528 "<ul id='ul' data-bind='foreach: results'>\n"
529 + " <li data-bind='text: $data, click: $root.call'/>\n"
533 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
534 m.getResults().add("Ahoj");
537 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
538 assertEquals(cnt, 1, "One child, but was " + cnt);
540 m.getResults().add("Hi");
542 cnt = Utils.countChildren(KnockoutTest.class, "ul");
543 assertEquals(cnt, 2, "Two children now, but was " + cnt);
545 triggerChildClick("ul", 1);
547 assertEquals(1, m.getCallbackCount(), "One callback " + m.getCallbackCount());
548 assertEquals("Hi", m.getName(), "We got callback from 2nd child " + m.getName());
550 Utils.exposeHTML(KnockoutTest.class, "");
554 @KOTest public void displayContentOfAsyncArray() throws Exception {
556 Utils.exposeHTML(KnockoutTest.class,
557 "<ul id='ul' data-bind='foreach: results'>\n"
558 + " <li data-bind='text: $data, click: $root.call'/>\n"
561 js = Models.bind(new KnockoutModel(), newContext());
562 js.getResults().add("Ahoj");
565 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
566 assertEquals(cnt, 1, "One child, but was " + cnt);
568 Timer t = new Timer("add to array");
569 t.schedule(new TimerTask() {
572 js.getResults().add("Hi");
578 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
580 throw new InterruptedException();
584 triggerChildClick("ul", 1);
586 assertEquals(1, js.getCallbackCount(), "One callback " + js.getCallbackCount());
587 assertEquals("Hi", js.getName(), "We got callback from 2nd child " + js.getName());
589 Utils.exposeHTML(KnockoutTest.class, "");
593 @KOTest public void displayContentOfComputedArray() throws Exception {
594 Object exp = Utils.exposeHTML(KnockoutTest.class,
595 "<ul id='ul' data-bind='foreach: bothNames'>\n"
596 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
600 Pair m = Models.bind(new Pair("First", "Last", null), newContext());
603 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
604 assertEquals(cnt, 2, "Two children now, but was " + cnt);
606 triggerChildClick("ul", 1);
608 assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
610 m.setLastName("Verylast");
612 cnt = Utils.countChildren(KnockoutTest.class, "ul");
613 assertEquals(cnt, 2, "Two children now, but was " + cnt);
615 triggerChildClick("ul", 1);
617 assertEquals("Verylast", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
620 Utils.exposeHTML(KnockoutTest.class, "");
624 @KOTest public void displayContentOfComputedArrayOnASubpair() throws Exception {
625 Object exp = Utils.exposeHTML(KnockoutTest.class,
626 "<div data-bind='with: next'>\n"
627 + "<ul id='ul' data-bind='foreach: bothNames'>\n"
628 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
633 final BrwsrCtx ctx = newContext();
634 Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), ctx);
637 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
638 assertEquals(cnt, 2, "Two children now, but was " + cnt);
640 triggerChildClick("ul", 1);
642 assertEquals(PairModel.ctx, ctx, "Context remains the same");
644 assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
646 Utils.exposeHTML(KnockoutTest.class, "");
650 @KOTest public void displayContentOfComputedArrayOnComputedASubpair() throws Exception {
651 Object exp = Utils.exposeHTML(KnockoutTest.class,
652 "<div data-bind='with: nextOne'>\n"
653 + "<ul id='ul' data-bind='foreach: bothNames'>\n"
654 + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
659 Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
662 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
663 assertEquals(cnt, 2, "Two children now, but was " + cnt);
665 triggerChildClick("ul", 1);
667 assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
669 Utils.exposeHTML(KnockoutTest.class, "");
673 @KOTest public void checkBoxToBooleanBinding() throws Exception {
674 Object exp = Utils.exposeHTML(KnockoutTest.class,
675 "<input type='checkbox' id='b' data-bind='checked: enabled'></input>\n"
678 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
681 assertFalse(m.isEnabled(), "Is disabled");
685 assertTrue(m.isEnabled(), "Now the model is enabled");
687 Utils.exposeHTML(KnockoutTest.class, "");
693 @KOTest public void displayContentOfDerivedArray() throws Exception {
694 Object exp = Utils.exposeHTML(KnockoutTest.class,
695 "<ul id='ul' data-bind='foreach: cmpResults'>\n"
696 + " <li><b data-bind='text: $data'></b></li>\n"
700 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
701 m.getResults().add("Ahoj");
704 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
705 assertEquals(cnt, 1, "One child, but was " + cnt);
707 m.getResults().add("hello");
709 cnt = Utils.countChildren(KnockoutTest.class, "ul");
710 assertEquals(cnt, 2, "Two children now, but was " + cnt);
712 Utils.exposeHTML(KnockoutTest.class, "");
716 @KOTest public void displayContentOfArrayOfPeople() throws Exception {
717 Object exp = Utils.exposeHTML(KnockoutTest.class,
718 "<ul id='ul' data-bind='foreach: people'>\n"
719 + " <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
723 final BrwsrCtx c = newContext();
724 KnockoutModel m = Models.bind(new KnockoutModel(), c);
726 final Person first = Models.bind(new Person(), c);
727 first.setFirstName("first");
728 m.getPeople().add(first);
732 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
733 assertEquals(cnt, 1, "One child, but was " + cnt);
735 final Person second = Models.bind(new Person(), c);
736 second.setFirstName("second");
737 m.getPeople().add(second);
739 cnt = Utils.countChildren(KnockoutTest.class, "ul");
740 assertEquals(cnt, 2, "Two children now, but was " + cnt);
742 triggerChildClick("ul", 1);
744 assertEquals(1, m.getCallbackCount(), "One callback " + m.getCallbackCount());
746 cnt = Utils.countChildren(KnockoutTest.class, "ul");
747 assertEquals(cnt , 1, "Again one child, but was " + cnt);
749 String txt = childText("ul", 0);
750 assertEquals("first", txt, "Expecting 'first': " + txt);
752 first.setFirstName("changed");
754 txt = childText("ul", 0);
755 assertEquals("changed", txt, "Expecting 'changed': " + txt);
757 Utils.exposeHTML(KnockoutTest.class, "");
762 static Person firstPerson(List<Person> people) {
763 return people.isEmpty() ? null : people.get(0);
766 @KOTest public void accessFirstPersonWithOnFunction() throws Exception {
767 Object exp = Utils.exposeHTML(KnockoutTest.class,
768 "<p id='ul' data-bind='with: firstPerson'>\n"
769 + " <span data-bind='text: firstName, click: changeSex'></span>\n"
775 Utils.exposeHTML(KnockoutTest.class, "");
779 @KOTest public void onPersonFunction() throws Exception {
780 Object exp = Utils.exposeHTML(KnockoutTest.class,
781 "<ul id='ul' data-bind='foreach: people'>\n"
782 + " <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
788 Utils.exposeHTML(KnockoutTest.class, "");
792 private void trasfertToFemale() throws Exception {
793 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
795 final Person first = Models.bind(new Person(), newContext());
796 first.setFirstName("first");
797 first.setSex(Sex.MALE);
798 m.getPeople().add(first);
803 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
804 assertEquals(cnt, 1, "One child, but was " + cnt);
807 triggerChildClick("ul", 0);
809 assertEquals(first.getSex(), Sex.FEMALE, "Transverted to female: " + first.getSex());
812 @KOTest public void stringArrayModificationVisible() throws Exception {
813 Object exp = Utils.exposeHTML(KnockoutTest.class,
815 + "<ul id='ul' data-bind='foreach: results'>\n"
816 + " <li data-bind='text: $data'></li>\n"
821 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
822 m.getResults().add("Ahoj");
823 m.getResults().add("Hello");
826 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
827 assertEquals(cnt, 2, "Two children " + cnt);
829 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
830 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
831 final int len = ((Object[])arr).length;
833 assertEquals(len, 3, "Three elements in the array " + len);
835 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
836 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
838 assertEquals(m.getResults().size(), 3, "Three java strings: " + m.getResults());
840 Utils.exposeHTML(KnockoutTest.class, "");
844 @KOTest public void intArrayModificationVisible() throws Exception {
845 Object exp = Utils.exposeHTML(KnockoutTest.class,
847 + "<ul id='ul' data-bind='foreach: numbers'>\n"
848 + " <li data-bind='text: $data'></li>\n"
853 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
854 m.getNumbers().add(1);
855 m.getNumbers().add(31);
858 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
859 assertEquals(cnt, 2, "Two children " + cnt);
861 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "numbers", 42);
862 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
863 final int len = ((Object[])arr).length;
865 assertEquals(len, 3, "Three elements in the array " + len);
867 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
868 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
870 assertEquals(m.getNumbers().size(), 3, "Three java ints: " + m.getNumbers());
871 assertEquals(m.getNumbers().get(2), 42, "Meaning of world: " + m.getNumbers());
873 Utils.exposeHTML(KnockoutTest.class, "");
877 @KOTest public void derivedIntArrayModificationVisible() throws Exception {
878 Object exp = Utils.exposeHTML(KnockoutTest.class,
880 + "<ul id='ul' data-bind='foreach: resultLengths'>\n"
881 + " <li data-bind='text: $data'></li>\n"
886 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
887 m.getResults().add("Ahoj");
888 m.getResults().add("Hello");
891 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
892 assertEquals(cnt, 2, "Two children " + cnt);
894 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
895 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
896 final int len = ((Object[])arr).length;
898 assertEquals(len, 3, "Three elements in the array " + len);
900 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
901 assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
903 assertEquals(m.getResultLengths().size(), 3, "Three java ints: " + m.getResultLengths());
904 assertEquals(m.getResultLengths().get(2), 2, "Size is two: " + m.getResultLengths());
906 Utils.exposeHTML(KnockoutTest.class, "");
910 @KOTest public void archetypeArrayModificationVisible() throws Exception {
911 Object exp = Utils.exposeHTML(KnockoutTest.class,
913 + "<ul id='ul' data-bind='foreach: archetypes'>\n"
914 + " <li data-bind='text: artifactId'></li>\n"
919 KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
922 int cnt = Utils.countChildren(KnockoutTest.class, "ul");
923 assertEquals(cnt, 0, "No children " + cnt);
925 Object arr = Utils.addChildren(KnockoutTest.class, "ul", "archetypes", new ArchetypeData("aid", "gid", "v", "n", "d", "u"));
926 assertTrue(arr instanceof Object[], "Got back an array: " + arr);
927 final int len = ((Object[])arr).length;
929 assertEquals(len, 1, "One element in the array " + len);
931 int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
932 assertEquals(newCnt, 1, "One child in the DOM: " + newCnt);
934 assertEquals(m.getArchetypes().size(), 1, "One archetype: " + m.getArchetypes());
935 assertNotNull(m.getArchetypes().get(0), "Not null: " + m.getArchetypes());
936 assertEquals(m.getArchetypes().get(0).getArtifactId(), "aid", "'aid' == " + m.getArchetypes());
938 Utils.exposeHTML(KnockoutTest.class, "");
943 static void call(KnockoutModel m, String data) {
945 m.setCallbackCount(m.getCallbackCount() + 1);
949 static void removePerson(KnockoutModel model, Person data) {
950 model.setCallbackCount(model.getCallbackCount() + 1);
951 model.getPeople().remove(data);
956 static String helloMessage(String name) {
957 return "Hello " + name + "!";
961 static List<String> cmpResults(List<String> results) {
965 private static void triggerClick(String id) throws Exception {
966 String s = "var id = arguments[0];"
967 + "var e = window.document.getElementById(id);\n "
968 + "if (e.checked) throw 'It should not be checked yet: ' + e;\n "
969 + "var ev = window.document.createEvent('MouseEvents');\n "
970 + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
971 + "e.dispatchEvent(ev);\n "
972 + "if (!e.checked) {\n"
973 + " e.checked = true;\n "
974 + " e.dispatchEvent(ev);\n "
980 private static void triggerChildClick(String id, int pos) throws Exception {
982 "var id = arguments[0]; var pos = arguments[1];\n" +
983 "var e = window.document.getElementById(id);\n " +
984 "var ev = window.document.createEvent('MouseEvents');\n " +
985 "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n " +
986 "var list = e.childNodes;\n" +
988 "for (var i = 0; i < list.length; i++) {\n" +
989 " if (list[i].nodeType == 1) cnt++;\n" +
990 " if (cnt == pos) return list[i].dispatchEvent(ev);\n" +
998 private static String childText(String id, int pos) throws Exception {
1000 "var id = arguments[0]; var pos = arguments[1];" +
1001 "var e = window.document.getElementById(id);\n" +
1002 "var list = e.childNodes;\n" +
1004 "for (var i = 0; i < list.length; i++) {\n" +
1005 " if (list[i].nodeType == 1) cnt++;\n" +
1006 " if (cnt == pos) return list[i].innerHTML;\n" +
1009 return (String)Utils.executeScript(
1014 private static BrwsrCtx newContext() {
1015 return Utils.newContext(KnockoutTest.class);