node_tests: Rewrite example8.js.

The previous code has a lot of code unrelated to mock_template.
So, this commit replaces it with a better example which also
demonstrates how to test conditionals in templates.
This commit is contained in:
Dinesh 2021-07-29 01:30:31 +05:30 committed by Tim Abbott
parent efe5fcde51
commit 55512a4247
1 changed files with 90 additions and 44 deletions

View File

@ -7,23 +7,52 @@ const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery"); const $ = require("../zjsunit/zjquery");
/* /*
Until now, we had seen various testing techniques, learnt Until now, we had seen various testing techniques, learned
how to use helper functions like `mock_esm`, `override` of how to use helper functions like `mock_esm`, `override` of
`run_test` etc., but we didn't see how to deal with `run_test` etc., but we didn't see how to deal with
render calls to handlebars templates. We'll learn that render calls to handlebars templates. We'll learn that
in this test. in this test.
The below code tests the rendering of alert words in settings UI The below code tests the rendering of typing notifications which
i.e., render_alert_words_ui function of static/js/alert_words_ui.js. is handled by the function `typing_events.render_notifications_for_narrow`.
The function relies on the `typing_notifications.hbs` template for
rendering html.
It is worthwhile to read those (they're short and simple) before proceeding
as that would help better understand the below test.
*/ */
const alert_words = zrequire("alert_words"); const typing_events = zrequire("typing_events");
const alert_words_ui = zrequire("alert_words_ui"); const people = zrequire("people");
// Let's first add a few alert words. // Let us add a few users to use as typists.
alert_words.initialize({ const anna = {
alert_words: ["foo", "bar"], email: "anna@example.com",
}); full_name: "Anna Karenina",
user_id: 8,
};
const vronsky = {
email: "vronsky@example.com",
full_name: "Alexei Vronsky",
user_id: 9,
};
const levin = {
email: "levin@example.com",
full_name: "Konstantin Levin",
user_id: 10,
};
const kitty = {
email: "kitty@example.com",
full_name: "Kitty S",
user_id: 11,
};
people.add_active_user(anna);
people.add_active_user(vronsky);
people.add_active_user(levin);
people.add_active_user(kitty);
/* /*
Notice the `mock_template` in the object passed to `run_test` wrapper below. Notice the `mock_template` in the object passed to `run_test` wrapper below.
@ -36,55 +65,72 @@ alert_words.initialize({
It's usage below will make it more clear to you. It's usage below will make it more clear to you.
*/ */
run_test("render_alert_words_ui", ({mock_template}) => { run_test("typing_events.render_notifications_for_narrow", ({override, mock_template}) => {
const word_list = $("#alert_words_list"); // All typists are rendered in `#typing_notifications`.
const typing_notifications = $("#typing_notifications");
// All the alert word elements will be rendered in `#alert_words_list`. That is const two_typing_users_ids = [anna.user_id, vronsky.user_id];
// done with the help of `append` in actual code. We can test that all alert words const two_typing_users = [anna, vronsky];
// are added to it by making its `append` add the values passed to it to an array
// as shown below and verifying its contents later.
const appended = [];
word_list.append = (rendered) => {
appended.push(rendered);
};
// Existing alert words in the actual code are removed before adding them // Based on typing_events.MAX_USERS_TO_DISPLAY_NAME (which is currently 3),
// to avoid duplicates by calling `remove` on find results of `#alert_words_list`. // we display either the list of all users typing (if they do not exceed
// We make sure that doesn't fail by creating stubs here. // MAX_USERS_TO_DISPLAY_NAME) or 'Several people are typing…'
const alert_word_items = $.create("alert_word_items");
word_list.set_find_results(".alert-word-item", alert_word_items);
alert_word_items.remove = () => {};
// As you can see below, the first argument to mock_template takes // As we are not testing any functionality of `get_users_typing_for_narrow`,
// let's override it to return two typists.
override(typing_events, "get_users_typing_for_narrow", () => two_typing_users_ids);
const two_typing_users_rendered_html = "Two typing users rendered html stub";
// As you can see below, the first argument of mock_template takes
// the relative path of the template we want to mock w.r.t static/templates/ // the relative path of the template we want to mock w.r.t static/templates/
// //
// The second argument takes a boolean determing whether to render html. // The second argument takes a boolean determing whether to render html.
// We mostly set this to `false` and recommend you avoid setting this to `true` // We mostly set this to `false` and recommend you avoid setting this to `true`
// unless necessary in situations where you want to test conditionals // unless necessary in situations where you want to test conditionals
// or something similar. Find and see examples where we set this to true with // or something similar. The latter examples below would make that more clear.
// help of `git grep mock_template | grep true`.
// //
// The third takes a function to run on calling this template. The function // The third takes a function to run on calling this template. The function
// gets passed an object(`args` below) containing arguments passed to the template. // gets passed an object(`args` below) containing arguments passed to the template.
// Additionally, it can also have rendered html passed to it if second argument of // Additionally, it can also have rendered html passed to it if second argument of
// mock_template was set to true. Any render calls to this template // mock_template was set to `true`. Any render calls to this template
// will run the function and return the function's return value. // will run the function and return the function's return value.
mock_template("settings/alert_word_settings_item.hbs", false, (args) => "stub-" + args.word); //
// We often use the function in third argument, like below, to make sure
// the arguments passed to the template are what we expect.
mock_template("typing_notifications.hbs", false, (args) => {
assert.deepEqual(args.users, two_typing_users);
assert.ok(!args.several_users); // Whether to show 'Several people are typing…'
return two_typing_users_rendered_html;
});
// On redering alert words UI, `#create_alert_word_name` will be focused. typing_events.render_notifications_for_narrow();
// Create a stub for that and make sure it isn't focused now but is focused // Make sure #typing_notifications's html content is set to the rendered template
// after calling `render_alert_words_ui`. // which we mocked and gave a custom return value.
const new_alert_word = $("#create_alert_word_name"); assert.equal(typing_notifications.html(), two_typing_users_rendered_html);
assert.ok(!new_alert_word.is_focused());
// This is the function we are testing. It gets all the alert words which // Now we'll see how setting the second argument to `true`
// are added with `alert_words.initialize` above, renders each alert word nicely // can be helpful in testing conditionals inside the template.
// with the help of `alert_word_settings_item.hbs`, appends each of those rendered
// elements to #alert_words_list and focuses #create_alert_word.
alert_words_ui.render_alert_words_ui();
// If you missed it, the `stub-` part prepended to alert words is an effect // Let's set the mock to just return the rendered html.
// of the return value of the function passed into `mock_template` call above. mock_template("typing_notifications.hbs", true, (args, rendered_html) => rendered_html);
assert.deepEqual(appended, ["stub-bar", "stub-foo"]);
assert.ok(new_alert_word.is_focused()); // Since we only have two(<MAX_USERS_TO_DISPLAY_NAME) typists, both of them
// should be rendered but not 'Several people are typing…'
typing_events.render_notifications_for_narrow();
assert.ok(typing_notifications.html().includes(`${anna.full_name} is typing…`));
assert.ok(typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
assert.ok(!typing_notifications.html().includes("Several people are typing…"));
// Change to having four typists and verify the rendered html has
// 'Several people are typing…' but not the list of users.
const four_typing_users_ids = [anna.user_id, vronsky.user_id, levin.user_id, kitty.user_id];
override(typing_events, "get_users_typing_for_narrow", () => four_typing_users_ids);
typing_events.render_notifications_for_narrow();
assert.ok(typing_notifications.html().includes("Several people are typing…"));
assert.ok(!typing_notifications.html().includes(`${anna.full_name} is typing…`));
assert.ok(!typing_notifications.html().includes(`${vronsky.full_name} is typing…`));
assert.ok(!typing_notifications.html().includes(`${levin.full_name} is typing…`));
assert.ok(!typing_notifications.html().includes(`${kitty.full_name} is typing…`));
}); });