2020-02-28 23:59:07 +01:00
const { JSDOM } = require ( "jsdom" ) ;
2019-07-25 09:13:22 +02:00
set _global ( 'bridge' , false ) ;
2018-08-01 21:17:03 +02:00
2019-11-02 00:06:25 +01:00
const noop = function ( ) { } ;
2018-08-01 21:17:03 +02:00
2017-06-27 14:55:11 +02:00
set _global ( '$' , global . make _zjquery ( ) ) ;
2020-02-28 23:59:07 +01:00
set _global ( 'DOMParser' , new JSDOM ( ) . window . DOMParser ) ;
2017-02-24 16:18:56 +01:00
2019-12-27 13:16:22 +01:00
const LazySet = zrequire ( 'lazy_set.js' ) . LazySet ;
2018-08-01 21:17:03 +02:00
const _navigator = {
2019-06-24 14:11:21 +02:00
platform : '' ,
2018-08-01 21:17:03 +02:00
} ;
2017-02-24 16:18:56 +01:00
2018-08-01 21:17:03 +02:00
const _document = {
2017-12-06 14:46:23 +01:00
getElementById : function ( ) { return $ ( '#compose-textarea' ) ; } ,
execCommand : function ( ) { return false ; } ,
location : { } ,
2018-08-01 21:17:03 +02:00
} ;
2017-06-27 14:55:11 +02:00
2018-08-01 21:17:03 +02:00
const _drafts = {
2017-06-29 06:54:10 +02:00
delete _draft _after _send : noop ,
2018-08-01 21:17:03 +02:00
} ;
const _resize = {
2017-06-29 06:54:10 +02:00
resize _bottom _whitespace : noop ,
2018-08-01 21:17:03 +02:00
} ;
2017-06-29 06:54:10 +02:00
2018-08-01 21:17:03 +02:00
const _sent _messages = {
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
start _tracking _message : noop ,
2018-08-01 21:17:03 +02:00
} ;
const _notifications = {
2018-01-04 21:31:23 +01:00
notify _above _composebox : noop ,
clear _compose _notifications : noop ,
2018-08-01 21:17:03 +02:00
} ;
const _reminder = {
2018-02-06 22:54:53 +01:00
is _deferred _delivery : noop ,
2018-08-01 21:17:03 +02:00
} ;
set _global ( 'document' , _document ) ;
set _global ( 'drafts' , _drafts ) ;
set _global ( 'navigator' , _navigator ) ;
set _global ( 'notifications' , _notifications ) ;
set _global ( 'reminder' , _reminder ) ;
set _global ( 'resize' , _resize ) ;
set _global ( 'sent_messages' , _sent _messages ) ;
2020-04-09 17:59:58 +02:00
set _global ( 'local_message' , { } ) ;
2018-08-01 21:17:03 +02:00
set _global ( 'transmit' , { } ) ;
set _global ( 'channel' , { } ) ;
set _global ( 'stream_edit' , { } ) ;
set _global ( 'markdown' , { } ) ;
set _global ( 'loading' , { } ) ;
set _global ( 'page_params' , { } ) ;
set _global ( 'subs' , { } ) ;
set _global ( 'ui_util' , { } ) ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
2017-07-06 21:57:25 +02:00
// Setting these up so that we can test that links to uploads within messages are
// automatically converted to server relative links.
global . document . location . protocol = 'https:' ;
global . document . location . host = 'foo.com' ;
2018-06-02 13:59:02 +02:00
zrequire ( 'zcommand' ) ;
2017-11-08 16:54:06 +01:00
zrequire ( 'compose_ui' ) ;
2020-02-13 22:34:29 +01:00
const util = zrequire ( 'util' ) ;
2018-07-05 12:17:20 +02:00
zrequire ( 'rtl' ) ;
2017-11-08 16:54:06 +01:00
zrequire ( 'common' ) ;
2019-07-12 02:03:55 +02:00
set _global ( 'Handlebars' , global . make _handlebars ( ) ) ;
2017-11-08 16:54:06 +01:00
zrequire ( 'stream_data' ) ;
zrequire ( 'compose_state' ) ;
zrequire ( 'people' ) ;
2018-03-06 15:07:55 +01:00
zrequire ( 'input_pill' ) ;
zrequire ( 'user_pill' ) ;
zrequire ( 'compose_pm_pill' ) ;
2020-04-09 17:59:58 +02:00
zrequire ( 'echo' ) ;
2017-11-08 16:54:06 +01:00
zrequire ( 'compose' ) ;
2017-11-23 15:00:05 +01:00
zrequire ( 'upload' ) ;
2017-02-24 16:18:56 +01:00
2018-06-27 20:55:56 +02:00
people . small _avatar _url _for _person = function ( ) {
return 'http://example.com/example.png' ;
} ;
2020-04-08 00:23:15 +02:00
function stub _out _video _calls ( ) {
const elem = $ ( "#below-compose-content .video_link" ) ;
elem . toggle = ( show ) => {
if ( show ) {
elem . show ( ) ;
} else {
elem . hide ( ) ;
}
} ;
}
function reset _jquery ( ) {
// Avoid leaks.
set _global ( '$' , global . make _zjquery ( ) ) ;
}
2020-02-04 21:50:55 +01:00
const new _user = {
email : 'new_user@example.com' ,
user _id : 101 ,
full _name : 'New User' ,
date _joined : new Date ( ) ,
} ;
2019-11-02 00:06:25 +01:00
const me = {
2017-02-24 23:51:23 +01:00
email : 'me@example.com' ,
user _id : 30 ,
full _name : 'Me Myself' ,
2018-08-13 00:46:29 +02:00
date _joined : new Date ( ) ,
2017-02-24 23:51:23 +01:00
} ;
2019-11-02 00:06:25 +01:00
const alice = {
2017-02-24 23:51:23 +01:00
email : 'alice@example.com' ,
user _id : 31 ,
full _name : 'Alice' ,
} ;
2019-11-02 00:06:25 +01:00
const bob = {
2017-02-24 23:51:23 +01:00
email : 'bob@example.com' ,
user _id : 32 ,
full _name : 'Bob' ,
} ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( new _user ) ;
people . add _active _user ( me ) ;
2017-02-24 23:51:23 +01:00
people . initialize _current _user ( me . user _id ) ;
2020-05-26 22:34:15 +02:00
people . add _active _user ( alice ) ;
people . add _active _user ( bob ) ;
2017-02-24 23:51:23 +01:00
2018-05-15 12:40:07 +02:00
run _test ( 'validate_stream_message_address_info' , ( ) => {
2019-11-02 00:06:25 +01:00
const sub = {
2017-06-28 12:55:04 +02:00
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2017-06-28 12:55:04 +02:00
assert ( compose . validate _stream _message _address _info ( 'social' ) ) ;
2017-06-28 13:10:46 +02:00
2018-11-13 17:16:02 +01:00
$ ( '#stream_message_recipient_stream' ) . select ( noop ) ;
2017-06-28 13:10:46 +02:00
assert ( ! compose . validate _stream _message _address _info ( 'foobar' ) ) ;
2018-02-05 09:21:58 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , "translated: <p>The stream <b>foobar</b> does not exist.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>" ) ;
2017-06-28 19:24:53 +02:00
sub . subscribed = false ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2019-07-11 05:06:20 +02:00
global . stub _templates ( function ( template _name ) {
2018-04-04 19:38:09 +02:00
assert . equal ( template _name , 'compose_not_subscribed' ) ;
return 'compose_not_subscribed_stub' ;
2019-07-11 05:06:20 +02:00
} ) ;
2017-06-28 19:24:53 +02:00
assert ( ! compose . validate _stream _message _address _info ( 'social' ) ) ;
2018-04-04 19:38:09 +02:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , 'compose_not_subscribed_stub' ) ;
2017-06-28 19:24:53 +02:00
2018-08-01 21:17:03 +02:00
page _params . narrow _stream = false ;
2017-06-28 19:24:53 +02:00
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'social' ) ;
payload . data . subscribed = true ;
payload . success ( payload . data ) ;
} ;
assert ( compose . validate _stream _message _address _info ( 'social' ) ) ;
sub . name = 'Frontend' ;
sub . stream _id = 102 ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2017-06-28 19:24:53 +02:00
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'Frontend' ) ;
payload . data . subscribed = false ;
payload . success ( payload . data ) ;
} ;
assert ( ! compose . validate _stream _message _address _info ( 'Frontend' ) ) ;
2018-04-04 19:38:09 +02:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , 'compose_not_subscribed_stub' ) ;
2017-06-28 19:24:53 +02:00
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'Frontend' ) ;
payload . error ( { status : 404 } ) ;
} ;
assert ( ! compose . validate _stream _message _address _info ( 'Frontend' ) ) ;
2018-02-05 09:21:58 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , "translated: <p>The stream <b>Frontend</b> does not exist.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>" ) ;
2017-06-28 19:24:53 +02:00
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'social' ) ;
payload . error ( { status : 500 } ) ;
} ;
assert ( ! compose . validate _stream _message _address _info ( 'social' ) ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( "Error checking subscription" ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-02-24 23:51:23 +01:00
2018-05-15 12:40:07 +02:00
run _test ( 'validate' , ( ) => {
2018-03-06 15:07:55 +01:00
function initialize _pm _pill ( ) {
set _global ( '$' , global . make _zjquery ( ) ) ;
$ ( "#compose-send-button" ) . prop ( 'disabled' , false ) ;
$ ( "#compose-send-button" ) . focus ( ) ;
$ ( "#sending-indicator" ) . hide ( ) ;
$ ( "#compose-textarea" ) . select ( noop ) ;
2019-11-02 00:06:25 +01:00
const pm _pill _container = $ . create ( 'fake-pm-pill-container' ) ;
2018-03-06 15:07:55 +01:00
$ ( '#private_message_recipient' ) . set _parent ( pm _pill _container ) ;
pm _pill _container . set _find _results ( '.input' , $ ( '#private_message_recipient' ) ) ;
$ ( '#private_message_recipient' ) . before = noop ;
compose _pm _pill . initialize ( ) ;
2018-08-01 21:17:03 +02:00
ui _util . place _caret _at _end = noop ;
2018-03-06 15:07:55 +01:00
$ ( "#zephyr-mirror-error" ) . is = noop ;
$ ( "#private_message_recipient" ) . select ( noop ) ;
2018-03-31 13:22:29 +02:00
2019-07-11 05:06:20 +02:00
global . stub _templates ( function ( fn ) {
2018-08-01 21:17:03 +02:00
assert . equal ( fn , 'input_pill' ) ;
return '<div>pill-html</div>' ;
2019-07-11 05:06:20 +02:00
} ) ;
2018-03-06 15:07:55 +01:00
}
function add _content _to _compose _box ( ) {
$ ( "#compose-textarea" ) . val ( 'foobarfoobar' ) ;
}
initialize _pm _pill ( ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
assert ( ! $ ( "#sending-indicator" ) . visible ( ) ) ;
assert ( ! $ ( "#compose-send-button" ) . is _focused ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
2017-06-27 14:55:11 +02:00
2018-07-26 09:46:10 +02:00
reminder . is _deferred _delivery = ( ) => true ;
compose . validate ( ) ;
2020-05-27 23:03:16 +02:00
assert . equal ( $ ( '#sending-indicator' ) . text ( ) , 'translated: Scheduling...' ) ;
2018-07-26 09:46:10 +02:00
reminder . is _deferred _delivery = noop ;
2018-03-06 15:07:55 +01:00
add _content _to _compose _box ( ) ;
2019-11-02 00:06:25 +01:00
let zephyr _checked = false ;
2017-06-27 14:55:11 +02:00
$ ( "#zephyr-mirror-error" ) . is = function ( ) {
if ( ! zephyr _checked ) {
zephyr _checked = true ;
return true ;
}
return false ;
} ;
assert ( ! compose . validate ( ) ) ;
assert ( zephyr _checked ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'You need to be running Zephyr mirroring in order to send messages!' ) ) ;
2017-06-27 14:55:11 +02:00
2018-03-06 15:07:55 +01:00
initialize _pm _pill ( ) ;
add _content _to _compose _box ( ) ;
2018-07-23 08:19:48 +02:00
// test validating private messages
2017-06-27 14:55:11 +02:00
compose _state . set _message _type ( 'private' ) ;
2018-07-23 08:19:48 +02:00
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient ( '' ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
2018-03-06 15:07:55 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'Please specify at least one valid recipient' ) ) ;
2017-06-27 14:55:11 +02:00
2018-03-06 15:07:55 +01:00
initialize _pm _pill ( ) ;
add _content _to _compose _box ( ) ;
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient ( 'foo@zulip.com' ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
2018-03-06 15:07:55 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'Please specify at least one valid recipient' , { } ) ) ;
2017-06-27 14:55:11 +02:00
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient ( 'foo@zulip.com,alice@zulip.com' ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
2018-03-06 15:07:55 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'Please specify at least one valid recipient' , { } ) ) ;
2017-06-27 14:55:11 +02:00
2020-05-26 22:34:15 +02:00
people . add _active _user ( bob ) ;
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient ( 'bob@example.com' ) ;
2017-06-27 14:55:11 +02:00
assert ( compose . validate ( ) ) ;
2018-07-23 08:19:48 +02:00
page _params . realm _is _zephyr _mirror _realm = true ;
assert ( compose . validate ( ) ) ;
page _params . realm _is _zephyr _mirror _realm = false ;
2017-06-27 14:55:11 +02:00
compose _state . set _message _type ( 'stream' ) ;
compose _state . stream _name ( '' ) ;
2018-11-13 17:16:02 +01:00
$ ( "#stream_message_recipient_stream" ) . select ( noop ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'Please specify a stream' ) ) ;
2017-06-27 14:55:11 +02:00
compose _state . stream _name ( 'Denmark' ) ;
2018-08-01 21:17:03 +02:00
page _params . realm _mandatory _topics = true ;
2018-11-04 17:04:17 +01:00
compose _state . topic ( '' ) ;
2018-11-13 17:16:02 +01:00
$ ( "#stream_message_recipient_topic" ) . select ( noop ) ;
2017-06-27 14:55:11 +02:00
assert ( ! compose . validate ( ) ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'Please specify a topic' ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-06-27 14:55:11 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'get_invalid_recipient_emails' , ( ) => {
2020-01-18 08:56:19 +01:00
const welcome _bot = {
email : 'welcome-bot@example.com' ,
2017-06-28 21:36:57 +02:00
user _id : 124 ,
2020-01-18 08:56:19 +01:00
full _name : 'Welcome Bot' ,
2017-06-28 21:36:57 +02:00
} ;
2020-02-25 12:16:26 +01:00
2018-08-01 21:17:03 +02:00
page _params . user _id = 30 ;
2020-02-25 12:16:26 +01:00
const params = { } ;
params . realm _users = [ ] ;
params . realm _non _active _users = [ ] ;
params . cross _realm _bots = [ welcome _bot ] ;
people . initialize ( page _params . user _id , params ) ;
2020-01-18 08:56:19 +01:00
compose _state . private _message _recipient ( 'welcome-bot@example.com' ) ;
2017-06-28 21:36:57 +02:00
assert . deepEqual ( compose . get _invalid _recipient _emails ( ) , [ ] ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-06-28 21:36:57 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'validate_stream_message' , ( ) => {
2017-06-28 20:28:18 +02:00
// This test is in kind of continuation to test_validate but since it is
2017-11-09 16:26:38 +01:00
// primarily used to get coverage over functions called from validate()
// we are separating it up in different test. Though their relative position
2017-06-28 20:28:18 +02:00
// of execution should not be changed.
2018-08-01 21:17:03 +02:00
page _params . realm _mandatory _topics = false ;
2019-11-02 00:06:25 +01:00
const sub = {
2017-06-28 20:28:18 +02:00
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2017-06-28 20:28:18 +02:00
compose _state . stream _name ( 'social' ) ;
assert ( compose . validate ( ) ) ;
assert ( ! $ ( "#compose-all-everyone" ) . visible ( ) ) ;
2017-11-26 19:58:36 +01:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-06-28 20:28:18 +02:00
stream _data . get _subscriber _count = function ( stream _name ) {
assert . equal ( stream _name , 'social' ) ;
return 16 ;
} ;
2019-07-11 05:06:20 +02:00
global . stub _templates ( function ( template _name , data ) {
2017-06-28 20:28:18 +02:00
assert . equal ( template _name , 'compose_all_everyone' ) ;
assert . equal ( data . count , 16 ) ;
return 'compose_all_everyone_stub' ;
2019-07-11 05:06:20 +02:00
} ) ;
2019-11-02 00:06:25 +01:00
let compose _content ;
2017-06-28 20:28:18 +02:00
$ ( '#compose-all-everyone' ) . append = function ( data ) {
compose _content = data ;
} ;
2018-01-24 17:18:07 +01:00
compose _state . message _content ( 'Hey @**all**' ) ;
2017-06-28 20:28:18 +02:00
assert ( ! compose . validate ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-11-26 19:58:36 +01:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-06-28 20:28:18 +02:00
assert . equal ( compose _content , 'compose_all_everyone_stub' ) ;
assert ( $ ( "#compose-all-everyone" ) . visible ( ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-06-28 20:28:18 +02:00
2020-02-04 21:50:55 +01:00
run _test ( 'test_validate_stream_message_post_policy' , ( ) => {
2020-03-28 01:25:56 +01:00
// This test is in continuation with test_validate but it has been separated out
// for better readability. Their relative position of execution should not be changed.
2018-05-14 12:06:56 +02:00
// Although the position with respect to test_validate_stream_message does not matter
2020-02-04 21:50:55 +01:00
// as `get_stream_post_policy` is reset at the end.
2018-08-01 21:17:03 +02:00
page _params . is _admin = false ;
2019-11-02 00:06:25 +01:00
const sub = {
2018-05-14 12:06:56 +02:00
stream _id : 102 ,
name : 'stream102' ,
subscribed : true ,
2020-02-04 21:50:55 +01:00
stream _post _policy : stream _data . stream _post _policy _values . admins . code ,
2018-05-14 12:06:56 +02:00
} ;
2020-02-04 21:50:55 +01:00
stream _data . get _stream _post _policy = function ( ) {
return 2 ;
2018-05-14 12:06:56 +02:00
} ;
2018-11-04 17:04:17 +01:00
compose _state . topic ( 'subject102' ) ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2018-05-14 12:06:56 +02:00
assert ( ! compose . validate ( ) ) ;
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( "Only organization admins are allowed to post to this stream." ) ) ;
2020-02-04 21:50:55 +01:00
// reset `get_stream_post_policy` so that any tests occurung after this
2018-05-14 12:06:56 +02:00
// do not reproduce this error.
2020-02-04 21:50:55 +01:00
stream _data . get _stream _post _policy = function ( ) {
return stream _data . stream _post _policy _values . everyone . code ;
2018-05-14 12:06:56 +02:00
} ;
} ) ;
2018-07-11 14:07:26 +02:00
run _test ( 'markdown_rtl' , ( ) => {
2019-11-02 00:06:25 +01:00
const textarea = $ ( '#compose-textarea' ) ;
2018-07-11 14:07:26 +02:00
2019-11-02 00:06:25 +01:00
const event = {
2018-07-11 14:07:26 +02:00
keyCode : 65 , // A
} ;
rtl . get _direction = ( text ) => {
assert . equal ( text , ' foo' ) ;
return 'rtl' ;
} ;
assert . equal ( textarea . hasClass ( 'rtl' ) , false ) ;
textarea . val ( '```quote foo' ) ;
2018-08-11 06:43:38 +02:00
compose . handle _keyup ( event , $ ( "#compose-textarea" ) ) ;
2018-07-11 14:07:26 +02:00
assert . equal ( textarea . hasClass ( 'rtl' ) , true ) ;
} ) ;
// This is important for subsequent tests--put
// us back to the "normal" ltr case.
rtl . get _direction = ( ) => 'ltr' ;
run _test ( 'markdown_ltr' , ( ) => {
2019-11-02 00:06:25 +01:00
const textarea = $ ( '#compose-textarea' ) ;
2018-07-11 14:07:26 +02:00
2019-11-02 00:06:25 +01:00
const event = {
2018-07-11 14:07:26 +02:00
keyCode : 65 , // A
} ;
assert . equal ( textarea . hasClass ( 'rtl' ) , true ) ;
textarea . val ( '```quote foo' ) ;
2018-08-11 06:43:38 +02:00
compose . handle _keyup ( event , textarea ) ;
2018-07-11 14:07:26 +02:00
assert . equal ( textarea . hasClass ( 'rtl' ) , false ) ;
} ) ;
2018-05-15 12:40:07 +02:00
run _test ( 'markdown_shortcuts' , ( ) => {
2019-11-02 00:06:25 +01:00
let queryCommandEnabled = true ;
const event = {
2017-12-06 14:46:23 +01:00
keyCode : 66 ,
target : {
id : 'compose-textarea' ,
} ,
stopPropagation : noop ,
preventDefault : noop ,
} ;
2019-11-02 00:06:25 +01:00
let input _text = "" ;
let range _start = 0 ;
let range _length = 0 ;
let compose _value = $ ( "#compose_textarea" ) . val ( ) ;
let selected _word = "" ;
2017-12-06 14:46:23 +01:00
global . document . queryCommandEnabled = function ( ) {
return queryCommandEnabled ;
} ;
global . document . execCommand = function ( cmd , bool , markdown ) {
2019-11-02 00:06:25 +01:00
const compose _textarea = $ ( "#compose-textarea" ) ;
const value = compose _textarea . val ( ) ;
2018-06-04 21:13:07 +02:00
$ ( "#compose-textarea" ) . val ( value . substring ( 0 , compose _textarea . range ( ) . start ) +
markdown + value . substring ( compose _textarea . range ( ) . end , value . length ) ) ;
2017-12-06 14:46:23 +01:00
} ;
$ ( "#compose-textarea" ) . range = function ( ) {
return {
start : range _start ,
end : range _start + range _length ,
length : range _length ,
range : noop ,
2018-06-04 21:13:07 +02:00
text : $ ( "#compose-textarea" ) . val ( ) . substring ( range _start , range _length + range _start ) ,
2017-12-06 14:46:23 +01:00
} ;
} ;
$ ( '#compose-textarea' ) . caret = noop ;
2018-02-17 17:21:45 +01:00
function test _i _typed ( isCtrl , isCmd ) {
// Test 'i' is typed correctly.
$ ( "#compose-textarea" ) . val ( 'i' ) ;
event . keyCode = undefined ;
event . which = 73 ;
event . metaKey = isCmd ;
event . ctrlKey = isCtrl ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "i" , $ ( '#compose-textarea' ) . val ( ) ) ;
}
function all _markdown _test ( isCtrl , isCmd ) {
input _text = "Any text." ;
$ ( "#compose-textarea" ) . val ( input _text ) ;
compose _value = $ ( "#compose-textarea" ) . val ( ) ;
// Select "text" word in compose box.
selected _word = "text" ;
range _start = compose _value . search ( selected _word ) ;
range _length = selected _word . length ;
// Test bold:
// Mac env = cmd+b
// Windows/Linux = ctrl+b
event . keyCode = 66 ;
event . ctrlKey = isCtrl ;
event . metaKey = isCmd ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "Any **text**." , $ ( '#compose-textarea' ) . val ( ) ) ;
// Test if no text is selected.
range _start = 0 ;
// Change cursor to first position.
range _length = 0 ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "****Any **text**." , $ ( '#compose-textarea' ) . val ( ) ) ;
// Test italic:
// Mac = cmd+i
// Windows/Linux = ctrl+i
$ ( "#compose-textarea" ) . val ( input _text ) ;
range _start = compose _value . search ( selected _word ) ;
range _length = selected _word . length ;
event . keyCode = 73 ;
event . shiftKey = false ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "Any *text*." , $ ( '#compose-textarea' ) . val ( ) ) ;
// Test if no text is selected.
range _length = 0 ;
// Change cursor to first position.
range _start = 0 ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "**Any *text*." , $ ( '#compose-textarea' ) . val ( ) ) ;
// Test link insertion:
// Mac = cmd+shift+l
// Windows/Linux = ctrl+shift+l
$ ( "#compose-textarea" ) . val ( input _text ) ;
range _start = compose _value . search ( selected _word ) ;
range _length = selected _word . length ;
event . keyCode = 76 ;
event . which = undefined ;
event . shiftKey = true ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( "Any [text](url)." , $ ( '#compose-textarea' ) . val ( ) ) ;
// Test if exec command is not enabled in browser.
queryCommandEnabled = false ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
}
// This function cross tests the cmd/ctrl + markdown shortcuts in
// Mac and Linux/Windows environments. So in short, this tests
// that e.g. Cmd+B should be ignored on Linux/Windows and Ctrl+B
// should be ignored on Mac.
function os _specific _markdown _test ( isCtrl , isCmd ) {
input _text = "Any text." ;
$ ( "#compose-textarea" ) . val ( input _text ) ;
compose _value = $ ( "#compose-textarea" ) . val ( ) ;
selected _word = "text" ;
range _start = compose _value . search ( selected _word ) ;
range _length = selected _word . length ;
event . metaKey = isCmd ;
event . ctrlKey = isCtrl ;
event . keyCode = 66 ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( input _text , $ ( '#compose-textarea' ) . val ( ) ) ;
event . keyCode = 73 ;
event . shiftKey = false ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( input _text , $ ( '#compose-textarea' ) . val ( ) ) ;
event . keyCode = 76 ;
event . shiftKey = true ;
2018-07-18 05:59:55 +02:00
compose . handle _keydown ( event , $ ( "#compose-textarea" ) ) ;
2018-02-17 17:21:45 +01:00
assert . equal ( input _text , $ ( '#compose-textarea' ) . val ( ) ) ;
}
// These keyboard shortcuts differ as to what key one should use
// on MacOS vs. other platforms: Cmd (Mac) vs. Ctrl (non-Mac).
// Default (Linux/Windows) userAgent tests:
test _i _typed ( false , false ) ;
// Check all the ctrl + markdown shortcuts work correctly
all _markdown _test ( true , false ) ;
// The Cmd + markdown shortcuts should do nothing on Linux/Windows
os _specific _markdown _test ( false , true ) ;
2019-06-24 14:11:21 +02:00
// Setting following platform to test in mac env
_navigator . platform = "MacIntel" ;
2018-02-17 17:21:45 +01:00
// Mac userAgent tests:
test _i _typed ( false , false ) ;
// The ctrl + markdown shortcuts should do nothing on mac
os _specific _markdown _test ( true , false ) ;
// Check all the Cmd + markdown shortcuts work correctly
all _markdown _test ( false , true ) ;
// Reset userAgent
2018-08-01 21:17:03 +02:00
_navigator . userAgent = "" ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-12-06 14:46:23 +01:00
2018-05-15 12:40:07 +02:00
run _test ( 'send_message_success' , ( ) => {
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( 'foobarfoobar' ) ;
$ ( "#compose-textarea" ) . blur ( ) ;
2017-11-26 19:58:36 +01:00
$ ( "#compose-send-status" ) . show ( ) ;
2017-06-29 06:54:10 +02:00
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#sending-indicator" ) . show ( ) ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
2019-11-02 00:06:25 +01:00
let reify _message _id _checked ;
2017-06-29 06:54:10 +02:00
echo . reify _message _id = function ( local _id , message _id ) {
2020-02-12 09:32:25 +01:00
assert . equal ( local _id , "1001" ) ;
2017-06-29 06:54:10 +02:00
assert . equal ( message _id , 12 ) ;
reify _message _id _checked = true ;
} ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
2020-02-12 09:32:25 +01:00
compose . send _message _success ( "1001" , 12 , false ) ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
2017-11-26 20:37:44 +01:00
assert . equal ( $ ( "#compose-textarea" ) . val ( ) , '' ) ;
assert ( $ ( "#compose-textarea" ) . is _focused ( ) ) ;
2017-11-26 19:58:36 +01:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-06-29 06:54:10 +02:00
assert ( ! $ ( "#sending-indicator" ) . visible ( ) ) ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
assert ( reify _message _id _checked ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-06-29 14:31:26 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'send_message' , ( ) => {
2017-07-06 21:57:25 +02:00
// This is the common setup stuff for all of the four tests.
2019-11-02 00:06:25 +01:00
let stub _state ;
2017-07-06 21:57:25 +02:00
function initialize _state _stub _dict ( ) {
stub _state = { } ;
2018-02-20 13:08:50 +01:00
stub _state . send _msg _called = 0 ;
2017-07-06 21:57:25 +02:00
stub _state . get _events _running _called = 0 ;
stub _state . reify _message _id _checked = 0 ;
return stub _state ;
}
global . patch _builtin ( 'setTimeout' , function ( func ) {
func ( ) ;
} ) ;
global . server _events = {
assert _get _events _running : function ( ) {
stub _state . get _events _running _called += 1 ;
} ,
} ;
// Tests start here.
( function test _message _send _success _codepath ( ) {
stub _state = initialize _state _stub _dict ( ) ;
2018-11-04 17:04:17 +01:00
compose _state . topic ( '' ) ;
2017-07-06 21:57:25 +02:00
compose _state . set _message _type ( 'private' ) ;
page _params . user _id = 101 ;
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient = function ( ) {
2018-03-31 13:22:29 +02:00
return 'alice@example.com' ;
} ;
2020-04-09 19:55:20 +02:00
const server _message _id = 127 ;
2020-04-09 17:59:58 +02:00
const fake _now = 555 ;
local _message . insert _message = ( message ) => {
assert . equal ( message . timestamp , fake _now ) ;
} ;
local _message . now = ( ) => fake _now ;
2020-04-09 19:55:20 +02:00
2020-04-09 17:59:58 +02:00
markdown . apply _markdown = ( ) => { } ;
markdown . add _topic _links = ( ) => { } ;
echo . try _deliver _locally = function ( message _request ) {
2020-04-09 19:55:20 +02:00
const local _id _float = 123.04 ;
2020-04-09 17:59:58 +02:00
return echo . insert _local _message ( message _request , local _id _float ) ;
2017-07-06 21:57:25 +02:00
} ;
2018-02-20 13:08:50 +01:00
transmit . send _message = function ( payload , success ) {
2019-11-02 00:06:25 +01:00
const single _msg = {
2018-05-07 03:30:13 +02:00
type : 'private' ,
content : '[foobar](/user_uploads/123456)' ,
sender _id : 101 ,
queue _id : undefined ,
stream : '' ,
2018-12-23 16:49:14 +01:00
topic : '' ,
2019-05-23 22:18:58 +02:00
to : ` [ ${ alice . user _id } ] ` ,
2018-05-07 03:30:13 +02:00
reply _to : 'alice@example.com' ,
private _message _recipient : 'alice@example.com' ,
to _user _ids : '31' ,
2020-04-09 19:55:20 +02:00
local _id : '123.04' ,
2018-05-07 03:30:13 +02:00
locally _echoed : true ,
2017-07-06 21:57:25 +02:00
} ;
2019-05-23 22:18:58 +02:00
2018-02-20 13:08:50 +01:00
assert . deepEqual ( payload , single _msg ) ;
2020-04-09 19:55:20 +02:00
payload . id = server _message _id ;
2018-02-20 13:08:50 +01:00
success ( payload ) ;
stub _state . send _msg _called += 1 ;
2017-07-06 21:57:25 +02:00
} ;
echo . reify _message _id = function ( local _id , message _id ) {
2020-02-12 09:32:25 +01:00
assert . equal ( typeof local _id , 'string' ) ;
2018-06-05 08:12:06 +02:00
assert . equal ( typeof message _id , 'number' ) ;
2020-04-09 19:55:20 +02:00
assert . equal ( message _id , server _message _id ) ;
2017-07-06 21:57:25 +02:00
stub _state . reify _message _id _checked += 1 ;
} ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
2017-07-06 21:57:25 +02:00
// Setting message content with a host server link and we will assert
// later that this has been converted to a relative link.
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( '[foobar]' +
2017-07-06 21:57:25 +02:00
'(https://foo.com/user_uploads/123456)' ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . blur ( ) ;
2017-11-26 19:58:36 +01:00
$ ( "#compose-send-status" ) . show ( ) ;
2017-07-06 21:57:25 +02:00
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#sending-indicator" ) . show ( ) ;
compose . send _message ( ) ;
2019-11-02 00:06:25 +01:00
const state = {
2017-07-06 21:57:25 +02:00
get _events _running _called : 1 ,
reify _message _id _checked : 1 ,
2018-02-20 13:08:50 +01:00
send _msg _called : 1 ,
2017-07-06 21:57:25 +02:00
} ;
assert . deepEqual ( stub _state , state ) ;
2017-11-26 20:37:44 +01:00
assert . equal ( $ ( "#compose-textarea" ) . val ( ) , '' ) ;
assert ( $ ( "#compose-textarea" ) . is _focused ( ) ) ;
2017-11-26 19:58:36 +01:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-07-06 21:57:25 +02:00
assert ( ! $ ( "#sending-indicator" ) . visible ( ) ) ;
} ( ) ) ;
// This is the additional setup which is common to both the tests below.
2018-02-20 13:08:50 +01:00
transmit . send _message = function ( payload , success , error ) {
stub _state . send _msg _called += 1 ;
error ( 'Error sending message: Server says 408' ) ;
2017-07-06 21:57:25 +02:00
} ;
2018-02-20 13:08:50 +01:00
2019-11-02 00:06:25 +01:00
let echo _error _msg _checked ;
2018-02-20 13:08:50 +01:00
2017-07-06 21:57:25 +02:00
echo . message _send _error = function ( local _id , error _response ) {
2020-04-09 17:43:30 +02:00
assert . equal ( local _id , 123.04 ) ;
2017-07-06 21:57:25 +02:00
assert . equal ( error _response , 'Error sending message: Server says 408' ) ;
echo _error _msg _checked = true ;
} ;
// Tests start here.
( function test _param _error _function _passed _from _send _message ( ) {
stub _state = initialize _state _stub _dict ( ) ;
compose . send _message ( ) ;
2019-11-02 00:06:25 +01:00
const state = {
2017-07-06 21:57:25 +02:00
get _events _running _called : 1 ,
reify _message _id _checked : 0 ,
2018-02-20 13:08:50 +01:00
send _msg _called : 1 ,
2017-07-06 21:57:25 +02:00
} ;
assert . deepEqual ( stub _state , state ) ;
assert ( echo _error _msg _checked ) ;
} ( ) ) ;
( function test _error _codepath _local _id _undefined ( ) {
stub _state = initialize _state _stub _dict ( ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( 'foobarfoobar' ) ;
$ ( "#compose-textarea" ) . blur ( ) ;
2017-11-26 19:58:36 +01:00
$ ( "#compose-send-status" ) . show ( ) ;
2017-07-06 21:57:25 +02:00
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#sending-indicator" ) . show ( ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . select ( noop ) ;
2017-07-06 21:57:25 +02:00
echo _error _msg _checked = false ;
echo . try _deliver _locally = function ( ) {
return ;
} ;
sending messages: Extract sent_messages.js.
This commit extract send_messages.js to clean up code related
to the following things:
* sending data to /json/report_send_time
* restarting the event loop if events don't arrive on time
The code related to /json/report changes the following ways:
* We track the state almost completely in the new
send_messages.js module, with other modules just
making one-line calls.
* We no longer send "displayed" times to the servers, since
we were kind of lying about them anyway.
* We now explicitly track the state of each single sent
message in its own object.
* We now look up data related to the messages by local_id,
instead of message_id. The problem with message_id was
that is was mutable. Now we use local_id, and we extend
the local_id concept to messages that don't get rendered
client side. We no longer need to react to the
'message_id_changed' event to change our hash key.
* The code used to live in many places:
* various big chunks were scattered among compose.js,
and those were all moved or reduced to one-line
calls into the new module
* echo.js continues to make basically one-line calls,
but it no longer calls compose.report_as_received(),
nor does it set the "start" time.
* message_util.js used to report received events, but
only when they finally got drawn in the home view;
this code is gone now
The code related to restarting the event loop if events don't arrive
changes as follows:
* The timer now gets set up from within
send_messages.message_state.report_server_ack,
where we can easily inspect the current state of the
possibly-still-in-flight message.
* The code to confirm that an event was received happens now
in server_events.js, rather than later, so that we don't
falsely blame the event loop for a downstream bug. (Plus
it's easier to just do it one place.)
This change removes a fair amount of code from our node tests. Some
of the removal is good stuff related to us completing killing off
unnecessary code. Other removals are more expediency-driven, and
we should make another sweep at ramping up our coverage on compose.js,
with possibly a little more mocking of the new `send_messages` code
layer, since it's now abstracted better.
There is also some minor cleanup to echo.resend_message() in this
commit.
See #5968 for a detailed breakdown of the changes.
2017-07-30 12:56:46 +02:00
sent _messages . get _new _local _id = function ( ) {
return 'loc-55' ;
} ;
2017-07-06 21:57:25 +02:00
compose . send _message ( ) ;
2019-11-02 00:06:25 +01:00
const state = {
2017-07-06 21:57:25 +02:00
get _events _running _called : 1 ,
reify _message _id _checked : 0 ,
2018-02-20 13:08:50 +01:00
send _msg _called : 1 ,
2017-07-06 21:57:25 +02:00
} ;
assert . deepEqual ( stub _state , state ) ;
assert ( ! echo _error _msg _checked ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) ,
2018-05-07 03:30:13 +02:00
'Error sending message: Server says 408' ) ;
2017-11-26 20:37:44 +01:00
assert . equal ( $ ( "#compose-textarea" ) . val ( ) , 'foobarfoobar' ) ;
assert ( $ ( "#compose-textarea" ) . is _focused ( ) ) ;
2017-11-26 19:58:36 +01:00
assert ( $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-07-06 21:57:25 +02:00
assert ( ! $ ( "#sending-indicator" ) . visible ( ) ) ;
} ( ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-06 21:57:25 +02:00
2018-04-12 18:06:39 +02:00
set _global ( 'document' , 'document-stub' ) ;
2018-05-15 12:40:07 +02:00
run _test ( 'enter_with_preview_open' , ( ) => {
2017-07-07 19:31:32 +02:00
// Test sending a message with content.
2018-02-20 13:08:50 +01:00
compose _state . set _message _type ( 'stream' ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( 'message me' ) ;
$ ( "#compose-textarea" ) . hide ( ) ;
2017-07-07 00:33:46 +02:00
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
page _params . enter _sends = true ;
2019-11-02 00:06:25 +01:00
let send _message _called = false ;
2017-07-07 00:33:46 +02:00
compose . send _message = function ( ) {
send _message _called = true ;
} ;
compose . enter _with _preview _open ( ) ;
2017-11-26 20:37:44 +01:00
assert ( $ ( "#compose-textarea" ) . visible ( ) ) ;
2017-07-07 00:33:46 +02:00
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
assert ( send _message _called ) ;
page _params . enter _sends = false ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . blur ( ) ;
2017-07-07 00:33:46 +02:00
compose . enter _with _preview _open ( ) ;
2017-11-26 20:37:44 +01:00
assert ( $ ( "#compose-textarea" ) . is _focused ( ) ) ;
2017-07-07 19:31:32 +02:00
// Test sending a message without content.
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( '' ) ;
2017-07-07 19:31:32 +02:00
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#enter_sends" ) . prop ( "checked" , true ) ;
page _params . enter _sends = true ;
compose . enter _with _preview _open ( ) ;
assert ( $ ( "#enter_sends" ) . prop ( "checked" ) ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( "#compose-error-msg" ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-07 00:33:46 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'finish' , ( ) => {
2017-07-07 00:48:51 +02:00
( function test _when _compose _validation _fails ( ) {
$ ( "#compose_invite_users" ) . show ( ) ;
2017-06-30 00:57:46 +02:00
$ ( "#compose-send-button" ) . prop ( 'disabled' , false ) ;
2017-07-07 00:48:51 +02:00
$ ( "#compose-send-button" ) . focus ( ) ;
$ ( "#sending-indicator" ) . hide ( ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . select ( noop ) ;
$ ( "#compose-textarea" ) . val ( '' ) ;
2019-11-02 00:06:25 +01:00
const res = compose . finish ( ) ;
2017-07-07 00:48:51 +02:00
assert . equal ( res , false ) ;
assert ( ! $ ( "#compose_invite_users" ) . visible ( ) ) ;
assert ( ! $ ( "#sending-indicator" ) . visible ( ) ) ;
assert ( ! $ ( "#compose-send-button" ) . is _focused ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-11-26 20:03:46 +01:00
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
2017-07-07 00:48:51 +02:00
} ( ) ) ;
( function test _when _compose _validation _succeed ( ) {
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . hide ( ) ;
2017-07-07 00:48:51 +02:00
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( 'foobarfoobar' ) ;
2017-07-07 00:48:51 +02:00
compose _state . set _message _type ( 'private' ) ;
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient = function ( ) {
2018-03-31 13:22:29 +02:00
return 'bob@example.com' ;
} ;
2019-11-02 00:06:25 +01:00
let compose _finished _event _checked = false ;
2018-04-12 18:06:39 +02:00
$ ( document ) . trigger = function ( e ) {
assert . equal ( e . name , 'compose_finished.zulip' ) ;
compose _finished _event _checked = true ;
} ;
2019-11-02 00:06:25 +01:00
let send _message _called = false ;
2017-07-07 00:48:51 +02:00
compose . send _message = function ( ) {
send _message _called = true ;
} ;
assert ( compose . finish ( ) ) ;
2017-11-26 20:37:44 +01:00
assert ( $ ( "#compose-textarea" ) . visible ( ) ) ;
2017-07-07 00:48:51 +02:00
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
assert ( send _message _called ) ;
assert ( compose _finished _event _checked ) ;
} ( ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-07 00:48:51 +02:00
2020-01-14 15:57:16 +01:00
run _test ( 'warn_if_private_stream_is_linked' , ( ) => {
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( {
name : compose _state . stream _name ( ) ,
2020-02-03 07:48:50 +01:00
subscribers : new LazySet ( [ 1 , 2 ] ) ,
2020-02-07 21:18:20 +01:00
stream _id : 99 ,
2020-01-14 15:57:16 +01:00
} ) ;
let denmark = {
name : 'Denmark' ,
2020-02-03 07:48:50 +01:00
subscribers : new LazySet ( [ 1 , 2 , 3 ] ) ,
2020-01-14 15:57:16 +01:00
} ;
function test _noop _case ( invite _only ) {
compose _state . set _message _type ( 'stream' ) ;
denmark . invite _only = invite _only ;
compose . warn _if _private _stream _is _linked ( denmark ) ;
assert . equal ( $ ( '#compose_private_stream_alert' ) . visible ( ) , false ) ;
}
test _noop _case ( false ) ;
// invite_only=true and current compose stream subscribers are a subset
// of mentioned_stream subscribers.
test _noop _case ( true ) ;
$ ( "#compose_private" ) . hide ( ) ;
compose _state . set _message _type ( 'stream' ) ;
const checks = [
( function ( ) {
let called ;
global . stub _templates ( function ( template _name , context ) {
called = true ;
assert . equal ( template _name , 'compose_private_stream_alert' ) ;
assert . equal ( context . stream _name , 'Denmark' ) ;
return 'fake-compose_private_stream_alert-template' ;
} ) ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
( function ( ) {
let called ;
$ ( "#compose_private_stream_alert" ) . append = function ( html ) {
called = true ;
assert . equal ( html , 'fake-compose_private_stream_alert-template' ) ;
} ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
] ;
denmark = {
invite _only : true ,
name : 'Denmark' ,
2020-02-03 07:48:50 +01:00
subscribers : new LazySet ( [ 1 ] ) ,
2020-01-14 15:57:16 +01:00
} ;
compose . warn _if _private _stream _is _linked ( denmark ) ;
assert . equal ( $ ( '#compose_private_stream_alert' ) . visible ( ) , true ) ;
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
for ( const f of checks ) { f ( ) ; }
2020-01-14 15:57:16 +01:00
} ) ;
2018-05-15 12:40:07 +02:00
run _test ( 'initialize' , ( ) => {
2017-07-07 15:14:00 +02:00
// In this test we mostly do the setup stuff in addition to testing the
// normal workflow of the function. All the tests for the on functions are
// done in subsequent tests directly below this test.
2019-11-02 00:06:25 +01:00
let resize _watch _manual _resize _checked = false ;
2017-07-07 15:14:00 +02:00
resize . watch _manual _resize = function ( elem ) {
2017-11-26 20:37:44 +01:00
assert . equal ( '#compose-textarea' , elem ) ;
2017-07-07 15:14:00 +02:00
resize _watch _manual _resize _checked = true ;
} ;
2019-07-25 09:13:22 +02:00
set _global ( 'bridge' , true ) ;
2019-11-02 00:06:25 +01:00
let xmlhttprequest _checked = false ;
2017-07-07 15:14:00 +02:00
set _global ( 'XMLHttpRequest' , function ( ) {
this . upload = true ;
xmlhttprequest _checked = true ;
} ) ;
$ ( "#compose #attach_files" ) . addClass ( "notdisplayed" ) ;
2017-07-08 15:16:19 +02:00
global . document = 'document-stub' ;
2017-07-07 15:14:00 +02:00
global . csrf _token = 'fake-csrf-token' ;
2020-05-08 06:57:19 +02:00
page _params . max _file _upload _size _mib = 512 ;
2017-07-07 15:14:00 +02:00
2019-11-21 05:24:55 +01:00
let setup _upload _called = false ;
let uppy _cancel _all _called = false ;
upload . setup _upload = function ( config ) {
assert . equal ( config . mode , "compose" ) ;
setup _upload _called = true ;
return {
cancelAll : ( ) => {
uppy _cancel _all _called = true ;
} ,
} ;
2017-07-07 15:14:00 +02:00
} ;
2020-04-08 00:23:15 +02:00
page _params . realm _available _video _chat _providers = {
disabled : {
id : 0 ,
name : "disabled" ,
} ,
jitsi _meet : {
id : 1 ,
name : "Jitsi Meet" ,
} ,
google _hangouts : {
id : 2 ,
name : "Google Hangouts" ,
} ,
zoom : {
id : 3 ,
name : "Zoom" ,
} ,
} ;
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . disabled . id ;
stub _out _video _calls ( ) ;
2017-07-07 15:14:00 +02:00
compose . initialize ( ) ;
assert ( resize _watch _manual _resize _checked ) ;
assert ( xmlhttprequest _checked ) ;
assert ( ! $ ( "#compose #attach_files" ) . hasClass ( "notdisplayed" ) ) ;
2019-11-21 05:24:55 +01:00
assert ( setup _upload _called ) ;
2017-07-07 15:14:00 +02:00
2019-11-02 00:06:25 +01:00
let compose _actions _start _checked ;
2017-07-07 15:14:00 +02:00
function set _up _compose _start _mock ( expected _opts ) {
compose _actions _start _checked = false ;
global . compose _actions = {
start : function ( msg _type , opts ) {
assert . equal ( msg _type , 'stream' ) ;
assert . deepEqual ( opts , expected _opts ) ;
compose _actions _start _checked = true ;
} ,
} ;
}
( function test _page _params _narrow _path ( ) {
page _params . narrow = true ;
reset _jquery ( ) ;
2020-04-08 00:23:15 +02:00
stub _out _video _calls ( ) ;
2017-07-07 15:14:00 +02:00
set _up _compose _start _mock ( { } ) ;
compose . initialize ( ) ;
assert ( compose _actions _start _checked ) ;
} ( ) ) ;
( function test _page _params _narrow _topic ( ) {
page _params . narrow _topic = 'testing' ;
reset _jquery ( ) ;
2020-04-08 00:23:15 +02:00
stub _out _video _calls ( ) ;
2018-11-15 19:14:16 +01:00
set _up _compose _start _mock ( { topic : 'testing' } ) ;
2017-07-07 15:14:00 +02:00
compose . initialize ( ) ;
assert ( compose _actions _start _checked ) ;
} ( ) ) ;
2019-11-21 05:24:55 +01:00
( function test _abort _xhr ( ) {
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
reset _jquery ( ) ;
2020-04-08 00:23:15 +02:00
stub _out _video _calls ( ) ;
2019-11-21 05:24:55 +01:00
compose . initialize ( ) ;
compose . abort _xhr ( ) ;
assert . equal ( $ ( "#compose-send-button" ) . attr ( ) , undefined ) ;
assert ( uppy _cancel _all _called ) ;
} ( ) ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-07 03:59:08 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'update_fade' , ( ) => {
2019-11-02 00:06:25 +01:00
const selector = '#stream_message_recipient_stream,#stream_message_recipient_topic,#private_message_recipient' ;
const keyup _handler _func = $ ( selector ) . get _on _handler ( 'keyup' ) ;
2017-07-07 15:41:13 +02:00
2019-11-02 00:06:25 +01:00
let set _focused _recipient _checked = false ;
let update _all _called = false ;
2017-07-07 15:41:13 +02:00
global . compose _fade = {
set _focused _recipient : function ( msg _type ) {
assert . equal ( msg _type , 'private' ) ;
set _focused _recipient _checked = true ;
} ,
2018-04-22 16:25:46 +02:00
update _all : function ( ) {
update _all _called = true ;
2017-07-07 15:41:13 +02:00
} ,
} ;
compose _state . set _message _type ( false ) ;
keyup _handler _func ( ) ;
assert ( ! set _focused _recipient _checked ) ;
2018-04-22 16:25:46 +02:00
assert ( ! update _all _called ) ;
2017-07-07 15:41:13 +02:00
compose _state . set _message _type ( 'private' ) ;
keyup _handler _func ( ) ;
assert ( set _focused _recipient _checked ) ;
2018-04-22 16:25:46 +02:00
assert ( update _all _called ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-07 15:41:13 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'trigger_submit_compose_form' , ( ) => {
2019-11-02 00:06:25 +01:00
let prevent _default _checked = false ;
let compose _finish _checked = false ;
const e = {
2017-07-07 15:42:51 +02:00
preventDefault : function ( ) {
prevent _default _checked = true ;
} ,
} ;
compose . finish = function ( ) {
compose _finish _checked = true ;
} ;
2019-11-02 00:06:25 +01:00
const submit _handler = $ ( '#compose form' ) . get _on _handler ( 'submit' ) ;
2017-07-07 15:42:51 +02:00
submit _handler ( e ) ;
assert ( prevent _default _checked ) ;
assert ( compose _finish _checked ) ;
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-07 15:42:51 +02:00
2018-05-18 16:23:35 +02:00
run _test ( 'needs_subscribe_warning' , ( ) => {
people . get _active _user _for _email = function ( ) {
return ;
} ;
assert . equal ( compose . needs _subscribe _warning ( ) , false ) ;
compose _state . stream _name ( 'random' ) ;
assert . equal ( compose . needs _subscribe _warning ( ) , false ) ;
2019-11-02 00:06:25 +01:00
const sub = {
2018-05-18 16:23:35 +02:00
stream _id : 111 ,
name : 'random' ,
subscribed : true ,
} ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2018-05-18 16:23:35 +02:00
assert . equal ( compose . needs _subscribe _warning ( ) , false ) ;
people . get _active _user _for _email = function ( ) {
return {
user _id : 99 ,
is _bot : true ,
} ;
} ;
assert . equal ( compose . needs _subscribe _warning ( ) , false ) ;
people . get _active _user _for _email = function ( ) {
return {
user _id : 99 ,
is _bot : false ,
} ;
} ;
stream _data . is _user _subscribed = function ( ) {
return true ;
} ;
assert . equal ( compose . needs _subscribe _warning ( ) , false ) ;
stream _data . is _user _subscribed = function ( ) {
return false ;
} ;
assert . equal ( compose . needs _subscribe _warning ( ) , true ) ;
} ) ;
2020-01-14 18:26:48 +01:00
run _test ( 'warn_if_mentioning_unsubscribed_user' , ( ) => {
let mentioned = {
email : 'foo@bar.com' ,
} ;
2017-07-08 00:06:38 +02:00
2020-01-14 18:26:48 +01:00
$ ( '#compose_invite_users .compose_invite_user' ) . length = 0 ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:39:10 +01:00
function test _noop _case ( is _private , is _zephyr _mirror , is _broadcast ) {
const msg _type = is _private ? 'private' : 'stream' ;
2020-01-14 18:26:48 +01:00
compose _state . set _message _type ( msg _type ) ;
page _params . realm _is _zephyr _mirror _realm = is _zephyr _mirror ;
2020-01-14 18:39:10 +01:00
mentioned . is _broadcast = is _broadcast ;
2020-01-14 18:26:48 +01:00
compose . warn _if _mentioning _unsubscribed _user ( mentioned ) ;
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , false ) ;
}
2017-07-08 00:06:38 +02:00
2020-01-14 18:39:10 +01:00
test _noop _case ( true , false , false ) ;
test _noop _case ( false , true , false ) ;
test _noop _case ( false , false , true ) ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
// Test mentioning a user that should gets a warning.
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
$ ( "#compose_invite_users" ) . hide ( ) ;
compose _state . set _message _type ( 'stream' ) ;
page _params . realm _is _zephyr _mirror _realm = false ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
const checks = [
( function ( ) {
let called ;
compose . needs _subscribe _warning = function ( email ) {
called = true ;
assert . equal ( email , 'foo@bar.com' ) ;
return true ;
} ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
( function ( ) {
let called ;
global . stub _templates ( function ( template _name , context ) {
called = true ;
assert . equal ( template _name , 'compose_invite_users' ) ;
assert . equal ( context . email , 'foo@bar.com' ) ;
assert . equal ( context . name , 'Foo Barson' ) ;
return 'fake-compose-invite-user-template' ;
} ) ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
( function ( ) {
let called ;
$ ( "#compose_invite_users" ) . append = function ( html ) {
called = true ;
assert . equal ( html , 'fake-compose-invite-user-template' ) ;
} ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
] ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
mentioned = {
email : 'foo@bar.com' ,
full _name : 'Foo Barson' ,
} ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
compose . warn _if _mentioning _unsubscribed _user ( mentioned ) ;
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , true ) ;
2017-07-09 14:13:42 +02:00
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
for ( const f of checks ) { f ( ) ; }
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
// Simulate that the row was added to the DOM.
const warning _row = $ ( '<warning row>' ) ;
2017-07-09 14:13:42 +02:00
2020-01-14 18:26:48 +01:00
let looked _for _existing ;
warning _row . data = function ( field ) {
assert . equal ( field , 'useremail' ) ;
looked _for _existing = true ;
return 'foo@bar.com' ;
} ;
2017-07-08 00:09:13 +02:00
2020-01-14 18:26:48 +01:00
const previous _users = $ ( '#compose_invite_users .compose_invite_user' ) ;
previous _users . length = 1 ;
previous _users [ 0 ] = warning _row ;
$ ( '#compose_invite_users' ) . hide ( ) ;
// Now try to mention the same person again. The template should
// not render.
global . stub _templates ( noop ) ;
compose . warn _if _mentioning _unsubscribed _user ( mentioned ) ;
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , true ) ;
assert ( looked _for _existing ) ;
} ) ;
run _test ( 'on_events' , ( ) => {
2017-07-08 23:16:19 +02:00
function setup _parents _and _mock _remove ( container _sel , target _sel , parent ) {
2019-11-02 00:06:25 +01:00
const container = $ . create ( 'fake ' + container _sel ) ;
let container _removed = false ;
2017-07-08 00:09:13 +02:00
container . remove = function ( ) {
container _removed = true ;
} ;
2019-11-02 00:06:25 +01:00
const target = $ . create ( 'fake click target (' + target _sel + ')' ) ;
2017-07-08 23:16:19 +02:00
target . set _parents _result ( parent , container ) ;
2017-07-08 00:09:13 +02:00
2019-11-02 00:06:25 +01:00
const event = {
2017-07-08 23:16:19 +02:00
preventDefault : noop ,
target : target ,
} ;
2019-02-02 15:44:51 +01:00
2019-11-02 00:06:25 +01:00
const helper = {
2019-02-02 15:44:51 +01:00
event : event ,
container : container ,
target : target ,
container _was _removed : ( ) => container _removed ,
} ;
return helper ;
2017-07-08 23:16:19 +02:00
}
( function test _compose _all _everyone _confirm _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose-all-everyone" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( 'click' , '.compose-all-everyone-confirm' ) ;
2017-07-08 23:16:19 +02:00
2019-11-02 00:06:25 +01:00
const helper = setup _parents _and _mock _remove (
2019-02-02 15:44:51 +01:00
'compose-all-everyone' ,
'compose-all-everyone' ,
'.compose-all-everyone'
) ;
2017-07-08 00:09:13 +02:00
$ ( "#compose-all-everyone" ) . show ( ) ;
2017-11-26 19:58:36 +01:00
$ ( "#compose-send-status" ) . show ( ) ;
2017-07-08 00:09:13 +02:00
2019-11-02 00:06:25 +01:00
let compose _finish _checked = false ;
2017-07-08 00:09:13 +02:00
compose . finish = function ( ) {
compose _finish _checked = true ;
} ;
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2017-07-08 00:09:13 +02:00
2019-02-02 15:44:51 +01:00
assert ( helper . container _was _removed ( ) ) ;
2017-07-08 00:09:13 +02:00
assert ( compose _finish _checked ) ;
assert ( ! $ ( "#compose-all-everyone" ) . visible ( ) ) ;
2017-11-26 19:58:36 +01:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
2017-07-08 00:09:13 +02:00
} ( ) ) ;
2017-07-08 00:11:52 +02:00
( function test _compose _invite _users _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose_invite_users" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( 'click' , '.compose_invite_link' ) ;
2019-11-02 00:06:25 +01:00
const subscription = {
2017-07-08 00:11:52 +02:00
stream _id : 102 ,
name : 'test' ,
subscribed : true ,
} ;
2019-11-02 00:06:25 +01:00
let invite _user _to _stream _called = false ;
2017-07-08 00:11:52 +02:00
stream _edit . invite _user _to _stream = function ( email , sub , success ) {
invite _user _to _stream _called = true ;
assert . equal ( email , 'foo@bar.com' ) ;
assert . equal ( sub , subscription ) ;
success ( ) ; // This will check success callback path.
} ;
2019-11-02 00:06:25 +01:00
const helper = setup _parents _and _mock _remove (
2019-02-02 15:44:51 +01:00
'compose_invite_users' ,
'compose_invite_link' ,
'.compose_invite_user'
) ;
2017-07-08 00:11:52 +02:00
// .data in zjquery is a noop by default, so handler should just return
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2017-07-08 00:11:52 +02:00
assert ( ! invite _user _to _stream _called ) ;
2019-02-02 15:44:51 +01:00
assert ( ! helper . container _was _removed ( ) ) ;
2017-07-08 00:11:52 +02:00
// !sub will result false here and we check the failure code path.
2020-04-03 17:18:04 +02:00
blueslip . expect ( 'warn' , 'Stream no longer exists: no-stream' ) ;
2018-11-13 17:16:02 +01:00
$ ( '#stream_message_recipient_stream' ) . val ( 'no-stream' ) ;
2019-02-02 15:44:51 +01:00
helper . container . data = function ( field ) {
2017-07-08 00:11:52 +02:00
assert . equal ( field , 'useremail' ) ;
return 'foo@bar.com' ;
} ;
2018-08-12 22:02:50 +02:00
$ ( "#compose-textarea" ) . select ( noop ) ;
2019-02-02 15:44:51 +01:00
helper . target . prop ( 'disabled' , false ) ;
2017-07-08 00:11:52 +02:00
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
assert ( helper . target . attr ( 'disabled' ) ) ;
2017-07-08 00:11:52 +02:00
assert ( ! invite _user _to _stream _called ) ;
2019-02-02 15:44:51 +01:00
assert ( ! helper . container _was _removed ( ) ) ;
2018-08-12 22:02:50 +02:00
assert ( ! $ ( "#compose_invite_users" ) . visible ( ) ) ;
assert . equal ( $ ( '#compose-error-msg' ) . html ( ) , "Stream no longer exists: no-stream" ) ;
2017-07-08 00:11:52 +02:00
// !sub will result in true here and we check the success code path.
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( subscription ) ;
2018-11-13 17:16:02 +01:00
$ ( '#stream_message_recipient_stream' ) . val ( 'test' ) ;
2019-11-02 00:06:25 +01:00
let all _invite _children _called = false ;
2017-07-08 00:11:52 +02:00
$ ( "#compose_invite_users" ) . children = function ( ) {
all _invite _children _called = true ;
return [ ] ;
} ;
$ ( "#compose_invite_users" ) . show ( ) ;
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2017-07-08 00:11:52 +02:00
2019-02-02 15:44:51 +01:00
assert ( helper . container _was _removed ( ) ) ;
2017-07-08 00:11:52 +02:00
assert ( ! $ ( "#compose_invite_users" ) . visible ( ) ) ;
assert ( invite _user _to _stream _called ) ;
assert ( all _invite _children _called ) ;
} ( ) ) ;
2017-07-08 00:13:14 +02:00
( function test _compose _invite _close _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose_invite_users" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( 'click' , '.compose_invite_close' ) ;
2017-07-08 00:13:14 +02:00
2019-11-02 00:06:25 +01:00
const helper = setup _parents _and _mock _remove (
2019-02-02 15:44:51 +01:00
'compose_invite_users_close' ,
'compose_invite_close' ,
'.compose_invite_user'
) ;
2017-07-08 00:13:14 +02:00
2019-11-02 00:06:25 +01:00
let all _invite _children _called = false ;
2017-07-08 00:13:14 +02:00
$ ( "#compose_invite_users" ) . children = function ( ) {
all _invite _children _called = true ;
return [ ] ;
} ;
$ ( "#compose_invite_users" ) . show ( ) ;
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2017-07-08 00:13:14 +02:00
2019-02-02 15:44:51 +01:00
assert ( helper . container _was _removed ( ) ) ;
2017-07-08 00:13:14 +02:00
assert ( all _invite _children _called ) ;
assert ( ! $ ( "#compose_invite_users" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-08 00:22:11 +02:00
2018-04-07 05:01:53 +02:00
( function test _compose _not _subscribed _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose-send-status" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( 'click' , '.sub_unsub_button' ) ;
2019-11-02 00:06:25 +01:00
const subscription = {
2018-04-07 05:01:53 +02:00
stream _id : 102 ,
name : 'test' ,
subscribed : false ,
} ;
2019-11-02 00:06:25 +01:00
let compose _not _subscribed _called = false ;
2018-04-07 05:01:53 +02:00
subs . sub _or _unsub = function ( ) {
compose _not _subscribed _called = true ;
} ;
2019-11-02 00:06:25 +01:00
const helper = setup _parents _and _mock _remove (
2019-02-02 15:44:51 +01:00
'compose-send-status' ,
'sub_unsub_button' ,
'.compose_not_subscribed'
) ;
2018-04-07 05:01:53 +02:00
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2018-04-07 05:01:53 +02:00
assert ( compose _not _subscribed _called ) ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( subscription ) ;
2018-11-13 17:16:02 +01:00
$ ( '#stream_message_recipient_stream' ) . val ( 'test' ) ;
2018-04-07 05:01:53 +02:00
$ ( "#compose-send-status" ) . show ( ) ;
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2018-04-07 05:01:53 +02:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
} ( ) ) ;
( function test _compose _not _subscribed _close _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose-send-status" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( 'click' , '#compose_not_subscribed_close' ) ;
2018-04-07 05:01:53 +02:00
2019-11-02 00:06:25 +01:00
const helper = setup _parents _and _mock _remove (
2019-02-02 15:44:51 +01:00
'compose_user_not_subscribed_close' ,
'compose_not_subscribed_close' ,
'.compose_not_subscribed'
) ;
2018-04-07 05:01:53 +02:00
$ ( "#compose-send-status" ) . show ( ) ;
2019-02-02 15:44:51 +01:00
handler ( helper . event ) ;
2018-04-07 05:01:53 +02:00
assert ( ! $ ( "#compose-send-status" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-08 00:22:11 +02:00
( function test _attach _files _compose _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( "click" , "#attach_files" ) ;
2017-07-08 00:22:11 +02:00
$ ( '#file_input' ) . clone = function ( param ) {
assert ( param ) ;
} ;
2019-11-02 00:06:25 +01:00
let compose _file _input _clicked = false ;
2017-07-08 00:22:11 +02:00
$ ( '#compose #file_input' ) . trigger = function ( ev _name ) {
assert . equal ( ev _name , 'click' ) ;
compose _file _input _clicked = true ;
} ;
2019-02-02 15:48:30 +01:00
2019-11-02 00:06:25 +01:00
const event = {
2019-02-02 15:48:30 +01:00
preventDefault : noop ,
} ;
2017-07-08 00:22:11 +02:00
handler ( event ) ;
assert ( compose _file _input _clicked ) ;
} ( ) ) ;
2017-07-08 01:21:20 +02:00
2017-08-11 01:51:48 +02:00
( function test _video _link _compose _clicked ( ) {
2018-04-03 01:46:55 +02:00
page _params . jitsi _server _url = 'https://meet.jit.si' ;
2019-11-02 00:06:25 +01:00
let syntax _to _insert ;
let called = false ;
2017-12-08 16:17:20 +01:00
2019-11-02 00:06:25 +01:00
const textarea = $ . create ( 'target-stub' ) ;
2019-01-23 08:04:53 +01:00
2019-11-02 00:06:25 +01:00
const ev = {
2019-01-23 08:04:53 +01:00
preventDefault : noop ,
target : {
to _$ : ( ) => textarea ,
} ,
} ;
2017-12-08 16:17:20 +01:00
compose _ui . insert _syntax _and _focus = function ( syntax ) {
syntax _to _insert = syntax ;
2018-07-23 01:19:57 +02:00
called = true ;
2017-10-31 07:06:04 +01:00
} ;
2019-11-02 00:06:25 +01:00
const handler = $ ( "body" ) . get _on _handler ( "click" , ".video_link" ) ;
2017-12-08 16:17:20 +01:00
$ ( '#compose-textarea' ) . val ( '' ) ;
2017-08-11 01:51:48 +02:00
2019-01-23 08:04:53 +01:00
handler ( ev ) ;
2020-04-08 00:23:15 +02:00
assert ( ! called ) ;
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . jitsi _meet . id ;
handler ( ev ) ;
2017-08-11 01:51:48 +02:00
// video link ids consist of 15 random digits
2019-11-02 00:06:25 +01:00
let video _link _regex = /\[Click to join video call\]\(https:\/\/meet.jit.si\/\d{15}\)/ ;
2017-12-08 16:17:20 +01:00
assert ( video _link _regex . test ( syntax _to _insert ) ) ;
2018-07-23 01:19:57 +02:00
2020-04-08 00:23:15 +02:00
page _params . jitsi _server _url = null ;
called = false ;
handler ( ev ) ;
assert ( ! called ) ;
2019-05-09 09:54:38 +02:00
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . google _hangouts . id ;
2018-07-23 01:19:57 +02:00
page _params . realm _google _hangouts _domain = 'zulip' ;
2019-01-23 08:04:53 +01:00
handler ( ev ) ;
2018-07-23 01:19:57 +02:00
video _link _regex = /\[Click to join video call\]\(https:\/\/hangouts.google.com\/hangouts\/\_\/zulip\/\d{15}\)/ ;
assert ( video _link _regex . test ( syntax _to _insert ) ) ;
2019-05-09 09:54:38 +02:00
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . zoom . id ;
2018-12-28 20:45:54 +01:00
page _params . realm _zoom _user _id = 'example@example.com' ;
page _params . realm _zoom _api _key = 'abc' ;
page _params . realm _zoom _api _secret = 'abc' ;
channel . get = function ( options ) {
assert ( options . url === '/json/calls/create' ) ;
options . success ( { zoom _url : 'example.zoom.com' } ) ;
} ;
2019-01-23 08:04:53 +01:00
handler ( ev ) ;
2018-12-28 20:45:54 +01:00
video _link _regex = /\[Click to join video call\]\(example\.zoom\.com\)/ ;
assert ( video _link _regex . test ( syntax _to _insert ) ) ;
2017-08-11 01:51:48 +02:00
} ( ) ) ;
2017-07-08 01:21:20 +02:00
( function test _markdown _preview _compose _clicked ( ) {
// Tests setup
function setup _visibilities ( ) {
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . show ( ) ;
2017-07-08 01:21:20 +02:00
$ ( "#markdown_preview" ) . show ( ) ;
$ ( "#undo_markdown_preview" ) . hide ( ) ;
$ ( "#preview_message_area" ) . hide ( ) ;
}
function assert _visibilities ( ) {
2017-11-26 20:37:44 +01:00
assert ( ! $ ( "#compose-textarea" ) . visible ( ) ) ;
2017-07-08 01:21:20 +02:00
assert ( ! $ ( "#markdown_preview" ) . visible ( ) ) ;
assert ( $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( $ ( "#preview_message_area" ) . visible ( ) ) ;
}
2017-07-29 02:51:33 +02:00
function setup _mock _markdown _contains _backend _only _syntax ( msg _content , return _val ) {
markdown . contains _backend _only _syntax = function ( msg ) {
2017-07-08 01:21:20 +02:00
assert . equal ( msg , msg _content ) ;
return return _val ;
} ;
}
2019-12-03 15:29:44 +01:00
function setup _mock _markdown _is _status _message ( msg _content , return _val ) {
markdown . is _status _message = function ( content ) {
2018-01-21 19:27:36 +01:00
assert . equal ( content , msg _content ) ;
return return _val ;
} ;
}
2017-07-08 01:21:20 +02:00
function test _post _success ( success _callback ) {
2019-11-02 00:06:25 +01:00
const resp = {
2017-07-08 01:21:20 +02:00
rendered : 'Server: foobarfoobar' ,
} ;
success _callback ( resp ) ;
assert . equal ( $ ( "#preview_content" ) . html ( ) , 'Server: foobarfoobar' ) ;
}
function test _post _error ( error _callback ) {
error _callback ( ) ;
assert . equal ( $ ( "#preview_content" ) . html ( ) ,
2018-05-07 03:30:13 +02:00
'translated: Failed to generate preview' ) ;
2017-07-08 01:21:20 +02:00
}
function mock _channel _post ( msg ) {
channel . post = function ( payload ) {
assert . equal ( payload . url , '/json/messages/render' ) ;
assert ( payload . idempotent ) ;
assert ( payload . data ) ;
assert . deepEqual ( payload . data . content , msg ) ;
function test ( func , param ) {
2019-11-02 00:06:25 +01:00
let destroy _indicator _called = false ;
2017-07-08 01:21:20 +02:00
loading . destroy _indicator = function ( spinner ) {
assert . equal ( spinner , $ ( "#markdown_preview_spinner" ) ) ;
destroy _indicator _called = true ;
} ;
2017-07-29 02:51:33 +02:00
setup _mock _markdown _contains _backend _only _syntax ( msg , true ) ;
2017-07-08 01:21:20 +02:00
func ( param ) ;
assert ( destroy _indicator _called ) ;
}
test ( test _post _error , payload . error ) ;
test ( test _post _success , payload . success ) ;
} ;
}
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( "click" , "#markdown_preview" ) ;
2017-07-08 01:21:20 +02:00
// Tests start here
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( '' ) ;
2017-07-08 01:21:20 +02:00
setup _visibilities ( ) ;
2019-11-02 00:06:25 +01:00
const event = {
2019-02-02 15:48:30 +01:00
preventDefault : noop ,
} ;
2017-07-08 01:21:20 +02:00
handler ( event ) ;
assert . equal ( $ ( "#preview_content" ) . html ( ) ,
2018-05-07 03:30:13 +02:00
'translated: Nothing to preview' ) ;
2017-07-08 01:21:20 +02:00
assert _visibilities ( ) ;
2019-11-02 00:06:25 +01:00
let make _indicator _called = false ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( '```foobarfoobar```' ) ;
2017-07-08 01:21:20 +02:00
setup _visibilities ( ) ;
2017-07-29 02:51:33 +02:00
setup _mock _markdown _contains _backend _only _syntax ( '```foobarfoobar```' , true ) ;
2019-12-03 15:29:44 +01:00
setup _mock _markdown _is _status _message ( '```foobarfoobar```' , false ) ;
2017-07-08 01:21:20 +02:00
loading . make _indicator = function ( spinner ) {
2019-04-18 21:11:30 +02:00
assert . equal ( spinner . selector , "#markdown_preview_spinner" ) ;
2017-07-08 01:21:20 +02:00
make _indicator _called = true ;
} ;
mock _channel _post ( '```foobarfoobar```' ) ;
handler ( event ) ;
assert ( make _indicator _called ) ;
assert _visibilities ( ) ;
2019-11-02 00:06:25 +01:00
let apply _markdown _called = false ;
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . val ( 'foobarfoobar' ) ;
2017-07-08 01:21:20 +02:00
setup _visibilities ( ) ;
2017-07-29 02:51:33 +02:00
setup _mock _markdown _contains _backend _only _syntax ( 'foobarfoobar' , false ) ;
2019-12-03 15:29:44 +01:00
setup _mock _markdown _is _status _message ( 'foobarfoobar' , false ) ;
2017-07-08 01:21:20 +02:00
mock _channel _post ( 'foobarfoobar' ) ;
markdown . apply _markdown = function ( msg ) {
2017-08-27 18:26:02 +02:00
assert . equal ( msg . raw _content , 'foobarfoobar' ) ;
2017-07-08 01:21:20 +02:00
apply _markdown _called = true ;
return msg ;
} ;
handler ( event ) ;
assert ( apply _markdown _called ) ;
assert _visibilities ( ) ;
assert . equal ( $ ( "#preview_content" ) . html ( ) ,
2018-05-07 03:30:13 +02:00
'Server: foobarfoobar' ) ;
2017-07-08 01:21:20 +02:00
} ( ) ) ;
2017-07-08 01:27:11 +02:00
( function test _undo _markdown _preview _clicked ( ) {
2019-11-02 00:06:25 +01:00
const handler = $ ( "#compose" )
2018-05-07 03:30:13 +02:00
. get _on _handler ( "click" , "#undo_markdown_preview" ) ;
2017-07-08 01:27:11 +02:00
2017-11-26 20:37:44 +01:00
$ ( "#compose-textarea" ) . hide ( ) ;
2017-07-08 01:27:11 +02:00
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
2019-11-02 00:06:25 +01:00
const event = {
2019-02-02 15:48:30 +01:00
preventDefault : noop ,
} ;
2017-07-08 01:27:11 +02:00
handler ( event ) ;
2017-11-26 20:37:44 +01:00
assert ( $ ( "#compose-textarea" ) . visible ( ) ) ;
2017-07-08 01:27:11 +02:00
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-14 19:30:23 +02:00
2018-05-15 12:40:07 +02:00
} ) ;
2017-07-08 00:06:38 +02:00
2018-05-15 12:40:07 +02:00
run _test ( 'create_message_object' , ( ) => {
2019-11-02 00:06:25 +01:00
const sub = {
2017-02-24 16:18:56 +01:00
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
2020-02-09 22:02:55 +01:00
stream _data . add _sub ( sub ) ;
2017-02-24 16:18:56 +01:00
2019-11-02 00:06:25 +01:00
const page = {
2018-11-13 17:16:02 +01:00
'#stream_message_recipient_stream' : 'social' ,
'#stream_message_recipient_topic' : 'lunch' ,
2017-11-26 20:37:44 +01:00
'#compose-textarea' : 'burrito' ,
2017-02-24 16:18:56 +01:00
} ;
global . $ = function ( selector ) {
return {
val : function ( ) {
return page [ selector ] ;
} ,
} ;
} ;
2017-04-24 20:35:26 +02:00
global . compose _state . get _message _type = function ( ) {
2017-02-24 16:18:56 +01:00
return 'stream' ;
} ;
global . $ . trim = function ( s ) {
return s ;
} ;
2019-11-02 00:06:25 +01:00
let message = compose . create _message _object ( ) ;
2020-02-07 21:18:20 +01:00
assert . equal ( message . to , sub . stream _id ) ;
assert . equal ( message . topic , 'lunch' ) ;
assert . equal ( message . content , 'burrito' ) ;
2020-04-03 17:18:04 +02:00
blueslip . expect ( 'error' , 'Trying to send message with bad stream name: BOGUS STREAM' ) ;
2020-02-07 21:18:20 +01:00
page [ '#stream_message_recipient_stream' ] = 'BOGUS STREAM' ;
message = compose . create _message _object ( ) ;
assert . equal ( message . to , 'BOGUS STREAM' ) ;
2018-12-23 16:49:14 +01:00
assert . equal ( message . topic , 'lunch' ) ;
2017-02-24 16:18:56 +01:00
assert . equal ( message . content , 'burrito' ) ;
2017-04-24 20:35:26 +02:00
global . compose _state . get _message _type = function ( ) {
2017-02-24 16:18:56 +01:00
return 'private' ;
} ;
2019-12-02 17:53:55 +01:00
compose _state . private _message _recipient = function ( ) {
2019-05-23 22:18:58 +02:00
return 'alice@example.com, bob@example.com' ;
2018-03-31 13:22:29 +02:00
} ;
2017-03-29 08:54:26 +02:00
message = compose . create _message _object ( ) ;
2019-05-23 22:18:58 +02:00
assert . deepEqual ( message . to , [ alice . user _id , bob . user _id ] ) ;
2017-02-24 23:51:23 +01:00
assert . equal ( message . to _user _ids , '31,32' ) ;
2017-02-24 16:18:56 +01:00
assert . equal ( message . content , 'burrito' ) ;
2019-11-02 00:06:25 +01:00
const { email _list _to _user _ids _string } = people ;
2019-05-23 22:18:58 +02:00
people . email _list _to _user _ids _string = ( ) => undefined ;
message = compose . create _message _object ( ) ;
assert . deepEqual ( message . to , [ alice . email , bob . email ] ) ;
people . email _list _to _user _ids _string = email _list _to _user _ids _string ;
2018-05-15 12:40:07 +02:00
} ) ;
2018-07-23 02:41:55 +02:00
run _test ( 'nonexistent_stream_reply_error' , ( ) => {
set _global ( '$' , global . make _zjquery ( ) ) ;
2020-02-01 04:46:54 +01:00
const actions = [ ] ;
2018-07-23 02:41:55 +02:00
$ ( "#nonexistent_stream_reply_error" ) . show = ( ) => {
2020-02-01 04:46:54 +01:00
actions . push ( "show" ) ;
2018-07-23 02:41:55 +02:00
} ;
$ ( "#nonexistent_stream_reply_error" ) . hide = ( ) => {
2020-02-01 04:46:54 +01:00
actions . push ( "hide" ) ;
2018-07-23 02:41:55 +02:00
} ;
compose . nonexistent _stream _reply _error ( ) ;
assert . equal ( $ ( "#compose-reply-error-msg" ) . html ( ) , 'There are no messages to reply to yet.' ) ;
2020-02-01 04:46:54 +01:00
assert . deepEqual ( actions , [ "show" , "hide" ] ) ;
2018-07-23 02:41:55 +02:00
} ) ;
2018-08-13 23:17:45 +02:00
run _test ( 'narrow_button_titles' , ( ) => {
util . is _mobile = ( ) => { return false ; } ;
2019-03-06 23:46:53 +01:00
compose . update _closed _compose _buttons _for _private ( ) ;
2018-08-13 23:17:45 +02:00
assert . equal ( $ ( "#left_bar_compose_stream_button_big" ) . text ( ) , i18n . t ( "New stream message" ) ) ;
2019-06-05 03:27:12 +02:00
assert . equal ( $ ( "#left_bar_compose_private_button_big" ) . text ( ) , i18n . t ( "New private message" ) ) ;
2018-08-13 23:17:45 +02:00
2019-03-06 23:46:53 +01:00
compose . update _closed _compose _buttons _for _stream ( ) ;
2018-08-13 23:17:45 +02:00
assert . equal ( $ ( "#left_bar_compose_stream_button_big" ) . text ( ) , i18n . t ( "New topic" ) ) ;
2019-03-06 23:46:53 +01:00
assert . equal ( $ ( "#left_bar_compose_private_button_big" ) . text ( ) , i18n . t ( "New private message" ) ) ;
2018-08-13 23:17:45 +02:00
} ) ;
2020-04-08 00:23:15 +02:00
run _test ( 'test_video_chat_button_toggle' , ( ) => {
reset _jquery ( ) ;
stub _out _video _calls ( ) ;
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . disabled . id ;
compose . initialize ( ) ;
assert . equal ( $ ( "#below-compose-content .video_link" ) . visible ( ) , false ) ;
reset _jquery ( ) ;
stub _out _video _calls ( ) ;
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . jitsi _meet . id ;
compose . initialize ( ) ;
assert . equal ( $ ( "#below-compose-content .video_link" ) . visible ( ) , false ) ;
reset _jquery ( ) ;
stub _out _video _calls ( ) ;
page _params . jitsi _server _url = 'https://meet.jit.si' ;
compose . initialize ( ) ;
assert . equal ( $ ( "#below-compose-content .video_link" ) . visible ( ) , true ) ;
reset _jquery ( ) ;
stub _out _video _calls ( ) ;
page _params . realm _video _chat _provider =
page _params . realm _available _video _chat _providers . google _hangouts . id ;
compose . initialize ( ) ;
assert . equal ( $ ( "#below-compose-content .video_link" ) . visible ( ) , true ) ;
} ) ;