";
var d: any = document.createElement("div");
// Passes a container, purposefully leave this going through render path
var templatePromise = Template.render(holder.firstChild, { rating: 3 }, d);
var rating = d.children[0].children[0].winControl;
LiveUnit.Assert.isTrue(rating instanceof global.MyCustomControl);
LiveUnit.Assert.areEqual(0, rating.userRating);
LiveUnit.Assert.areEqual(10, rating.maxRating);
var async = d.children[1].winControl;
LiveUnit.Assert.isTrue(async instanceof global.AsyncTemplate.AsyncControl);
// bindings should not run until async controls are done being constructed
//
async.completeMe();
LiveUnit.Assert.areEqual(3, rating.userRating);
return templatePromise;
});
testBooleanAttributes = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "
";
var data = as({ a: null });
return this._render(new Template(holder), data).then(function (d) {
var content = d.querySelector(".content").textContent;
// Firefox has a bug where undefined gets coerced to empty string
if (content !== "undefined" && content !== "") {
LiveUnit.Assert.fail("Binding to an empty object should set textContent to undefined.");
}
});
});
testDeadCodeElimination = async(function () {
var holder = document.createElement("div");
holder.innerHTML = '
\
\
some text
\
\
\
\
some other content
';
var data = as({ x: 1, y: 2, foo: "foo text" });
return this._render(new Template(holder), data).then(function (d) {
LiveUnit.Assert.areEqual(null, d.querySelector(".mycustomcontrol"));
LiveUnit.Assert.areEqual(null, d.querySelector(".two"));
});
});
testSelectors = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "\
";
var data = as({});
return this._render(new Template(holder), data).then(function (d) {
LiveUnit.Assert.areEqual(3, d.querySelector(".one").winControl.userRating);
LiveUnit.Assert.areEqual(3, d.querySelector(".two").winControl.userRating);
});
});
testErrorInBindingExpression = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "\
";
var data = as({});
return this._render(new Template(holder), data).then(
function () {
LiveUnit.Assert.fail("Should not complete successfully");
},
function () {
// should get here
}
);
});
testErrorInOptionsRecord = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "\
";
var data = as({});
return this._render(new Template(holder), data).then(
function () {
LiveUnit.Assert.fail("Should not complete successfully");
},
function () {
// should get here
}
);
});
testCustomInitializers = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "\
\
\
\
";
var data = as({ text1: "text1", text2: "text2" });
var template = new Template(holder);
var that = this;
return this._render(template, data).then(function (d) {
LiveUnit.Assert.areEqual("text1", d.querySelector(".one").textContent);
LiveUnit.Assert.areEqual("text2", d.querySelector(".two").textContent);
// The gotcha with .delayable is that it only delays for the renderItem pipe with compiled templates.
//
if (that._isRenderItem && template._shouldCompile) {
LiveUnit.Assert.areEqual("text2", d.querySelector(".three").textContent);
} else {
LiveUnit.Assert.areEqual("text1", d.querySelector(".three").textContent);
}
});
});
testExtractFirst = async(function () {
var holder = document.createElement("div");
holder.innerHTML = "\
\
\
";
var data = as({ text1: "text1", text2: "text2" });
var template = new Template(holder, { extractChild: true });
return this._render(template, data).then(function (d) {
LiveUnit.Assert.isTrue(WinJS.Utilities._matchesSelector(d, ".one"));
LiveUnit.Assert.areEqual("text1", d.textContent);
});
});
testDisposingRenderedItemBeforeAsyncDataWasFetched = async(function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
";
// Mimic an async data source by return an async item promise
var itemPromise = WinJS.Promise.timeout().then(function () {
return WinJS.Promise.wrap({ data: "testValue" });
});
var div1 = document.createElement("div");
var div2 = document.createElement("div");
var template = new WinJS.Binding.Template(templateDiv);
var item1 = template.render(itemPromise, div1);
var item2 = template.render(itemPromise, div2);
// No bindings should be processed at this point
LiveUnit.Assert.areEqual("", div1.querySelector('.testclass').textContent);
LiveUnit.Assert.areEqual("", div2.querySelector('.testclass').textContent);
// Dispose the first rendered item before bindings were processed
item1.cancel();
return item1.then(() => {
LiveUnit.Assert.fail("Should not complete");
}, function () {
return item2.then(function (e) {
// The first item should have no value and its ratings control is disposed
LiveUnit.Assert.isTrue(div1.querySelector(".mycustomcontrol").winControl._disposed);
LiveUnit.Assert.areEqual("", div1.querySelector('.testclass').textContent);
// The second item should have a value bound to it and an intact rating control
LiveUnit.Assert.isFalse(div2.querySelector(".mycustomcontrol").winControl._disposed);
LiveUnit.Assert.areEqual("testValue", div2.querySelector('.testclass').textContent);
}, LiveUnit.Assert.fail);
});
});
testAddClassOneTimeSimple = async(function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
";
var template = new WinJS.Binding.Template(templateDiv);
var data: any = {
x: function () { },
};
data.x.y = function () { };
data.x.y.z = 12;
// should not error with security check
return template.render(data).then(function (d) {
LiveUnit.Assert.areEqual(undefined, (d.querySelector(".one")).foo);
}, function () {
LiveUnit.Assert.fail("should not be here");
});
});
testControlWhichIsDeclarativeControlContainer = async(function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
default text
\
";
var data = as({ text1: "text1", text2: "text2" });
var template = new WinJS.Binding.Template(templateDiv);
return this._render(template, data).then(function (d) {
var control = d.querySelector(".mycustomcontroldeclarativecontrolcontainer").winControl;
LiveUnit.Assert.isNotNull(control);
LiveUnit.Assert.areEqual(2, control.delayedProcessorCount);
var one = d.querySelector(".one");
var two = d.querySelector(".two");
LiveUnit.Assert.isFalse(one.winControl);
LiveUnit.Assert.areEqual("default text", two.textContent);
control.runDelayedProcessing();
LiveUnit.Assert.isTrue(one.winControl);
LiveUnit.Assert.isTrue(one.winControl instanceof global.MyCustomControl);
LiveUnit.Assert.areEqual("text1", two.textContent);
});
});
testInvalidBindings = async(function () {
// add this, id, and multi attribute
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var data = as({
text1: "text1",
text2: "text2",
text3: "text3",
text4: "text4"
});
var template = new WinJS.Binding.Template(templateDiv);
var temp = WinJS.log;
var messages = []
WinJS.log = function (m) {
messages.push(m);
};
return this._render(template, data).then(function (d) {
var one = d.querySelector(".one");
LiveUnit.Assert.isTrue(messages.length >= 3);
LiveUnit.Assert.areEqual("text3", one.foo);
LiveUnit.Assert.areNotEqual("text1", one.id);
LiveUnit.Assert.areEqual(null, one.getAttribute("bar"));
}).then(
function () {
WinJS.log = temp;
},
function (e) {
WinJS.log = temp;
return WinJS.Promise.wrapError(e);
}
);
});
};
export class Templates_Interpreted extends TemplatesTestBase {
_interpretAllSetting;
_isRenderItem = false;
constructor() {
super();
}
setUp() {
this._interpretAllSetting = Template._interpretAll;
Template._interpretAll = true;
}
tearDown() {
Template._interpretAll = this._interpretAllSetting;
}
_render(template, data) {
return template.render(data);
}
};
// Test fixture to run all the tests using .renderItem instead of .render on the template
//
export class Templates_Interpreted_renderItem extends TemplatesTestBase {
_interpretAllSetting;
_isRenderItem = true;
constructor() {
super();
}
setUp() {
this._interpretAllSetting = Template._interpretAll;
Template._interpretAll = true;
}
tearDown() {
Template._interpretAll = this._interpretAllSetting;
}
// replace _render method with use of .renderItem instead of .render
//
_render(template, data) {
var item = {
key: "key",
data: data,
ready: WinJS.Promise.timeout().then(function () { return item; }),
isImageCached: function () { return false; },
isOnScreen: function () { return true; },
loadImage: function (srcUrl, image) {
image.src = srcUrl;
},
};
var itemPromise = WinJS.Promise.as(item);
var result = template.renderItem(itemPromise);
return result.renderComplete.then(function () { return result.element; });
}
}
// Test fixture to run all the old template tests in compiled mode
//
export class Templates_Compiled extends Templates_Interpreted {
constructor() {
super();
}
// Make templates run in compiled mode
//
setUp() {
this._interpretAllSetting = Template._interpretAll;
Template._interpretAll = false;
}
tearDown() {
Template._interpretAll = this._interpretAllSetting;
}
}
// Test fixture to run all the old templates tests in compiled mode using .renderItem instead of .render on the template
//
export class Templates_Compiled_renderItem extends Templates_Interpreted_renderItem {
constructor() {
super();
}
// Make templates run in compiled mode
//
setUp() {
this._interpretAllSetting = Template._interpretAll;
Template._interpretAll = false;
}
tearDown() {
Template._interpretAll = this._interpretAllSetting;
}
}
// New test fixture targeting compiled templates.
//
export class TemplateCompilerTests {
testDebugBreak = function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
content
";
var templateWithBreakpoint = new Template(templateDiv);
templateWithBreakpoint.debugBreakOnRender = true;
templateWithBreakpoint._renderImpl = templateWithBreakpoint._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof templateWithBreakpoint._renderImpl);
LiveUnit.Assert.areNotEqual(-1, templateWithBreakpoint._renderImpl.toString().indexOf("debugger;"));
var templateWithoutBreakpoint = new Template(templateDiv);
templateWithoutBreakpoint.debugBreakOnRender = false;
templateWithoutBreakpoint._renderImpl = templateWithoutBreakpoint._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof templateWithoutBreakpoint._renderImpl);
LiveUnit.Assert.areEqual(-1, templateWithoutBreakpoint._renderImpl.toString().indexOf("debugger;"));
var templateWithoutBreakpointWithoutSpecifying = new Template(templateDiv);
templateWithoutBreakpointWithoutSpecifying._renderImpl = templateWithoutBreakpointWithoutSpecifying._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof templateWithoutBreakpointWithoutSpecifying._renderImpl);
LiveUnit.Assert.areEqual(-1, templateWithoutBreakpointWithoutSpecifying._renderImpl.toString().indexOf("debugger;"));
}
testDisableOptimizedProcessing = function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
content
";
var template = new Template(templateDiv, { disableOptimizedProcessing: true });
LiveUnit.Assert.isFalse(template._shouldCompile);
template.disableOptimizedProcessing = false;
LiveUnit.Assert.isTrue(template._shouldCompile);
}
testStyleOptimizations = async(function () {
var userSelect = WinJS.Utilities._browserStyleEquivalents["user-select"];
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Assert that the supported style properties get turned into CSS style named properties
//
LiveUnit.Assert.areNotEqual(-1, string.indexOf("background-color:"));
LiveUnit.Assert.areNotEqual(-1, string.indexOf(userSelect.cssName + ":"));
LiveUnit.Assert.areEqual(0, userSelect.cssName.indexOf('-'));
LiveUnit.Assert.areNotEqual(-1, string.indexOf("background:"));
// Assert that my new property doesn't get turned into a text replacement because it isn't part of the
// style object.
//
LiveUnit.Assert.areEqual(-1, string.indexOf("purplePeopleEater:"));
// Assert that cssText doesn't get turned into a text replacement because we don't support that.
//
LiveUnit.Assert.areEqual(-1, string.indexOf("css-text:"));
LiveUnit.Assert.areEqual(-1, string.indexOf("cssText:"));
return template.render({ color: "red", userSelect: "none", background: "purple" }).then(function (d) {
var target = d.querySelector('.target');
LiveUnit.Assert.areEqual("purple", target.style.backgroundColor);
LiveUnit.Assert.areEqual("none", target.style[userSelect.scriptName]);
});
});
testUnsupportedStyleProperty = function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Assert that my new property doesn't get turned into a text replacement because it isn't part of the
// style object.
//
LiveUnit.Assert.areEqual(-1, string.indexOf("purplePeopleEater:"));
// Assert that cssText doesn't get turned into a text replacement because we don't support that.
//
LiveUnit.Assert.areEqual(-1, string.indexOf("css-text:"));
LiveUnit.Assert.areEqual(-1, string.indexOf("cssText:"));
};
testBindings = async(function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
\
";
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Because these need to setup reoccurant bindings we should find evidence in the form of
// the parsed binding expressions.
//
LiveUnit.Assert.areNotEqual(-1, string.indexOf('["style","backgroundColor"]'));
LiveUnit.Assert.areNotEqual(-1, string.indexOf('["tabIndex"]'));
return template.render({ x: "red", y: 100 }).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
LiveUnit.Assert.areEqual(100, d.querySelector(".two").tabIndex);
});
});
testOneTimeBindings = function () {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
\
";
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Because these are one-time bindings we should find no evidence of the binding
// initializers being called...
//
LiveUnit.Assert.areEqual(-1, string.indexOf('["style","backgroundColor"]'));
LiveUnit.Assert.areEqual(-1, string.indexOf('["tabIndex"]'));
return template.render({ x: "red", y: 100 }).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
LiveUnit.Assert.areEqual(100, d.querySelector(".two").tabIndex);
});
};
testDefaultInitializerOneTime = function (complete) {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var template = new Template(templateDiv, { bindingInitializer: WinJS.Binding.oneTime });
template._renderImpl = template._compileTemplate({
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Because these are one-time bindings we should find no evidence of the binding
// initializers being called...
//
LiveUnit.Assert.areEqual(-1, string.indexOf('["style","backgroundColor"]'));
var data = WinJS.Binding.as({ x: "red", y: 100 });
return template.render(data).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
data.x = "green";
return WinJS.Promise.timeout().then(function () { return d; });
}).then(function (d) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
complete();
});
};
// In order to support blend we need to support changing the template and recompiling
//
testResetOnFragmentTreeChange = function (complete) {
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var metaOne: any = templateDiv.querySelector(".one");
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
defaultInitializer: WinJS.Binding.oneTime,
resetOnFragmentChange: true,
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Because these are one-time bindings we should find no evidence of the binding
// initializers being called...
//
LiveUnit.Assert.areEqual(-1, string.indexOf('["style","backgroundColor"]'));
template.render({ x: "red", y: 100 }).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
}).then(function () {
metaOne.innerHTML = "";
return WinJS.Promise.timeout();
}).then(function () {
// @TODO, once mutation observers for DOM elements come online we can remove this whole block
template._reset();
}).then(function () {
LiveUnit.Assert.areEqual(Template.prototype._renderImpl, template._renderImpl);
// recompile
template._renderImpl = template._compileTemplate({
defaultInitializer: WinJS.Binding.oneTime,
resetOnFragmentChange: true,
target: "render",
});
LiveUnit.Assert.areNotEqual(Template.prototype._renderImpl, template._renderImpl);
return template.render({ x: "red", y: 100 });
}).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
LiveUnit.Assert.areEqual("100", d.querySelector(".two").textContent);
complete();
});
};
testResetOnFragmentAttributeChange = function (complete) {
if (WinJS.Utilities._MutationObserver._isShim) {
// The Template Compiler will not automatically regenerate
// when the raw DOM is modified on platforms without
// MutationObserver support.
return complete();
}
var templateDiv = document.createElement("div");
templateDiv.innerHTML = "
\
\
";
var metaOne = templateDiv.querySelector(".one");
var template = new Template(templateDiv);
template._renderImpl = template._compileTemplate({
defaultInitializer: WinJS.Binding.oneTime,
resetOnFragmentChange: true,
target: "render",
});
LiveUnit.Assert.areEqual("function", typeof template._renderImpl);
var string = template._renderImpl.toString();
// Because these are one-time bindings we should find no evidence of the binding
// initializers being called...
//
LiveUnit.Assert.areEqual(-1, string.indexOf('["style","backgroundColor"]'));
template.render({ x: "red", y: 100 }).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
}).then(function () {
// go change an attribute value and verify that the template reset itself.
WinJS.Utilities.data(template.element).docFragment.querySelector(".one").setAttribute("aria-label", "something");
return WinJS.Promise.timeout();
}).then(function () {
LiveUnit.Assert.areEqual(Template.prototype._renderImpl, template._renderImpl);
// recompile
template._renderImpl = template._compileTemplate({
defaultInitializer: WinJS.Binding.oneTime,
resetOnFragmentChange: true,
target: "render",
});
LiveUnit.Assert.areNotEqual(Template.prototype._renderImpl, template._renderImpl);
return template.render({ x: "red", y: 100 });
}).then(function (d: any) {
LiveUnit.Assert.areEqual("red", d.querySelector(".one").style.backgroundColor);
LiveUnit.Assert.areEqual("something", d.querySelector(".one").getAttribute("aria-label"));
complete();
});
};
testCSETreeWithNormalAccessGenerator = function () {
var compiler = {
_instanceVariables: {},
_instanceVariablesCount: {},
defineInstance: WinJS.Binding._TemplateCompiler.prototype.defineInstance,
formatCode: WinJS.Binding._TemplateCompiler.prototype.formatCode,
nullableIdentifierAccessTemporary: "t0",
};
var cse = new WinJS.Binding._TemplateCompiler._TreeCSE(compiler, "root", "data", WinJS.Binding._TemplateCompiler.prototype.generateNormalAccess.bind(compiler));
cse.createPathExpression(["data", "moreData", "detail1"], "data_moreData_detail1");
cse.createPathExpression(["data", "moreData", "detail2"], "data_moreData_detail2");
cse.createPathExpression(["data", "moreData", "detail2", "evenMoreDetail"], "data_moreData_detail2_evenMoreDetail");
cse.lower();
var definitions = cse.definitions();
// MoreData should have been aliased
LiveUnit.Assert.areEqual(definitions[0], "d3_data_moreData = (t0 = root) && (t0 = (t0.data)) && (t0.moreData)");
// Detail1 and Detail2 should reference off the aliased moreData
LiveUnit.Assert.areEqual(definitions[1], "d0_data_moreData_detail1 = (t0 = d3_data_moreData) && (t0.detail1)");
LiveUnit.Assert.areEqual(definitions[2], "d1_data_moreData_detail2 = (t0 = d3_data_moreData) && (t0.detail2)");
// EvenMoreDetail should reference off detail2
LiveUnit.Assert.areEqual(definitions[3], "d2_data_moreData_detail2_evenMoreDetail = (t0 = d1_data_moreData_detail2) && (t0.evenMoreDetail)");
};
testCSETreeWithNormalElementCaptureAccessGenerator = function () {
var compiler = {
_instanceVariables: {},
_instanceVariablesCount: {},
defineInstance: WinJS.Binding._TemplateCompiler.prototype.defineInstance,
formatCodeN: WinJS.Binding._TemplateCompiler.prototype.formatCodeN,
nullableIdentifierAccessTemporary: "t0",
};
var cse = new WinJS.Binding._TemplateCompiler._TreeCSE(compiler, "container", "capture", WinJS.Binding._TemplateCompiler.prototype.generateElementCaptureAccess.bind(compiler));
cse.createPathExpression(["0", "0"], "one_two");
cse.createPathExpression(["0", "1"], "one_two");
cse.createPathExpression(["0", "1", "0"], "one_two_three");
cse.lower();
var definitions = cse.definitions();
// 0_0 should have been aliased
LiveUnit.Assert.areEqual(definitions[0], "c3_0 = container.children[startIndex]");
// Detail1 and Detail2 should reference off the aliased moreData
LiveUnit.Assert.areEqual(definitions[1], "c0_one_two = c3_0.children[0]");
LiveUnit.Assert.areEqual(definitions[2], "c1_one_two = c3_0.children[1]");
// EvenMoreDetail should reference off detail2
LiveUnit.Assert.areEqual(definitions[3], "c2_one_two_three = c1_one_two.children[0]");
};
};
}
LiveUnit.registerTestClass("CorsicaTests.Templates_Interpreted");
LiveUnit.registerTestClass("CorsicaTests.Templates_Interpreted_renderItem");
LiveUnit.registerTestClass("CorsicaTests.Templates_Compiled");
LiveUnit.registerTestClass("CorsicaTests.Templates_Compiled_renderItem");
LiveUnit.registerTestClass("CorsicaTests.TemplateCompilerTests");