Commits

Stephen McKamey committed bf90d74

- reorganizing files

  • Participants
  • Parent commits 80d3966

Comments (0)

Files changed (10)

File src/duel.tests.html

-<!DOCTYPE html>
-<html>
-<head>
-	<title>duel.js tests</title>
-
-	<link href="../lib/qunit/qunit.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-	<script src="../lib/qunit/qunit.js" type="text/javascript"></script>
-	<script src="../duel.min.js" type="text/javascript"></script>
-
-	<h1 id="qunit-header">duel.js tests</h1>  
-	<h2 id="qunit-banner"></h2>  
-	<h2 id="qunit-userAgent"></h2>  
-	<ol id="qunit-tests"></ol> 
-
-	<script src="domUtils.js" type="text/javascript"></script>
-	<script src="bind.js" type="text/javascript"></script>
-	<script src="render.js" type="text/javascript"></script>
-	<script src="build.js" type="text/javascript"></script>
-
-</body>
-</html>

File src/tests/bind.js

-module("View.bind()");
-
-test("static view", function() {
-
-	var expected =
-		["div", { "class" : "list", "style" : "color:blue" },
-			["h2", "This is the title"],
-			["ul",
-				["li", { "class" : "item" },
-					["b", "Example"],
-					": ",
-					["i", "First!"]
-				],
-				["li", { "class" : "item" },
-					["b", "Sample"],
-					": ",
-					["i", "Last!"]
-				]
-			]
-		];
-
-	var actual = duel(expected).bind().value;
-
-	same(actual, expected, "");
-});
-
-test("simple expressions", function() {
-
-	var model = {
-	        name: "Foo.js",
-	        url: "http://example.com/foo.js",
-	        size: 5.87,
-	        details: "Lorem ipsum dolor sit amet"
-	    };
-
-	var view = duel(
-		["div", { "class" : "download" },
-			["h2",
-			 	"Filename: ",
-				function(model, index, count) { return model.name; }
-			],
-			["p",
-			 	"URL: ",
-			 	["a", { "href" : function(model, index, count) { return model.url; }, "target" : "_blank" },
-			 	 	function(model, index, count) { return model.url ;}
-			 	],
-			 	" (",
-			 	function(model, index, count) { return model.size ;},
-			 	"KB)"
-		 	],
-			["p",
-			 	"Description: ",
-			 	function(model, index, count) { return model.details; }
-			]
-		]);
-
-	var actual = view.bind(model).value;
-
-	var expected = 
-		["div", { "class" : "download" },
-			["h2",
-			 	"Filename: Foo.js"
-			],
-			["p",
-			 	"URL: ",
-			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank" },
-			 		"http://example.com/foo.js"
-		 		],
-			 	" (5.87KB)"
-		 	],
-			["p",
-			 	"Description: Lorem ipsum dolor sit amet"
-			]
-		];
-
-	same(actual, expected, "");
-});
-
-test("simple orphaned if/else", function() {
-
-	var view = duel(
-		["",
-		 	["$if", { "test" : function(model, index, count) { return model.name === "Example"; } },
-		 	 	["p", "True: Example === ", function(model, index, count) { return model.name; } ]
-		 	],
-		 	["$if", { "test" : function(model, index, count) { return model.name !== "Example"; } },
-		 	 	["p", "False: Example !== ", function(model, index, count) { return model.name; } ]
-		 	],
-		 	["$else",
-		 	 	["p", "Both: orphaned else always executes" ]
-		 	]
-		]);
-
-	var model1 = { name: "Example" };
-	var actual1 = view.bind(model1).value;
-	var expected1 =
-		["",
-		 	["p", "True: Example === Example"],
-		 	["p", "Both: orphaned else always executes" ]
-		];
-
-	same(actual1, expected1, "Binding with simple if statements.");
-
-	var model2 = { name: "Sample" };
-	var actual2 = view.bind(model2).value;
-	var expected2 =
-		["",
-		 	["p", "False: Example !== Sample"],
-		 	["p", "Both: orphaned else always executes" ]
-		];
-
-	same(actual2, expected2, "");
-});
-
-test("choose", function() {
-
-	var view = duel(
-	 	["$choose",
-		 	["$if", { "test" : function(model, index, count) { return !model.children || !model.children.length; } },
-		 	 	["p", "Has no items."]
-		 	],
-		 	["$if", { "test" : function(model, index, count) { return model.children && model.children.length === 1; } },
-		 	 	["p", "Has only one item."]
-		 	],
-		 	["$else",
-		 	 	["p", "Has ", function(model, index, count) { return model.children.length; }, " items."]
-		 	]
-	 	]);
-
-	var model1 = { name: "Three", children: [0,2,4] };
-	var actual1 = view.bind(model1).value;
-	var expected1 = ["p", "Has 3 items."];
-
-	same(actual1, expected1, "Binding with choose block.");
-
-	var model2 = { name: "One", children: [42] };
-	var actual2 = view.bind(model2).value;
-	var expected2 = ["p", "Has only one item."];
-
-	same(actual2, expected2, "Binding with choose block.");
-
-	var model3 = { name: "Zero", children: [] };
-	var actual3 = view.bind(model3).value;
-	var expected3 = ["p", "Has no items."];
-
-	same(actual3, expected3, "");
-});
-
-test("foreach array", function() {
-
-	var model = {
-	        title: "This is the title",
-	        items: [
-	            { name: "One" },
-	            { name: "Two" },
-	            { name: "Three" },
-	            { name: "Four" },
-	            { name: "Five" }
-	        ]
-	    };
-
-	var view = duel(
-		["div", { "class" : "list", "style" : "color:blue" },
-			["h2",
-			 	function(model, index, count) { return model.title; }
-			],
-			["ul",
-			 	["$for", { "each" : function(model, index, count) { return model.items; } },
-					["li", { "class" : "item" },
-						["b",
-						 	function(model, index, count) { return model.name; }
-						],
-						": ",
-						["i",
-						 	function(model, index, count) { return index + 1; },
-							" of ",
-							function(model, index, count) { return count; }
-						]
-					]
-			 	]
-			]
-		]);
-
-	var actual = view.bind(model).value;
-
-	var expected =
-		["div", { "class" : "list", "style" : "color:blue" },
-			["h2", "This is the title"],
-			["ul",
-				["li", { "class" : "item" },
-					["b", "One"],
-					": ",
-					["i", "1 of 5"]
-				],
-				["li", { "class" : "item" },
-					["b", "Two"],
-					": ",
-					["i", "2 of 5" ]
-				],
-				["li", { "class" : "item" },
-					["b", "Three"],
-					": ",
-					["i", "3 of 5"]
-				],
-				["li", { "class" : "item" },
-					["b", "Four"],
-					": ",
-					["i", "4 of 5"]
-				],
-				["li", { "class" : "item" },
-					["b", "Five"],
-					": ",
-					["i", "5 of 5"]
-				]
-			]
-		];
-
-	same(actual, expected, "");
-});
-
-test("foreach object", function() {
-	var model = {
-	        name: "List of items",
-	        total: 5,
-	        items: [
-	            "One",
-	            "Two",
-	            "Three",
-	            "Four",
-	            "Five"
-	        ]
-	    };
-
-	var view = duel(
-		["",
-		 	"model => ",
-		 	["dl",
-				["$for", { "each" : function(model, index, count) { return model; } },
-				 	["dt",
-					 	function(model, index, count) { return index; },
-					 	" : "],
-					["dd",
-					 	"(",
-					 	function(model, index, count) { return (model instanceof Array) ? "array" : typeof model; },
-					 	") ",
-					 	function(model, index, count) { return "" + model; }
-				 	]
-			 	]
-		 	]
-	 	]);
-
-	var actual = view.bind(model).value;
-
-	var expected =
-		["",
-		 	"model => ",
-		 	["dl",
-		 	 	["dt", "name : "],
-		 	 	["dd", "(string) List of items"],
-		 	 	["dt", "total : "],
-		 	 	["dd", "(number) 5"],
-		 	 	["dt", "items : "],
-				["dd", "(array) One,Two,Three,Four,Five"]
-		 	]
-	 	];
-
-	same(actual, expected, "");
-});
-
-test("markup data", function() {
-
-	var model = {
-	        details: "<blink>Lorem ipsum dolor sit amet</blink>"
-	    };
-
-	var view = duel(
-		["div", { "class" : "test" },
-			["p",
-			 	"Description: ",
-			 	function(model, index, count) { return duel.raw(model.details); }
-			]
-		]);
-
-	var actual = view.bind(model).value;
-
-	var expected = 
-		["div", { "class" : "test" },
-			["p",
-			 	"Description: ",
-			 	duel.raw("<blink>Lorem ipsum dolor sit amet</blink>")
-			]
-		];
-
-	same(actual, expected, "");
-});
-
-test("call view", function() {
-
-	var model = {
-	        name: "Outer list",
-	        items: ["One", "Two", "Three"]
-	    };
-
-	var Foo = {
-			itemView: duel(
-					["li",
-					 	"model: ",
-					 	function(model, index, count) { return model; },
-					 	["br"],
-					 	"index: ",
-					 	function(model, index, count) { return index; },
-					 	["br"],
-					 	"count: ",
-					 	function(model, index, count) { return count; },
-					]),
-			listView: duel(
-					["div",
-					 	["h2", function(model, index, count) { return model.name; } ],
-						["ul",
-						 	["$for", { "each" : function(model, index, count) { return model.items; } },
-						 		["$call", {
-							 			"view" : function(model, index, count) { return Foo.itemView; },
-							 			"model" :  function(model, index, count) { return model; },
-							 			"index" :  function(model, index, count) { return index; },
-							 			"count" :  function(model, index, count) { return count; }
-						 			}
-						 		]
-						 	]
-						]
-					])
-			};
-
-	var actual = Foo.listView.bind(model).value;
-
-	var expected = 
-		["div",
-		 	["h2", "Outer list" ],
-			["ul",
-				["li",
-					"model: One",
-					["br"],
-					"index: 0",
-					["br"],
-					"count: 3"
-				],
-				["li",
-					"model: Two",
-					["br"],
-					"index: 1",
-					["br"],
-					"count: 3"
-				],
-				["li",
-					"model: Three",
-					["br"],
-					"index: 2",
-					["br"],
-					"count: 3"
-				]
-			]
-		];
-
-	same(actual, expected, "");
-});

