mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Port html_scanner tests; detect duplicate templates
Reintroduce a Template.__define__ (like on devel) Remove old compiler tests
This commit is contained in:
@@ -332,151 +332,6 @@ Tinytest.add("spacebars - parser", function (test) {
|
||||
{"type":"EndTag","name":"div"}]});
|
||||
});
|
||||
|
||||
Tinytest.add("spacebars - compiler", function (test) {
|
||||
|
||||
var run = function (input/*, expectedLines*/) {
|
||||
var expectedLines = Array.prototype.slice.call(arguments, 1);
|
||||
var expected = expectedLines.join('\n');
|
||||
if (arguments[1].fail) {
|
||||
var expectedMessage = arguments[1].fail;
|
||||
// test for error starting with expectedMessage
|
||||
var msg = '';
|
||||
test.throws(function () {
|
||||
try {
|
||||
Spacebars.compile(input);
|
||||
} catch (e) {
|
||||
msg = e.message;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
test.equal(msg.slice(0, expectedMessage.length),
|
||||
expectedMessage);
|
||||
} else {
|
||||
var output = Spacebars.compile(input);
|
||||
test.equal(output, expected);
|
||||
}
|
||||
};
|
||||
|
||||
run('abc',
|
||||
|
||||
'function (buf) {',
|
||||
' buf.write("abc");',
|
||||
'}');
|
||||
|
||||
run('<a foo=bar>abc</a>',
|
||||
|
||||
'function (buf) {',
|
||||
' buf.write("<a",',
|
||||
' {attrs: {"foo": "bar"}},',
|
||||
' ">abc</a>");',
|
||||
'}');
|
||||
|
||||
// NOTE: These are old tests of code generation from various previous versions
|
||||
// of the compiler. Once the form of generated code stabilizes, it would be
|
||||
// nice to have these tests as a way of seeing that code generation is working
|
||||
// as intended and pretty-printing remains correct, as well as as a form of
|
||||
// documentation.
|
||||
/*
|
||||
run('<a foo={{bar}}>',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.write("<a",',
|
||||
' {attrs: function () { return {"foo": Spacebars.dstache(self.lookup("bar"))}; }},',
|
||||
' ">");',
|
||||
'}');
|
||||
|
||||
run('<a name={{foo bar}}>',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.write("<a",',
|
||||
' {attrs: function () { return {"name": Spacebars.dstache(self.lookup("foo"), self.lookup("bar"))}; }},',
|
||||
' ">");',
|
||||
'}');
|
||||
|
||||
run('<a foo={{bar.baz}}>',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.openTag("a", {"foo": function () { return String(Spacebars.call(Spacebars.index(self.lookup("bar"), "baz")) || ""); }});',
|
||||
'}');
|
||||
|
||||
run('foo {{bar}} baz',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.text("foo ");',
|
||||
' buf.text(function () { return String(Spacebars.call(self.lookup("bar")) || ""); });',
|
||||
' buf.text(" baz");',
|
||||
'}');
|
||||
|
||||
run('foo {{{bar}}} baz',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.text("foo ");',
|
||||
' buf.rawHtml(function () { return String(Spacebars.call(self.lookup("bar")) || ""); });',
|
||||
' buf.text(" baz");',
|
||||
'}');
|
||||
|
||||
run('foo {{bar "hello"}} baz',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.text("foo ");',
|
||||
' buf.text(function () { return String(Spacebars.call(self.lookup("bar"), "hello") || ""); });',
|
||||
' buf.text(" baz");',
|
||||
'}');
|
||||
|
||||
run('foo {{bar hello}} baz',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.text("foo ");',
|
||||
' buf.text(function () { return String(Spacebars.call(self.lookup("bar"), Spacebars.call(self.lookup("hello"))) || ""); });',
|
||||
' buf.text(" baz");',
|
||||
'}');
|
||||
|
||||
run('{{foo.bar x.y abc=z.w 0 null "hi" z=123.4}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.text(function () { return String(Spacebars.call(Spacebars.index(self.lookup("foo"), "bar"), Spacebars.call(Spacebars.index(self.lookup("x"), "y")), 0, null, "hi", {"abc": Spacebars.call(Spacebars.index(self.lookup("z"), "w")), "z": 123.4}) || ""); });',
|
||||
'}');
|
||||
|
||||
run('{{> foo bar baz=x.y}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.component(function () { return ((self.lookup("foo")) || Component).create({"data": Spacebars.call(self.lookup("bar")), "baz": Spacebars.call(Spacebars.index(self.lookup("x"), "y"))}); });',
|
||||
'}');
|
||||
|
||||
run('{{#foo.bar}}{{/foo.baz}}', {fail: 'Close tag'});
|
||||
run('{{/foo.bar}}{{#foo.bar}}', {fail: 'Unexpected close tag'});
|
||||
|
||||
run('{{#if foo}}bar{{/if}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.component(function () { return ((self.lookup("if")) || Component).create({"data": Spacebars.call(self.lookup("foo")), "content": Component.extend({render: function (buf) {',
|
||||
' buf.text("bar");',
|
||||
' }})}); });',
|
||||
'}');
|
||||
|
||||
run('{{#if foo}}bar{{else}}baz{{/if}}',
|
||||
|
||||
'function (buf) {',
|
||||
' var self = this;',
|
||||
' buf.component(function () { return ((self.lookup("if")) || Component).create({"data": Spacebars.call(self.lookup("foo")), "content": Component.extend({render: function (buf) {',
|
||||
' buf.text("bar");',
|
||||
' }}), "elseContent": Component.extend({render: function (buf) {',
|
||||
' buf.text("baz");',
|
||||
' }})}); });',
|
||||
'}');
|
||||
*/
|
||||
});
|
||||
|
||||
Tinytest.add("spacebars - Spacebars.index", function (test) {
|
||||
test.equal(Spacebars.index(null, 'foo'), null);
|
||||
test.equal(Spacebars.index('foo', 'foo'), undefined);
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
// Create an empty template object. Packages and apps add templates on
|
||||
// to this object.
|
||||
Template = {};
|
||||
Template = {};
|
||||
|
||||
Template.__define__ = function (templateName, renderFunc) {
|
||||
if (Template.hasOwnProperty(templateName))
|
||||
throw new Error("Can't have two templates named: " + templateName);
|
||||
|
||||
Template[templateName] = UI.Component.extend({
|
||||
kind: "Template_" + templateName,
|
||||
render: renderFunc
|
||||
});
|
||||
};
|
||||
|
||||
@@ -45,7 +45,7 @@ Package.on_test(function (api) {
|
||||
'templating_tests.html2'
|
||||
], 'client');
|
||||
api.add_files([
|
||||
'plugin/html_scanner.js',
|
||||
'plugin/html2_scanner.js',
|
||||
'scanner_tests.js'
|
||||
], 'server');
|
||||
});
|
||||
|
||||
@@ -154,10 +154,8 @@ html2_scanner = {
|
||||
sourceName: 'Template "' + name + '"'
|
||||
});
|
||||
|
||||
results.js += "\nTemplate[" + JSON.stringify(name) +
|
||||
"] = UI.Component.extend({kind: " +
|
||||
JSON.stringify("Template_" + name) + ", render: " +
|
||||
renderFuncCode + "});\n";
|
||||
results.js += "\nTemplate.__define__(" + JSON.stringify(name) +
|
||||
", " + renderFuncCode + ");\n";
|
||||
} else {
|
||||
// <body>
|
||||
if (hasAttribs)
|
||||
|
||||
@@ -22,12 +22,17 @@ Tinytest.add("templating - html scanner", function (test) {
|
||||
test.fail("Parse error didn't throw exception");
|
||||
};
|
||||
|
||||
var BODY_PREAMBLE = "Meteor.startup(function(){" +
|
||||
"document.body.appendChild(Spark.render(" +
|
||||
"Template.__define__(null,";
|
||||
var BODY_POSTAMBLE = ")));});";
|
||||
var TEMPLATE_PREAMBLE = "Template.__define__(";
|
||||
var TEMPLATE_POSTAMBLE = ");\n";
|
||||
// returns the appropriate code to put content in the body,
|
||||
// where content is something simple like the string "Hello"
|
||||
// (passed in as a source string including the quotes).
|
||||
var simpleBody = function (content) {
|
||||
return "\nUI.body2.contentParts.push(UI.Component.extend({render: (function() {\n var self = this;\n return " + content + ";\n})}));\nMeteor.startup(function () { if (! UI.body2.INSTANTIATED) { UI.materialize(UI.body2, document.body); } });\n";
|
||||
};
|
||||
|
||||
// arguments are quoted strings like '"hello"'
|
||||
var simpleTemplate = function (templateName, content) {
|
||||
return '\nTemplate.__define__(' + templateName + ', (function() {\n var self = this;\n var __content = self.__content, __elseContent = self.__elseContent;\n return ' + content + ';\n}));\n';
|
||||
};
|
||||
|
||||
var checkResults = function(results, expectJs, expectHead) {
|
||||
test.equal(results.body, '');
|
||||
@@ -35,6 +40,8 @@ Tinytest.add("templating - html scanner", function (test) {
|
||||
test.equal(results.head, expectHead || '');
|
||||
};
|
||||
|
||||
var html_scanner = html2_scanner;
|
||||
|
||||
checkError(function() {
|
||||
return html_scanner.scan("asdf");
|
||||
}, "formatting in HTML template", 1);
|
||||
@@ -42,73 +49,65 @@ Tinytest.add("templating - html scanner", function (test) {
|
||||
// body all on one line
|
||||
checkResults(
|
||||
html_scanner.scan("<body>Hello</body>"),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["Hello"])'+BODY_POSTAMBLE);
|
||||
simpleBody('"Hello"'));
|
||||
|
||||
// multi-line body, contents trimmed
|
||||
checkResults(
|
||||
html_scanner.scan("\n\n\n<body>\n\nHello\n\n</body>\n\n\n"),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["Hello"])'+BODY_POSTAMBLE);
|
||||
simpleBody('"Hello"'));
|
||||
|
||||
// same as previous, but with various HTML comments
|
||||
checkResults(
|
||||
html_scanner.scan("\n<!--\n\nfoo\n-->\n<!-- -->\n"+
|
||||
"<body>\n\nHello\n\n</body>\n\n<!----\n>\n\n"),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["Hello"])'+BODY_POSTAMBLE);
|
||||
simpleBody('"Hello"'));
|
||||
|
||||
// head and body
|
||||
checkResults(
|
||||
html_scanner.scan("<head>\n<title>Hello</title>\n</head>\n\n<body>World</body>\n\n"),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["World"])'+BODY_POSTAMBLE,
|
||||
simpleBody('"World"'),
|
||||
"<title>Hello</title>");
|
||||
|
||||
// head and body with tag whitespace
|
||||
checkResults(
|
||||
html_scanner.scan("<head\n>\n<title>Hello</title>\n</head >\n\n<body>World</body\n\n>\n\n"),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["World"])'+BODY_POSTAMBLE,
|
||||
simpleBody('"World"'),
|
||||
"<title>Hello</title>");
|
||||
|
||||
// head, body, and template
|
||||
checkResults(
|
||||
html_scanner.scan("<head>\n<title>Hello</title>\n</head>\n\n<body>World</body>\n\n"+
|
||||
'<template name="favoritefood">\n pizza\n</template>\n'),
|
||||
BODY_PREAMBLE+'Package.handlebars.Handlebars.json_ast_to_func(["World"])'+BODY_POSTAMBLE+
|
||||
TEMPLATE_PREAMBLE+'"favoritefood",Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE,
|
||||
simpleBody('"World"') + simpleTemplate('"favoritefood"', '"pizza"'),
|
||||
"<title>Hello</title>");
|
||||
|
||||
// one-line template
|
||||
checkResults(
|
||||
html_scanner.scan('<template name="favoritefood">pizza</template>'),
|
||||
TEMPLATE_PREAMBLE+'"favoritefood",Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE);
|
||||
simpleTemplate('"favoritefood"', '"pizza"'));
|
||||
|
||||
// template with other attributes
|
||||
checkResults(
|
||||
html_scanner.scan('<template foo="bar" name="favoritefood" baz="qux">'+
|
||||
'pizza</template>'),
|
||||
TEMPLATE_PREAMBLE+'"favoritefood",Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE);
|
||||
simpleTemplate('"favoritefood"', '"pizza"'));
|
||||
|
||||
// whitespace around '=' in attributes and at end of tag
|
||||
checkResults(
|
||||
html_scanner.scan('<template foo = "bar" name ="favoritefood" baz= "qux" >'+
|
||||
'pizza</template\n\n>'),
|
||||
TEMPLATE_PREAMBLE+'"favoritefood",Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE);
|
||||
simpleTemplate('"favoritefood"', '"pizza"'));
|
||||
|
||||
// whitespace around template name
|
||||
checkResults(
|
||||
html_scanner.scan('<template name=" favoritefood ">pizza</template>'),
|
||||
TEMPLATE_PREAMBLE+'"favoritefood",Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE);
|
||||
simpleTemplate('"favoritefood"', '"pizza"'));
|
||||
|
||||
// single quotes around template name
|
||||
checkResults(
|
||||
html_scanner.scan('<template name=\'the "cool" template\'>'+
|
||||
'pizza</template>'),
|
||||
TEMPLATE_PREAMBLE+'"the \\"cool\\" template",'+
|
||||
'Package.handlebars.Handlebars.json_ast_to_func(["pizza"])'+
|
||||
TEMPLATE_POSTAMBLE);
|
||||
simpleTemplate('"the \\"cool\\" template"', '"pizza"'));
|
||||
|
||||
// error cases; exact line numbers are not critical, these just reflect
|
||||
// the current implementation
|
||||
|
||||
@@ -556,3 +556,9 @@ Tinytest.add('templating - each falsy Issue #801', function (test) {
|
||||
test.equal(canonicalizeHtml(div.innerHTML), "12null");
|
||||
});
|
||||
|
||||
Tinytest.add('templating - duplicate template error', function (test) {
|
||||
Template.__define__("foo", function () {});
|
||||
test.throws(function () {
|
||||
Template.__define__("foo", function () {});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user