Files
zulip/web/tests/narrow_unread.test.js
roanster007 522f6cfaf9 filter: Fix adjusted_terms_if_moved handling for non stream messages.
Previously, when "adjusted_terms_if_moved" was called for non stream
messages, it used to return "null" for adjusted terms. This is true
for some extent since the non stream messages can not be moved.

However, in case of narrow containing "with" operator, this would
be buggy since there, we want the narrow terms to be adjusted
according to the "with" operand to point to the current narrow,
rather than returning null.

This commit updates the method to return null only if  the "raw_terms"
dont contain "with" operator. Else, adjust the "raw_terms" according
to the message.
2024-07-15 14:00:59 -07:00

273 lines
7.8 KiB
JavaScript

"use strict";
const {strict: assert} = require("assert");
const {mock_esm, zrequire} = require("./lib/namespace");
const {run_test} = require("./lib/test");
const blueslip = require("./lib/zblueslip");
mock_esm("../src/user_topics", {
is_topic_muted: () => false,
});
const {Filter} = zrequire("../src/filter");
const message_store = zrequire("message_store");
const people = zrequire("people");
const stream_data = zrequire("stream_data");
const unread = zrequire("unread");
// The main code we are testing lives here.
const narrow_state = zrequire("narrow_state");
const message_lists = zrequire("message_lists");
const alice = {
email: "alice@example.com",
user_id: 11,
full_name: "Alice",
};
people.init();
people.add_active_user(alice);
function set_filter(terms) {
const filter = new Filter(terms);
filter.try_adjusting_for_moved_with_target();
message_lists.set_current({
data: {
filter,
},
});
}
function assert_unread_info(expected) {
assert.deepEqual(
narrow_state.get_first_unread_info(message_lists.current?.data.filter),
expected,
);
}
function candidate_ids() {
return narrow_state._possible_unread_message_ids();
}
run_test("get_unread_ids", () => {
unread.declare_bankruptcy();
message_lists.set_current(undefined);
let unread_ids;
let terms;
const sub = {
name: "My stream",
stream_id: 55,
};
const stream_msg = {
id: 101,
type: "stream",
stream_id: sub.stream_id,
display_recipient: sub.name,
topic: "my topic",
unread: true,
mentioned: true,
mentioned_me_directly: true,
};
const private_msg = {
id: 102,
type: "private",
unread: true,
display_recipient: [{id: alice.user_id, email: alice.email}],
};
const other_topic_message = {
id: 103,
type: "stream",
stream_id: sub.stream_id,
display_recipient: sub.name,
topic: "another topic",
unread: true,
mentioned: false,
mentioned_me_directly: false,
};
message_store.update_message_cache(stream_msg);
message_store.update_message_cache(private_msg);
message_store.update_message_cache(other_topic_message);
stream_data.add_sub(sub);
unread_ids = candidate_ids();
assert.equal(unread_ids, undefined);
terms = [{operator: "search", operand: "whatever"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.equal(unread_ids, undefined);
assert_unread_info({flavor: "cannot_compute"});
terms = [{operator: "bogus_operator", operand: "me@example.com"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
assert_unread_info({flavor: "not_found"});
terms = [{operator: "stream", operand: "bogus"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
terms = [{operator: "stream", operand: sub.name}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
assert_unread_info({flavor: "not_found"});
unread.process_loaded_messages([stream_msg]);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
assert_unread_info({
flavor: "found",
msg_id: stream_msg.id,
});
terms = [
{operator: "stream", operand: "bogus"},
{operator: "topic", operand: "my topic"},
];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
terms = [
{operator: "stream", operand: sub.name},
{operator: "topic", operand: "my topic"},
];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
terms = [{operator: "is", operand: "mentioned"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
terms = [{operator: "is", operand: "resolved"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
terms = [{operator: "sender", operand: "me@example.com"}];
set_filter(terms);
// note that our candidate ids are just "all" ids now
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
// this actually does filtering
assert_unread_info({flavor: "not_found"});
terms = [{operator: "dm", operand: "alice@example.com"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
unread.process_loaded_messages([private_msg]);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [private_msg.id]);
assert_unread_info({
flavor: "found",
msg_id: private_msg.id,
});
// "is:private" was renamed to "is:dm"
terms = [{operator: "is", operand: "private"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [private_msg.id]);
terms = [{operator: "is", operand: "dm"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [private_msg.id]);
// For a negated search, our candidate ids will be all
// unread messages, even ones that don't pass the filter.
terms = [{operator: "is", operand: "dm", negated: true}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id, private_msg.id]);
terms = [{operator: "dm", operand: "bob@example.com"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
terms = [{operator: "is", operand: "starred"}];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, []);
terms = [{operator: "search", operand: "needle"}];
set_filter(terms);
assert_unread_info({
flavor: "cannot_compute",
});
// For a search using `with` operator, our candidate ids
// will be the messages present in the channel/topic
// containing the message for which the `with` operand
// is id to.
//
// Here we use an empty topic for the operators, and show that
// adding the with operator causes us to see unreads in the
// destination topic.
unread.process_loaded_messages([other_topic_message]);
terms = [
{operator: "channel", operand: sub.name},
{operator: "topic", operand: "another topic"},
];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [other_topic_message.id]);
terms = [
{operator: "channel", operand: sub.name},
{operator: "topic", operand: "another topic"},
{operator: "with", operand: stream_msg.id},
];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [stream_msg.id]);
terms = [
{operator: "channel", operand: sub.name},
{operator: "topic", operand: "another topic"},
{operator: "with", operand: private_msg.id},
];
set_filter(terms);
unread_ids = candidate_ids();
assert.deepEqual(unread_ids, [private_msg.id]);
message_lists.set_current(undefined);
blueslip.expect("error", "unexpected call to get_first_unread_info");
assert_unread_info({
flavor: "cannot_compute",
});
});
run_test("defensive code", ({override_rewire}) => {
// Test defensive code. We actually avoid calling
// _possible_unread_message_ids for any case where we
// couldn't compute the unread message ids, but that
// invariant is hard to future-proof.
override_rewire(narrow_state, "_possible_unread_message_ids", () => undefined);
const terms = [{operator: "some-unhandled-case", operand: "whatever"}];
set_filter(terms);
assert_unread_info({
flavor: "cannot_compute",
});
});