File src/tests/build.js

-module("Result.toDOM()");
-
-test("nested elements with attributes", function() {
-
-	var view = duel(
-		["div", { "class" : "download" },
-			["h2",
-			 	"Filename: Foo.js"
-			],
-			["p",
-			 	"URL: ",
-			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank", "title" : "Lorem ipsum dolor sit amet" },
-			 		"http://example.com/foo.js"
-		 		],
-			 	" (5.87KB)"
-		 	],
-			["p",
-			 	"Description: Lorem ipsum dolor sit amet"
-			]
-		]);
-
-	var actual = view.bind().toDOM();
-
-	var temp, expected = document.createElement("div");
-	expected.setAttribute("class", "download");
-
-	temp = document.createElement("h2");
-	temp.appendChild(document.createTextNode("Filename: Foo.js"));
-	expected.appendChild(temp);
-
-	temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("URL: "));
-	var temp2 = document.createElement("a");
-	temp2.setAttribute("href", "http://example.com/foo.js");
-	temp2.setAttribute("target", "_blank");
-	temp2.setAttribute("title", "Lorem ipsum dolor sit amet");
-	temp2.appendChild(document.createTextNode("http://example.com/foo.js"));
-	temp.appendChild(temp2);
-	temp.appendChild(document.createTextNode(" (5.87KB)"));
-	expected.appendChild(temp);
-
-	temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Description: Lorem ipsum dolor sit amet"));
-	expected.appendChild(temp);
-
-	same(toHTML(actual), toHTML(expected), "");
-});
-
-test("docFrag root", function() {
-
-	var view = duel(
-		["",
-		 	["p", "Inner child one."],
-		 	["p", "Inner child two." ]
-		]);
-
-	var actual = view.bind().toDOM();
-
-	var expected = document.createDocumentFragment();
-
-	var temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Inner child one."));
-	expected.appendChild(temp);
-
-	temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Inner child two."));
-	expected.appendChild(temp);
-
-	same(toHTML(actual), toHTML(expected), "");
-});
-
-test("docFrag inner", function() {
-
-	var view = duel(
-		["div",
-			["",
-			 	["p", "Inner child one."],
-			 	["p", "Inner child two." ]
-			]
-		]);
-
-	var actual = view.bind().toDOM();
-
-	var expected = document.createElement("div");
-
-	var temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Inner child one."));
-	expected.appendChild(temp);
-
-	temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Inner child two."));
-	expected.appendChild(temp);
-
-	same(toHTML(actual), toHTML(expected), "");
-});
-
-test("markup data", function() {
-
-	var view = duel(
-		["div", { "class" : "test" },
-			["p",
-			 	"Description: ",
-			 	duel.raw("<b>Lorem </b>"),
-			 	duel.raw("<blink>ipsum</blink>"),
-			 	" ",
-			 	duel.raw("<i>dolor sit amet</i>")
-			]
-		]);
-
-	var actual = view.bind().toDOM();
-
-	var expected = document.createElement("div");
-	expected.className = "test";
-
-	var temp = document.createElement("p");
-	temp.appendChild(document.createTextNode("Description: "));
-
-	var temp2 = document.createElement("div");
-	temp2.innerHTML = "<b>Lorem </b>";
-	while (temp2.firstChild) {
-		temp.appendChild(temp2.firstChild);
-	}
-	temp2.innerHTML = "<blink>ipsum</blink>";
-	while (temp2.firstChild) {
-		temp.appendChild(temp2.firstChild);
-	}
-
-	temp.appendChild(document.createTextNode(" "));
-	temp2.innerHTML = "<i>dolor sit amet</i>";
-	while (temp2.firstChild) {
-		temp.appendChild(temp2.firstChild);
-	}
-
-	expected.appendChild(temp);
-
-	same(toHTML(actual), toHTML(expected), "");
-});

