Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
6056 efrain 1
/*global test, equal, module, ok*/
2
(function(global, $, undefined) {
3
"use strict";
4
 
5
var isIE8 = window.attachEvent && !window.addEventListener;
6
 
7
function sort(array) {
8
	var ret = "";
9
	if (this.tagCtx.props.reverse) {
10
		// Render in reverse order
11
		for (var i = array.length; i; i--) {
12
			ret += this.tagCtx.render(array[ i - 1 ]);
13
		}
14
	} else {
15
		// Render in original order
16
		ret += this.tmpl.render(array);
17
	}
18
	return ret;
19
}
20
 
21
var person = {name: "Jo"},
22
	people = [{name: "Jo"},{name: "Bill"}],
23
	towns = [{name: "Seattle"},{name: "Paris"},{name: "Delhi"}];
24
 
25
var tmplString = "A_{{:name}}_B";
26
 
27
QUnit.module("api");
28
 
29
QUnit.test("templates", function(assert) {
30
	var tmplElem = document.getElementById("./test/templates/file/path.html");
31
 
32
	// =============================== Arrange ===============================
33
	$.removeData(tmplElem, "jsvTmpl"); // In case data has been set in a previous test
34
 
35
	// ................................ Act ..................................
36
	var tmpl0 = $.templates({markup: "./test/templates/file/path.html"}); // Compile template but do not cache
37
 
38
	// ............................... Assert .................................
39
	assert.equal(!$.data(tmplElem).jsvTmpl && tmpl0.render({name: "Jo0"}), isIE8 ? "\nServerRenderedTemplate_Jo0_B" : "ServerRenderedTemplate_Jo0_B", "Compile server-generated template, without caching");
40
 
41
	// ................................ Act ..................................
42
	var tmpl1 = $.templates("./test/templates/file/path.html"); // Compile and cache, using $.data(elem, "jsvTmpl", tmpl);
43
 
44
	// ............................... Assert .................................
45
	assert.equal(tmpl1 !== tmpl0 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl1.render({name: "Jo1"}), isIE8 ? "\nServerRenderedTemplate_Jo1_B" : "ServerRenderedTemplate_Jo1_B", "Compile server-generated template, and cache on file path");
46
 
47
	// ................................ Act ..................................
48
	var tmpl2 = $.templates("./test/templates/file/path.html"); // Use cached template, accessed by path as key
49
 
50
	// ............................... Assert .................................
51
	assert.equal(tmpl2 === tmpl1 && tmpl1.render({name: "Jo2"}), isIE8 ? "\nServerRenderedTemplate_Jo2_B" : "ServerRenderedTemplate_Jo2_B", "Re-use cached server-generated template");
52
 
53
	// ................................ Act ..................................
54
	var tmpl3 = $.templates({markup: "./test/templates/file/path.html"}); // Re-compile template but do not cache. Leaved cached template.
55
 
56
	// ............................... Assert .................................
57
	assert.equal(tmpl3 !== tmpl0 && tmpl3 !== tmpl1 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl3.render({name: "Jo3"}), isIE8 ? "\nServerRenderedTemplate_Jo3_B" : "ServerRenderedTemplate_Jo3_B", "Recompile server-generated template, without caching");
58
 
59
	// ................................ Reset ................................
60
	delete $.data(tmplElem).jsvTmpl;
61
	document.getElementById("./test/templates/file/path.html").removeAttribute("data-jsv-tmpl");
62
 
63
	tmplElem = $("#myTmpl")[0];
64
	delete $.data(tmplElem).jsvTmpl;
65
	tmplElem.removeAttribute("data-jsv-tmpl");
66
 
67
	// ................................ Act ..................................
68
	tmpl0 = $.templates({markup: "#myTmpl"}); // Compile template declared in script block, but do not cache
69
 
70
	// ............................... Assert .................................
71
	assert.equal(!$.data(tmplElem).jsvTmpl && tmpl0.render({name: "Jo0"}), isIE8 ? "\nA_Jo0_B" : "A_Jo0_B", "Compile template declared in script block, without caching");
72
 
73
	// ................................ Act ..................................
74
	tmpl1 = $.templates("#myTmpl"); // Compile and cache, using $.data(elem, "jsvTmpl", tmpl);
75
 
76
	// ............................... Assert .................................
77
	assert.equal(tmpl1 !== tmpl0 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl1.render({name: "Jo1"}), isIE8 ? "\nA_Jo1_B" : "A_Jo1_B", "Compile template declared in script block, and cache on file path");
78
 
79
	// ................................ Act ..................................
80
	tmpl2 = $.templates("#myTmpl"); // Use cached template, accessed by $.data(elem, "jsvTmpl")
81
 
82
	// ............................... Assert .................................
83
	assert.equal(tmpl2 === tmpl1 && tmpl1.render({name: "Jo2"}), isIE8 ? "\nA_Jo2_B" : "A_Jo2_B", "Re-use cached template declared in script block");
84
 
85
	// ................................ Act ..................................
86
	tmpl3 = $.templates({markup: "#myTmpl"}); // Re-compile template but do not cache. Leave cached template.
87
 
88
	// ............................... Assert .................................
89
	assert.equal(tmpl3 !== tmpl0 && tmpl3 !== tmpl1 && $.data(tmplElem).jsvTmpl === tmpl1 && tmpl3.render({name: "Jo3"}), isIE8 ? "\nA_Jo3_B" : "A_Jo3_B", "Recompile template declared in script block, without caching");
90
 
91
	// ................................ Reset ................................
92
	delete $.data(tmplElem).jsvTmpl;
93
	tmplElem.removeAttribute("data-jsv-tmpl");
94
 
95
	// =============================== Arrange ===============================
96
	// ............................... Assert .................................
97
	assert.equal($.templates("#my_tmpl2").render(), isIE8 ? "\n' \" \\ \\' \\\"" : "' \" \\ \\' \\\"", "correct treatment of ' \" and ' in template declared in script block");
98
 
99
	assert.equal($.templates("' \" \\ \\' \\\"").render(), "' \" \\ \\' \\\"", "correct treatment of ' \" and ' in template compiled from string");
100
 
101
	$.templates("my_tmpl", tmplString);
102
	assert.equal($.render.my_tmpl(person), "A_Jo_B", 'Compile a template and then render it: $.templates("my_tmpl", tmplString); $.render.my_tmpl(data);');
103
 
104
	$.templates({myTmpl2: tmplString});
105
	assert.equal($.render.myTmpl2(person), "A_Jo_B", 'Compile and register templates: $.templates({"my_tmpl", tmplString, ...}); $.render.my_tmpl(data);');
106
 
107
	assert.equal($.templates.myTmpl2.render(person), "A_Jo_B", 'Get named template: $.templates.my_tmpl.render(data);');
108
 
109
	assert.equal($.templates(tmplString).render(person), "A_Jo_B", 'Compile without registering as named template: $.templates(tmplString).render(person);');
110
 
111
	tmpl2 = $.templates("#my_tmpl");
112
	tmpl3 = $.templates("#my_tmpl");
113
	assert.equal(tmpl2 === tmpl3 && $.trim(tmpl2.render(person)), "A_Jo_B", 'var tmpl = $.templates("#my_tmpl"); returns compiled template for script element');
114
 
115
	$.templates({
116
		my_tmpl3: {
117
			markup: "#my_tmpl"
118
		}
119
	});
120
 
121
	assert.equal($.render.my_tmpl3 === $.templates.my_tmpl3 && $.templates.my_tmpl3 !== tmpl2 && $.trim($.render.my_tmpl3(person)), "A_Jo_B", 'Named template for template object with selector: {markup: "#my_tmpl"}');
122
 
123
	tmpl3 = $.templates("", {
124
		markup: "#my_tmpl"
125
	});
126
	assert.equal($.trim(tmpl3.render(person)), "A_Jo_B", 'Compile from template object with selector, without registering: {markup: "#my_tmpl"}');
127
 
128
	var tmpl4 = $.templates({
129
		markup: "#my_tmpl"
130
	});
131
	assert.equal($.trim(tmpl4.render(person)), "A_Jo_B", 'Compile from template object with selector, without registering: {markup: "#my_tmpl"}');
132
 
133
	assert.equal($.templates("#my_tmpl"), $.templates("#my_tmpl"), '$.templates("#my_tmpl") caches compiled template, and does not recompile each time;');
134
 
135
	assert.ok($.templates({markup: "#my_tmpl"}) !== $.templates({markup: "#my_tmpl"}), '$.templates({markup: "#my_tmpl" ...}) recompiles template, so as to merge additional options;');
136
 
137
	assert.equal($.templates("", "#my_tmpl"), $.templates("#my_tmpl"), '$.templates("#my_tmpl") and $.templates("", "#my_tmpl") are equivalent');
138
 
139
	var renamed = $.templates("renamed", "#my_tmpl");
140
	assert.ok(renamed === tmpl2 && renamed.tmplName === "renamed", '$.templates("renamed", "#my_tmpl") will rename the cached template');
141
 
142
	$.templates({renamed2: "#my_tmpl"});
143
	assert.ok($.templates.renamed2 === tmpl2 && $.templates.renamed2.tmplName === "renamed2", '$.templates({renamed2: "#my_tmpl"}) will rename the cached template');
144
 
145
	$.templates("cloned", {markup: "#my_tmpl"});
146
	assert.ok($.templates.cloned !== tmpl2 && $.templates.cloned.tmplName === "cloned", '$.templates("cloned", {markup: "#my_tmpl"}}) will clone the cached template');
147
 
148
	$.templates({cloned2: {markup: "#my_tmpl"}});
149
	assert.ok($.templates.cloned2 !== tmpl2 && $.templates.cloned2.tmplName === "cloned2", '$.templates({cloned: {markup: "#my_tmpl"}}) will clone the cached template');
150
 
151
	$.templates("my_tmpl", null);
152
	assert.equal($.templates.my_tmpl, undefined, 'Remove a named template: $.templates("my_tmpl", null);');
153
 
154
	$.templates({
155
		scriptTmpl: {
156
			markup: "#my_tmpl",
157
			debug:true
158
		},
159
		tmplFromString: {
160
			markup: "X_{{:name}}_Y",
161
			debug:true
162
		}
163
	});
164
	assert.equal($.templates.tmplFromString.fn.toString().indexOf("debugger;") > 0
165
		&& $.templates.scriptTmpl.fn.toString().indexOf("debugger;") > 0
166
		&& $.templates.scriptTmpl({name: "Jo"}) + $.templates.tmplFromString({name: "Jo"}), isIE8
167
		? "\nA_Jo_BX_Jo_Y"
168
		: "A_Jo_BX_Jo_Y",
169
		'Debug a template: set debug:true on object');
170
 
171
	// reset
172
	$("#my_tmpl")[0].removeAttribute("data-jsv-tmpl");
173
 
174
	delete $.templates.scriptTmpl;
175
});
176
 
177
QUnit.test("render", function(assert) {
178
	assert.equal($.trim($("#my_tmpl").render(person)), "A_Jo_B", '$(tmplSelector).render(data);'); // Trimming because IE adds whitespace
179
 
180
	var tmpl3 = $.templates("my_tmpl4", tmplString);
181
 
182
	assert.equal($.render.my_tmpl4(person), "A_Jo_B", '$.render.my_tmpl(object);');
183
	assert.equal($.render.my_tmpl4(people), "A_Jo_BA_Bill_B", '$.render.my_tmpl(array);');
184
 
185
	var tmplObject = $.templates.my_tmpl4;
186
	assert.equal(tmplObject.render(people), "A_Jo_BA_Bill_B", 'var tmplObject = $.templates.my_tmpl; tmplObject.render(data);');
187
 
188
	$.templates("my_tmpl5", "A_{{for}}inner{{:name}}content{{/for}}_B");
189
	assert.equal($.templates.my_tmpl5.tmpls[0].render(person), "innerJocontent", 'Nested template objects: $.templates.my_tmpl.tmpls');
190
 
191
	$("#result").html("<script id='tmpl' type='text/x-jsrender'>Content{{for #data}}{{:#index}}{{/for}}{{:~foo}}</script>");
192
	assert.equal($("#tmpl").render([null,undefined,1], {foo:"foovalue"}, true), (isIE8 ? "\n" : "") + "Content012foovalue", 'render(array, helpers, true) renders an array without iteration, while passing in helpers');
193
 
194
	$("#result").html("<script id='tmpl' type='text/x-jsrender'>Content{{for #data}}{{:#index}}{{/for}}{{:~foo}}</script>");
195
	assert.equal($("#tmpl").render([null, undefined, 1], true), (isIE8 ? "\n" : "") + "Content012", 'render(array, true) renders an array without iteration');
196
	$("#result").empty();
197
});
198
 
199
QUnit.test("converters", function(assert) {
200
	function loc(data) {
201
		switch (data) {case "desktop": return "bureau"; }
202
	}
203
	$.views.converters({loc: loc});
204
	assert.equal($.templates("{{loc:#data}}:{{loc:'desktop'}}").render("desktop"), "bureau:bureau", "$.views.converters({loc: locFunction})");
205
 
206
	$.views.converters("loc2", loc);
207
	assert.equal($.views.converters.loc2 === loc, true, 'locFunction === $.views.converters.loc');
208
 
209
	$.views.converters({loc2: null});
210
	assert.equal($.views.converters.loc2, undefined, 'Remove a registered converter: $.views.converters({loc: null})');
211
});
212
 
213
QUnit.test("tags", function(assert) {
214
	$.views.tags({sort1: sort});
215
	assert.equal($.templates("{{sort1 people reverse=true}}{{:name}}{{/sort1}}").render({people: people}), "BillJo", "$.views.tags({sort: sortFunction})");
216
 
217
	$.views.tags("sort2", sort);
218
	assert.equal($.views.tags.sort1.render === sort, true, 'sortFunction === $.views.tags.sort');
219
 
220
	$.views.tags("sort2", null);
221
	assert.equal($.views.tags.sort2, undefined, 'Remove a registered tag: $.views.tag({sor: null})');
222
});
223
 
224
QUnit.test("helpers", function(assert) {
225
	function concat() {
226
		return "".concat.apply("", arguments);
227
	}
228
 
229
	$.views.helpers({
230
		not: function(value) {
231
			return !value;
232
		},
233
		concat: concat
234
	});
235
	assert.equal($.templates("{{:~concat(a, 'b', ~not(false))}}").render({a: "aVal"}), "aValbtrue", "$.views.helpers({concat: concatFunction})");
236
 
237
	$.views.helpers({concat2: concat});
238
 
239
	assert.equal($.views.helpers.concat === concat, true, 'concatFunction === $.views.helpers.concat');
240
 
241
	$.views.helpers("concat2", null);
242
	assert.equal($.views.helpers.concat2, undefined, 'Remove a registered helper: $.views.helpers({concat: null})');
243
});
244
 
245
QUnit.test("template encapsulation", function(assert) {
246
	$.templates({
247
		myTmpl6: {
248
			markup: "{{sort reverse=true people}}{{:name}}{{/sort}}",
249
			tags: {
250
				sort: sort
251
			}
252
		}
253
	});
254
	assert.equal($.render.myTmpl6({people: people}), "BillJo", '$.templates("my_tmpl", tmplObjWithNestedItems);');
255
});
256
 
257
QUnit.test("$.views.viewModels", function(assert) {
258
	// =============================== Arrange ===============================
259
	var Constr = $.views.viewModels({getters: ["a", "b"]});
260
	// ................................ Act ..................................
261
	var vm = Constr("a1 ", "b1 ");
262
	var result = vm.a() + vm.b();
263
	vm.a("a2 ");
264
	vm.b("b2 ");
265
	result += vm.a() + vm.b();
266
	// ............................... Assert .................................
267
	assert.equal(result, "a1 b1 a2 b2 ", "viewModels, two getters, no methods");
268
 
269
	// =============================== Arrange ===============================
270
	Constr = $.views.viewModels({getters: ["a", "b", "c"], extend: {add: function(val) {
271
		this.c(val + this.a() + this.b() + this.c());
272
	}}});
273
	// ................................ Act ..................................
274
	vm = Constr("a1 ", "b1 ", "c1 ");
275
	vm.add("before ");
276
	result = vm.c();
277
	// ............................... Assert .................................
278
	assert.equal(result, "before a1 b1 c1 ", "viewModels, two getters, one method");
279
 
280
	// =============================== Arrange ===============================
281
	Constr = $.views.viewModels({extend: {add: function(val) {
282
		this.foo = val;
283
	}}});
284
	// ................................ Act ..................................
285
	vm = Constr();
286
	vm.add("before");
287
	result = vm.foo;
288
	// ............................... Assert .................................
289
	assert.equal(result, "before", "viewModels, no getters, one method");
290
 
291
	// =============================== Arrange ===============================
292
	Constr = $.views.viewModels({getters: []});
293
	// ................................ Act ..................................
294
	vm = Constr();
295
	result = JSON.stringify(vm);
296
	// ............................... Assert .................................
297
	assert.equal(result, "{}", "viewModels, no getters, no methods");
298
 
299
	// =============================== Arrange ===============================
300
	$.views.viewModels({
301
		T1: {
302
			getters: ["a", "b"]
303
		}
304
	});
305
	// ................................ Act ..................................
306
	vm = $.views.viewModels.T1.map({a: "a1 ", b: "b1 "});
307
 
308
	result = vm.a() + vm.b();
309
	vm.a("a2 ");
310
	vm.b("b2 ");
311
	result += vm.a() + vm.b();
312
 
313
	// ............................... Assert .................................
314
	assert.equal(result, "a1 b1 a2 b2 ", "viewModels, two getters, no methods");
315
 
316
	// ................................ Act ..................................
317
	vm.merge({a: "a3 ", b: "b3 "});
318
 
319
	result = vm.a() + vm.b();
320
 
321
	// ............................... Assert .................................
322
	assert.equal(result, "a3 b3 ", "viewModels merge, two getters, no methods");
323
 
324
	// ................................ Act ..................................
325
	result = vm.unmap();
326
	result = JSON.stringify(result);
327
 
328
	// ............................... Assert .................................
329
	assert.equal(result, '{"a":"a3 ","b":"b3 "}', "viewModels unmap, two getters, no methods");
330
 
331
	// =============================== Arrange ===============================
332
	var viewModels = $.views.viewModels({
333
		T1: {
334
			getters: ["a", {getter: "b"}, "c", "d", {getter: "e", type: undefined}, {getter: "f", type: null}, {getter: "g", type: "foo"}, {getter: "h", type: ""}]
335
		}
336
	}, {});
337
	// ................................ Act ..................................
338
	vm = viewModels.T1.map({a: "a1 ", b: "b1 ", c: "c1 ", d: "d1 ", e: "e1 ", f: "f1 ", g: "g1 ", h: "h1 "});
339
	result = vm.a() + vm.b() + vm.c() + vm.d() + vm.e() + vm.f() + vm.g() + vm.h();
340
	vm.a("a2 ");
341
	vm.b("b2 ");
342
	result += vm.a() + vm.b();
343
	// ............................... Assert .................................
344
	assert.equal(result, "a1 b1 c1 d1 e1 f1 g1 h1 a2 b2 ",
345
		"viewModels, multiple unmapped getters, no methods");
346
 
347
	// ................................ Act ..................................
348
	vm.merge({a: "a3 ", b: "b3 ", c: "c3 ", d: "d3 ", e: "e3 ", f: "f3 ", g: "g3 ", h: "h3 "});
349
 
350
	result = vm.a() + vm.b() + vm.c() + vm.d() + vm.e() + vm.f() + vm.g() + vm.h();
351
 
352
	// ............................... Assert .................................
353
	assert.equal(result, "a3 b3 c3 d3 e3 f3 g3 h3 ",
354
		"viewModels merge, multiple unmapped getters, no methods");
355
 
356
	// ................................ Act ..................................
357
	result = vm.unmap();
358
	result = JSON.stringify(result);
359
 
360
	// ............................... Assert .................................
361
	assert.equal(result, '{"a":"a3 ","b":"b3 ","c":"c3 ","d":"d3 ","e":"e3 ","f":"f3 ","g":"g3 ","h":"h3 "}',
362
		"viewModels unmap, multiple unmapped getters, no methods");
363
 
364
	// =============================== Arrange ===============================
365
	$.views.viewModels({
366
		T1: {
367
			getters: ["a", "b", "c"],
368
			extend : {
369
				add: function(val) {
370
					this.c(val + this.a() + this.b() + this.c());
371
				}
372
			}
373
		}
374
	});
375
 
376
	// ................................ Act ..................................
377
	vm = $.views.viewModels.T1.map({a: "a1 ", b: "b1 ", c: "c1 "});
378
 
379
	vm.add("before ");
380
	result = vm.c();
381
 
382
	// ............................... Assert .................................
383
	assert.equal(result, "before a1 b1 c1 ", "viewModels, getters and one method");
384
 
385
	// ................................ Act ..................................
386
	vm.merge({a: "a3 ", b: "b3 ", c: "c3 "});
387
	vm.add("updated ");
388
	result = vm.c();
389
 
390
	// ............................... Assert .................................
391
	assert.equal(result, "updated a3 b3 c3 ", "viewModels merge, getters and one method");
392
 
393
	// ................................ Act ..................................
394
	result = vm.unmap();
395
	result = JSON.stringify(result);
396
 
397
	// ............................... Assert .................................
398
	assert.equal(result, '{"a":"a3 ","b":"b3 ","c":"updated a3 b3 c3 "}', "viewModels unmap, getters and one method");
399
 
400
	// =============================== Arrange ===============================
401
	$.views.viewModels({
402
		T1: {
403
			getters: ["a", "b"]
404
		},
405
		T2: {
406
			getters: [{getter: "t1", type: "T1"}, {getter: "t1Arr", type: "T1"}, {getter: "t1OrNull", type: "T1", defaultVal: null}]
407
		}
408
	});
409
	viewModels = $.views.viewModels;
410
	// ................................ Act ..................................
411
	var t1 = viewModels.T1.map({a: "a1 ", b: "b1 "}); // Create a T1
412
	var t2 = viewModels.T2.map({t1: {a: "a3 ", b: "b3 "}, t1Arr: [t1.unmap(), {a: "a2 ", b: "b2 "}]}); // Create a T2 (using unmap to scrape values the T1: vm)
413
 
414
	result = JSON.stringify(t2.unmap());
415
 
416
	// ............................... Assert .................................
417
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
418
		"viewModels, hierarchy");
419
 
420
	// ................................ Act ..................................
421
	t2.t1Arr()[0].merge({a: "a1x ", b: "b1x "}); // merge not the root, but a VM instance within hierarchy: vm2.t1Arr()[0] - leaving rest unchanged
422
	result = JSON.stringify(t2.unmap());
423
 
424
	// ............................... Assert .................................
425
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1x ","b":"b1x "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
426
		"viewModels, merge deep node");
427
 
428
	// ................................ Act ..................................
429
	var t1Arr = viewModels.T1.map([{a: "a1 ", b: "b1 "}, {a: "a2 ", b: "b2 "}]); // Create a T1 array
430
	var t2FromArr =  viewModels.T2.map({t1: {a: "a3 ", b: "b3 "}, t1Arr: t1Arr.unmap()}); // Create a T2 (using unmap to scrape values the T1: vm)
431
	result = JSON.stringify(t2FromArr.unmap());
432
 
433
	// ............................... Assert .................................
434
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":null}',
435
		"viewModels, hierarchy");
436
 
437
	// ................................ Act ..................................
438
	t1Arr = viewModels.T1.map([{a: "a1 ", b: "b1 "}, {a: "a2 ", b: "b2 "}]); // Create a T1 array
439
	t1Arr.push(viewModels.T1("a3 ", "b3 "));
440
	t2FromArr = viewModels.T2.map({t1: {a: "a4 ", b: "b4 "}, t1Arr: t1Arr.unmap()}); // Create a T2 (using unmap to scrape values the T1: vm)
441
	result = JSON.stringify(t2FromArr.unmap());
442
 
443
	// ............................... Assert .................................
444
	assert.equal(result, '{"t1":{"a":"a4 ","b":"b4 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "},{"a":"a3 ","b":"b3 "}],"t1OrNull":null}',
445
		"viewModels, hierarchy");
446
 
447
	// ................................ Act ..................................
448
	var t2new= viewModels.T2(viewModels.T1("a3 ", "b3 "), [viewModels.T1("a1 ", "b1 "), viewModels.T1("a2 ", "b2 ")], viewModels.T1("a4 ", "b4 "));
449
	result = JSON.stringify(t2new.unmap());
450
 
451
	// ............................... Assert .................................
452
	assert.equal(result, '{"t1":{"a":"a3 ","b":"b3 "},"t1Arr":[{"a":"a1 ","b":"b1 "},{"a":"a2 ","b":"b2 "}],"t1OrNull":{"a":"a4 ","b":"b4 "}}',
453
		"viewModels, hierarchy");
454
});
455
 
456
})(this, this.jQuery);