2020-08-01 03:43:15 +02:00
|
|
|
"use strict";
|
|
|
|
|
2020-11-30 23:46:45 +01:00
|
|
|
const {strict: assert} = require("assert");
|
|
|
|
|
2020-12-01 00:02:16 +01:00
|
|
|
const {set_global, zrequire} = require("../zjsunit/namespace");
|
2020-12-01 00:39:47 +01:00
|
|
|
const {run_test} = require("../zjsunit/test");
|
2020-12-01 00:02:16 +01:00
|
|
|
|
2021-02-10 04:53:22 +01:00
|
|
|
const typing = zrequire("typing");
|
|
|
|
const compose_pm_pill = zrequire("compose_pm_pill");
|
zjsunit: Remove rewiremock dependency.
We now just use a module._load hook to inject
stubs into our code.
For conversion purposes I temporarily maintain
the API of rewiremock, apart from the enable/disable
pieces, but I will make a better wrapper in an
upcoming commit.
We can detect when rewiremock is called after
zrequire now, and I fix all the violations in
this commit, mostly by using override.
We can also detect when a mock is needlessly
created, and I fix all the violations in this
commit.
The one minor nuisance that this commit introduces
is that you can only stub out modules in the Zulip
source tree, which is now static/js. This should
not really be a problem--there are usually better
techniques to deal with third party depenencies.
In the prior commit I show a typical workaround,
which is to create a one-line wrapper in your
test code. It's often the case that you can simply
use override(), as well.
In passing I kill off `reset_modules`, and I
eliminated the second argument to zrequire,
which dates back to pre-es6 days.
2021-03-06 12:47:54 +01:00
|
|
|
const typing_status = zrequire("../shared/js/typing_status");
|
2017-03-22 00:41:09 +01:00
|
|
|
|
|
|
|
function make_time(secs) {
|
|
|
|
// make times semi-realistic
|
|
|
|
return 1000000 + 1000 * secs;
|
|
|
|
}
|
|
|
|
|
|
|
|
function returns_time(secs) {
|
2020-07-15 00:34:28 +02:00
|
|
|
return function () {
|
|
|
|
return make_time(secs);
|
|
|
|
};
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
run_test("basics", () => {
|
2017-03-22 00:41:09 +01:00
|
|
|
// invalid conversation basically does nothing
|
2019-11-02 00:06:25 +01:00
|
|
|
let worker = {};
|
2019-10-22 02:52:01 +02:00
|
|
|
typing_status.update(worker, null);
|
2017-03-22 00:41:09 +01:00
|
|
|
|
|
|
|
// Start setting up more testing state.
|
|
|
|
typing_status.initialize_state();
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const events = {};
|
2017-03-22 00:41:09 +01:00
|
|
|
|
|
|
|
function set_timeout(f, delay) {
|
|
|
|
assert.equal(delay, 5000);
|
|
|
|
events.idle_callback = f;
|
2020-07-15 01:29:15 +02:00
|
|
|
return "idle_timer_stub";
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function clear_timeout() {
|
|
|
|
events.timer_cleared = true;
|
|
|
|
}
|
|
|
|
|
2020-12-01 00:02:16 +01:00
|
|
|
set_global("setTimeout", set_timeout);
|
|
|
|
set_global("clearTimeout", clear_timeout);
|
2017-03-22 00:41:09 +01:00
|
|
|
|
|
|
|
function notify_server_start(recipient) {
|
|
|
|
assert.equal(recipient, "alice");
|
|
|
|
events.started = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function notify_server_stop(recipient) {
|
|
|
|
assert.equal(recipient, "alice");
|
|
|
|
events.stopped = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clear_events() {
|
|
|
|
events.idle_callback = undefined;
|
|
|
|
events.started = false;
|
|
|
|
events.stopped = false;
|
|
|
|
events.timer_cleared = false;
|
|
|
|
}
|
|
|
|
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
function call_handler(new_recipient) {
|
2017-03-22 00:41:09 +01:00
|
|
|
clear_events();
|
2019-10-22 02:38:51 +02:00
|
|
|
typing_status.update(worker, new_recipient);
|
2017-03-22 00:41:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
worker = {
|
|
|
|
get_current_time: returns_time(5),
|
2020-07-20 22:18:43 +02:00
|
|
|
notify_server_start,
|
|
|
|
notify_server_stop,
|
2017-03-22 00:41:09 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Start talking to alice.
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(5 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
|
|
|
// type again 3 seconds later
|
|
|
|
worker.get_current_time = returns_time(8);
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(5 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: false,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
|
|
|
// type after 15 secs, so that we can notify the server
|
|
|
|
// again
|
|
|
|
worker.get_current_time = returns_time(18);
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(18 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Now call alice's idle callback that we captured earlier.
|
2019-11-02 00:06:25 +01:00
|
|
|
const callback = events.idle_callback;
|
2017-03-22 00:41:09 +01:00
|
|
|
clear_events();
|
|
|
|
callback();
|
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: undefined,
|
|
|
|
idle_timer: undefined,
|
2020-02-12 11:49:02 +01:00
|
|
|
current_recipient: null,
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: undefined,
|
|
|
|
started: false,
|
|
|
|
stopped: true,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Call stop with nothing going on.
|
2019-10-22 02:52:01 +02:00
|
|
|
call_handler(null);
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: undefined,
|
|
|
|
idle_timer: undefined,
|
2020-02-12 11:49:02 +01:00
|
|
|
current_recipient: null,
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: undefined,
|
|
|
|
started: false,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Start talking to alice again.
|
|
|
|
worker.get_current_time = returns_time(50);
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(50 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
|
|
|
// Explicitly stop alice.
|
2019-10-22 02:52:01 +02:00
|
|
|
call_handler(null);
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: undefined,
|
|
|
|
idle_timer: undefined,
|
2020-02-12 11:49:02 +01:00
|
|
|
current_recipient: null,
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: undefined,
|
|
|
|
started: false,
|
|
|
|
stopped: true,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Start talking to alice again.
|
|
|
|
worker.get_current_time = returns_time(80);
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(80 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
|
|
|
// Switch to an invalid conversation.
|
2019-10-22 02:52:01 +02:00
|
|
|
call_handler(null);
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: undefined,
|
|
|
|
idle_timer: undefined,
|
2020-02-12 11:49:02 +01:00
|
|
|
current_recipient: null,
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: undefined,
|
|
|
|
started: false,
|
|
|
|
stopped: true,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Switch to another invalid conversation.
|
2019-10-22 02:52:01 +02:00
|
|
|
call_handler(null);
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: undefined,
|
|
|
|
idle_timer: undefined,
|
2020-02-12 11:49:02 +01:00
|
|
|
current_recipient: null,
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: undefined,
|
|
|
|
started: false,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Start talking to alice again.
|
|
|
|
worker.get_current_time = returns_time(170);
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("alice");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(170 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "alice",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: false,
|
|
|
|
timer_cleared: false,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
|
|
|
// Switch to bob now.
|
|
|
|
worker.get_current_time = returns_time(171);
|
|
|
|
|
2021-02-23 14:37:26 +01:00
|
|
|
worker.notify_server_start = (recipient) => {
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.equal(recipient, "bob");
|
|
|
|
events.started = true;
|
|
|
|
};
|
|
|
|
|
typing_status: Combine two parameters into one, with a maybe-type.
The main motivation for this change is to simplify this interface
and make it easier to reason about.
The case where it affects the behavior is when
is_valid_conversation() returns false, while current_recipient
and get_recipient() agree on some truthy value.
This means the message-content textarea is empty -- in fact the
user just cleared it, because we got here from an input event on
it -- but the compose box is still open to some PM thread that we
have a typing notification still outstanding for.
The old behavior is that in this situation we would ignore the
fact that the content was empty, and go ahead and prolong the
typing notification, by updating our timer and possibly sending a
"still typing" notice.
This contrasts with the behavior (both old and new) in the case
where the content is empty and we *don't* already have an
outstanding typing notification, or we have one to some other
thread. In that case, we cancel any existing notification and
don't start a new one, exactly as if `stop` were called
(e.g. because the user closed the compose box.)
The new behavior is that we always treat clearing the input as
"stopped typing": not only in those cases where we already did,
but also in the case where we still have the same recipients.
(Which seems like probably the common case.)
That seems like the preferable behavior; indeed it's hard to see
the point of the "compose_empty" logic if restricted to the other
cases. It also makes the interface simpler.
Those two properties don't seem like a coincidence, either: the
complicated interface made it difficult to unpack exactly what
logic we actually had, which made it easy for surprising wrinkles
to hang out indefinitely.
2019-10-21 23:37:22 +02:00
|
|
|
call_handler("bob");
|
2017-03-22 00:41:09 +01:00
|
|
|
assert.deepEqual(typing_status.state, {
|
|
|
|
next_send_start_time: make_time(171 + 10),
|
2020-07-15 01:29:15 +02:00
|
|
|
idle_timer: "idle_timer_stub",
|
|
|
|
current_recipient: "bob",
|
2017-03-22 00:41:09 +01:00
|
|
|
});
|
|
|
|
assert.deepEqual(events, {
|
|
|
|
idle_callback: events.idle_callback,
|
|
|
|
started: true,
|
|
|
|
stopped: true,
|
|
|
|
timer_cleared: true,
|
|
|
|
});
|
|
|
|
assert(events.idle_callback);
|
|
|
|
|
2019-06-07 03:17:35 +02:00
|
|
|
// test that we correctly detect if worker.get_recipient
|
|
|
|
// and typing_status.state.current_recipient are the same
|
2019-10-21 23:03:19 +02:00
|
|
|
|
2021-02-28 00:38:58 +01:00
|
|
|
compose_pm_pill.__Rewire__("get_user_ids_string", () => "1,2,3");
|
2019-06-07 03:17:35 +02:00
|
|
|
typing_status.state.current_recipient = typing.get_recipient();
|
|
|
|
|
|
|
|
const call_count = {
|
|
|
|
maybe_ping_server: 0,
|
2019-10-22 02:02:32 +02:00
|
|
|
actually_ping_server: 0,
|
2019-06-07 03:17:35 +02:00
|
|
|
start_or_extend_idle_timer: 0,
|
|
|
|
stop_last_notification: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
// stub functions to see how may time they are called
|
2020-05-27 00:50:02 +02:00
|
|
|
for (const method of Object.keys(call_count)) {
|
2020-07-02 01:45:54 +02:00
|
|
|
typing_status.__Rewire__(method, () => {
|
2019-06-07 03:17:35 +02:00
|
|
|
call_count[method] += 1;
|
2019-10-12 04:48:15 +02:00
|
|
|
});
|
2019-06-07 03:17:35 +02:00
|
|
|
}
|
|
|
|
|
2020-03-28 01:25:56 +01:00
|
|
|
// User ids of people in compose narrow doesn't change and is same as stat.current_recipient
|
2019-06-07 03:17:35 +02:00
|
|
|
// so counts of function should increase except stop_last_notification
|
2019-10-22 02:38:51 +02:00
|
|
|
typing_status.update(worker, typing.get_recipient());
|
2019-06-07 03:17:35 +02:00
|
|
|
assert.deepEqual(call_count.maybe_ping_server, 1);
|
|
|
|
assert.deepEqual(call_count.start_or_extend_idle_timer, 1);
|
|
|
|
assert.deepEqual(call_count.stop_last_notification, 0);
|
|
|
|
|
2019-10-22 02:38:51 +02:00
|
|
|
typing_status.update(worker, typing.get_recipient());
|
2019-06-07 03:17:35 +02:00
|
|
|
assert.deepEqual(call_count.maybe_ping_server, 2);
|
|
|
|
assert.deepEqual(call_count.start_or_extend_idle_timer, 2);
|
|
|
|
assert.deepEqual(call_count.stop_last_notification, 0);
|
|
|
|
|
|
|
|
// change in recipient and new_recipient should make us
|
|
|
|
// call typing_status.stop_last_notification
|
2021-02-28 00:38:58 +01:00
|
|
|
compose_pm_pill.__Rewire__("get_user_ids_string", () => "2,3,4");
|
2019-10-22 02:38:51 +02:00
|
|
|
typing_status.update(worker, typing.get_recipient());
|
2019-06-07 03:17:35 +02:00
|
|
|
assert.deepEqual(call_count.maybe_ping_server, 2);
|
2019-10-22 02:02:32 +02:00
|
|
|
assert.deepEqual(call_count.start_or_extend_idle_timer, 3);
|
2019-06-07 03:17:35 +02:00
|
|
|
assert.deepEqual(call_count.stop_last_notification, 1);
|
2019-12-02 18:01:31 +01:00
|
|
|
|
|
|
|
// Stream messages are represented as get_user_ids_string being empty
|
2021-02-28 00:38:58 +01:00
|
|
|
compose_pm_pill.__Rewire__("get_user_ids_string", () => "");
|
2019-12-02 18:01:31 +01:00
|
|
|
typing_status.update(worker, typing.get_recipient());
|
|
|
|
assert.deepEqual(call_count.maybe_ping_server, 2);
|
|
|
|
assert.deepEqual(call_count.start_or_extend_idle_timer, 3);
|
|
|
|
assert.deepEqual(call_count.stop_last_notification, 2);
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|