File src/tests/domUtils.js

-function toHTML(node) {
-	var root = document.createElement("div");
-	root.appendChild(node);
-	return root.innerHTML;
-}

File src/tests/render.js

-module("Result.toString()");
-
-test("nested elements with attributes", function() {
-
-	var view = duel(
-		["div", { "class" : "download" },
-			["h2",
-			 	"Filename: Foo.js"
-			],
-			["p",
-			 	"URL: ",
-			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank", "title" : "Lorem ipsum dolor sit amet" },
-			 		"http://example.com/foo.js"
-		 		],
-			 	" (5.87KB)"
-		 	],
-			["p",
-			 	"Description: Lorem ipsum dolor sit amet"
-			]
-		]);
-
-	var actual = view.bind().toString();
-
-	var expected =
-		'<div class="download"><h2>Filename: Foo.js</h2>'+
-		'<p>URL: <a href="http://example.com/foo.js" target="_blank" title="Lorem ipsum dolor sit amet">http://example.com/foo.js</a> (5.87KB)</p>'+
-		'<p>Description: Lorem ipsum dolor sit amet</p>'+
-		'</div>';
-
-	same(actual, expected, "");
-});
-
-test("docFrag root", function() {
-
-	var view = duel(
-		["",
-		 	["p", "Inner child one."],
-		 	["p", "Inner child two." ]
-		]);
-
-	var actual = view.bind().toString();
-	var expected = '<p>Inner child one.</p><p>Inner child two.</p>';
-
-	same(actual, expected, "");
-});
-
-test("docFrag inner", function() {
-
-	var view = duel(
-		["div",
-			["",
-			 	["p", "Inner child one."],
-			 	["p", "Inner child two." ]
-			]
-		]);
-
-	var actual = view.bind().toString();
-	var expected = '<div><p>Inner child one.</p><p>Inner child two.</p></div>';
-
-	same(actual, expected, "");
-});
-
-test("encoding literal", function() {
-
-	var view = duel(
-		["p",
-		 	'&hello"foo<bar><&>'
-		]);
-
-	var actual = view.bind().toString();
-
-	var expected =  '<p>&amp;hello"foo&lt;bar&gt;&lt;&amp;&gt;</p>';
-	
-	same(actual, expected, "");
-});
-
-test("encoding attributes", function() {
-
-	var view = duel(
-		["p", { "title" : '&hello"foo<bar><&>' },
-		 	"Encoded attributes"
-		]);
-
-	var actual = view.bind().toString();
-
-	var expected =  '<p title="&amp;hello&quot;foo&lt;bar&gt;&lt;&amp;&gt;">Encoded attributes</p>';
-	
-	same(actual, expected, "");
-});
-
-test("markup data", function() {
-
-	var view = duel(
-		["div", { "class" : "test" },
-			["p",
-			 	"Description: ",
-			 	duel.raw("<b>Lorem </b>"),
-			 	duel.raw("<blink>ipsum</blink>"),
-			 	" ",
-			 	duel.raw("<i>dolor sit amet</i>")
-			]
-		]);
-
-	var actual = view.bind().toString();
-
-	var expected = 
-		'<div class="test">'+
-		'<p>Description: <b>Lorem </b><blink>ipsum</blink> <i>dolor sit amet</i></p>'+
-		'</div>';
-	same(actual, expected, "");
-});

