2017-06-27 14:55:11 +02:00
set _global ( '$' , global . make _zjquery ( ) ) ;
2017-06-29 20:46:27 +02:00
set _global ( 'i18n' , global . stub _i18n ) ;
2017-02-24 16:18:56 +01:00
set _global ( 'page_params' , {
2017-07-07 03:59:08 +02:00
use _websockets : true ,
2017-02-24 16:18:56 +01:00
} ) ;
2017-07-07 03:59:08 +02:00
set _global ( 'navigator' , { } ) ;
2017-02-24 16:18:56 +01:00
set _global ( 'document' , {
location : {
} ,
} ) ;
2017-06-28 19:24:53 +02:00
set _global ( 'channel' , { } ) ;
2017-06-28 20:28:18 +02:00
set _global ( 'templates' , { } ) ;
2017-02-24 16:18:56 +01:00
2017-06-27 14:55:11 +02:00
var noop = function ( ) { } ;
2017-06-29 06:54:10 +02:00
set _global ( 'blueslip' , { } ) ;
set _global ( 'drafts' , {
delete _draft _after _send : noop ,
} ) ;
set _global ( 'resize' , {
resize _bottom _whitespace : noop ,
} ) ;
set _global ( 'feature_flags' , {
resize _bottom _whitespace : noop ,
} ) ;
set _global ( 'echo' , { } ) ;
2017-07-07 03:59:08 +02:00
set _global ( 'socket' , { } ) ;
set _global ( 'Socket' , function ( ) {
return global . socket ;
} ) ;
2017-07-08 00:11:52 +02:00
set _global ( 'stream_edit' , { } ) ;
2017-07-08 01:21:20 +02:00
set _global ( 'markdown' , { } ) ;
set _global ( 'loading' , { } ) ;
2017-06-29 06:54:10 +02:00
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
set _global ( 'sent_messages' , {
start _tracking _message : noop ,
report _server _ack : noop ,
} ) ;
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' ;
2017-02-24 16:18:56 +01:00
add _dependencies ( {
2017-06-27 14:55:11 +02:00
common : 'js/common' ,
2017-04-15 01:15:59 +02:00
compose _state : 'js/compose_state' ,
2017-06-29 06:54:10 +02:00
compose _ui : 'js/compose_ui.js' ,
2017-06-28 13:10:46 +02:00
Handlebars : 'handlebars' ,
2017-02-24 23:51:23 +01:00
people : 'js/people' ,
2017-02-24 16:18:56 +01:00
stream _data : 'js/stream_data' ,
util : 'js/util' ,
} ) ;
var compose = require ( 'js/compose.js' ) ;
2017-07-07 03:59:08 +02:00
page _params . use _websockets = false ;
2017-02-24 16:18:56 +01:00
2017-02-24 23:51:23 +01:00
var me = {
email : 'me@example.com' ,
user _id : 30 ,
full _name : 'Me Myself' ,
} ;
var alice = {
email : 'alice@example.com' ,
user _id : 31 ,
full _name : 'Alice' ,
} ;
var bob = {
email : 'bob@example.com' ,
user _id : 32 ,
full _name : 'Bob' ,
} ;
people . add ( me ) ;
people . initialize _current _user ( me . user _id ) ;
people . add ( alice ) ;
people . add ( bob ) ;
2017-06-28 21:52:36 +02:00
( function test _update _email ( ) {
compose _state . recipient ( '' ) ;
assert . equal ( compose . update _email ( ) , undefined ) ;
compose _state . recipient ( 'bob@example.com' ) ;
compose . update _email ( 32 , 'bob_alias@example.com' ) ;
assert . equal ( compose _state . recipient ( ) , 'bob_alias@example.com' ) ;
} ( ) ) ;
2017-06-28 12:55:04 +02:00
( function test _validate _stream _message _address _info ( ) {
var sub = {
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
stream _data . add _sub ( 'social' , sub ) ;
assert ( compose . validate _stream _message _address _info ( 'social' ) ) ;
2017-06-28 13:10:46 +02:00
$ ( '#stream' ) . select ( noop ) ;
assert ( ! compose . validate _stream _message _address _info ( 'foobar' ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , "<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 ;
stream _data . add _sub ( 'social' , sub ) ;
assert ( ! compose . validate _stream _message _address _info ( 'social' ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , "<p>You're not subscribed to the stream <b>social</b>.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>" ) ;
global . page _params . narrow _stream = false ;
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 ;
stream _data . add _sub ( 'Frontend' , sub ) ;
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' ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , "<p>You're not subscribed to the stream <b>Frontend</b>.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>" ) ;
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'Frontend' ) ;
payload . error ( { status : 404 } ) ;
} ;
assert ( ! compose . validate _stream _message _address _info ( 'Frontend' ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , "<p>The stream <b>Frontend</b> does not exist.</p><p>Manage your subscriptions <a href='#streams/all'>on your Streams page</a>.</p>" ) ;
channel . post = function ( payload ) {
assert . equal ( payload . data . stream , 'social' ) ;
payload . error ( { status : 500 } ) ;
} ;
assert ( ! compose . validate _stream _message _address _info ( 'social' ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( "Error checking subscription" ) ) ;
2017-06-28 12:55:04 +02:00
} ( ) ) ;
2017-02-24 23:51:23 +01:00
2017-06-27 14:55:11 +02:00
( function test _validate ( ) {
2017-06-30 00:57:46 +02:00
$ ( "#compose-send-button" ) . prop ( 'disabled' , false ) ;
2017-06-27 14:55:11 +02:00
$ ( "#compose-send-button" ) . focus ( ) ;
$ ( "#sending-indicator" ) . hide ( ) ;
$ ( "#new_message_content" ) . select ( noop ) ;
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-06-29 20:48:49 +02:00
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
2017-06-27 14:55:11 +02:00
$ ( "#new_message_content" ) . val ( 'foobarfoobar' ) ;
var zephyr _checked = false ;
$ ( "#zephyr-mirror-error" ) . is = function ( ) {
if ( ! zephyr _checked ) {
zephyr _checked = true ;
return true ;
}
return false ;
} ;
assert ( ! compose . validate ( ) ) ;
assert ( zephyr _checked ) ;
2017-06-29 20:48:49 +02:00
assert . equal ( $ ( '#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
compose _state . set _message _type ( 'private' ) ;
compose _state . recipient ( '' ) ;
$ ( "#private_message_recipient" ) . select ( noop ) ;
assert ( ! compose . validate ( ) ) ;
2017-06-29 20:48:49 +02:00
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'Please specify at least one recipient' ) ) ;
2017-06-27 14:55:11 +02:00
compose _state . recipient ( 'foo@zulip.com' ) ;
global . page _params . realm _is _zephyr _mirror _realm = true ;
assert ( compose . validate ( ) ) ;
global . page _params . realm _is _zephyr _mirror _realm = false ;
assert ( ! compose . validate ( ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'The recipient foo@zulip.com is not valid' , { } ) ) ;
compose _state . recipient ( 'foo@zulip.com,alice@zulip.com' ) ;
assert ( ! compose . validate ( ) ) ;
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'The recipients foo@zulip.com,alice@zulip.com are not valid' , { } ) ) ;
people . add _in _realm ( bob ) ;
compose _state . recipient ( 'bob@example.com' ) ;
assert ( compose . validate ( ) ) ;
compose _state . set _message _type ( 'stream' ) ;
compose _state . stream _name ( '' ) ;
$ ( "#stream" ) . select ( noop ) ;
assert ( ! compose . validate ( ) ) ;
2017-06-29 20:48:49 +02:00
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'Please specify a stream' ) ) ;
2017-06-27 14:55:11 +02:00
compose _state . stream _name ( 'Denmark' ) ;
global . page _params . realm _mandatory _topics = true ;
compose _state . subject ( '' ) ;
$ ( "#subject" ) . select ( noop ) ;
assert ( ! compose . validate ( ) ) ;
2017-06-29 20:48:49 +02:00
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'Please specify a topic' ) ) ;
2017-06-27 14:55:11 +02:00
} ( ) ) ;
2017-06-28 21:36:57 +02:00
( function test _get _invalid _recipient _emails ( ) {
var feedback _bot = {
email : 'feedback@example.com' ,
user _id : 124 ,
full _name : 'Feedback Bot' ,
} ;
global . page _params . cross _realm _bots = [ feedback _bot ] ;
global . page _params . user _id = 30 ;
people . initialize ( ) ;
compose _state . recipient ( 'feedback@example.com' ) ;
assert . deepEqual ( compose . get _invalid _recipient _emails ( ) , [ ] ) ;
} ( ) ) ;
2017-06-28 20:28:18 +02:00
( function test _validate _stream _message ( ) {
// This test is in kind of continuation to test_validate but since it is
// primarly used to get coverage over functions called from validate()
// we are seperating it up in different test. Though their relative position
// of execution should not be changed.
global . page _params . realm _mandatory _topics = false ;
var sub = {
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
stream _data . add _sub ( 'social' , sub ) ;
compose _state . stream _name ( 'social' ) ;
assert ( compose . validate ( ) ) ;
assert ( ! $ ( "#compose-all-everyone" ) . visible ( ) ) ;
assert ( ! $ ( "#send-status" ) . visible ( ) ) ;
stream _data . get _subscriber _count = function ( stream _name ) {
assert . equal ( stream _name , 'social' ) ;
return 16 ;
} ;
global . templates . render = function ( template _name , data ) {
assert . equal ( template _name , 'compose_all_everyone' ) ;
assert . equal ( data . count , 16 ) ;
return 'compose_all_everyone_stub' ;
} ;
$ ( '#compose-all-everyone' ) . is = function ( sel ) {
if ( sel === ':visible' ) {
return $ ( '#compose-all-everyone' ) . visible ( ) ;
}
} ;
var compose _content ;
$ ( '#compose-all-everyone' ) . append = function ( data ) {
compose _content = data ;
} ;
compose _state . message _content ( 'Hey @all' ) ;
assert ( ! compose . validate ( ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-06-28 20:28:18 +02:00
assert ( ! $ ( "#send-status" ) . visible ( ) ) ;
assert . equal ( compose _content , 'compose_all_everyone_stub' ) ;
assert ( $ ( "#compose-all-everyone" ) . visible ( ) ) ;
} ( ) ) ;
2017-06-29 06:54:10 +02:00
( function test _send _message _success ( ) {
blueslip . error = noop ;
blueslip . log = noop ;
$ ( "#new_message_content" ) . val ( 'foobarfoobar' ) ;
$ ( "#new_message_content" ) . blur ( ) ;
$ ( "#send-status" ) . show ( ) ;
$ ( "#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
2017-06-29 06:54:10 +02:00
var reify _message _id _checked ;
echo . reify _message _id = function ( local _id , message _id ) {
assert . equal ( local _id , 1001 ) ;
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
compose . send _message _success ( 1001 , 12 , false ) ;
2017-06-29 06:54:10 +02:00
assert . equal ( $ ( "#new_message_content" ) . val ( ) , '' ) ;
assert ( $ ( "#new_message_content" ) . is _focused ( ) ) ;
assert ( ! $ ( "#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 ) ;
2017-06-29 14:31:26 +02:00
} ( ) ) ;
2017-07-06 21:57:25 +02:00
( function test _send _message ( ) {
// This is the common setup stuff for all of the four tests.
var stub _state ;
function initialize _state _stub _dict ( ) {
stub _state = { } ;
stub _state . local _id _counter = 0 ;
stub _state . send _msg _ajax _post _called = 0 ;
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 ( ) ;
compose _state . subject ( '' ) ;
compose _state . set _message _type ( 'private' ) ;
page _params . user _id = 101 ;
compose _state . recipient ( 'alice@example.com' ) ;
echo . try _deliver _locally = function ( ) {
stub _state . local _id _counter += 1 ;
return stub _state . local _id _counter ;
} ;
channel . post = function ( payload ) {
var single _msg = {
type : 'private' ,
content : '[foobar](/user_uploads/123456)' ,
sender _id : 101 ,
queue _id : undefined ,
stream : '' ,
subject : '' ,
to : '["alice@example.com"]' ,
reply _to : 'alice@example.com' ,
private _message _recipient : 'alice@example.com' ,
to _user _ids : '31' ,
local _id : 1 ,
2017-07-17 16:52:57 +02:00
locally _echoed : true ,
2017-07-06 21:57:25 +02:00
} ;
assert . equal ( payload . url , '/json/messages' ) ;
2017-07-17 16:52:57 +02:00
assert . equal ( _ . keys ( payload . data ) . length , 12 ) ;
2017-07-06 21:57:25 +02:00
assert . deepEqual ( payload . data , single _msg ) ;
payload . data . id = stub _state . local _id _counter ;
payload . success ( payload . data ) ;
stub _state . send _msg _ajax _post _called += 1 ;
} ;
echo . reify _message _id = function ( local _id , message _id ) {
assert . equal ( typeof ( local _id ) , 'number' ) ;
assert . equal ( typeof ( message _id ) , 'number' ) ;
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.
$ ( "#new_message_content" ) . val ( '[foobar]' +
'(https://foo.com/user_uploads/123456)' ) ;
$ ( "#new_message_content" ) . blur ( ) ;
$ ( "#send-status" ) . show ( ) ;
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#sending-indicator" ) . show ( ) ;
compose . send _message ( ) ;
var state = {
local _id _counter : 1 ,
get _events _running _called : 1 ,
reify _message _id _checked : 1 ,
send _msg _ajax _post _called : 1 ,
} ;
assert . deepEqual ( stub _state , state ) ;
assert . equal ( $ ( "#new_message_content" ) . val ( ) , '' ) ;
assert ( $ ( "#new_message_content" ) . is _focused ( ) ) ;
assert ( ! $ ( "#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 ( ) ) ;
} ( ) ) ;
( function test _error _code _path _when _error _type _not _timeout ( ) {
stub _state = initialize _state _stub _dict ( ) ;
compose _state . set _message _type ( 'stream' ) ;
var server _error _triggered = false ;
channel . post = function ( payload ) {
payload . error ( '500' , 'Internal Server Error' ) ;
stub _state . send _msg _ajax _post _called += 1 ;
server _error _triggered = true ;
} ;
var reload _initiate _triggered = false ;
global . reload = {
is _pending : function ( ) { return true ; } ,
initiate : function ( ) {
reload _initiate _triggered = true ;
} ,
} ;
compose . send _message ( ) ;
var state = {
local _id _counter : 1 ,
get _events _running _called : 1 ,
reify _message _id _checked : 0 ,
send _msg _ajax _post _called : 1 ,
} ;
assert . deepEqual ( stub _state , state ) ;
assert ( server _error _triggered ) ;
assert ( reload _initiate _triggered ) ;
} ( ) ) ;
// This is the additional setup which is common to both the tests below.
var server _error _triggered = false ;
var reload _initiate _triggered = false ;
channel . post = function ( payload ) {
payload . error ( '408' , 'timeout' ) ;
stub _state . send _msg _ajax _post _called += 1 ;
server _error _triggered = true ;
} ;
var xhr _error _msg _checked = false ;
channel . xhr _error _message = function ( error , xhr ) {
assert . equal ( error , 'Error sending message' ) ;
assert . equal ( xhr , '408' ) ;
xhr _error _msg _checked = true ;
return 'Error sending message: Server says 408' ;
} ;
var echo _error _msg _checked = false ;
echo . message _send _error = function ( local _id , error _response ) {
assert . equal ( local _id , 1 ) ;
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 ( ) ;
var state = {
local _id _counter : 1 ,
get _events _running _called : 1 ,
reify _message _id _checked : 0 ,
send _msg _ajax _post _called : 1 ,
} ;
assert . deepEqual ( stub _state , state ) ;
assert ( server _error _triggered ) ;
assert ( ! reload _initiate _triggered ) ;
assert ( xhr _error _msg _checked ) ;
assert ( echo _error _msg _checked ) ;
} ( ) ) ;
( function test _error _codepath _local _id _undefined ( ) {
stub _state = initialize _state _stub _dict ( ) ;
$ ( "#new_message_content" ) . val ( 'foobarfoobar' ) ;
$ ( "#new_message_content" ) . blur ( ) ;
$ ( "#send-status" ) . show ( ) ;
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#sending-indicator" ) . show ( ) ;
$ ( "#new_message_content" ) . select ( noop ) ;
echo _error _msg _checked = false ;
xhr _error _msg _checked = false ;
server _error _triggered = false ;
reload _initiate _triggered = 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 ( ) ;
var state = {
local _id _counter : 0 ,
get _events _running _called : 1 ,
reify _message _id _checked : 0 ,
send _msg _ajax _post _called : 1 ,
} ;
assert . deepEqual ( stub _state , state ) ;
assert ( server _error _triggered ) ;
assert ( ! reload _initiate _triggered ) ;
assert ( xhr _error _msg _checked ) ;
assert ( ! echo _error _msg _checked ) ;
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 . equal ( $ ( '#error-msg' ) . html ( ) ,
'Error sending message: Server says 408' ) ;
assert . equal ( $ ( "#new_message_content" ) . val ( ) , 'foobarfoobar' ) ;
assert ( $ ( "#new_message_content" ) . is _focused ( ) ) ;
assert ( $ ( "#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 ( ) ) ;
} ( ) ) ;
} ( ) ) ;
2017-07-07 00:33:46 +02:00
( function test _enter _with _preview _open ( ) {
2017-07-07 19:31:32 +02:00
// Test sending a message with content.
$ ( "#new_message_content" ) . val ( 'message me' ) ;
2017-07-07 00:33:46 +02:00
$ ( "#new_message_content" ) . hide ( ) ;
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
page _params . enter _sends = true ;
var send _message _called = false ;
compose . send _message = function ( ) {
send _message _called = true ;
} ;
compose . enter _with _preview _open ( ) ;
assert ( $ ( "#new_message_content" ) . visible ( ) ) ;
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
assert ( send _message _called ) ;
page _params . enter _sends = false ;
$ ( "#new_message_content" ) . blur ( ) ;
compose . enter _with _preview _open ( ) ;
assert ( $ ( "#new_message_content" ) . is _focused ( ) ) ;
2017-07-07 19:31:32 +02:00
// Test sending a message without content.
$ ( "#new_message_content" ) . val ( '' ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#enter_sends" ) . prop ( "checked" , true ) ;
page _params . enter _sends = true ;
compose . enter _with _preview _open ( ) ;
assert ( $ ( "#enter_sends" ) . prop ( "checked" ) ) ;
assert . equal ( $ ( "#error-msg" ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
2017-07-07 00:33:46 +02:00
} ( ) ) ;
2017-07-07 00:48:51 +02:00
( function test _finish ( ) {
( 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 ( ) ;
$ ( "#new_message_content" ) . select ( noop ) ;
$ ( "#new_message_content" ) . val ( '' ) ;
var res = compose . finish ( ) ;
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-07-07 00:48:51 +02:00
assert . equal ( $ ( '#error-msg' ) . html ( ) , i18n . t ( 'You have nothing to send!' ) ) ;
} ( ) ) ;
( function test _when _compose _validation _succeed ( ) {
$ ( "#new_message_content" ) . hide ( ) ;
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
$ ( "#new_message_content" ) . val ( 'foobarfoobar' ) ;
compose _state . set _message _type ( 'private' ) ;
compose _state . recipient ( 'bob@example.com' ) ;
var compose _finished _event _checked = false ;
$ . stub _selector ( document , {
trigger : function ( e ) {
assert . equal ( e . name , 'compose_finished.zulip' ) ;
compose _finished _event _checked = true ;
} ,
} ) ;
var send _message _called = false ;
compose . send _message = function ( ) {
send _message _called = true ;
} ;
assert ( compose . finish ( ) ) ;
assert ( $ ( "#new_message_content" ) . visible ( ) ) ;
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
assert ( send _message _called ) ;
assert ( compose _finished _event _checked ) ;
} ( ) ) ;
} ( ) ) ;
2017-07-07 15:44:39 +02:00
( function test _abort _xhr ( ) {
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
var compose _removedata _checked = false ;
$ ( '#compose' ) . removeData = function ( sel ) {
assert . equal ( sel , 'filedrop_xhr' ) ;
compose _removedata _checked = true ;
} ;
var xhr _abort _checked = false ;
$ ( "#compose" ) . data = function ( sel ) {
assert . equal ( sel , 'filedrop_xhr' ) ;
return {
abort : function ( ) {
xhr _abort _checked = true ;
} ,
} ;
} ;
compose . abort _xhr ( ) ;
assert . equal ( $ ( "#compose-send-button" ) . attr ( ) , undefined ) ;
assert ( xhr _abort _checked ) ;
assert ( compose _removedata _checked ) ;
} ( ) ) ;
2017-07-07 15:14:00 +02:00
function verify _filedrop _payload ( payload ) {
2017-07-31 20:52:17 +02:00
assert . equal ( payload . url , '/json/user_uploads' ) ;
2017-07-07 15:14:00 +02:00
assert . equal ( payload . fallback _id , 'file_input' ) ;
assert . equal ( payload . paramname , 'file' ) ;
assert . equal ( payload . maxfilesize , 512 ) ;
assert . equal ( payload . data . csrfmiddlewaretoken , 'fake-csrf-token' ) ;
assert . deepEqual ( payload . raw _droppable , [ 'text/uri-list' , 'text/plain' ] ) ;
assert . equal ( typeof ( payload . drop ) , 'function' ) ;
assert . equal ( typeof ( payload . progressUpdated ) , 'function' ) ;
assert . equal ( typeof ( payload . error ) , 'function' ) ;
assert . equal ( typeof ( payload . uploadFinished ) , 'function' ) ;
assert . equal ( typeof ( payload . rawDrop ) , 'function' ) ;
}
function test _raw _file _drop ( raw _drop _func ) {
compose _state . set _message _type ( false ) ;
var compose _actions _start _checked = false ;
global . compose _actions = {
start : function ( msg _type ) {
assert . equal ( msg _type , 'stream' ) ;
compose _actions _start _checked = true ;
} ,
} ;
$ ( "#new_message_content" ) . val ( 'Old content ' ) ;
var compose _ui _autosize _textarea _checked = false ;
compose _ui . autosize _textarea = function ( ) {
compose _ui _autosize _textarea _checked = true ;
} ;
// Call the method here!
raw _drop _func ( 'new contents' ) ;
assert ( compose _actions _start _checked ) ;
assert . equal ( $ ( "#new_message_content" ) . val ( ) , 'Old content new contents' ) ;
assert ( compose _ui _autosize _textarea _checked ) ;
}
( function test _initialize ( ) {
// 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.
var resize _watch _manual _resize _checked = false ;
resize . watch _manual _resize = function ( elem ) {
assert . equal ( '#new_message_content' , elem ) ;
resize _watch _manual _resize _checked = true ;
} ;
global . window = {
XMLHttpRequest : true ,
bridge : true ,
} ;
var xmlhttprequest _checked = false ;
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' ;
var filedrop _in _compose _checked = false ;
page _params . maxfilesize = 512 ;
$ ( "#compose" ) . filedrop = function ( payload ) {
verify _filedrop _payload ( payload ) ;
test _raw _file _drop ( payload . rawDrop ) ;
filedrop _in _compose _checked = true ;
} ;
compose . initialize ( ) ;
assert ( resize _watch _manual _resize _checked ) ;
assert ( xmlhttprequest _checked ) ;
assert ( ! $ ( "#compose #attach_files" ) . hasClass ( "notdisplayed" ) ) ;
assert ( filedrop _in _compose _checked ) ;
function reset _jquery ( ) {
// Avoid leaks.
set _global ( '$' , global . make _zjquery ( ) ) ;
// Bypass filedrop (we already tested it above).
$ ( "#compose" ) . filedrop = noop ;
}
var compose _actions _start _checked ;
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 ( ) ;
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 ( ) ;
set _up _compose _start _mock ( { subject : 'testing' } ) ;
compose . initialize ( ) ;
assert ( compose _actions _start _checked ) ;
} ( ) ) ;
} ( ) ) ;
2017-07-07 03:59:08 +02:00
function test _with _mock _socket ( test _params ) {
var socket _send _called ;
var send _args = { } ;
global . socket . send = function ( request , success , error ) {
global . socket . send = undefined ;
socket _send _called = true ;
// Save off args for check_send_args callback.
send _args . request = request ;
send _args . success = success ;
send _args . error = error ;
} ;
// Run the actual code here.
test _params . run _code ( ) ;
assert ( socket _send _called ) ;
test _params . check _send _args ( send _args ) ;
}
( function test _transmit _message ( ) {
page _params . use _websockets = true ;
global . navigator . userAgent = 'unittest_transmit_message' ;
// Our request is mostly unimportant, except that the
// socket_user_agent field will be added.
var request = { foo : 'bar' } ;
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
var success _func _checked = false ;
var success = function ( ) {
success _func _checked = true ;
} ;
2017-07-07 03:59:08 +02:00
2017-07-14 19:30:23 +02:00
// Our error function gets wrapped, so we set up a real
// function to test the wrapping mechanism.
2017-07-07 03:59:08 +02:00
var error _func _checked = false ;
var error = function ( error _msg ) {
assert . equal ( error _msg , 'Error sending message: simulated_error' ) ;
error _func _checked = true ;
} ;
test _with _mock _socket ( {
run _code : function ( ) {
compose . transmit _message ( request , success , error ) ;
} ,
check _send _args : function ( send _args ) {
// The real code patches new data on the request, rather
// than making a copy, so we test both that it didn't
// clone the object and that it did add a field.
assert . equal ( send _args . request , request ) ;
assert . deepEqual ( send _args . request , {
foo : 'bar' ,
socket _user _agent : 'unittest_transmit_message' ,
} ) ;
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
send _args . success ( { } ) ;
assert ( success _func _checked ) ;
2017-07-07 03:59:08 +02:00
// Our error function does get wrapped, so we test by
// using socket.send's error callback, which should
// invoke our test error function via a wrapper
// function in the real code.
send _args . error ( 'response' , { msg : 'simulated_error' } ) ;
assert ( error _func _checked ) ;
} ,
} ) ;
} ( ) ) ;
2017-07-07 15:41:13 +02:00
( function test _update _fade ( ) {
var selector = '#stream,#subject,#private_message_recipient' ;
var keyup _handler _func = $ ( selector ) . get _on _handler ( 'keyup' ) ;
var set _focused _recipient _checked = false ;
var update _faded _messages _checked = false ;
global . compose _fade = {
set _focused _recipient : function ( msg _type ) {
assert . equal ( msg _type , 'private' ) ;
set _focused _recipient _checked = true ;
} ,
update _faded _messages : function ( ) {
update _faded _messages _checked = true ;
} ,
} ;
compose _state . set _message _type ( false ) ;
keyup _handler _func ( ) ;
assert ( ! set _focused _recipient _checked ) ;
assert ( ! update _faded _messages _checked ) ;
compose _state . set _message _type ( 'private' ) ;
keyup _handler _func ( ) ;
assert ( set _focused _recipient _checked ) ;
assert ( update _faded _messages _checked ) ;
} ( ) ) ;
2017-07-07 15:42:51 +02:00
( function test _trigger _submit _compose _form ( ) {
var prevent _default _checked = false ;
var compose _finish _checked = false ;
var e = {
preventDefault : function ( ) {
prevent _default _checked = true ;
} ,
} ;
compose . finish = function ( ) {
compose _finish _checked = true ;
} ;
var submit _handler = $ ( '#compose form' ) . get _on _handler ( 'submit' ) ;
submit _handler ( e ) ;
assert ( prevent _default _checked ) ;
assert ( compose _finish _checked ) ;
} ( ) ) ;
2017-07-08 00:06:38 +02:00
( function test _on _events ( ) {
( function test _usermention _completed _zulip _triggered ( ) {
var handler = $ ( document ) . get _on _handler ( 'usermention_completed.zulip' ) ;
var data = {
mentioned : {
email : 'foo@bar.com' ,
} ,
} ;
2017-07-09 14:13:42 +02:00
$ ( '#compose_invite_users .compose_invite_user' ) . length = 0 ;
function test _noop _case ( msg _type , is _zephyr _mirror , mentioned _full _name ) {
2017-07-08 00:06:38 +02:00
compose _state . set _message _type ( msg _type ) ;
page _params . realm _is _zephyr _mirror _realm = is _zephyr _mirror ;
data . mentioned . full _name = mentioned _full _name ;
handler ( { } , data ) ;
2017-07-09 14:13:42 +02:00
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , false ) ;
2017-07-08 00:06:38 +02:00
}
2017-07-09 14:13:42 +02:00
test _noop _case ( 'private' , true , 'everyone' ) ;
test _noop _case ( 'stream' , true , 'everyone' ) ;
test _noop _case ( 'stream' , false , 'everyone' ) ;
// Test mentioning a user that should gets a warning.
$ ( "#compose_invite_users" ) . hide ( ) ;
compose _state . set _message _type ( 'stream' ) ;
page _params . realm _is _zephyr _mirror _realm = false ;
var checks = [
( function ( ) {
var called ;
compose _fade . would _receive _message = function ( email ) {
called = true ;
assert . equal ( email , 'foo@bar.com' ) ;
return false ;
} ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
( function ( ) {
var called ;
templates . render = 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 ( ) {
var called ;
$ ( "#compose_invite_users" ) . append = function ( html ) {
called = true ;
assert . equal ( html , 'fake-compose-invite-user-template' ) ;
} ;
return function ( ) { assert ( called ) ; } ;
} ( ) ) ,
] ;
data = {
mentioned : {
email : 'foo@bar.com' ,
full _name : 'Foo Barson' ,
} ,
} ;
handler ( { } , data ) ;
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , true ) ;
_ . each ( checks , function ( f ) { f ( ) ; } ) ;
// Simulate that the row was added to the DOM.
var warning _row = $ ( '<warning row>' ) ;
var looked _for _existing ;
warning _row . data = function ( field ) {
assert . equal ( field , 'useremail' ) ;
looked _for _existing = true ;
return 'foo@bar.com' ;
} ;
var previous _users = $ ( '#compose_invite_users .compose_invite_user' ) ;
previous _users . length = 1 ;
previous _users [ 0 ] = warning _row ;
2017-07-10 14:50:37 +02:00
$ ( '#compose_invite_users' ) . hide ( ) ;
2017-07-09 14:13:42 +02:00
// Now try to mention the same person again. The template should
// not render.
templates . render = noop ;
handler ( { } , data ) ;
assert . equal ( $ ( '#compose_invite_users' ) . visible ( ) , true ) ;
assert ( looked _for _existing ) ;
2017-07-08 00:06:38 +02:00
} ( ) ) ;
2017-07-08 00:09:13 +02:00
2017-07-08 23:16:19 +02:00
var event ;
var container ;
var target ;
var container _removed ;
function setup _parents _and _mock _remove ( container _sel , target _sel , parent ) {
container = $ . create ( 'fake ' + container _sel ) ;
container _removed = false ;
2017-07-08 00:09:13 +02:00
container . remove = function ( ) {
container _removed = true ;
} ;
2017-07-08 23:16:19 +02:00
target = $ . create ( 'fake click target (' + target _sel + ')' ) ;
target . set _parents _result ( parent , container ) ;
2017-07-08 00:09:13 +02:00
2017-07-08 23:16:19 +02:00
event = {
preventDefault : noop ,
target : target ,
} ;
}
( function test _compose _all _everyone _confirm _clicked ( ) {
var handler = $ ( "#compose-all-everyone" )
. get _on _handler ( 'click' , '.compose-all-everyone-confirm' ) ;
setup _parents _and _mock _remove ( 'compose-all-everyone' ,
'compose-all-everyone' ,
'.compose-all-everyone' ) ;
2017-07-08 00:09:13 +02:00
$ ( "#compose-all-everyone" ) . show ( ) ;
$ ( "#send-status" ) . show ( ) ;
var compose _finish _checked = false ;
compose . finish = function ( ) {
compose _finish _checked = true ;
} ;
handler ( event ) ;
assert ( container _removed ) ;
assert ( compose _finish _checked ) ;
assert ( ! $ ( "#compose-all-everyone" ) . visible ( ) ) ;
assert ( ! $ ( "#send-status" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-08 00:11:52 +02:00
( function test _compose _invite _users _clicked ( ) {
var handler = $ ( "#compose_invite_users" )
. get _on _handler ( 'click' , '.compose_invite_link' ) ;
var subscription = {
stream _id : 102 ,
name : 'test' ,
subscribed : true ,
} ;
var invite _user _to _stream _called = false ;
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.
} ;
2017-07-08 23:16:19 +02:00
setup _parents _and _mock _remove ( '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
handler ( event ) ;
assert ( ! invite _user _to _stream _called ) ;
assert ( ! container _removed ) ;
// !sub will result false here and we check the failure code path.
blueslip . warn = function ( err _msg ) {
assert . equal ( err _msg , 'Stream no longer exists: no-stream' ) ;
} ;
$ ( '#stream' ) . val ( 'no-stream' ) ;
container . data = function ( field ) {
assert . equal ( field , 'useremail' ) ;
return 'foo@bar.com' ;
} ;
var invite _err _sel = '.compose_invite_user_error' ;
container . set _find _results ( invite _err _sel , $ ( invite _err _sel ) ) ;
2017-06-30 00:57:46 +02:00
target . prop ( 'disabled' , false ) ;
2017-07-08 00:11:52 +02:00
$ ( invite _err _sel ) . hide ( ) ;
handler ( event ) ;
assert ( $ ( invite _err _sel ) . visible ( ) ) ;
assert ( target . attr ( 'disabled' ) ) ;
assert ( ! invite _user _to _stream _called ) ;
assert ( ! container _removed ) ;
// !sub will result in true here and we check the success code path.
stream _data . add _sub ( 'test' , subscription ) ;
$ ( '#stream' ) . val ( 'test' ) ;
var all _invite _children _called = false ;
$ ( "#compose_invite_users" ) . children = function ( ) {
all _invite _children _called = true ;
return [ ] ;
} ;
$ ( "#compose_invite_users" ) . show ( ) ;
handler ( event ) ;
assert ( container _removed ) ;
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 ( ) {
var handler = $ ( "#compose_invite_users" )
. get _on _handler ( 'click' , '.compose_invite_close' ) ;
2017-07-08 23:16:19 +02:00
setup _parents _and _mock _remove ( 'compose_invite_users_close' ,
'compose_invite_close' ,
'.compose_invite_user' ) ;
2017-07-08 00:13:14 +02:00
var all _invite _children _called = false ;
$ ( "#compose_invite_users" ) . children = function ( ) {
all _invite _children _called = true ;
return [ ] ;
} ;
$ ( "#compose_invite_users" ) . show ( ) ;
handler ( event ) ;
assert ( container _removed ) ;
assert ( all _invite _children _called ) ;
assert ( ! $ ( "#compose_invite_users" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-08 00:22:11 +02:00
2017-07-08 23:16:19 +02:00
event = {
2017-07-08 00:22:11 +02:00
preventDefault : noop ,
} ;
( function test _attach _files _compose _clicked ( ) {
var handler = $ ( "#compose" )
. get _on _handler ( "click" , "#attach_files" ) ;
$ ( '#file_input' ) . clone = function ( param ) {
assert ( param ) ;
} ;
var compose _file _input _clicked = false ;
$ ( '#compose #file_input' ) . trigger = function ( ev _name ) {
assert . equal ( ev _name , 'click' ) ;
compose _file _input _clicked = true ;
} ;
handler ( event ) ;
assert ( compose _file _input _clicked ) ;
} ( ) ) ;
2017-07-08 01:21:20 +02:00
( function test _markdown _preview _compose _clicked ( ) {
// Tests setup
function setup _visibilities ( ) {
$ ( "#new_message_content" ) . show ( ) ;
$ ( "#markdown_preview" ) . show ( ) ;
$ ( "#undo_markdown_preview" ) . hide ( ) ;
$ ( "#preview_message_area" ) . hide ( ) ;
}
function assert _visibilities ( ) {
assert ( ! $ ( "#new_message_content" ) . visible ( ) ) ;
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 ;
} ;
}
function test _post _success ( success _callback ) {
var resp = {
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 ( ) ,
'translated: Failed to generate preview' ) ;
}
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 ) {
var destroy _indicator _called = false ;
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 ) ;
} ;
}
var handler = $ ( "#compose" )
. get _on _handler ( "click" , "#markdown_preview" ) ;
// Tests start here
$ ( "#new_message_content" ) . val ( '' ) ;
setup _visibilities ( ) ;
handler ( event ) ;
assert . equal ( $ ( "#preview_content" ) . html ( ) ,
'translated: Nothing to preview' ) ;
assert _visibilities ( ) ;
var make _indicator _called = false ;
$ ( "#new_message_content" ) . val ( '```foobarfoobar```' ) ;
setup _visibilities ( ) ;
2017-07-29 02:51:33 +02:00
setup _mock _markdown _contains _backend _only _syntax ( '```foobarfoobar```' , true ) ;
2017-07-08 01:21:20 +02:00
loading . make _indicator = function ( spinner ) {
assert . equal ( spinner , $ ( "#markdown_preview_spinner" ) ) ;
make _indicator _called = true ;
} ;
mock _channel _post ( '```foobarfoobar```' ) ;
handler ( event ) ;
assert ( make _indicator _called ) ;
assert _visibilities ( ) ;
var apply _markdown _called = false ;
$ ( "#new_message_content" ) . val ( 'foobarfoobar' ) ;
setup _visibilities ( ) ;
2017-07-29 02:51:33 +02:00
setup _mock _markdown _contains _backend _only _syntax ( '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 ( ) ,
'Server: foobarfoobar' ) ;
} ( ) ) ;
2017-07-08 01:27:11 +02:00
( function test _undo _markdown _preview _clicked ( ) {
var handler = $ ( "#compose" )
. get _on _handler ( "click" , "#undo_markdown_preview" ) ;
$ ( "#new_message_content" ) . hide ( ) ;
$ ( "#undo_markdown_preview" ) . show ( ) ;
$ ( "#preview_message_area" ) . show ( ) ;
$ ( "#markdown_preview" ) . hide ( ) ;
handler ( event ) ;
assert ( $ ( "#new_message_content" ) . visible ( ) ) ;
assert ( ! $ ( "#undo_markdown_preview" ) . visible ( ) ) ;
assert ( ! $ ( "#preview_message_area" ) . visible ( ) ) ;
assert ( $ ( "#markdown_preview" ) . visible ( ) ) ;
} ( ) ) ;
2017-07-14 19:30:23 +02:00
2017-07-08 00:06:38 +02:00
} ( ) ) ;
2017-07-08 01:46:12 +02:00
( function test _upload _started ( ) {
2017-06-30 00:57:46 +02:00
$ ( "#compose-send-button" ) . prop ( 'disabled' , false ) ;
2017-07-08 01:46:12 +02:00
$ ( "#send-status" ) . removeClass ( "alert-info" ) . hide ( ) ;
$ ( ".send-status-close" ) . one = function ( ev _name , handler ) {
assert . equal ( ev _name , 'click' ) ;
assert ( handler ) ;
} ;
$ ( "#error-msg" ) . html ( '' ) ;
var test _html = '<div class="progress progress-striped active">' +
'<div class="bar" id="upload-bar" style="width: 00%;">' +
'</div></div>' ;
$ ( "<p>" ) . after = function ( html ) {
assert . equal ( html , test _html ) ;
return 'fake-html' ;
} ;
compose . uploadStarted ( ) ;
assert . equal ( $ ( "#compose-send-button" ) . attr ( "disabled" ) , '' ) ;
assert ( $ ( "#send-status" ) . hasClass ( "alert-info" ) ) ;
assert ( $ ( "#send-status" ) . visible ( ) ) ;
assert . equal ( $ ( "<p>" ) . text ( ) , 'translated: Uploading…' ) ;
assert . equal ( $ ( "#error-msg" ) . html ( ) , 'fake-html' ) ;
} ( ) ) ;
2017-07-08 01:51:08 +02:00
( function test _progress _updated ( ) {
var width _update _checked = false ;
$ ( "#upload-bar" ) . width = function ( width _percent ) {
assert . equal ( width _percent , '39%' ) ;
width _update _checked = true ;
} ;
compose . progressUpdated ( 1 , '' , 39 ) ;
assert ( width _update _checked ) ;
} ( ) ) ;
2017-07-08 02:07:40 +02:00
( function test _upload _error ( ) {
function setup _test ( ) {
$ ( "#send-status" ) . removeClass ( "alert-error" ) ;
$ ( "#send-status" ) . addClass ( "alert-info" ) ;
$ ( "#compose-send-button" ) . attr ( "disabled" , 'disabled' ) ;
$ ( "#error-msg" ) . text ( '' ) ;
}
2017-09-05 18:16:40 +02:00
function assert _side _effects ( msg , check _html = false ) {
2017-07-08 02:07:40 +02:00
assert ( $ ( "#send-status" ) . hasClass ( "alert-error" ) ) ;
assert ( ! $ ( "#send-status" ) . hasClass ( "alert-info" ) ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( "disabled" ) , false ) ;
2017-09-05 18:16:40 +02:00
if ( check _html ) {
assert . equal ( $ ( "#error-msg" ) . html ( ) , msg ) ;
} else {
assert . equal ( $ ( "#error-msg" ) . text ( ) , msg ) ;
}
2017-07-08 02:07:40 +02:00
}
function test ( err , file , msg ) {
setup _test ( ) ;
compose . uploadError ( err , file ) ;
2017-09-05 18:16:40 +02:00
// The text function and html function in zjquery is not in sync
// with each other. QuotaExceeded changes html while all other errors
// changes body.
if ( err === 'QuotaExceeded' ) {
assert _side _effects ( msg , true ) ;
} else {
assert _side _effects ( msg ) ;
}
2017-07-08 02:07:40 +02:00
}
var msg _prefix = 'translated: ' ;
var msg _1 = 'File upload is not yet available for your browser.' ;
var msg _2 = 'Unable to upload that many files at once.' ;
var msg _3 = '"foobar.txt" was too large; the maximum file size is 25MiB.' ;
var msg _4 = 'Sorry, the file was too large.' ;
2017-09-05 18:16:40 +02:00
var msg _5 = 'Upload would exceed your maximum quota. You can delete old attachments to ' +
'free up space. <a href="#settings/uploaded-files">translated: Click here</a>' ;
2017-07-08 02:07:40 +02:00
var msg _6 = 'An unknown error occurred.' ;
test ( 'BrowserNotSupported' , { } , msg _prefix + msg _1 ) ;
test ( 'TooManyFiles' , { } , msg _prefix + msg _2 ) ;
test ( 'FileTooLarge' , { name : 'foobar.txt' } , msg _prefix + msg _3 ) ;
test ( 'REQUEST ENTITY TOO LARGE' , { } , msg _prefix + msg _4 ) ;
test ( 'QuotaExceeded' , { } , msg _prefix + msg _5 ) ;
test ( 'Do-not-match-any-case' , { } , msg _prefix + msg _6 ) ;
} ( ) ) ;
2017-07-08 08:58:41 +02:00
( function test _upload _finish ( ) {
function test ( i , response , textbox _val ) {
var compose _ui _autosize _textarea _checked = false ;
var compose _actions _start _checked = false ;
var clear _out _file _input _triggered = false ;
function setup _clearout _file _list _func ( ) {
var event = {
preventDefault : noop ,
} ;
$ ( '#compose #file_input' ) . trigger = noop ;
var handler = $ ( "#compose" )
. get _on _handler ( "click" , "#attach_files" ) ;
handler ( event ) ;
$ ( '#file_input' ) . replaceWith = function ( ele ) {
assert . equal ( ele , $ ( '#file_input' ) ) ;
clear _out _file _input _triggered = true ;
} ;
}
function setup ( ) {
$ ( "#new_message_content" ) . val ( '' ) ;
compose _ui . autosize _textarea = function ( ) {
compose _ui _autosize _textarea _checked = true ;
} ;
compose _state . set _message _type ( ) ;
global . compose _actions = {
start : function ( msg _type ) {
assert . equal ( msg _type , 'stream' ) ;
compose _actions _start _checked = true ;
} ,
} ;
$ ( "#compose-send-button" ) . attr ( 'disabled' , 'disabled' ) ;
$ ( "#send-status" ) . addClass ( "alert-info" ) ;
$ ( "#send-status" ) . show ( ) ;
$ ( '#file_input' ) . clone = function ( param ) {
assert ( param ) ;
return $ ( '#file_input' ) ;
} ;
setup _clearout _file _list _func ( ) ;
}
function assert _side _effects ( ) {
assert . equal ( $ ( "#new_message_content" ) . val ( ) , textbox _val ) ;
if ( response . uri ) {
assert ( compose _actions _start _checked ) ;
assert ( compose _ui _autosize _textarea _checked ) ;
2017-06-30 00:57:46 +02:00
assert . equal ( $ ( "#compose-send-button" ) . prop ( 'disabled' ) , false ) ;
2017-07-08 08:58:41 +02:00
assert ( ! $ ( '#send-status' ) . hasClass ( 'alert-info' ) ) ;
assert ( ! $ ( '#send-status' ) . visible ( ) ) ;
assert ( clear _out _file _input _triggered ) ;
}
}
setup ( ) ;
compose . uploadFinished ( i , { } , response ) ;
assert _side _effects ( ) ;
}
var msg _1 = '[pasted image](https://foo.com/uploads/122456) ' ;
var msg _2 = '[foobar.jpeg](https://foo.com/user_uploads/foobar.jpeg) ' ;
test ( - 1 , { } , '' ) ;
test ( - 1 , { uri : 'https://foo.com/uploads/122456' } , msg _1 ) ;
test ( 1 , { uri : '/user_uploads/foobar.jpeg' } , msg _2 ) ;
} ( ) ) ;
2017-02-24 16:18:56 +01:00
( function test _set _focused _recipient ( ) {
var sub = {
stream _id : 101 ,
name : 'social' ,
subscribed : true ,
} ;
stream _data . add _sub ( 'social' , sub ) ;
var page = {
'#stream' : 'social' ,
'#subject' : 'lunch' ,
'#new_message_content' : 'burrito' ,
'#private_message_recipient' : 'alice@example.com, bob@example.com' ,
} ;
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 ;
} ;
2017-03-29 08:54:26 +02:00
var message = compose . create _message _object ( ) ;
2017-02-24 16:18:56 +01:00
assert . equal ( message . to , 'social' ) ;
assert . equal ( message . subject , 'lunch' ) ;
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' ;
} ;
2017-03-29 08:54:26 +02:00
message = compose . create _message _object ( ) ;
2017-02-24 16:18:56 +01:00
assert . deepEqual ( message . to , [ 'alice@example.com' , 'bob@example.com' ] ) ;
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' ) ;
} ( ) ) ;