diff --git a/tools/test-js-with-node b/tools/test-js-with-node
index 990d6a2644..74e43dba30 100755
--- a/tools/test-js-with-node
+++ b/tools/test-js-with-node
@@ -153,7 +153,6 @@ EXEMPT_FILES = make_set(
"web/src/scheduled_messages_overlay_ui.js",
"web/src/scroll_bar.ts",
"web/src/scroll_util.ts",
- "web/src/search_pill_widget.js",
"web/src/sent_messages.js",
"web/src/sentry.ts",
"web/src/server_events.js",
diff --git a/web/src/hotkey.js b/web/src/hotkey.js
index 7a54966566..53194dfa4a 100644
--- a/web/src/hotkey.js
+++ b/web/src/hotkey.js
@@ -25,7 +25,6 @@ import * as list_util from "./list_util";
import * as message_edit from "./message_edit";
import * as message_lists from "./message_lists";
import * as message_scroll from "./message_scroll";
-import * as message_view_header from "./message_view_header";
import * as muted_topics_ui from "./muted_topics_ui";
import * as narrow from "./narrow";
import * as narrow_state from "./narrow_state";
@@ -320,17 +319,6 @@ export function process_escape_key(e) {
return true;
}
- if ($("#searchbox").has(":focus")) {
- $("input:focus,textarea:focus").trigger("blur");
- if (page_params.search_pills_enabled) {
- $("#searchbox .pill").trigger("blur");
- $("#searchbox #search_query").trigger("blur");
- } else {
- message_view_header.exit_search();
- }
- return true;
- }
-
// We pressed Esc and something was focused, and the composebox
// wasn't open. In that case, we should blur the input.
$("input:focus,textarea:focus").trigger("blur");
diff --git a/web/src/message_view_header.js b/web/src/message_view_header.js
index c22c252748..3aa1a60e83 100644
--- a/web/src/message_view_header.js
+++ b/web/src/message_view_header.js
@@ -4,7 +4,6 @@ import render_message_view_header from "../templates/message_view_header.hbs";
import {$t} from "./i18n";
import * as narrow_state from "./narrow_state";
-import {page_params} from "./page_params";
import * as peer_data from "./peer_data";
import * as popovers from "./popovers";
import * as recent_topics_util from "./recent_topics_util";
@@ -132,11 +131,7 @@ function build_message_view_header(filter) {
const message_view_header_data = make_message_view_header(filter);
append_and_display_title_area(message_view_header_data);
bind_title_area_handlers();
- if (page_params.search_pills_enabled && $("#search_query").is(":focus")) {
- open_search_bar_and_close_narrow_description();
- } else {
- close_search_bar_and_open_narrow_description();
- }
+ close_search_bar_and_open_narrow_description();
}
}
@@ -145,7 +140,7 @@ function build_message_view_header(filter) {
export function reset_searchbox_text() {
let search_string = narrow_state.search_string();
if (search_string !== "") {
- if (!page_params.search_pills_enabled && !narrow_state.filter().is_search()) {
+ if (!narrow_state.filter().is_search()) {
// saves the user a keystroke for quick searches
search_string = search_string + " ";
}
diff --git a/web/src/narrow.js b/web/src/narrow.js
index 7886d97a83..6fb2bea434 100644
--- a/web/src/narrow.js
+++ b/web/src/narrow.js
@@ -36,8 +36,6 @@ import * as recent_topics_ui from "./recent_topics_ui";
import * as recent_topics_util from "./recent_topics_util";
import * as resize from "./resize";
import * as search from "./search";
-import * as search_pill from "./search_pill";
-import * as search_pill_widget from "./search_pill_widget";
import {web_mark_read_on_scroll_policy_values} from "./settings_config";
import * as spectators from "./spectators";
import * as stream_data from "./stream_data";
@@ -534,15 +532,6 @@ export function activate(raw_operators, opts) {
hashchange.save_narrow(operators);
}
- if (page_params.search_pills_enabled && opts.trigger !== "search") {
- search_pill_widget.widget.clear(true);
-
- for (const operator of operators) {
- const search_string = Filter.unparse([operator]);
- search_pill.append_search_string(search_string, search_pill_widget.widget);
- }
- }
-
if (filter.contains_only_private_messages()) {
compose_closed_ui.update_buttons_for_private();
} else {
@@ -995,11 +984,6 @@ export function to_compose_target() {
function handle_post_narrow_deactivate_processes() {
compose_fade.update_message_list();
- // clear existing search pills
- if (page_params.search_pills_enabled) {
- search_pill_widget.widget.clear(true);
- }
-
top_left_corner.handle_narrow_deactivated();
pm_list.handle_narrow_deactivated();
stream_list.handle_narrow_deactivated();
diff --git a/web/src/search.js b/web/src/search.js
index 21f90c006c..488c792fe6 100644
--- a/web/src/search.js
+++ b/web/src/search.js
@@ -7,11 +7,7 @@ import * as keydown_util from "./keydown_util";
import * as message_view_header from "./message_view_header";
import * as narrow from "./narrow";
import * as narrow_state from "./narrow_state";
-import {page_params} from "./page_params";
-import * as search_pill from "./search_pill";
-import * as search_pill_widget from "./search_pill_widget";
import * as search_suggestion from "./search_suggestion";
-import * as ui_util from "./ui_util";
// Exported for unit testing
export let is_using_input_method = false;
@@ -25,18 +21,7 @@ export function narrow_or_search_for_term(search_string) {
return $search_query_box.val();
}
- let operators;
- if (page_params.search_pills_enabled) {
- // We have to take care to append the new pill before calling this
- // function, so that the base_query includes the suggestion selected
- // along with query corresponding to the existing pills.
- const base_query = search_pill.get_search_string_for_current_filter(
- search_pill_widget.widget,
- );
- operators = Filter.parse(base_query);
- } else {
- operators = Filter.parse(search_string);
- }
+ const operators = Filter.parse(search_string);
narrow.activate(operators, {trigger: "search"});
// It's sort of annoying that this is not in a position to
@@ -45,9 +30,7 @@ export function narrow_or_search_for_term(search_string) {
// Narrowing will have already put some operators in the search box,
// so leave the current text in.
- if (!page_params.search_pills_enabled) {
- $search_query_box.trigger("blur");
- }
+ $search_query_box.trigger("blur");
return $search_query_box.val();
}
@@ -68,7 +51,6 @@ export function update_button_visibility() {
export function initialize() {
const $search_query_box = $("#search_query");
const $searchbox_form = $("#searchbox_form");
- const $searchbox = $("#searchbox");
// Data storage for the typeahead.
// This maps a search string to an object with a "description_html" field.
@@ -79,23 +61,15 @@ export function initialize() {
$search_query_box.typeahead({
source(query) {
- let base_query = "";
- if (page_params.search_pills_enabled) {
- base_query = search_pill.get_search_string_for_current_filter(
- search_pill_widget.widget,
- );
- }
+ const base_query = "";
const suggestions = search_suggestion.get_suggestions(base_query, query);
// Update our global search_map hash
search_map = suggestions.lookup_table;
return suggestions.strings;
},
- parentElement: "#searchbox_legacy",
+ parentElement: "#searchbox",
items: search_suggestion.max_num_of_search_results,
helpOnEmptyStrings: true,
- // With search pills, the contenteditable input will be empty
- // even if some pills are present.
- hideOnEmpty: page_params.search_pills_enabled,
naturalSearch: true,
highlighter(item) {
const obj = search_map.get(item);
@@ -105,23 +79,13 @@ export function initialize() {
return true;
},
updater(search_string) {
- if (page_params.search_pills_enabled) {
- search_pill.append_search_string(search_string, search_pill_widget.widget);
- return $search_query_box.val();
- }
return narrow_or_search_for_term(search_string);
},
sorter(items) {
return items;
},
- stopAdvance: page_params.search_pills_enabled,
advanceKeyCodes: [8],
- on_move() {
- if (page_params.search_pills_enabled) {
- ui_util.place_caret_at_end($search_query_box[0]);
- }
- },
// Use our custom typeahead `on_escape` hook to exit
// the search bar as soon as the user hits Esc.
on_escape: message_view_header.exit_search,
@@ -172,7 +136,7 @@ export function initialize() {
// more work to re-order everything and make them private.
$search_query_box.on("focus", focus_search);
- $search_query_box.on("blur", (e) => {
+ $search_query_box.on("blur", () => {
// The search query box is a visual cue as to
// whether search or narrowing is active. If
// the user blurs the search box, then we should
@@ -187,33 +151,10 @@ export function initialize() {
// enough for the search to have gone through, but
// short enough that the user won't notice (though
// really it would be OK if they did).
-
- if (page_params.search_pills_enabled) {
- const $element = $(e.relatedTarget).closest(".pill");
- const search_pill = search_pill_widget.widget.getByElement($element[0]);
- if (search_pill) {
- // The searchbox loses focus while the search
- // pill element gains focus.
- // We do not consider the searchbox to actually
- // lose focus when a pill inside it gets selected
- // or deleted by a click.
- return;
- }
- }
setTimeout(() => {
update_button_visibility();
}, 100);
});
-
- if (page_params.search_pills_enabled) {
- // Uses jquery instead of pure css as the `:focus` event occurs on `#search_query`,
- // while we want to add box-shadow to `#searchbox`. This could have been done
- // with `:focus-within` CSS selector, but it is not supported in IE or Opera.
- $searchbox.on("focusout", () => {
- message_view_header.close_search_bar_and_open_narrow_description();
- $searchbox.css({"box-shadow": "unset"});
- });
- }
}
export function focus_search() {
@@ -223,12 +164,7 @@ export function focus_search() {
export function initiate_search() {
message_view_header.open_search_bar_and_close_narrow_description();
- $("#searchbox").css({"box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)"});
$("#search_query").typeahead("lookup").trigger("select");
- if (page_params.search_pills_enabled) {
- $("#search_query").trigger("focus");
- ui_util.place_caret_at_end($("#search_query")[0]);
- }
}
export function clear_search_form() {
diff --git a/web/src/search_pill.js b/web/src/search_pill.js
deleted file mode 100644
index edfa33c119..0000000000
--- a/web/src/search_pill.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import {Filter} from "./filter";
-import * as input_pill from "./input_pill";
-
-export function create_item_from_search_string(search_string) {
- const operator = Filter.parse(search_string);
- const description_html = Filter.describe(operator);
- return {
- display_value: search_string,
- description_html,
- };
-}
-
-export function get_search_string_from_item(item) {
- return item.display_value;
-}
-
-export function create_pills($pill_container) {
- const pills = input_pill.create({
- $container: $pill_container,
- create_item_from_text: create_item_from_search_string,
- get_text_from_item: get_search_string_from_item,
- });
- return pills;
-}
-
-export function append_search_string(search_string, pill_widget) {
- const operators = Filter.parse(search_string);
- for (const operator of operators) {
- const input = Filter.unparse([operator]);
- pill_widget.appendValue(input);
- }
- if (pill_widget.clear_text !== undefined) {
- pill_widget.clear_text();
- }
-}
-
-export function get_search_string_for_current_filter(pill_widget) {
- const items = pill_widget.items();
- const search_strings = items.map((item) => item.display_value);
- return search_strings.join(" ");
-}
diff --git a/web/src/search_pill_widget.js b/web/src/search_pill_widget.js
deleted file mode 100644
index ad271477b5..0000000000
--- a/web/src/search_pill_widget.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import $ from "jquery";
-
-import * as browser_history from "./browser_history";
-import {page_params} from "./page_params";
-import * as search_pill from "./search_pill";
-
-export let widget;
-
-export function initialize() {
- if (!page_params.search_pills_enabled) {
- return;
- }
- const $container = $("#search_arrows");
- widget = search_pill.create_pills($container);
-
- widget.onPillRemove(() => {
- if (widget.items().length === 0) {
- browser_history.go_to_location("");
- }
- });
-
- widget.createPillonPaste(() => false);
-}
diff --git a/web/src/search_suggestion.js b/web/src/search_suggestion.js
index 966dbcf4bd..fee5b40e02 100644
--- a/web/src/search_suggestion.js
+++ b/web/src/search_suggestion.js
@@ -707,28 +707,14 @@ class Attacher {
export function get_search_result(base_query, query) {
let suggestion;
- let all_operators;
// search_operators correspond to the operators for the query in the input.
- // For search_pills_enabled, this includes just editable query where search pills
- // have not been created yet.
- // And for this disabled case, this includes the entire query entered in the searchbox.
+ // This includes the entire query entered in the searchbox.
// operators correspond to the operators for the entire query entered in the searchbox.
- if (page_params.search_pills_enabled) {
- all_operators = Filter.parse((base_query + " " + query).trim());
- }
const search_operators = Filter.parse(query);
let last = {operator: "", operand: "", negated: false};
if (search_operators.length > 0) {
last = search_operators.at(-1);
- } else if (page_params.search_pills_enabled) {
- // We push an empty term so that we can get suggestions
- // on the empty string based on the base query which is
- // calculated from the created search pills.
- // Else search results are returned as if the user is still
- // typing the non-editable last search pill.
- all_operators.push(last);
- search_operators.push(last);
}
const person_suggestion_ops = ["sender", "dm", "dm-including", "from", "pm-with"];
@@ -751,10 +737,6 @@ export function get_search_result(base_query, query) {
operand: person_op.operand + " " + last.operand,
negated: person_op.negated,
};
- if (page_params.search_pills_enabled) {
- all_operators.splice(-2);
- all_operators.push(last);
- }
search_operators.splice(-2);
search_operators.push(last);
}
@@ -808,10 +790,7 @@ export function get_search_result(base_query, query) {
];
}
- if (!page_params.search_pills_enabled) {
- all_operators = search_operators;
- }
- const base_operators = all_operators.slice(0, -1);
+ const base_operators = search_operators.slice(0, -1);
const max_items = max_num_of_search_results;
for (const filterer of filterers) {
@@ -821,15 +800,7 @@ export function get_search_result(base_query, query) {
}
}
- if (
- !page_params.search_pills_enabled &&
- // This is unique to the legacy search system. With pills
- // it is difficult to "suggest" a subset of operators,
- // and there's a more natural mechanism under that paradigm,
- // where the user just deletes one or more pills. So you
- // won't see this is in the new code.
- attacher.result.length < max_items
- ) {
+ if (attacher.result.length < max_items) {
const subset_suggestions = get_operator_subset_suggestions(search_operators);
attacher.push_many(subset_suggestions);
}
diff --git a/web/src/ui_init.js b/web/src/ui_init.js
index b3b4645cdb..2d4fbf716b 100644
--- a/web/src/ui_init.js
+++ b/web/src/ui_init.js
@@ -80,7 +80,6 @@ import * as scheduled_messages_overlay_ui from "./scheduled_messages_overlay_ui"
import * as scroll_bar from "./scroll_bar";
import * as scroll_util from "./scroll_util";
import * as search from "./search";
-import * as search_pill_widget from "./search_pill_widget";
import * as sent_messages from "./sent_messages";
import * as server_events from "./server_events";
import * as settings from "./settings";
@@ -221,7 +220,6 @@ function initialize_right_sidebar() {
function initialize_navbar() {
const rendered_navbar = render_navbar({
embedded: page_params.narrow_stream !== undefined,
- search_pills_enabled: page_params.search_pills_enabled,
});
$("#header-container").html(rendered_navbar);
@@ -676,7 +674,6 @@ export function initialize_everything() {
compose_recipient.initialize();
compose_pm_pill.initialize();
compose_closed_ui.initialize();
- search_pill_widget.initialize();
reload.initialize();
user_groups.initialize(user_groups_params);
unread.initialize(unread_params);
diff --git a/web/styles/search.css b/web/styles/search.css
index 80384ed79b..97e9911e35 100644
--- a/web/styles/search.css
+++ b/web/styles/search.css
@@ -1,5 +1,4 @@
-#searchbox,
-#searchbox_legacy {
+#searchbox {
width: 100%;
height: var(--header-height);
@@ -67,7 +66,6 @@
font-size: 16px;
height: calc(var(--header-height) - 1px);
padding: 0;
- padding-left: 5px;
padding-right: 40px;
border: none;
border-radius: 0;
@@ -77,6 +75,7 @@
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
+ padding-left: 35px;
@media (width < $sm_min) {
vertical-align: text-bottom;
@@ -107,6 +106,8 @@
}
.search_close_button {
+ right: 0;
+
&:hover {
opacity: 1;
}
@@ -133,59 +134,8 @@
#search_arrows {
font-size: 90%;
letter-spacing: normal;
- }
-}
-
-/* in progress: searchbox with pills */
-#searchbox {
- #search_arrows {
- padding-left: 35px;
- }
-
- .pill-container {
- display: flex;
- flex-wrap: nowrap;
- align-items: center;
- border: none;
- padding: 0;
- }
-
- @media (width >= $sm_min) {
- .pill {
- padding: 2px 0 !important;
- font-size: 14px;
- }
- }
-
- @media (width < $sm_min) {
- #search_arrows .pill {
- line-height: 20px;
-
- .exit {
- top: 0;
- }
- }
- }
-}
-
-#searchbox_legacy {
- #search_arrows {
padding-left: 0;
}
-
- #search_query {
- padding-left: 35px;
- }
-
- .search_close_button {
- right: 0;
- }
-
- .navbar-search.expanded {
- .search_close_button {
- margin-right: 5px;
- }
- }
}
.typeahead-menu li a {
diff --git a/web/styles/zulip.css b/web/styles/zulip.css
index a2e0947425..3b956943ad 100644
--- a/web/styles/zulip.css
+++ b/web/styles/zulip.css
@@ -3036,7 +3036,6 @@ select.invite-as {
.navbar-search,
#message_view_header,
#searchbox,
- #searchbox_legacy,
.header {
line-height: var(--header-height);
height: var(--header-height);
diff --git a/web/templates/navbar.hbs b/web/templates/navbar.hbs
index 3e3f54eb82..a45fd3c8fd 100644
--- a/web/templates/navbar.hbs
+++ b/web/templates/navbar.hbs
@@ -17,22 +17,7 @@
diff --git a/web/tests/search_now.test.js b/web/tests/search.test.js
similarity index 97%
rename from web/tests/search_now.test.js
rename to web/tests/search.test.js
index 0c00d36e4b..b03ca6654a 100644
--- a/web/tests/search_now.test.js
+++ b/web/tests/search.test.js
@@ -5,9 +5,6 @@ const {strict: assert} = require("assert");
const {mock_esm, set_global, zrequire} = require("./lib/namespace");
const {run_test} = require("./lib/test");
const $ = require("./lib/zjquery");
-const {page_params} = require("./lib/zpage_params");
-
-page_params.search_pills_enabled = false;
const narrow = mock_esm("../src/narrow");
const narrow_state = mock_esm("../src/narrow_state");
@@ -386,21 +383,11 @@ run_test("initiate_search", () => {
is_searchbox_text_selected = true;
});
- let searchbox_css_args;
-
- $("#searchbox").css = (args) => {
- searchbox_css_args = args;
- };
-
search.initiate_search();
assert.ok(typeahead_forced_open);
assert.ok(is_searchbox_text_selected);
assert.equal($("#search_query").val(), "ver");
- assert.deepEqual(searchbox_css_args, {
- "box-shadow": "inset 0px 0px 0px 2px hsl(204, 20%, 74%)",
- });
-
// test that we append space for user convenience
narrow_state.filter = () => ({is_search: () => false});
search.initiate_search();
diff --git a/web/tests/search_future.test.js b/web/tests/search_future.test.js
deleted file mode 100644
index 3e72226b1d..0000000000
--- a/web/tests/search_future.test.js
+++ /dev/null
@@ -1,457 +0,0 @@
-"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_close_button").prop("disabled", false);
-
- search.clear_search_form();
-
- assert.equal($("#search_query").is_focused(), false);
- assert.equal($("#search_query").val(), "");
- assert.equal($(".search_close_button").prop("disabled"), true);
-});
-
-test("update_button_visibility", () => {
- const $search_query = $("#search_query");
- const $close_button = $(".search_close_button");
-
- $search_query.is = () => false;
- $search_query.val("");
- narrow_state.active = () => false;
- $close_button.prop("disabled", true);
- search.update_button_visibility();
- assert.ok($close_button.prop("disabled"));
-
- $search_query.is = () => true;
- $search_query.val("");
- delete narrow_state.active;
- $close_button.prop("disabled", true);
- search.update_button_visibility();
- assert.ok(!$close_button.prop("disabled"));
-
- $search_query.is = () => false;
- $search_query.val("Test search term");
- delete narrow_state.active;
- $close_button.prop("disabled", true);
- search.update_button_visibility();
- assert.ok(!$close_button.prop("disabled"));
-
- $search_query.is = () => false;
- $search_query.val("");
- narrow_state.active = () => true;
- $close_button.prop("disabled", true);
- search.update_button_visibility();
- assert.ok(!$close_button.prop("disabled"));
-});
-
-test("initialize", ({mock_template}) => {
- const $search_query_box = $("#search_query");
- const $searchbox_form = $("#searchbox_form");
- const $close_button = $(".search_close_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.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([
- [
- "dm-including:zo",
- {
- description_html: "group direct messages including",
- is_person: true,
- search_string: "dm-including: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",
- },
- },
- ],
- [
- "dm:zo",
- {
- description_html: "direct messages with",
- is_person: true,
- search_string: "dm: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", "dm:zo", "dm-including: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
direct 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 direct 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;
- $close_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(!$close_button.prop("disabled"));
-
- ev.key = "Enter";
- $search_query_box.is = () => false;
- $searchbox_form.trigger(ev);
-
- assert.ok(!is_blurred);
- assert.ok(!$close_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(!$close_button.prop("disabled"));
-
- _setup("ver");
- ev.key = "Enter";
- $search_query_box.is = () => true;
- $searchbox_form.trigger(ev);
- assert.ok(is_blurred);
- assert.ok(!$close_button.prop("disabled"));
-
- $close_button.prop("disabled", true);
- $search_query_box.trigger("focus");
- assert.ok(!$close_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%)"});
-});
diff --git a/web/tests/search_pill.test.js b/web/tests/search_pill.test.js
deleted file mode 100644
index 6d436bf121..0000000000
--- a/web/tests/search_pill.test.js
+++ /dev/null
@@ -1,85 +0,0 @@
-"use strict";
-
-const {strict: assert} = require("assert");
-
-const {mock_esm, zrequire} = require("./lib/namespace");
-const {run_test} = require("./lib/test");
-
-const input_pill = mock_esm("../src/input_pill");
-
-const search_pill = zrequire("search_pill");
-
-const is_starred_item = {
- display_value: "is:starred",
- description_html: "starred messages",
-};
-
-const is_private_item = {
- display_value: "is:private",
- description_html: "direct messages",
-};
-
-run_test("create_item", () => {
- function test_create_item(search_string, current_items, expected_item) {
- const item = search_pill.create_item_from_search_string(search_string, current_items);
- assert.deepEqual(item, expected_item);
- }
-
- test_create_item("is:starred", [], is_starred_item);
-});
-
-run_test("get_search_string", () => {
- assert.equal(search_pill.get_search_string_from_item(is_starred_item), "is:starred");
-});
-
-run_test("append", () => {
- let appended;
- let cleared;
-
- function fake_append(search_string) {
- appended = true;
- assert.equal(search_string, is_starred_item.display_value);
- }
-
- function fake_clear() {
- cleared = true;
- }
-
- const pill_widget = {
- appendValue: fake_append,
- clear_text: fake_clear,
- };
-
- search_pill.append_search_string(is_starred_item.display_value, pill_widget);
-
- assert.ok(appended);
- assert.ok(cleared);
-});
-
-run_test("get_items", () => {
- const items = [is_starred_item, is_private_item];
-
- const pill_widget = {
- items() {
- return items;
- },
- };
-
- assert.deepEqual(
- search_pill.get_search_string_for_current_filter(pill_widget),
- is_starred_item.display_value + " " + is_private_item.display_value,
- );
-});
-
-run_test("create_pills", ({override}) => {
- let input_pill_create_called = false;
-
- override(input_pill, "create", () => {
- input_pill_create_called = true;
- return {dummy: "dummy"};
- });
-
- const pills = search_pill.create_pills({});
- assert.ok(input_pill_create_called);
- assert.deepEqual(pills, {dummy: "dummy"});
-});
diff --git a/web/tests/search_suggestion_now.test.js b/web/tests/search_suggestion.test.js
similarity index 99%
rename from web/tests/search_suggestion_now.test.js
rename to web/tests/search_suggestion.test.js
index 17da94a5b3..08302bd287 100644
--- a/web/tests/search_suggestion_now.test.js
+++ b/web/tests/search_suggestion.test.js
@@ -53,7 +53,6 @@ const example_avatar_url = "http://example.com/example.png";
function init() {
page_params.is_admin = true;
- page_params.search_pills_enabled = false;
people.init();
people.add_active_user(bob);
diff --git a/web/tests/search_suggestion_future.test.js b/web/tests/search_suggestion_future.test.js
deleted file mode 100644
index 7fd96daebf..0000000000
--- a/web/tests/search_suggestion_future.test.js
+++ /dev/null
@@ -1,1020 +0,0 @@
-"use strict";
-
-const {strict: assert} = require("assert");
-
-const {mock_esm, zrequire} = require("./lib/namespace");
-const {run_test} = require("./lib/test");
-const {page_params} = require("./lib/zpage_params");
-
-const narrow_state = mock_esm("../src/narrow_state");
-const stream_topic_history_util = mock_esm("../src/stream_topic_history_util");
-
-const huddle_data = zrequire("huddle_data");
-
-const stream_data = zrequire("stream_data");
-const stream_topic_history = zrequire("stream_topic_history");
-const people = zrequire("people");
-const search = zrequire("search_suggestion");
-
-search.__Rewire__("max_num_of_search_results", 15);
-
-const me = {
- email: "myself@zulip.com",
- full_name: "Me Myself",
- user_id: 41,
-};
-
-const bob = {
- email: "bob@zulip.com",
- full_name: "Bob Roberts",
- user_id: 42,
-};
-
-const ted = {
- email: "ted@zulip.com",
- delivery_email: "ted@zulip.com",
- user_id: 101,
- full_name: "Ted Smith",
-};
-
-const alice = {
- email: "alice@zulip.com",
- user_id: 102,
- full_name: "Alice Ignore",
-};
-
-const jeff = {
- email: "jeff@zulip.com",
- user_id: 103,
- full_name: "Jeff Zoolipson",
-};
-
-const noop = () => {};
-const example_avatar_url = "http://example.com/example.png";
-
-function init() {
- page_params.is_admin = true;
- page_params.search_pills_enabled = true;
-
- people.init();
- people.add_active_user(bob);
- people.add_active_user(me);
- people.add_active_user(ted);
- people.add_active_user(alice);
- people.add_active_user(jeff);
-
- people.initialize_current_user(me.user_id);
-
- stream_topic_history.reset();
- huddle_data.clear_for_testing();
- stream_data.clear_subscriptions();
-}
-
-function get_suggestions(base_query, query) {
- return search.get_suggestions(base_query, query);
-}
-
-function test(label, f) {
- run_test(label, (helpers) => {
- init();
- f(helpers);
- });
-}
-
-test("basic_get_suggestions", ({override}) => {
- const query = "fred";
-
- override(narrow_state, "stream", () => "office");
-
- const suggestions = get_suggestions("", query);
-
- const expected = ["fred"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("basic_get_suggestions_for_spectator", () => {
- page_params.is_spectator = true;
-
- const query = "";
- const suggestions = get_suggestions("", query);
- assert.deepEqual(suggestions.strings, ["", "has:link", "has:image", "has:attachment"]);
- page_params.is_spectator = false;
-});
-
-test("subset_suggestions", () => {
- const query = "shakespeare";
- const base_query = "stream:Denmark topic:Hamlet";
-
- const suggestions = get_suggestions(base_query, query);
-
- const expected = ["shakespeare"];
-
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("dm_suggestions", ({override}) => {
- let query = "is:dm";
- let suggestions = get_suggestions("", query);
- let expected = [
- "is:dm",
- "dm:alice@zulip.com",
- "dm:bob@zulip.com",
- "dm:jeff@zulip.com",
- "dm:myself@zulip.com",
- "dm:ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "al";
- let base_query = "is:dm";
- suggestions = get_suggestions(base_query, query);
- expected = [
- "al",
- "is:alerted",
- "sender:alice@zulip.com",
- "dm:alice@zulip.com",
- "dm-including:alice@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // "is:private" was renamed to "is:dm", so
- // we suggest "is:dm" to anyone with "is:private"
- // in their muscle memory.
- query = "is:pr";
- suggestions = get_suggestions("", query);
- expected = ["is:dm"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "is:private";
- suggestions = get_suggestions("", query);
- expected = ["is:dm"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "dm:t";
- suggestions = get_suggestions("", query);
- expected = ["dm:t", "dm:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-dm:t";
- suggestions = get_suggestions("", query);
- expected = ["-dm:t", "is:dm -dm:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "dm:ted@zulip.com";
- suggestions = get_suggestions("", query);
- expected = ["dm:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:ted";
- suggestions = get_suggestions("", query);
- expected = ["sender:ted", "sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:te";
- suggestions = get_suggestions("", query);
- expected = ["sender:te", "sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-sender:te";
- suggestions = get_suggestions("", query);
- expected = ["-sender:te", "-sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:ted@zulip.com";
- suggestions = get_suggestions("", query);
- expected = ["sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "from:ted";
- base_query = "is:unread";
- suggestions = get_suggestions(base_query, query);
- expected = ["from:ted", "from:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- // Users can enter bizarre queries, and if they do, we want to
- // be conservative with suggestions.
- query = "near:3";
- base_query = "is:dm";
- suggestions = get_suggestions(base_query, query);
- expected = ["near:3"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "near:3";
- base_query = "dm:ted@zulip.com";
- suggestions = get_suggestions(base_query, query);
- expected = ["near:3"];
- assert.deepEqual(suggestions.strings, expected);
-
- // Make sure suggestions still work if preceding tokens
- query = "sender:ted@zulip.com";
- base_query = "is:alerted";
- suggestions = get_suggestions(base_query, query);
- expected = ["sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "al";
- base_query = "is:starred has:link is:dm";
- suggestions = get_suggestions(base_query, query);
- expected = [
- "al",
- "is:alerted",
- "sender:alice@zulip.com",
- "dm:alice@zulip.com",
- "dm-including:alice@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // Make sure it handles past context correctly
- query = "dm:";
- base_query = "stream:Denmark";
- suggestions = get_suggestions(base_query, query);
- expected = ["dm:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:";
- base_query = "sender:ted@zulip.com";
- suggestions = get_suggestions(base_query, query);
- expected = ["sender:"];
- assert.deepEqual(suggestions.strings, expected);
-
- // "pm-with" operator returns search result
- // and "dm" operator as a suggestions
- override(narrow_state, "stream", () => undefined);
- query = "pm-with";
- suggestions = get_suggestions("", query);
- expected = ["pm-with", "dm:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "pm-with:t";
- suggestions = get_suggestions("", query);
- expected = ["pm-with:t", "dm:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("group_suggestions", () => {
- // Entering a comma in a dm query should immediately generate
- // suggestions for the next person.
- let query = "dm:bob@zulip.com,";
- let suggestions = get_suggestions("", query);
- let expected = [
- "dm:bob@zulip.com,",
- "dm:bob@zulip.com,alice@zulip.com",
- "dm:bob@zulip.com,jeff@zulip.com",
- "dm:bob@zulip.com,ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // Only the last part of a comma-separated dm query should be used to
- // generate suggestions.
- query = "dm:bob@zulip.com,t";
- suggestions = get_suggestions("", query);
- expected = ["dm:bob@zulip.com,t", "dm:bob@zulip.com,ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- // Smit should also generate ted@zulip.com (Ted Smith) as a suggestion.
- query = "dm:bob@zulip.com,Smit";
- suggestions = get_suggestions("", query);
- expected = ["dm:bob@zulip.com,Smit", "dm:bob@zulip.com,ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- // Do not suggest "myself@zulip.com" (the name of the current user)
- query = "dm:ted@zulip.com,mys";
- suggestions = get_suggestions("", query);
- expected = ["dm:ted@zulip.com,mys"];
- assert.deepEqual(suggestions.strings, expected);
-
- // No superfluous suggestions should be generated.
- query = "dm:bob@zulip.com,red";
- suggestions = get_suggestions("", query);
- expected = ["dm:bob@zulip.com,red"];
- assert.deepEqual(suggestions.strings, expected);
-
- // "is:dm" should be properly prepended to each suggestion
- // if the "dm" operator is negated.
-
- query = "-dm:bob@zulip.com,";
- suggestions = get_suggestions("", query);
- expected = [
- "-dm:bob@zulip.com,",
- "is:dm -dm:bob@zulip.com,alice@zulip.com",
- "is:dm -dm:bob@zulip.com,jeff@zulip.com",
- "is:dm -dm:bob@zulip.com,ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-dm:bob@zulip.com,t";
- suggestions = get_suggestions("", query);
- expected = ["-dm:bob@zulip.com,t", "is:dm -dm:bob@zulip.com,ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-dm:bob@zulip.com,Smit";
- suggestions = get_suggestions("", query);
- expected = ["-dm:bob@zulip.com,Smit", "is:dm -dm:bob@zulip.com,ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-dm:bob@zulip.com,red";
- suggestions = get_suggestions("", query);
- expected = ["-dm:bob@zulip.com,red"];
- assert.deepEqual(suggestions.strings, expected);
-
- // If user types "pm-with" operator, an email and a comma,
- // show suggestions for group direct messages with the "dm"
- // operator.
- query = "pm-with:bob@zulip.com,";
- suggestions = get_suggestions("", query);
- expected = [
- "pm-with:bob@zulip.com,",
- "dm:bob@zulip.com,alice@zulip.com",
- "dm:bob@zulip.com,jeff@zulip.com",
- "dm:bob@zulip.com,ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // Test multiple operators
- query = "dm:bob@zulip.com,Smit";
- let base_query = "is:starred has:link";
- suggestions = get_suggestions(base_query, query);
- expected = ["dm:bob@zulip.com,Smit", "dm:bob@zulip.com,ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "dm:bob@zulip.com,Smit";
- base_query = "stream:Denmark has:link";
- suggestions = get_suggestions(base_query, query);
- expected = ["dm:bob@zulip.com,Smit"];
- assert.deepEqual(suggestions.strings, expected);
-
- function message(user_ids, timestamp) {
- return {
- type: "private",
- display_recipient: user_ids.map((id) => ({
- id,
- })),
- timestamp,
- };
- }
-
- huddle_data.process_loaded_messages([
- message([bob.user_id, ted.user_id], 99),
- message([bob.user_id, ted.user_id, jeff.user_id], 98),
- ]);
-
- // Simulate a past group direct message which should now
- // prioritize ted over alice
- query = "dm:bob@zulip.com,";
- suggestions = get_suggestions("", query);
- expected = [
- "dm:bob@zulip.com,",
- "dm:bob@zulip.com,ted@zulip.com",
- "dm:bob@zulip.com,alice@zulip.com",
- "dm:bob@zulip.com,jeff@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // bob, ted, and jeff are already an existing group direct message,
- // so prioritize this one
- query = "dm:bob@zulip.com,ted@zulip.com,";
- suggestions = get_suggestions("", query);
- expected = [
- "dm:bob@zulip.com,ted@zulip.com,",
- "dm:bob@zulip.com,ted@zulip.com,jeff@zulip.com",
- "dm:bob@zulip.com,ted@zulip.com,alice@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // bob, ted, and jeff are already an existing group direct message,
- // but if we start with just jeff, then don't prioritize ted over
- // alice because it doesn't complete the full group direct message.
- query = "dm:jeff@zulip.com,";
- suggestions = get_suggestions("", query);
- expected = [
- "dm:jeff@zulip.com,",
- "dm:jeff@zulip.com,alice@zulip.com",
- "dm:jeff@zulip.com,bob@zulip.com",
- "dm:jeff@zulip.com,ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "dm:jeff@zulip.com,ted@zulip.com hi";
- suggestions = get_suggestions("", query);
- expected = ["dm:jeff@zulip.com,ted@zulip.com hi"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("empty_query_suggestions", () => {
- const query = "";
-
- stream_data.add_sub({stream_id: 44, name: "devel", subscribed: true});
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
-
- const suggestions = get_suggestions("", query);
-
- const expected = [
- "",
- "streams:public",
- "is:dm",
- "is:starred",
- "is:mentioned",
- "is:alerted",
- "is:unread",
- "is:resolved",
- "sender:myself@zulip.com",
- "stream:devel",
- "stream:office",
- "has:link",
- "has:image",
- "has:attachment",
- ];
-
- assert.deepEqual(suggestions.strings, expected);
-
- function describe(q) {
- return suggestions.lookup_table.get(q).description_html;
- }
- assert.equal(describe("is:dm"), "Direct messages");
- assert.equal(describe("is:starred"), "Starred messages");
- assert.equal(describe("is:mentioned"), "@-mentions");
- assert.equal(describe("is:alerted"), "Alerted messages");
- assert.equal(describe("is:unread"), "Unread messages");
- assert.equal(describe("is:resolved"), "Topics marked as resolved");
- assert.equal(describe("sender:myself@zulip.com"), "Sent by me");
- assert.equal(describe("has:link"), "Messages with one or more link");
- assert.equal(describe("has:image"), "Messages with one or more image");
- assert.equal(describe("has:attachment"), "Messages with one or more attachment");
-});
-
-test("has_suggestions", ({override}) => {
- // Checks that category wise suggestions are displayed instead of a single
- // default suggestion when suggesting `has` operator.
- let query = "h";
- stream_data.add_sub({stream_id: 44, name: "devel", subscribed: true});
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
- override(narrow_state, "stream", () => {});
-
- let suggestions = get_suggestions("", query);
- let expected = ["h", "has:link", "has:image", "has:attachment"];
- assert.deepEqual(suggestions.strings, expected);
-
- function describe(q) {
- return suggestions.lookup_table.get(q).description_html;
- }
-
- assert.equal(describe("has:link"), "Messages with one or more link");
- assert.equal(describe("has:image"), "Messages with one or more image");
- assert.equal(describe("has:attachment"), "Messages with one or more attachment");
-
- query = "-h";
- suggestions = get_suggestions("", query);
- expected = ["-h", "-has:link", "-has:image", "-has:attachment"];
- assert.deepEqual(suggestions.strings, expected);
- assert.equal(describe("-has:link"), "Exclude messages with one or more link");
- assert.equal(describe("-has:image"), "Exclude messages with one or more image");
- assert.equal(describe("-has:attachment"), "Exclude messages with one or more attachment");
-
- // operand suggestions follow.
-
- query = "has:";
- suggestions = get_suggestions("", query);
- expected = ["has:link", "has:image", "has:attachment"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "has:im";
- suggestions = get_suggestions("", query);
- expected = ["has:image"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-has:im";
- suggestions = get_suggestions("", query);
- expected = ["-has:image"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "att";
- suggestions = get_suggestions("", query);
- expected = ["att", "has:attachment"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "has:lin";
- const base_query = "stream:Denmark is:alerted";
- suggestions = get_suggestions(base_query, query);
- expected = ["has:link"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("check_is_suggestions", ({override}) => {
- let query = "i";
- stream_data.add_sub({stream_id: 44, name: "devel", subscribed: true});
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
- override(narrow_state, "stream", () => {});
-
- let suggestions = get_suggestions("", query);
- let expected = [
- "i",
- "is:dm",
- "is:starred",
- "is:mentioned",
- "is:alerted",
- "is:unread",
- "is:resolved",
- "sender:alice@zulip.com",
- "dm:alice@zulip.com",
- "dm-including:alice@zulip.com",
- "has:image",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- function describe(q) {
- return suggestions.lookup_table.get(q).description_html;
- }
-
- assert.equal(describe("is:dm"), "Direct messages");
- assert.equal(describe("is:starred"), "Starred messages");
- assert.equal(describe("is:mentioned"), "@-mentions");
- assert.equal(describe("is:alerted"), "Alerted messages");
- assert.equal(describe("is:unread"), "Unread messages");
- assert.equal(describe("is:resolved"), "Topics marked as resolved");
-
- query = "-i";
- suggestions = get_suggestions("", query);
- expected = [
- "-i",
- "-is:dm",
- "-is:starred",
- "-is:mentioned",
- "-is:alerted",
- "-is:unread",
- "-is:resolved",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- assert.equal(describe("-is:dm"), "Exclude direct messages");
- assert.equal(describe("-is:starred"), "Exclude starred messages");
- assert.equal(describe("-is:mentioned"), "Exclude @-mentions");
- assert.equal(describe("-is:alerted"), "Exclude alerted messages");
- assert.equal(describe("-is:unread"), "Exclude unread messages");
- assert.equal(describe("-is:resolved"), "Exclude topics marked as resolved");
-
- query = "";
- suggestions = get_suggestions("", query);
- expected = [
- "",
- "streams:public",
- "is:dm",
- "is:starred",
- "is:mentioned",
- "is:alerted",
- "is:unread",
- "is:resolved",
- "sender:myself@zulip.com",
- "stream:devel",
- "stream:office",
- "has:link",
- "has:image",
- "has:attachment",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "";
- let base_query = "is:dm";
- suggestions = get_suggestions(base_query, query);
- expected = [
- "is:starred",
- "is:mentioned",
- "is:alerted",
- "is:unread",
- "sender:myself@zulip.com",
- "has:link",
- "has:image",
- "has:attachment",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- // operand suggestions follow.
-
- query = "is:";
- suggestions = get_suggestions("", query);
- expected = ["is:dm", "is:starred", "is:mentioned", "is:alerted", "is:unread", "is:resolved"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "is:st";
- suggestions = get_suggestions("", query);
- expected = ["is:starred"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-is:st";
- suggestions = get_suggestions("", query);
- expected = ["-is:starred"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "st";
- suggestions = get_suggestions("", query);
- expected = ["st", "streams:public", "is:starred", "stream:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "is:sta";
- base_query = "stream:Denmark has:link";
- suggestions = get_suggestions(base_query, query);
- expected = ["is:starred"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("sent_by_me_suggestions", ({override}) => {
- override(narrow_state, "stream", () => {});
-
- let query = "";
- let suggestions = get_suggestions("", query);
- assert.ok(suggestions.strings.includes("sender:myself@zulip.com"));
- assert.equal(
- suggestions.lookup_table.get("sender:myself@zulip.com").description_html,
- "Sent by me",
- );
-
- query = "sender";
- suggestions = get_suggestions("", query);
- let expected = ["sender", "sender:myself@zulip.com", "sender:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-sender";
- suggestions = get_suggestions("", query);
- expected = ["-sender", "-sender:myself@zulip.com", "-sender:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "from";
- suggestions = get_suggestions("", query);
- expected = ["from", "from:myself@zulip.com", "from:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-from";
- suggestions = get_suggestions("", query);
- expected = ["-from", "-from:myself@zulip.com", "-from:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:bob@zulip.com";
- suggestions = get_suggestions("", query);
- expected = ["sender:bob@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "from:bob@zulip.com";
- suggestions = get_suggestions("", query);
- expected = ["from:bob@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sent";
- suggestions = get_suggestions("", query);
- expected = ["sent", "sender:myself@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-sent";
- suggestions = get_suggestions("", query);
- expected = ["-sent", "-sender:myself@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sent";
- let base_query = "stream:Denmark topic:Denmark1";
- suggestions = get_suggestions(base_query, query);
- expected = ["sent", "sender:myself@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:m";
- base_query = "is:starred";
- suggestions = get_suggestions(base_query, query);
- expected = ["sender:m", "sender:myself@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:";
- base_query = "is:starred";
- suggestions = get_suggestions(base_query, query);
- expected = [
- "sender:",
- "sender:myself@zulip.com",
- "sender:alice@zulip.com",
- "sender:bob@zulip.com",
- "sender:jeff@zulip.com",
- "sender:ted@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("topic_suggestions", ({override}) => {
- let suggestions;
- let expected;
-
- override(stream_topic_history_util, "get_server_history", () => {});
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
- override(narrow_state, "stream", () => "office");
-
- const devel_id = 44;
- const office_id = 77;
- stream_data.add_sub({stream_id: devel_id, name: "devel", subscribed: true});
- stream_data.add_sub({stream_id: office_id, name: "office", subscribed: true});
-
- suggestions = get_suggestions("", "te");
- expected = ["te", "sender:ted@zulip.com", "dm:ted@zulip.com", "dm-including:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-
- stream_topic_history.add_message({
- stream_id: devel_id,
- topic_name: "REXX",
- });
-
- for (const topic_name of ["team", "ignore", "test"]) {
- stream_topic_history.add_message({
- stream_id: office_id,
- topic_name,
- });
- }
-
- suggestions = get_suggestions("", "te");
- expected = [
- "te",
- "sender:ted@zulip.com",
- "dm:ted@zulip.com",
- "dm-including:ted@zulip.com",
- "stream:office topic:team",
- "stream:office topic:test",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- function describe(q) {
- return suggestions.lookup_table.get(q).description_html;
- }
- assert.equal(describe("te"), "Search for te");
- assert.equal(describe("stream:office topic:team"), "Stream office > team");
-
- suggestions = get_suggestions("topic:staplers", "stream:office");
- expected = ["stream:office"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("stream:devel", "topic:");
- expected = ["topic:", "topic:REXX"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("stream:devel", "-topic:");
- expected = ["-topic:", "-topic:REXX"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("", "-topic:te");
- expected = ["-topic:te", "stream:office -topic:team", "stream:office -topic:test"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("is:alerted stream:devel is:starred", "topic:");
- expected = ["topic:", "topic:REXX"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("is:dm stream:devel", "topic:");
- expected = ["topic:"];
- assert.deepEqual(suggestions.strings, expected);
-
- suggestions = get_suggestions("topic:REXX stream:devel", "topic:");
- expected = ["topic:"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("topic_suggestions (limits)", () => {
- let candidate_topics = [];
-
- function assert_result(guess, expected_topics) {
- assert.deepEqual(
- search.get_topic_suggestions_from_candidates({candidate_topics, guess}),
- expected_topics,
- );
- }
-
- assert_result("", []);
- assert_result("zzz", []);
-
- candidate_topics = ["a", "b", "c"];
- assert_result("", ["a", "b", "c"]);
- assert_result("b", ["b"]);
- assert_result("z", []);
-
- candidate_topics = [
- "a1",
- "a2",
- "b1",
- "b2",
- "a3",
- "a4",
- "a5",
- "c1",
- "a6",
- "a7",
- "a8",
- "c2",
- "a9",
- "a10",
- "a11",
- "a12",
- ];
- // We max out at 10 topics, so as not to overwhelm the user.
- assert_result("", ["a1", "a2", "b1", "b2", "a3", "a4", "a5", "c1", "a6", "a7"]);
- assert_result("a", ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10"]);
- assert_result("b", ["b1", "b2"]);
- assert_result("z", []);
-});
-
-test("whitespace_glitch", ({override}) => {
- const query = "stream:office "; // note trailing space
-
- override(stream_topic_history_util, "get_server_history", () => {});
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
-
- const suggestions = get_suggestions("", query);
-
- const expected = ["stream:office"];
-
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("stream_completion", ({override}) => {
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
- stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true});
-
- override(narrow_state, "stream", () => {});
-
- let query = "stream:of";
- let suggestions = get_suggestions("", query);
- let expected = ["stream:of", "stream:office"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-stream:of";
- suggestions = get_suggestions("", query);
- expected = ["-stream:of", "-stream:office"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "hel";
- suggestions = get_suggestions("", query);
- expected = ["hel", "stream:dev+help"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-function people_suggestion_setup() {
- const ted = {
- email: "ted@zulip.com",
- user_id: 201,
- full_name: "Ted Smith",
- };
- people.add_active_user(ted);
-
- const bob = {
- email: "bob@zulip.com",
- user_id: 202,
- full_name: "Bob Térry",
- avatar_url: example_avatar_url,
- };
-
- people.add_active_user(bob);
- const alice = {
- email: "alice@zulip.com",
- user_id: 203,
- full_name: "Alice Ignore",
- };
- people.add_active_user(alice);
-}
-
-test("people_suggestions", ({override}) => {
- override(narrow_state, "stream", noop);
- people_suggestion_setup();
-
- let query = "te";
- let suggestions = get_suggestions("", query);
- let expected = [
- "te",
- "sender:bob@zulip.com",
- "sender:ted@zulip.com",
- "dm:bob@zulip.com", // bob térry
- "dm:ted@zulip.com",
- "dm-including:bob@zulip.com",
- "dm-including:ted@zulip.com",
- ];
-
- assert.deepEqual(suggestions.strings, expected);
-
- const is_person = (q) => suggestions.lookup_table.get(q).is_person;
- assert.equal(is_person("dm:ted@zulip.com"), true);
- assert.equal(is_person("sender:ted@zulip.com"), true);
- assert.equal(is_person("dm-including:ted@zulip.com"), true);
-
- const has_image = (q) => suggestions.lookup_table.get(q).user_pill_context.has_image;
- assert.equal(has_image("dm:bob@zulip.com"), true);
- assert.equal(has_image("sender:bob@zulip.com"), true);
- assert.equal(has_image("dm-including:bob@zulip.com"), true);
-
- const describe = (q) => suggestions.lookup_table.get(q).description_html;
- assert.equal(describe("dm:ted@zulip.com"), "Direct messages with");
- assert.equal(describe("sender:ted@zulip.com"), "Sent by");
- assert.equal(describe("dm-including:ted@zulip.com"), "Direct messages including");
-
- let expectedString = "Ted Smith";
-
- const get_full_name = (q) =>
- suggestions.lookup_table.get(q).user_pill_context.display_value.string;
- assert.equal(get_full_name("sender:ted@zulip.com"), expectedString);
- assert.equal(get_full_name("dm:ted@zulip.com"), expectedString);
- assert.equal(get_full_name("dm-including:ted@zulip.com"), expectedString);
-
- expectedString = `${example_avatar_url}?s=50`;
-
- const get_avatar_url = (q) => suggestions.lookup_table.get(q).user_pill_context.img_src;
- assert.equal(get_avatar_url("dm:bob@zulip.com"), expectedString);
- assert.equal(get_avatar_url("sender:bob@zulip.com"), expectedString);
- assert.equal(get_avatar_url("dm-including:bob@zulip.com"), expectedString);
-
- suggestions = get_suggestions("", "Ted "); // note space
- expected = ["Ted", "sender:ted@zulip.com", "dm:ted@zulip.com", "dm-including:ted@zulip.com"];
-
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:ted sm";
- let base_query = "";
- expected = ["sender:ted+sm", "sender:ted@zulip.com"];
- suggestions = get_suggestions(base_query, query);
- assert.deepEqual(suggestions.strings, expected);
-
- query = "new";
- base_query = "sender:ted@zulip.com";
- expected = ["new"];
- suggestions = get_suggestions(base_query, query);
- assert.deepEqual(suggestions.strings, expected);
-
- query = "sender:ted@tulip.com new";
- base_query = "";
- expected = ["sender:ted@tulip.com+new"];
- suggestions = get_suggestions(base_query, query);
- assert.deepEqual(suggestions.strings, expected);
-
- query = "new";
- base_query = "sender:ted@tulip.com";
- expected = ["new"];
- suggestions = get_suggestions(base_query, query);
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("operator_suggestions", ({override}) => {
- override(narrow_state, "stream", () => undefined);
-
- // Completed operator should return nothing
- let query = "stream:";
- let suggestions = get_suggestions("", query);
- let expected = ["stream:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "st";
- suggestions = get_suggestions("", query);
- expected = ["st", "streams:public", "is:starred", "stream:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-s";
- suggestions = get_suggestions("", query);
- expected = ["-s", "-streams:public", "-sender:myself@zulip.com", "-stream:", "-sender:"];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "-f";
- const base_query = "stream:Denmark is:alerted";
- suggestions = get_suggestions(base_query, query);
- expected = ["-f", "-from:myself@zulip.com", "-from:"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-test("queries_with_spaces", () => {
- stream_data.add_sub({stream_id: 77, name: "office", subscribed: true});
- stream_data.add_sub({stream_id: 88, name: "dev help", subscribed: true});
-
- // test allowing spaces with quotes surrounding operand
- let query = 'stream:"dev he"';
- let suggestions = get_suggestions("", query);
- let expected = ["stream:dev+he", "stream:dev+help"];
- assert.deepEqual(suggestions.strings, expected);
-
- // test mismatched quote
- query = 'stream:"dev h';
- suggestions = get_suggestions("", query);
- expected = ["stream:dev+h", "stream:dev+help"];
- assert.deepEqual(suggestions.strings, expected);
-
- // test extra space after operator still works
- query = "stream: offi";
- suggestions = get_suggestions("", query);
- expected = ["stream:offi", "stream:office"];
- assert.deepEqual(suggestions.strings, expected);
-});
-
-// When input search query contains multiple operators
-// and a pill hasn't been formed from those operators.
-test("multiple_operators_without_pills", () => {
- let query = "is:dm al";
- let base_query = "";
- let suggestions = get_suggestions(base_query, query);
- let expected = [
- "is:dm al",
- "is:dm is:alerted",
- "is:dm sender:alice@zulip.com",
- "is:dm dm:alice@zulip.com",
- "is:dm dm-including:alice@zulip.com",
- ];
- assert.deepEqual(suggestions.strings, expected);
-
- query = "abc is:alerted sender:ted@zulip.com";
- base_query = "";
- suggestions = get_suggestions(base_query, query);
- expected = ["abc is:alerted sender:ted@zulip.com"];
- assert.deepEqual(suggestions.strings, expected);
-});
diff --git a/zerver/lib/home.py b/zerver/lib/home.py
index 370eeb598a..4d123efe59 100644
--- a/zerver/lib/home.py
+++ b/zerver/lib/home.py
@@ -187,7 +187,6 @@ def build_page_params_for_home_page_load(
insecure_desktop_app=insecure_desktop_app,
login_page=settings.HOME_NOT_LOGGED_IN,
warn_no_email=settings.WARN_NO_EMAIL,
- search_pills_enabled=settings.SEARCH_PILLS_ENABLED,
# Only show marketing email settings if on Zulip Cloud
corporate_enabled=settings.CORPORATE_ENABLED,
## Misc. extra data.
diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py
index b03d6ab80a..14f9256c59 100644
--- a/zerver/tests/test_home.py
+++ b/zerver/tests/test_home.py
@@ -188,7 +188,6 @@ class HomeTest(ZulipTestCase):
"recent_private_conversations",
"request_language",
"scheduled_messages",
- "search_pills_enabled",
"server_avatar_changes_disabled",
"server_emoji_data_url",
"server_generation",
@@ -355,7 +354,6 @@ class HomeTest(ZulipTestCase):
"queue_id",
"realm_rendered_description",
"request_language",
- "search_pills_enabled",
"server_sentry_dsn",
"show_billing",
"show_plans",
diff --git a/zproject/default_settings.py b/zproject/default_settings.py
index 9941671964..7523a97fbe 100644
--- a/zproject/default_settings.py
+++ b/zproject/default_settings.py
@@ -293,9 +293,6 @@ ALWAYS_SEND_ALL_HOTSPOTS = False
# self-hosters who want to disable the tutorial entirely on their system.
TUTORIAL_ENABLED = True
-# In-development search pills feature.
-SEARCH_PILLS_ENABLED = False
-
# We log emails in development environment for accessing
# them easily through /emails page
DEVELOPMENT_LOG_EMAILS = DEVELOPMENT
diff --git a/zproject/dev_settings.py b/zproject/dev_settings.py
index b45085c30b..2033fbbdec 100644
--- a/zproject/dev_settings.py
+++ b/zproject/dev_settings.py
@@ -164,8 +164,6 @@ if FAKE_LDAP_MODE:
THUMBNAIL_IMAGES = True
-SEARCH_PILLS_ENABLED = bool(os.getenv("SEARCH_PILLS_ENABLED"))
-
BILLING_ENABLED = True
LANDING_PAGE_NAVBAR_MESSAGE: Optional[str] = None
diff --git a/zproject/test_extra_settings.py b/zproject/test_extra_settings.py
index 14e8e97f65..ee546e59d9 100644
--- a/zproject/test_extra_settings.py
+++ b/zproject/test_extra_settings.py
@@ -49,10 +49,6 @@ else:
CAMO_URI = "https://external-content.zulipcdn.net/external_content/"
CAMO_KEY = "dummy"
-if PUPPETEER_TESTS:
- # Disable search pills prototype for production use
- SEARCH_PILLS_ENABLED = False
-
if "RUNNING_OPENAPI_CURL_TEST" in os.environ:
RUNNING_OPENAPI_CURL_TEST = True