File test/index.html

+<!DOCTYPE html>
+<html>
+<head>
+	<title>duel.js tests</title>
+
+	<link href="../lib/qunit/qunit.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+	<script src="../lib/qunit/qunit.js" type="text/javascript"></script>
+	<script src="../src/duel.min.js" type="text/javascript"></script>
+
+	<h1 id="qunit-header">duel.js tests</h1>  
+	<h2 id="qunit-banner"></h2>  
+	<h2 id="qunit-userAgent"></h2>  
+	<ol id="qunit-tests"></ol> 
+
+	<script src="utils.js" type="text/javascript"></script>
+	<script src="unit/bind.js" type="text/javascript"></script>
+	<script src="unit/render.js" type="text/javascript"></script>
+	<script src="unit/build.js" type="text/javascript"></script>
+</body>
+</html>

File test/unit/bind.js

+module("View.bind()");
+
+test("static view", function() {
+
+	var expected =
+		["div", { "class" : "list", "style" : "color:blue" },
+			["h2", "This is the title"],
+			["ul",
+				["li", { "class" : "item" },
+					["b", "Example"],
+					": ",
+					["i", "First!"]
+				],
+				["li", { "class" : "item" },
+					["b", "Sample"],
+					": ",
+					["i", "Last!"]
+				]
+			]
+		];
+
+	var actual = duel(expected).bind().value;
+
+	same(actual, expected, "");
+});
+
+test("simple expressions", function() {
+
+	var model = {
+	        name: "Foo.js",
+	        url: "http://example.com/foo.js",
+	        size: 5.87,
+	        details: "Lorem ipsum dolor sit amet"
+	    };
+
+	var view = duel(
+		["div", { "class" : "download" },
+			["h2",
+			 	"Filename: ",
+				function(model, index, count) { return model.name; }
+			],
+			["p",
+			 	"URL: ",
+			 	["a", { "href" : function(model, index, count) { return model.url; }, "target" : "_blank" },
+			 	 	function(model, index, count) { return model.url ;}
+			 	],
+			 	" (",
+			 	function(model, index, count) { return model.size ;},
+			 	"KB)"
+		 	],
+			["p",
+			 	"Description: ",
+			 	function(model, index, count) { return model.details; }
+			]
+		]);
+
+	var actual = view.bind(model).value;
+
+	var expected = 
+		["div", { "class" : "download" },
+			["h2",
+			 	"Filename: Foo.js"
+			],
+			["p",
+			 	"URL: ",
+			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank" },
+			 		"http://example.com/foo.js"
+		 		],
+			 	" (5.87KB)"
+		 	],
+			["p",
+			 	"Description: Lorem ipsum dolor sit amet"
+			]
+		];
+
+	same(actual, expected, "");
+});
+
+test("simple orphaned if/else", function() {
+
+	var view = duel(
+		["",
+		 	["$if", { "test" : function(model, index, count) { return model.name === "Example"; } },
+		 	 	["p", "True: Example === ", function(model, index, count) { return model.name; } ]
+		 	],
+		 	["$if", { "test" : function(model, index, count) { return model.name !== "Example"; } },
+		 	 	["p", "False: Example !== ", function(model, index, count) { return model.name; } ]
+		 	],
+		 	["$else",
+		 	 	["p", "Both: orphaned else always executes" ]
+		 	]
+		]);
+
+	var model1 = { name: "Example" };
+	var actual1 = view.bind(model1).value;
+	var expected1 =
+		["",
+		 	["p", "True: Example === Example"],
+		 	["p", "Both: orphaned else always executes" ]
+		];
+
+	same(actual1, expected1, "Binding with simple if statements.");
+
+	var model2 = { name: "Sample" };
+	var actual2 = view.bind(model2).value;
+	var expected2 =
+		["",
+		 	["p", "False: Example !== Sample"],
+		 	["p", "Both: orphaned else always executes" ]
+		];
+
+	same(actual2, expected2, "");
+});
+
+test("choose", function() {
+
+	var view = duel(
+	 	["$choose",
+		 	["$if", { "test" : function(model, index, count) { return !model.children || !model.children.length; } },
+		 	 	["p", "Has no items."]
+		 	],
+		 	["$if", { "test" : function(model, index, count) { return model.children && model.children.length === 1; } },
+		 	 	["p", "Has only one item."]
+		 	],
+		 	["$else",
+		 	 	["p", "Has ", function(model, index, count) { return model.children.length; }, " items."]
+		 	]
+	 	]);
+
+	var model1 = { name: "Three", children: [0,2,4] };
+	var actual1 = view.bind(model1).value;
+	var expected1 = ["p", "Has 3 items."];
+
+	same(actual1, expected1, "Binding with choose block.");
+
+	var model2 = { name: "One", children: [42] };
+	var actual2 = view.bind(model2).value;
+	var expected2 = ["p", "Has only one item."];
+
+	same(actual2, expected2, "Binding with choose block.");
+
+	var model3 = { name: "Zero", children: [] };
+	var actual3 = view.bind(model3).value;
+	var expected3 = ["p", "Has no items."];
+
+	same(actual3, expected3, "");
+});
+
+test("foreach array", function() {
+
+	var model = {
+	        title: "This is the title",
+	        items: [
+	            { name: "One" },
+	            { name: "Two" },
+	            { name: "Three" },
+	            { name: "Four" },
+	            { name: "Five" }
+	        ]
+	    };
+
+	var view = duel(
+		["div", { "class" : "list", "style" : "color:blue" },
+			["h2",
+			 	function(model, index, count) { return model.title; }
+			],
+			["ul",
+			 	["$for", { "each" : function(model, index, count) { return model.items; } },
+					["li", { "class" : "item" },
+						["b",
+						 	function(model, index, count) { return model.name; }
+						],
+						": ",
+						["i",
+						 	function(model, index, count) { return index + 1; },
+							" of ",
+							function(model, index, count) { return count; }
+						]
+					]
+			 	]
+			]
+		]);
+
+	var actual = view.bind(model).value;
+
+	var expected =
+		["div", { "class" : "list", "style" : "color:blue" },
+			["h2", "This is the title"],
+			["ul",
+				["li", { "class" : "item" },
+					["b", "One"],
+					": ",
+					["i", "1 of 5"]
+				],
+				["li", { "class" : "item" },
+					["b", "Two"],
+					": ",
+					["i", "2 of 5" ]
+				],
+				["li", { "class" : "item" },
+					["b", "Three"],
+					": ",
+					["i", "3 of 5"]
+				],
+				["li", { "class" : "item" },
+					["b", "Four"],
+					": ",
+					["i", "4 of 5"]
+				],
+				["li", { "class" : "item" },
+					["b", "Five"],
+					": ",
+					["i", "5 of 5"]
+				]
+			]
+		];
+
+	same(actual, expected, "");
+});
+
+test("foreach object", function() {
+	var model = {
+	        name: "List of items",
+	        total: 5,
+	        items: [
+	            "One",
+	            "Two",
+	            "Three",
+	            "Four",
+	            "Five"
+	        ]
+	    };
+
+	var view = duel(
+		["",
+		 	"model => ",
+		 	["dl",
+				["$for", { "each" : function(model, index, count) { return model; } },
+				 	["dt",
+					 	function(model, index, count) { return index; },
+					 	" : "],
+					["dd",
+					 	"(",
+					 	function(model, index, count) { return (model instanceof Array) ? "array" : typeof model; },
+					 	") ",
+					 	function(model, index, count) { return "" + model; }
+				 	]
+			 	]
+		 	]
+	 	]);
+
+	var actual = view.bind(model).value;
+
+	var expected =
+		["",
+		 	"model => ",
+		 	["dl",
+		 	 	["dt", "name : "],
+		 	 	["dd", "(string) List of items"],
+		 	 	["dt", "total : "],
+		 	 	["dd", "(number) 5"],
+		 	 	["dt", "items : "],
+				["dd", "(array) One,Two,Three,Four,Five"]
+		 	]
+	 	];
+
+	same(actual, expected, "");
+});
+
+test("markup data", function() {
+
+	var model = {
+	        details: "<blink>Lorem ipsum dolor sit amet</blink>"
+	    };
+
+	var view = duel(
+		["div", { "class" : "test" },
+			["p",
+			 	"Description: ",
+			 	function(model, index, count) { return duel.raw(model.details); }
+			]
+		]);
+
+	var actual = view.bind(model).value;
+
+	var expected = 
+		["div", { "class" : "test" },
+			["p",
+			 	"Description: ",
+			 	duel.raw("<blink>Lorem ipsum dolor sit amet</blink>")
+			]
+		];
+
+	same(actual, expected, "");
+});
+
+test("call view", function() {
+
+	var model = {
+	        name: "Outer list",
+	        items: ["One", "Two", "Three"]
+	    };
+
+	var Foo = {
+			itemView: duel(
+					["li",
+					 	"model: ",
+					 	function(model, index, count) { return model; },
+					 	["br"],
+					 	"index: ",
+					 	function(model, index, count) { return index; },
+					 	["br"],
+					 	"count: ",
+					 	function(model, index, count) { return count; },
+					]),
+			listView: duel(
+					["div",
+					 	["h2", function(model, index, count) { return model.name; } ],
+						["ul",
+						 	["$for", { "each" : function(model, index, count) { return model.items; } },
+						 		["$call", {
+							 			"view" : function(model, index, count) { return Foo.itemView; },
+							 			"model" :  function(model, index, count) { return model; },
+							 			"index" :  function(model, index, count) { return index; },
+							 			"count" :  function(model, index, count) { return count; }
+						 			}
+						 		]
+						 	]
+						]
+					])
+			};
+
+	var actual = Foo.listView.bind(model).value;
+
+	var expected = 
+		["div",
+		 	["h2", "Outer list" ],
+			["ul",
+				["li",
+					"model: One",
+					["br"],
+					"index: 0",
+					["br"],
+					"count: 3"
+				],
+				["li",
+					"model: Two",
+					["br"],
+					"index: 1",
+					["br"],
+					"count: 3"
+				],
+				["li",
+					"model: Three",
+					["br"],
+					"index: 2",
+					["br"],
+					"count: 3"
+				]
+			]
+		];
+
+	same(actual, expected, "");
+});

