snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
This commit is contained in:
160
web/tests/example7.test.cjs
Normal file
160
web/tests/example7.test.cjs
Normal file
@@ -0,0 +1,160 @@
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert/strict");
|
||||
|
||||
const {make_stream} = require("./lib/example_stream.cjs");
|
||||
const {mock_esm, set_global, zrequire} = require("./lib/namespace.cjs");
|
||||
const {run_test, noop} = require("./lib/test.cjs");
|
||||
const {$} = require("./lib/zjquery.cjs");
|
||||
|
||||
/*
|
||||
|
||||
Let's continue to explore how we can test complex
|
||||
interactions in the real code.
|
||||
|
||||
When a new message comes in, we update the three major
|
||||
panes of the app:
|
||||
|
||||
* left sidebar - stream list
|
||||
* middle pane - message view
|
||||
* right sidebar - buddy list (aka "activity" list)
|
||||
|
||||
These are reflected by the following calls:
|
||||
|
||||
stream_list.update_streams_sidebar
|
||||
message_util.add_new_messages
|
||||
activity.process_loaded_messages
|
||||
|
||||
For now, though, let's focus on another side effect
|
||||
of processing incoming messages:
|
||||
|
||||
unread_ops.process_visible
|
||||
|
||||
When new messages come in, they are often immediately
|
||||
visible to users, so the app will communicate this
|
||||
back to the server by calling unread_ops.process_visible.
|
||||
|
||||
In order to unit test this, we don't want to require
|
||||
an actual server to be running. Instead, this example
|
||||
will stub many of the "boundaries" to focus on the
|
||||
core behavior.
|
||||
|
||||
The two key pieces here are as follows:
|
||||
|
||||
* Use mock_esm to avoid compiling the "real"
|
||||
modules that are immaterial to our current
|
||||
testing concerns.
|
||||
|
||||
* Use override(...) to simulate how we want
|
||||
methods to behave. (Often we want them to
|
||||
do nothing at all or return a simple
|
||||
value.)
|
||||
*/
|
||||
|
||||
set_global("document", {hasFocus: () => true});
|
||||
|
||||
const channel = mock_esm("../src/channel");
|
||||
const desktop_notifications = mock_esm("../src/desktop_notifications");
|
||||
const message_lists = mock_esm("../src/message_lists");
|
||||
const message_viewport = mock_esm("../src/message_viewport");
|
||||
const unread_ui = mock_esm("../src/unread_ui");
|
||||
|
||||
message_lists.current = {view: {}};
|
||||
message_lists.all_rendered_message_lists = () => [message_lists.current];
|
||||
|
||||
const message_store = zrequire("message_store");
|
||||
const stream_data = zrequire("stream_data");
|
||||
const unread = zrequire("unread");
|
||||
const unread_ops = zrequire("unread_ops");
|
||||
|
||||
const denmark_stream = make_stream({
|
||||
color: "blue",
|
||||
name: "Denmark",
|
||||
stream_id: 101,
|
||||
subscribed: false,
|
||||
});
|
||||
|
||||
run_test("unread_ops", ({override}) => {
|
||||
stream_data.clear_subscriptions();
|
||||
stream_data.add_sub_for_tests(denmark_stream);
|
||||
message_store.clear_for_testing();
|
||||
unread.declare_bankruptcy();
|
||||
|
||||
const message_id = 50;
|
||||
const test_messages = [
|
||||
{
|
||||
id: message_id,
|
||||
type: "stream",
|
||||
stream_id: denmark_stream.stream_id,
|
||||
topic: "copenhagen",
|
||||
unread: true,
|
||||
},
|
||||
];
|
||||
|
||||
// Make our test message appear to be unread, so that
|
||||
// we then need to subsequently process them as read.
|
||||
message_store.update_message_cache({
|
||||
type: "server_message",
|
||||
message: test_messages[0],
|
||||
});
|
||||
unread.process_loaded_messages(test_messages);
|
||||
|
||||
// Make our message_viewport appear visible.
|
||||
$("#message_feed_container").show();
|
||||
|
||||
// Make our "test" message appear visible.
|
||||
override(message_viewport, "bottom_rendered_message_visible", () => true);
|
||||
|
||||
// Set message_lists.current containing messages that can be marked read
|
||||
override(message_lists.current, "all_messages", () => test_messages);
|
||||
|
||||
// Ignore these interactions for now:
|
||||
override(message_lists.current.view, "show_message_as_read", noop);
|
||||
override(desktop_notifications, "close_notification", noop);
|
||||
override(unread_ui, "update_unread_counts", noop);
|
||||
override(unread_ui, "notify_messages_remain_unread", noop);
|
||||
|
||||
// Set up a way to capture the options passed in to channel.post.
|
||||
let channel_post_opts;
|
||||
override(channel, "post", (opts) => {
|
||||
channel_post_opts = opts;
|
||||
});
|
||||
|
||||
let can_mark_messages_read;
|
||||
|
||||
// Set up an override to point to the above var, so we can
|
||||
// toggle it easily from within the test (and avoid complicated
|
||||
// data setup).
|
||||
override(message_lists.current, "can_mark_messages_read", () => can_mark_messages_read);
|
||||
override(message_lists.current, "has_unread_messages", () => true);
|
||||
override(message_lists.current.view, "is_fetched_end_rendered", () => true);
|
||||
|
||||
// First, test for a message list that cannot read messages.
|
||||
can_mark_messages_read = false;
|
||||
unread_ops.process_visible();
|
||||
|
||||
assert.deepEqual(channel_post_opts, undefined);
|
||||
|
||||
// Now flip the boolean, and get to the main thing we are testing.
|
||||
can_mark_messages_read = true;
|
||||
// Don't mark messages as read until all messages in the narrow are fetched and rendered.
|
||||
override(message_lists.current.view, "is_fetched_end_rendered", () => false);
|
||||
unread_ops.process_visible();
|
||||
assert.deepEqual(channel_post_opts, undefined);
|
||||
|
||||
override(message_lists.current.view, "is_fetched_end_rendered", () => true);
|
||||
unread_ops.process_visible();
|
||||
|
||||
// The most important side effect of the above call is that
|
||||
// we post info to the server. We can verify that the correct
|
||||
// url and parameters are specified:
|
||||
assert.deepEqual(channel_post_opts, {
|
||||
url: "/json/messages/flags",
|
||||
data: {messages: "[50]", op: "add", flag: "read"},
|
||||
success: channel_post_opts.success,
|
||||
});
|
||||
|
||||
// Simulate a successful post (which also clears the queue
|
||||
// in our message_flag code).
|
||||
channel_post_opts.success({messages: [message_id]});
|
||||
});
|
||||
Reference in New Issue
Block a user