From 1432c6613b0126b38ac1645daa5e82d4b8366a9a Mon Sep 17 00:00:00 2001 From: Brock Whittaker Date: Tue, 1 Nov 2016 22:45:06 -0700 Subject: [PATCH] zjsunit: Remove manual need to call global.use_template. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the render function is run now, it uses the partial_finder function to search recursively through files for partials and add them so that test writers don’t have to. This means that we no longer have to do any manual work to maintain the templates.js check that all handlebars templates are rendered by the node tests. --- frontend_tests/node_tests/templates.js | 17 ++----- frontend_tests/zjsunit/index.js | 2 + frontend_tests/zjsunit/render.js | 70 ++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/frontend_tests/node_tests/templates.js b/frontend_tests/node_tests/templates.js index 56a96b7260..e6761cf77c 100644 --- a/frontend_tests/node_tests/templates.js +++ b/frontend_tests/node_tests/templates.js @@ -32,7 +32,9 @@ var _ = global._; // ./tools/get-handlebar-vars static/templates/*.handlebars function render(template_name, args) { - global.use_template(template_name); + global.partial_finder(template_name, function (name) { + global.use_template(name); + }); return global.templates.render(template_name, args); } @@ -100,7 +102,6 @@ fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forE }()); (function admin_emoji_list() { - global.use_template('admin_emoji_list'); var args = { emoji: { "name": "MouseFace", @@ -437,10 +438,6 @@ fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forE } ]; - global.use_template('single_message'); // partial - global.use_template('recipient_row'); // partial - global.use_template('bookend'); // partial - var html = render('message_group', {message_groups: groups, use_match_properties: true}); var first_message_text = $(html).next('.recipient_row').find('div.messagebox:first .message_content').text().trim(); @@ -641,8 +638,6 @@ fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forE }()); (function stream_sidebar_row() { - global.use_template('stream_privacy'); // partial - var args = { name: "devel", color: "red", @@ -687,11 +682,6 @@ fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forE ] }; - global.use_template('subscription'); // partial - global.use_template('subscription_settings'); // partial - global.use_template('subscription_type'); // partial - global.use_template('subscription_setting_icon'); // partial - global.use_template('change_stream_privacy'); // partial var html = ''; html += '
'; html += render('subscription_table_body', args); @@ -797,7 +787,6 @@ fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forE }()); (function user_presence_rows() { - global.use_template('user_presence_row'); // partial var args = { users: [ { diff --git a/frontend_tests/zjsunit/index.js b/frontend_tests/zjsunit/index.js index 1e79baebe1..04953480a1 100644 --- a/frontend_tests/zjsunit/index.js +++ b/frontend_tests/zjsunit/index.js @@ -23,6 +23,8 @@ global.stub_out_jquery = namespace.stub_out_jquery; var render = require('./render.js'); global.use_template = render.use_template; global.make_sure_all_templates_have_been_compiled = render.make_sure_all_templates_have_been_compiled; +global.partial_finder = render.partial_finder; +global.walk = render.walk; // Set up helpers to output HTML var output = require('./output.js'); diff --git a/frontend_tests/zjsunit/render.js b/frontend_tests/zjsunit/render.js index 0248483521..57d9aa727c 100644 --- a/frontend_tests/zjsunit/render.js +++ b/frontend_tests/zjsunit/render.js @@ -60,6 +60,76 @@ exports.use_template = function (name) { Handlebars.templates[name] = Handlebars.compile(data); }; +// list all files in a directory and it's subdirectories in a recursive sync way. +exports.walk = function (dir, filelist) { + filelist = filelist || []; + + // grab files one level deep. + var files = fs.readdirSync(dir); + + // for each file, check if it's a directory. If so, continue recursion. + // if not add to the file list. + files.forEach(function (file) { + if (fs.statSync(dir + "/" + file).isDirectory()) { + filelist = exports.walk(dir + "/" + file, filelist); + } else { + filelist.push({ + url: dir + "/" + file, + name: file + }); + } + }); + + // return all recursively found files. + return filelist; +}; + +exports.partial_finder = (function () { + var meta = { + read: [] + }; + + // get all files and then map them into friendlier names. + var files = exports.walk(path.join(__dirname, "../../static/templates")).map(function (file) { + return { + url: file.url, + name: file.name.replace(/\.handlebars$/, "") + }; + }); + + // this is the external function that is called that will recursively search + // for partials in a file and partials inside partials until it finds them all. + // it then adds them to a maintenance list of already read partials so that + // they don't have to be read/searched again. + var __prototype__ = function (name, callback) { + if (meta.read.indexOf(name) === -1) { + if (callback) { + callback(name); + } + + meta.read.push(name); + + var file = files.find(function (file) { + return file.name === name; + }); + + if (file) { + var template = fs.readFileSync(file.url, "utf8"); + + // match partial tags. + // this uses String.prototype.replace which is kind of hacky but + // it is the only JS function IIRC that allows you to match all + // instances of a pattern AND return capture groups. + template.replace(/\{\{\s*partial\s*"(.+?)"/ig, function (match, $1) { + __prototype__($1, callback); + }); + } + } + }; + + return __prototype__; +}()); + fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forEach(function (o) { exports.use_template(o.replace(/\.handlebars/, "")); });