"use strict"; const {strict: assert} = require("assert"); const {mock_esm, zrequire} = require("./lib/namespace"); const {run_test} = require("./lib/test"); const $ = require("./lib/zjquery"); const {page_params} = require("./lib/zpage_params"); const noop = () => {}; const narrow = mock_esm("../src/narrow"); const narrow_state = mock_esm("../src/narrow_state", { filter: () => false, }); const search_suggestion = mock_esm("../src/search_suggestion"); mock_esm("../src/search_pill_widget", { widget: { getByElement: () => true, }, }); mock_esm("../src/ui_util", { place_caret_at_end: noop, }); const search = zrequire("search"); const search_pill = zrequire("search_pill"); const {Filter} = zrequire("../src/filter"); function test(label, f) { run_test(label, ({override, mock_template}) => { page_params.search_pills_enabled = true; f({override, mock_template}); }); } test("clear_search_form", () => { $("#search_query").val("noise"); $("#search_query").trigger("focus"); $(".search_button").prop("disabled", false); search.clear_search_form(); assert.equal($("#search_query").is_focused(), false); assert.equal($("#search_query").val(), ""); assert.equal($(".search_button").prop("disabled"), true); }); test("update_button_visibility", () => { const $search_query = $("#search_query"); const $search_button = $(".search_button"); $search_query.is = () => false; $search_query.val(""); narrow_state.active = () => false; $search_button.prop("disabled", true); search.update_button_visibility(); assert.ok($search_button.prop("disabled")); $search_query.is = () => true; $search_query.val(""); delete narrow_state.active; $search_button.prop("disabled", true); search.update_button_visibility(); assert.ok(!$search_button.prop("disabled")); $search_query.is = () => false; $search_query.val("Test search term"); delete narrow_state.active; $search_button.prop("disabled", true); search.update_button_visibility(); assert.ok(!$search_button.prop("disabled")); $search_query.is = () => false; $search_query.val(""); narrow_state.active = () => true; $search_button.prop("disabled", true); search.update_button_visibility(); assert.ok(!$search_button.prop("disabled")); }); test("initialize", ({mock_template}) => { const $search_query_box = $("#search_query"); const $searchbox_form = $("#searchbox_form"); const $search_button = $(".search_button"); const $searchbox = $("#searchbox"); mock_template("search_list_item.hbs", true, (data, html) => { assert.equal(typeof data.description_html, "string"); if (data.is_person) { assert.equal(typeof data.user_pill_context.id, "number"); assert.equal(typeof data.user_pill_context.display_value, "string"); assert.equal(typeof data.user_pill_context.has_image, "boolean"); assert.equal(typeof data.user_pill_context.img_src, "string"); } return html; }); $search_query_box[0] = "stub"; search_pill.get_search_string_for_current_filter = () => "is:starred"; search_suggestion.max_num_of_search_results = 99; $search_query_box.typeahead = (opts) => { assert.equal(opts.fixed, true); assert.equal(opts.items, 99); assert.equal(opts.naturalSearch, true); assert.equal(opts.helpOnEmptyStrings, true); assert.equal(opts.matcher(), true); opts.on_move(); { const search_suggestions = { lookup_table: new Map([ [ "stream:Verona", { description_html: "Stream Verona", search_string: "stream:Verona", }, ], [ "ver", { description_html: "Search for ver", search_string: "ver", }, ], ]), strings: ["ver", "stream:Verona"], }; /* Test source */ search_suggestion.get_suggestions = () => search_suggestions; const expected_source_value = search_suggestions.strings; const source = opts.source("ver"); assert.equal(source, expected_source_value); /* Test highlighter */ let expected_value = `
\n Search for ver\n
\n`; assert.equal(opts.highlighter(source[0]), expected_value); expected_value = `
\n Stream Verona\n
\n`; assert.equal(opts.highlighter(source[1]), expected_value); /* Test sorter */ assert.equal(opts.sorter(search_suggestions.strings), search_suggestions.strings); } { const search_suggestions = { lookup_table: new Map([ [ "group-pm-with:zo", { description_html: "group private messages including", is_person: true, search_string: "group-pm-with:user7@zulipdev.com", user_pill_context: { display_value: "Zoe", has_image: true, id: 7, img_src: "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", }, }, ], [ "pm-with:zo", { description_html: "private messages with", is_person: true, search_string: "pm-with:user7@zulipdev.com", user_pill_context: { display_value: "Zoe", has_image: true, id: 7, img_src: "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", }, }, ], [ "sender:zo", { description_html: "sent by", is_person: true, search_string: "sender:user7@zulipdev.com", user_pill_context: { display_value: "Zoe", has_image: true, id: 7, img_src: "https://secure.gravatar.com/avatar/0f030c97ab51312c7bbffd3966198ced?d=identicon&version=1&s=50", }, }, ], [ "zo", { description_html: "Search for zo", search_string: "zo", }, ], ]), strings: ["zo", "sender:zo", "pm-with:zo", "group-pm-with:zo"], }; /* Test source */ search_suggestion.get_suggestions = () => search_suggestions; const expected_source_value = search_suggestions.strings; const source = opts.source("zo"); assert.equal(source, expected_source_value); /* Test highlighter */ let expected_value = `
\n Search for zo\n
\n`; assert.equal(opts.highlighter(source[0]), expected_value); expected_value = `
\n sent by\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; assert.equal(opts.highlighter(source[1]), expected_value); expected_value = `
\n private messages with\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; assert.equal(opts.highlighter(source[2]), expected_value); expected_value = `
\n group private messages including\n \n
\n \n <strong>Zo</strong>e\n
\n \n
\n
\n
\n
\n`; assert.equal(opts.highlighter(source[3]), expected_value); /* Test sorter */ assert.equal(opts.sorter(search_suggestions.strings), search_suggestions.strings); } { let operators; let is_blurred; let is_append_search_string_called; $search_query_box.on( "blur", /* istanbul ignore next */ () => { is_blurred = true; }, ); search_pill.append_search_string = () => { is_append_search_string_called = true; }; /* Test updater */ const _setup = (search_box_val) => { is_blurred = false; is_append_search_string_called = false; $search_query_box.val(search_box_val); /* istanbul ignore next */ Filter.parse = (search_string) => { assert.equal(search_string, search_box_val); return operators; }; /* istanbul ignore next */ narrow.activate = (raw_operators, options) => { assert.deepEqual(raw_operators, operators); assert.deepEqual(options, {trigger: "search"}); }; /* istanbul ignore next */ search_pill.get_search_string_for_current_filter = () => search_box_val; }; operators = [ { negated: false, operator: "search", operand: "ver", }, ]; _setup("ver"); assert.equal(opts.updater("ver"), "ver"); assert.ok(!is_blurred); assert.ok(is_append_search_string_called); operators = [ { negated: false, operator: "stream", operand: "Verona", }, ]; _setup("stream:Verona"); assert.equal(opts.updater("stream:Verona"), "stream:Verona"); assert.ok(!is_blurred); assert.ok(is_append_search_string_called); search.__Rewire__("is_using_input_method", true); _setup("stream:Verona"); assert.equal(opts.updater("stream:Verona"), "stream:Verona"); assert.ok(!is_blurred); assert.ok(is_append_search_string_called); $search_query_box.off("blur"); } }; search.initialize(); const $search_pill_stub = $.create(".pill"); $search_pill_stub.closest = () => ({data: noop}); const stub_event = { // FIXME: event.relatedTarget should not be a jQuery object relatedTarget: $search_pill_stub, }; $search_query_box.val("test string"); narrow_state.search_string = () => "ver"; $search_query_box.trigger(new $.Event("blur", stub_event)); assert.equal($search_query_box.val(), "test string"); let css_args; $searchbox.css = (args) => { css_args = args; }; $searchbox.trigger("focusout"); assert.deepEqual(css_args, {"box-shadow": "unset"}); search.__Rewire__("is_using_input_method", false); $searchbox_form.trigger("compositionend"); assert.ok(search.is_using_input_method); const keydown = $searchbox_form.get_on_handler("keydown"); let default_prevented = false; let ev = { type: "keydown", key: "a", preventDefault() { default_prevented = true; }, }; $search_query_box.is = () => false; assert.equal(keydown(ev), undefined); assert.ok(!default_prevented); ev.key = "Enter"; assert.equal(keydown(ev), undefined); assert.ok(!default_prevented); ev.key = "Enter"; $search_query_box.is = () => true; assert.equal(keydown(ev), undefined); assert.ok(default_prevented); let operators; let is_blurred; narrow_state.active = () => false; $search_query_box.off("blur"); $search_query_box.on("blur", () => { is_blurred = true; }); const _setup = (search_box_val) => { is_blurred = false; $search_button.prop("disabled", false); $search_query_box.val(search_box_val); Filter.parse = (search_string) => { assert.equal(search_string, search_box_val); return operators; }; narrow.activate = (raw_operators, options) => { assert.deepEqual(raw_operators, operators); assert.deepEqual(options, {trigger: "search"}); }; search_pill.get_search_string_for_current_filter = () => search_box_val; }; operators = [ { negated: false, operator: "search", operand: "", }, ]; _setup(""); ev = { type: "keyup", which: 15, }; /* istanbul ignore next */ $search_query_box.is = () => false; $searchbox_form.trigger(ev); assert.ok(!is_blurred); assert.ok(!$search_button.prop("disabled")); ev.key = "Enter"; $search_query_box.is = () => false; $searchbox_form.trigger(ev); assert.ok(!is_blurred); assert.ok(!$search_button.prop("disabled")); ev.key = "Enter"; $search_query_box.is = () => true; $searchbox_form.trigger(ev); assert.ok(is_blurred); _setup("ver"); search.__Rewire__("is_using_input_method", true); $searchbox_form.trigger(ev); // No change on Enter keyup event when using input tool assert.ok(!is_blurred); assert.ok(!$search_button.prop("disabled")); _setup("ver"); ev.key = "Enter"; $search_query_box.is = () => true; $searchbox_form.trigger(ev); assert.ok(is_blurred); assert.ok(!$search_button.prop("disabled")); $search_button.prop("disabled", true); $search_query_box.trigger("focus"); assert.ok(!$search_button.prop("disabled")); }); test("initiate_search", () => { // open typeahead and select text when navbar is open // this implicitly expects the code to used the chained // function calls, which is something to keep in mind if // this test ever fails unexpectedly. let typeahead_forced_open = false; let is_searchbox_text_selected = false; let is_searchbox_focused = false; $("#search_query").off("focus"); $("#search_query").on("focus", () => { is_searchbox_focused = true; }); $("#search_query").typeahead = (lookup) => { if (lookup === "lookup") { typeahead_forced_open = true; } return $("#search_query"); }; $("#search_query").on("select", () => { is_searchbox_text_selected = true; }); $("#search_query")[0] = "stub"; const $searchbox = $("#searchbox"); let css_args; $searchbox.css = (args) => { css_args = args; }; search.initiate_search(); assert.ok(typeahead_forced_open); assert.ok(is_searchbox_text_selected); assert.ok(is_searchbox_focused); assert.deepEqual(css_args, {"box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)"}); });