File test/unit/build.js

+module("Result.toDOM()");
+
+test("nested elements with attributes", function() {
+
+	var view = duel(
+		["div", { "class" : "download" },
+			["h2",
+			 	"Filename: Foo.js"
+			],
+			["p",
+			 	"URL: ",
+			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank", "title" : "Lorem ipsum dolor sit amet" },
+			 		"http://example.com/foo.js"
+		 		],
+			 	" (5.87KB)"
+		 	],
+			["p",
+			 	"Description: Lorem ipsum dolor sit amet"
+			]
+		]);
+
+	var actual = view.bind().toDOM();
+
+	var temp, expected = document.createElement("div");
+	expected.setAttribute("class", "download");
+
+	temp = document.createElement("h2");
+	temp.appendChild(document.createTextNode("Filename: Foo.js"));
+	expected.appendChild(temp);
+
+	temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("URL: "));
+	var temp2 = document.createElement("a");
+	temp2.setAttribute("href", "http://example.com/foo.js");
+	temp2.setAttribute("target", "_blank");
+	temp2.setAttribute("title", "Lorem ipsum dolor sit amet");
+	temp2.appendChild(document.createTextNode("http://example.com/foo.js"));
+	temp.appendChild(temp2);
+	temp.appendChild(document.createTextNode(" (5.87KB)"));
+	expected.appendChild(temp);
+
+	temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Description: Lorem ipsum dolor sit amet"));
+	expected.appendChild(temp);
+
+	same(toHTML(actual), toHTML(expected), "");
+});
+
+test("docFrag root", function() {
+
+	var view = duel(
+		["",
+		 	["p", "Inner child one."],
+		 	["p", "Inner child two." ]
+		]);
+
+	var actual = view.bind().toDOM();
+
+	var expected = document.createDocumentFragment();
+
+	var temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Inner child one."));
+	expected.appendChild(temp);
+
+	temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Inner child two."));
+	expected.appendChild(temp);
+
+	same(toHTML(actual), toHTML(expected), "");
+});
+
+test("docFrag inner", function() {
+
+	var view = duel(
+		["div",
+			["",
+			 	["p", "Inner child one."],
+			 	["p", "Inner child two." ]
+			]
+		]);
+
+	var actual = view.bind().toDOM();
+
+	var expected = document.createElement("div");
+
+	var temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Inner child one."));
+	expected.appendChild(temp);
+
+	temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Inner child two."));
+	expected.appendChild(temp);
+
+	same(toHTML(actual), toHTML(expected), "");
+});
+
+test("markup data", function() {
+
+	var view = duel(
+		["div", { "class" : "test" },
+			["p",
+			 	"Description: ",
+			 	duel.raw("<b>Lorem </b>"),
+			 	duel.raw("<blink>ipsum</blink>"),
+			 	" ",
+			 	duel.raw("<i>dolor sit amet</i>")
+			]
+		]);
+
+	var actual = view.bind().toDOM();
+
+	var expected = document.createElement("div");
+	expected.className = "test";
+
+	var temp = document.createElement("p");
+	temp.appendChild(document.createTextNode("Description: "));
+
+	var temp2 = document.createElement("div");
+	temp2.innerHTML = "<b>Lorem </b>";
+	while (temp2.firstChild) {
+		temp.appendChild(temp2.firstChild);
+	}
+	temp2.innerHTML = "<blink>ipsum</blink>";
+	while (temp2.firstChild) {
+		temp.appendChild(temp2.firstChild);
+	}
+
+	temp.appendChild(document.createTextNode(" "));
+	temp2.innerHTML = "<i>dolor sit amet</i>";
+	while (temp2.firstChild) {
+		temp.appendChild(temp2.firstChild);
+	}
+
+	expected.appendChild(temp);
+
+	same(toHTML(actual), toHTML(expected), "");
+});

