2021-03-15 13:03:00 +01:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const {strict: assert} = require("assert");
|
|
|
|
|
|
|
|
const {zrequire} = require("../zjsunit/namespace");
|
|
|
|
const {run_test} = require("../zjsunit/test");
|
|
|
|
|
|
|
|
// Hopefully the basic patterns for testing data-oriented modules
|
|
|
|
// are starting to become apparent. To reinforce that, we will present
|
|
|
|
// few more examples that also expose you to some of our core
|
|
|
|
// data objects. Also, we start testing some objects that have
|
|
|
|
// deeper dependencies.
|
|
|
|
|
2021-03-28 17:57:53 +02:00
|
|
|
const message_helper = zrequire("message_helper");
|
2021-03-15 13:03:00 +01:00
|
|
|
const message_store = zrequire("message_store");
|
|
|
|
const people = zrequire("people");
|
|
|
|
const stream_data = zrequire("stream_data");
|
|
|
|
const stream_topic_history = zrequire("stream_topic_history");
|
|
|
|
const unread = zrequire("unread");
|
|
|
|
|
|
|
|
// It's typical to set up a little bit of data at the top of a
|
|
|
|
// test module, but you can also do this within tests. Here we
|
|
|
|
// will set up things at the top.
|
|
|
|
|
|
|
|
const isaac = {
|
|
|
|
email: "isaac@example.com",
|
|
|
|
user_id: 30,
|
|
|
|
full_name: "Isaac Newton",
|
|
|
|
};
|
|
|
|
|
|
|
|
const denmark_stream = {
|
|
|
|
color: "blue",
|
|
|
|
name: "Denmark",
|
|
|
|
stream_id: 101,
|
|
|
|
subscribed: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
const messages = {
|
|
|
|
isaac_to_denmark_stream: {
|
|
|
|
id: 400,
|
|
|
|
sender_id: isaac.user_id,
|
|
|
|
stream_id: denmark_stream.stream_id,
|
|
|
|
type: "stream",
|
|
|
|
flags: ["has_alert_word"],
|
|
|
|
topic: "copenhagen",
|
|
|
|
// note we don't have every field that a "real" message
|
|
|
|
// would have, and that can be fine
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// We aren't going to modify isaac in our tests, so we will
|
|
|
|
// create him at the top.
|
|
|
|
people.add_active_user(isaac);
|
|
|
|
|
|
|
|
// We are going to test a core module called messages_store.js next.
|
|
|
|
// This is an example of a deep unit test, where our dependencies
|
|
|
|
// are easy to test.
|
|
|
|
|
|
|
|
run_test("message_store", () => {
|
|
|
|
message_store.clear_for_testing();
|
|
|
|
stream_data.clear_subscriptions();
|
|
|
|
stream_data.add_sub(denmark_stream);
|
|
|
|
|
|
|
|
const in_message = {...messages.isaac_to_denmark_stream};
|
|
|
|
|
|
|
|
assert.equal(in_message.alerted, undefined);
|
|
|
|
|
|
|
|
// Let's add a message into our message_store via
|
2021-03-28 17:57:53 +02:00
|
|
|
// message_helper.process_new_message.
|
2021-03-15 13:03:00 +01:00
|
|
|
assert.equal(message_store.get(in_message.id), undefined);
|
2021-03-28 17:57:53 +02:00
|
|
|
message_helper.process_new_message(in_message);
|
2021-03-15 13:03:00 +01:00
|
|
|
const message = message_store.get(in_message.id);
|
narrow: Fix messages being cached without flags set.
f0c680e9c0d1a62fd414bccc82e4ac255173aaa9 introduced a call to
message_helper.process_new_message without first calling
message_store.set_message_flags on the message.
This resulted in it being possible as a race, when loading the Zulip
app to a stream/topic/near narrow, for a message to have the
`historical` flag be undefined due to not being initialized.
That invalid state, in turn, resulted in the message_list_view code
path for rendering the message feed incorrectly displaying additional
recipient bars around the message.
We could fix this by just calling message_store.set_message_booleans
in this code path. However, this bug exposes the fact that it's very
fragile to expect every code path to call that function before
message_helper.process_new_message.
So we instead fix this by moving message_store.set_message_booleans
inside message_helper.process_new_message.
One call point of concern in this change is maybe_add_narrow_messages,
which could theoretically reintroduce the double set_message_flags
bugs detailed in 9729b1a4ad51b69c98ce4f8374c9d9f8cf69430c. However, I
believe that to not be possible, because that call should never
experience a cache miss.
The other existing code paths were already calling
set_message_booleans immediately before
message_helper.process_new_message. They are still changing here, in
that we now do a cache lookup before attempting to call
set_message_booleans. Because the message booleans do not affect the
cache lookup and the local message object is discarded in case of a
cache hit, this should have no functional impact.
Because I found the existing comment at that call site confusing and
almost proposed removing it as pointless, extend the block comment to
explicitly mention that the purpose is refreshing our object.
Fixes #21503.
2022-03-24 01:07:56 +01:00
|
|
|
assert.equal(in_message.alerted, true);
|
2021-03-15 13:03:00 +01:00
|
|
|
assert.equal(message, in_message);
|
|
|
|
|
|
|
|
// There are more side effects.
|
|
|
|
const topic_names = stream_topic_history.get_recent_topic_names(denmark_stream.stream_id);
|
|
|
|
assert.deepEqual(topic_names, ["copenhagen"]);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Tracking unread messages is a very fundamental part of the Zulip
|
|
|
|
// app, and we use the unread object to track unread messages.
|
|
|
|
|
|
|
|
run_test("unread", () => {
|
|
|
|
unread.declare_bankruptcy();
|
|
|
|
stream_data.clear_subscriptions();
|
|
|
|
stream_data.add_sub(denmark_stream);
|
|
|
|
|
|
|
|
const stream_id = denmark_stream.stream_id;
|
|
|
|
const topic_name = "copenhagen";
|
|
|
|
|
|
|
|
assert.equal(unread.num_unread_for_topic(stream_id, topic_name), 0);
|
|
|
|
|
|
|
|
const in_message = {...messages.isaac_to_denmark_stream};
|
|
|
|
message_store.set_message_booleans(in_message);
|
|
|
|
|
|
|
|
unread.process_loaded_messages([in_message]);
|
|
|
|
assert.equal(unread.num_unread_for_topic(stream_id, topic_name), 1);
|
|
|
|
});
|