[FIX] web: fix JavaScript qweb and activate tests
Fix the issue of the t-esc display the content before the tag. Activate qweb qunit test (same test for the JavaScript and python) Use the same behavior as python: keep attributes order, and display content as default value when the variable is falsy.
This commit is contained in:
@@ -56,8 +56,8 @@
|
||||
ok
|
||||
</result>
|
||||
|
||||
<t t-name="basic-caller">
|
||||
<t t-name="expression-caller">
|
||||
<t t-call="{{True and '_basic-callee' or 'other'}}"/>
|
||||
</t>
|
||||
<result id="basic-caller">ok</result>
|
||||
<result id="expression-caller">ok</result>
|
||||
</templates>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</t>
|
||||
</t>
|
||||
<t t-call="_callee-asc-toto"/>
|
||||
<t t-set="toto"><t t-set="truc" t-value="'bbb'"/><i t-att-notruc="not truc" t-att-truc="bool(truc)">i</i></t>
|
||||
<t t-set="toto"><t t-set="truc" t-value="'bbb'"/><i t-att-notruc="not truc or None" t-att-truc="bool(truc)">i</i></t>
|
||||
<t t-call="_callee-asc-toto"/>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
var QWeb2 = {
|
||||
expressions_cache: { },
|
||||
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,typeof,eval,void,Math,RegExp,Array,Object,Date'.split(','),
|
||||
ACTIONS_PRECEDENCE: 'foreach,if,elif,else,call,set,esc,raw,js,debug,log'.split(','),
|
||||
ACTIONS_PRECEDENCE: 'foreach,if,elif,else,call,set,tag,esc,raw,js,debug,log'.split(','),
|
||||
WORD_REPLACEMENT: {
|
||||
'and': '&&',
|
||||
'or': '||',
|
||||
@@ -542,7 +542,7 @@ QWeb2.Element = (function() {
|
||||
this.engine = engine;
|
||||
this.node = node;
|
||||
this.tag = node.tagName;
|
||||
this.actions = {};
|
||||
this.actions = {tag: this.tag};
|
||||
this.actions_done = [];
|
||||
this.attributes = {};
|
||||
this.children = [];
|
||||
@@ -568,7 +568,11 @@ QWeb2.Element = (function() {
|
||||
if (name === 'name') {
|
||||
continue;
|
||||
}
|
||||
this.actions[name] = attr.value;
|
||||
if (name.match(/^attf?(-.*)?/)) {
|
||||
this.attributes[m[0]] = attr.value;
|
||||
} else {
|
||||
this.actions[name] = attr.value;
|
||||
}
|
||||
} else {
|
||||
this.attributes[name] = attr.value;
|
||||
}
|
||||
@@ -736,26 +740,25 @@ QWeb2.Element = (function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
compile_action_tag : function() {
|
||||
if (this.tag.toLowerCase() !== this.engine.prefix) {
|
||||
var tag = "<" + this.tag;
|
||||
this.top_string("<" + this.tag);
|
||||
for (var a in this.attributes) {
|
||||
tag += this.engine.tools.gen_attribute([a, this.attributes[a]]);
|
||||
}
|
||||
this.top_string(tag);
|
||||
if (this.actions.att) {
|
||||
this.top("r.push(context.engine.tools.gen_attribute(" + (this.format_expression(this.actions.att)) + "));");
|
||||
}
|
||||
for (var a in this.actions) {
|
||||
var v = this.actions[a];
|
||||
var m = a.match(/att-(.+)/);
|
||||
if (m) {
|
||||
this.top("r.push(context.engine.tools.gen_attribute(['" + m[1] + "', (" + (this.format_expression(v)) + ")]));");
|
||||
}
|
||||
var m = a.match(/attf-(.+)/);
|
||||
if (m) {
|
||||
this.top("r.push(context.engine.tools.gen_attribute(['" + m[1] + "', (" + (this.string_interpolation(v)) + ")]));");
|
||||
var v = this.attributes[a];
|
||||
var d = a.split('-');
|
||||
if (d[0] === this.engine.prefix && d.length > 1) {
|
||||
if (d.length === 2) {
|
||||
this.top("r.push(context.engine.tools.gen_attribute(" + (this.format_expression(v)) + "));");
|
||||
} else {
|
||||
this.top("r.push(context.engine.tools.gen_attribute(['" + d.slice(2).join('-') + "', (" +
|
||||
(d[1] === 'att' ? this.format_expression(v) : this.string_interpolation(v)) + ")]));");
|
||||
}
|
||||
} else {
|
||||
this.top_string(this.engine.tools.gen_attribute([a, v]));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.actions.opentag === 'true' || (!this.children.length && this.is_void_element)) {
|
||||
// We do not enforce empty content on void elements
|
||||
// because QWeb rendering is not necessarily html.
|
||||
@@ -823,12 +826,18 @@ QWeb2.Element = (function() {
|
||||
}
|
||||
},
|
||||
compile_action_esc : function(value) {
|
||||
this.top("r.push(context.engine.tools.html_escape("
|
||||
+ this.format_expression(value)
|
||||
+ "));");
|
||||
this.top("var t = " + this.format_str(value) + ";");
|
||||
this.top("if (t != null) r.push(context.engine.tools.html_escape(t));");
|
||||
this.top("else {");
|
||||
this.bottom("}");
|
||||
this.indent();
|
||||
},
|
||||
compile_action_raw : function(value) {
|
||||
this.top("r.push(" + (this.format_str(value)) + ");");
|
||||
this.top("var t = " + this.format_str(value) + ";");
|
||||
this.top("if (t != null) r.push(t);");
|
||||
this.top("else {");
|
||||
this.bottom("}");
|
||||
this.indent();
|
||||
},
|
||||
compile_action_js : function(value) {
|
||||
this.top("(function(" + value + ") {");
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
odoo.define('web.qweb', function (require) {
|
||||
"use strict";
|
||||
|
||||
var qwebPath = '/web/static/lib/qweb/';
|
||||
|
||||
function trim(s) {
|
||||
return s.replace(/(^\s+|\s+$)/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the template file, and executes all the test template in a
|
||||
* qunit module $title
|
||||
*/
|
||||
function loadTest(assert, template, context) {
|
||||
var done = assert.async();
|
||||
assert.expect(1);
|
||||
|
||||
var def = $.Deferred();
|
||||
var qweb = new window.QWeb2.Engine();
|
||||
|
||||
qweb.add_template(qwebPath + template, function (error, doc) {
|
||||
if (error) {
|
||||
return $.Deferred().reject(error);
|
||||
}
|
||||
def.resolve({
|
||||
qweb: qweb,
|
||||
doc: doc
|
||||
});
|
||||
});
|
||||
|
||||
def.then(function (r) {
|
||||
var qweb = r.qweb;
|
||||
var doc = r.doc;
|
||||
assert.expect(doc.querySelectorAll('result').length);
|
||||
|
||||
var templates = qweb.templates;
|
||||
for (var template in templates) {
|
||||
try {
|
||||
if (!templates.hasOwnProperty(template)) {
|
||||
continue;
|
||||
}
|
||||
// ignore templates whose name starts with _, they're
|
||||
// helpers/internal
|
||||
if (/^_/.test(template)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var params = doc.querySelector('params#' + template);
|
||||
var args = params ? JSON.parse(params.textContent) : (context ? _.clone(context) : {});
|
||||
|
||||
var results = doc.querySelector('result#' + template);
|
||||
assert.equal(
|
||||
trim(qweb.render(template, args)),
|
||||
trim(results.textContent),
|
||||
template);
|
||||
} catch (error) {
|
||||
assert.notOk(error.stack || error, 'Rendering error');
|
||||
}
|
||||
}
|
||||
done();
|
||||
});
|
||||
return def;
|
||||
}
|
||||
|
||||
QUnit.module('QWeb', {}, function () {
|
||||
QUnit.test('Output', function (assert) {
|
||||
loadTest(assert, 'qweb-test-output.xml');
|
||||
});
|
||||
QUnit.test('Context-setting', function (assert) {
|
||||
loadTest(assert, 'qweb-test-set.xml');
|
||||
});
|
||||
QUnit.test('Conditionals', function (assert) {
|
||||
loadTest(assert, 'qweb-test-conditionals.xml');
|
||||
});
|
||||
QUnit.test('Attributes manipulation', function (assert) {
|
||||
loadTest(assert, 'qweb-test-attributes.xml');
|
||||
});
|
||||
QUnit.test('Template calling (to the faraway pages)', function (assert) {
|
||||
loadTest(assert, 'qweb-test-call.xml', {True: true});
|
||||
});
|
||||
QUnit.test('Foreach', function (assert) {
|
||||
loadTest(assert, 'qweb-test-foreach.xml');
|
||||
});
|
||||
QUnit.test('Global', function (assert) {
|
||||
// test use python syntax
|
||||
var WORD_REPLACEMENT = window.QWeb2.WORD_REPLACEMENT;
|
||||
window.QWeb2.WORD_REPLACEMENT = _.extend({not: '!', None: 'undefined'}, WORD_REPLACEMENT);
|
||||
loadTest(assert, 'qweb-test-global.xml', {bool: function (v) { return !!v ? 'True' : 'False';}})
|
||||
.always(function () {
|
||||
window.QWeb2.WORD_REPLACEMENT = WORD_REPLACEMENT;
|
||||
});
|
||||
});
|
||||
QUnit.test('Template inheritance', function (assert) {
|
||||
loadTest(assert, 'qweb-test-extend.xml');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -186,7 +186,7 @@ QUnit.module('Services', {
|
||||
var $notification = $('body .o_notification_manager .o_notification');
|
||||
assert.strictEqual($notification.eq(0).find('.o_close').length, 1, "should display the close button in notification");
|
||||
assert.strictEqual(_.str.trim($notification.eq(0).html().replace(/\s+/g, ' ')),
|
||||
"<a aria-label=\"Close\" class=\"fa fa-times o_close\" href=\"#\" title=\"Close\"></a> <div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-question-circle-o\" title=\"Notification undefined\"></span> a0 </div> <div class=\"o_notification_content\">b0</div> <div class=\"o_buttons\"> <button type=\"button\" class=\"btn btn-primary\"> <span>accept0</span> </button><button type=\"button\" class=\"btn btn-secondary\"> <span>refuse0</span> </button> </div>",
|
||||
"<a aria-label=\"Close\" class=\"fa fa-times o_close\" href=\"#\" title=\"Close\"></a> <div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-question-circle-o\" title=\"Notification undefined\"></span> a0 </div> <div class=\"o_notification_content\">b0</div> <div class=\"o_buttons\"> <button class=\"btn btn-primary\" type=\"button\"> <span>accept0</span> </button><button class=\"btn btn-secondary\" type=\"button\"> <span>refuse0</span> </button> </div>",
|
||||
"should display notification");
|
||||
|
||||
$notification.find('.o_buttons button:contains(accept0)').click();
|
||||
|
||||
@@ -525,6 +525,8 @@
|
||||
|
||||
<script type="text/javascript" src="/base/static/tests/base_settings_tests.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/qweb_tests.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/services/notification_service_tests.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/fields/basic_fields_tests.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user