File test/unit/render.js

+module("Result.toString()");
+
+test("nested elements with attributes", function() {
+
+	var view = duel(
+		["div", { "class" : "download" },
+			["h2",
+			 	"Filename: Foo.js"
+			],
+			["p",
+			 	"URL: ",
+			 	["a", { "href" : "http://example.com/foo.js", "target" : "_blank", "title" : "Lorem ipsum dolor sit amet" },
+			 		"http://example.com/foo.js"
+		 		],
+			 	" (5.87KB)"
+		 	],
+			["p",
+			 	"Description: Lorem ipsum dolor sit amet"
+			]
+		]);
+
+	var actual = view.bind().toString();
+
+	var expected =
+		'<div class="download"><h2>Filename: Foo.js</h2>'+
+		'<p>URL: <a href="http://example.com/foo.js" target="_blank" title="Lorem ipsum dolor sit amet">http://example.com/foo.js</a> (5.87KB)</p>'+
+		'<p>Description: Lorem ipsum dolor sit amet</p>'+
+		'</div>';
+
+	same(actual, expected, "");
+});
+
+test("docFrag root", function() {
+
+	var view = duel(
+		["",
+		 	["p", "Inner child one."],
+		 	["p", "Inner child two." ]
+		]);
+
+	var actual = view.bind().toString();
+	var expected = '<p>Inner child one.</p><p>Inner child two.</p>';
+
+	same(actual, expected, "");
+});
+
+test("docFrag inner", function() {
+
+	var view = duel(
+		["div",
+			["",
+			 	["p", "Inner child one."],
+			 	["p", "Inner child two." ]
+			]
+		]);
+
+	var actual = view.bind().toString();
+	var expected = '<div><p>Inner child one.</p><p>Inner child two.</p></div>';
+
+	same(actual, expected, "");
+});
+
+test("encoding literal", function() {
+
+	var view = duel(
+		["p",
+		 	'&hello"foo<bar><&>'
+		]);
+
+	var actual = view.bind().toString();
+
+	var expected =  '<p>&amp;hello"foo&lt;bar&gt;&lt;&amp;&gt;</p>';
+	
+	same(actual, expected, "");
+});
+
+test("encoding attributes", function() {
+
+	var view = duel(
+		["p", { "title" : '&hello"foo<bar><&>' },
+		 	"Encoded attributes"
+		]);
+
+	var actual = view.bind().toString();
+
+	var expected =  '<p title="&amp;hello&quot;foo&lt;bar&gt;&lt;&amp;&gt;">Encoded attributes</p>';
+	
+	same(actual, expected, "");
+});
+
+test("markup data", function() {
+
+	var view = duel(
+		["div", { "class" : "test" },
+			["p",
+			 	"Description: ",
+			 	duel.raw("<b>Lorem </b>"),
+			 	duel.raw("<blink>ipsum</blink>"),
+			 	" ",
+			 	duel.raw("<i>dolor sit amet</i>")
+			]
+		]);
+
+	var actual = view.bind().toString();
+
+	var expected = 
+		'<div class="test">'+
+		'<p>Description: <b>Lorem </b><blink>ipsum</blink> <i>dolor sit amet</i></p>'+
+		'</div>';
+	same(actual, expected, "");
+});

File test/utils.js

+function toHTML(node) {
+	var root = document.createElement("div");
+	root.appendChild(node);
+	return root.innerHTML;
+}