chatroom.js 19.6 KB
Newer Older
1 2
(function (root, factory) {
    define([
3 4 5 6
        "mock",
        "utils"
        ], function (mock, utils) {
            return factory(mock, utils);
7 8
        }
    );
9
} (this, function (mock, utils) {
10
    return describe("ChatRooms", $.proxy(function (mock, utils) {
11
        describe("A Chat Room", $.proxy(function () {
12
            beforeEach(function () {
13 14 15 16 17 18 19 20 21 22 23
                runs(function () {
                    utils.closeAllChatBoxes();
                });
                waits(250);
                runs(function () {
                    utils.openControlBox();
                });
                waits(250);
                runs(function () {
                    utils.openRoomsPanel();
                });
JC Brand's avatar
JC Brand committed
24
                waits(501);
25 26
                runs(function () {
                    // Open a new chatroom
27
                    var roomspanel = converse.chatboxviews.get('controlbox').roomspanel;
28 29 30 31 32 33 34 35 36 37 38 39 40 41
                    var $input = roomspanel.$el.find('input.new-chatroom-name');
                    var $nick = roomspanel.$el.find('input.new-chatroom-nick');
                    var $server = roomspanel.$el.find('input.new-chatroom-server');
                    $input.val('lounge');
                    $nick.val('dummy');
                    $server.val('muc.localhost');
                    roomspanel.$el.find('form').submit();
                });
                waits(250);
                runs(function () {
                    utils.closeControlBox();
                });
                waits(250);
                runs(function () {});
42 43
            });

44
            it("shows users currently present in the room", $.proxy(function () {
45
                var chatroomview = this.chatboxviews.get('lounge@muc.localhost'),
JC Brand's avatar
JC Brand committed
46
                    $participant_list;
47
                var roster = {}, room = {}, i;
48 49
                for (i=0; i<mock.chatroom_names.length-1; i++) {
                    roster[mock.chatroom_names[i]] = {};
50
                    chatroomview.onChatRoomRoster(roster, room);
JC Brand's avatar
JC Brand committed
51
                    $participant_list = chatroomview.$el.find('.participant-list');
52
                    expect($participant_list.find('li').length).toBe(1+i);
53
                    expect($($participant_list.find('li')[i]).text()).toBe(mock.chatroom_names[i]);
54 55 56 57 58
                }
                roster[converse.bare_jid] = {};
                chatroomview.onChatRoomRoster(roster, room);
            }, converse));

59
            it("indicates moderators by means of a special css class and tooltip", $.proxy(function () {
60
                var chatroomview = this.chatboxviews.get('lounge@muc.localhost');
61 62 63
                var roster = {}, idx = mock.chatroom_names.length-1;
                roster[mock.chatroom_names[idx]] = {};
                roster[mock.chatroom_names[idx]].role = 'moderator';
64
                chatroomview.onChatRoomRoster(roster, {});
JC Brand's avatar
JC Brand committed
65
                var occupant = chatroomview.$el.find('.participant-list').find('li');
66
                expect(occupant.length).toBe(1);
67
                expect($(occupant).text()).toBe(mock.chatroom_names[idx]);
68 69 70 71
                expect($(occupant).attr('class')).toBe('moderator');
                expect($(occupant).attr('title')).toBe('This user is a moderator');
            }, converse));

72 73
            it("shows received groupchat messages", $.proxy(function () {
                spyOn(converse, 'emit');
74
                var view = this.chatboxviews.get('lounge@muc.localhost');
JC Brand's avatar
JC Brand committed
75
                if (!view.$el.find('.chat-area').length) { view.renderChatArea(); }
76
                var nick = mock.chatroom_names[0];
JC Brand's avatar
JC Brand committed
77 78 79 80 81 82 83 84 85 86 87
                var text = 'This is a received message';
                var message = $msg({
                    from: 'lounge@muc.localhost/'+nick,
                    id: '1',
                    to: 'dummy@localhost',
                    type: 'groupchat'
                }).c('body').t(text);
                view.onChatRoomMessage(message.nodeTree);
                var $chat_content = view.$el.find('.chat-content');
                expect($chat_content.find('.chat-message').length).toBe(1);
                expect($chat_content.find('.chat-message-content').text()).toBe(text);
88 89 90 91 92
                expect(converse.emit).toHaveBeenCalledWith('onMessage', message.nodeTree);
            }, converse));

            it("shows sent groupchat messages", $.proxy(function () {
                spyOn(converse, 'emit');
93
                var view = this.chatboxviews.get('lounge@muc.localhost');
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
                if (!view.$el.find('.chat-area').length) { view.renderChatArea(); }
                var nick = mock.chatroom_names[0];
                var text = 'This is a sent message';
                view.$el.find('.chat-textarea').text(text);
                view.$el.find('textarea.chat-textarea').trigger($.Event('keypress', {keyCode: 13}));
                expect(converse.emit).toHaveBeenCalledWith('onMessageSend', text);

                var message = $msg({
                    from: 'lounge@muc.localhost/dummy',
                    id: '2',
                    to: 'dummy@localhost.com',
                    type: 'groupchat'
                }).c('body').t(text);
                view.onChatRoomMessage(message.nodeTree);
                var $chat_content = view.$el.find('.chat-content');
                expect($chat_content.find('.chat-message').length).toBe(1);
                expect($chat_content.find('.chat-message-content').last().text()).toBe(text);
                // We don't emit an event if it's our own message
                expect(converse.emit.callCount, 1);
JC Brand's avatar
JC Brand committed
113 114
            }, converse));

115 116 117
            it("can be saved to, and retrieved from, localStorage", $.proxy(function () {
                // We instantiate a new ChatBoxes collection, which by default
                // will be empty.
JC Brand's avatar
JC Brand committed
118
                utils.openControlBox();
119 120 121 122 123
                var newchatboxes = new this.ChatBoxes();
                expect(newchatboxes.length).toEqual(0);
                // The chatboxes will then be fetched from localStorage inside the
                // onConnected method
                newchatboxes.onConnected();
JC Brand's avatar
JC Brand committed
124
                expect(newchatboxes.length).toEqual(2); // XXX: Includes controlbox, is this a bug?
125 126 127 128 129 130
                // Check that the chatrooms retrieved from localStorage
                // have the same attributes values as the original ones.
                attrs = ['id', 'box_id', 'visible'];
                for (i=0; i<attrs.length; i++) {
                    new_attrs = _.pluck(_.pluck(newchatboxes.models, 'attributes'), attrs[i]);
                    old_attrs = _.pluck(_.pluck(this.chatboxes.models, 'attributes'), attrs[i]);
JC Brand's avatar
JC Brand committed
131 132 133 134 135
                    // FIXME: should have have to sort here? Order must
                    // probably be the same...
                    // This should be fixed once the controlbox always opens
                    // only on the right.
                    expect(_.isEqual(new_attrs.sort(), old_attrs.sort())).toEqual(true);
136 137 138 139
                }
                this.rosterview.render();
            }, converse));

JC Brand's avatar
JC Brand committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
            it("can be toggled by clicking a DOM element with class 'toggle-chatbox-button'", function () {
                var view = this.chatboxviews.get('lounge@muc.localhost'),
                    chatroom = view.model, $el;
                spyOn(view, 'toggleChatBox').andCallThrough();
                spyOn(converse, 'emit');
                view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
                runs(function () {
                    view.$el.find('.toggle-chatbox-button').click();
                });
                waits(250);
                runs(function () {
                    expect(view.toggleChatBox).toHaveBeenCalled();
                    expect(converse.emit).toHaveBeenCalledWith('onChatBoxToggled', jasmine.any(Object));
                    expect(converse.emit.callCount, 2);
                    expect(view.$el.find('.chat-body').is(':visible')).toBeFalsy();
                    expect(view.$el.find('.toggle-chatbox-button').hasClass('icon-minus')).toBeFalsy();
                    expect(view.$el.find('.toggle-chatbox-button').hasClass('icon-plus')).toBeTruthy();
                    expect(view.model.get('minimized')).toBeTruthy();
                    view.$el.find('.toggle-chatbox-button').click();
                });
                waits(250);
                runs(function () {
                    expect(view.toggleChatBox).toHaveBeenCalled();
                    expect(converse.emit).toHaveBeenCalledWith('onChatBoxToggled', jasmine.any(Object));
                    expect(view.$el.find('.chat-body').is(':visible')).toBeTruthy();
                    expect(view.$el.find('.toggle-chatbox-button').hasClass('icon-minus')).toBeTruthy();
                    expect(view.$el.find('.toggle-chatbox-button').hasClass('icon-plus')).toBeFalsy();
                    expect(view.model.get('minimized')).toBeFalsy();
                    expect(converse.emit.callCount, 3);
                });
            }.bind(converse));


173
            it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", $.proxy(function () {
174
                var view = this.chatboxviews.get('lounge@muc.localhost'), chatroom = view.model, $el;
175
                spyOn(view, 'closeChat').andCallThrough();
176
                spyOn(converse, 'emit');
177 178
                spyOn(converse.connection.muc, 'leave');
                view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
179 180 181 182 183 184 185 186 187
                runs(function () {
                    view.$el.find('.close-chatbox-button').click();
                });
                waits(250);
                runs(function () {
                    expect(view.closeChat).toHaveBeenCalled();
                    expect(this.connection.muc.leave).toHaveBeenCalled();
                    expect(this.emit).toHaveBeenCalledWith('onChatBoxClosed', jasmine.any(Object));
                }.bind(converse));
188 189 190 191 192
            }, converse));
        }, converse));

        describe("When attempting to enter a chatroom", $.proxy(function () {
            beforeEach($.proxy(function () {
193
                var roomspanel = this.chatboxviews.get('controlbox').roomspanel;
194
                var $input = roomspanel.$el.find('input.new-chatroom-name');
195
                var $nick = roomspanel.$el.find('input.new-chatroom-nick');
196 197
                var $server = roomspanel.$el.find('input.new-chatroom-server');
                $input.val('problematic');
198
                $nick.val('dummy');
199 200 201 202 203
                $server.val('muc.localhost');
                roomspanel.$el.find('form').submit();
            }, converse));

            afterEach($.proxy(function () {
204
                var view = this.chatboxviews.get('problematic@muc.localhost');
205 206 207 208 209
                view.closeChat();
            }, converse));

            it("will show an error message if the room requires a password", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
210 211 212 213
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
214 215 216
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'auth'})
                    .c('not-authorized').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
JC Brand's avatar
JC Brand committed
217

218
                var view = this.chatboxviews.get('problematic@muc.localhost');
JC Brand's avatar
JC Brand committed
219 220 221 222 223 224 225 226 227
                spyOn(view, 'renderPasswordForm').andCallThrough();
                runs(function () {
                    view.onChatRoomPresence(presence, {'nick': 'dummy'});
                });
                waits(250);
                runs(function () {
                    var $chat_body = view.$el.find('.chat-body');
                    expect(view.renderPasswordForm).toHaveBeenCalled();
                    expect($chat_body.find('form.chatroom-form').length).toBe(1);
JC Brand's avatar
JC Brand committed
228
                    expect($chat_body.find('legend').text()).toBe('This chatroom requires a password');
JC Brand's avatar
JC Brand committed
229
                });
230 231 232 233
            }, converse));

            it("will show an error message if the room is members-only and the user not included", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
234 235 236 237
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
238 239 240
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'auth'})
                    .c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
241
                var view = this.chatboxviews.get('problematic@muc.localhost');
242
                spyOn(view, 'showErrorMessage').andCallThrough();
243
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
244
                expect(view.$el.find('.chat-body p').text()).toBe('You are not on the member list of this room');
245 246 247 248
            }, converse));

            it("will show an error message if the user has been banned", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
249 250 251 252
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
253 254 255
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'auth'})
                    .c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
256
                var view = this.chatboxviews.get('problematic@muc.localhost');
257
                spyOn(view, 'showErrorMessage').andCallThrough();
258
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
259
                expect(view.$el.find('.chat-body p').text()).toBe('You have been banned from this room');
260 261 262 263
            }, converse));

            it("will show an error message if no nickname was specified for the user", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
264 265 266 267
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
268 269 270
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'modify'})
                    .c('jid-malformed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
271
                var view = this.chatboxviews.get('problematic@muc.localhost');
272
                spyOn(view, 'showErrorMessage').andCallThrough();
273
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
274
                expect(view.$el.find('.chat-body p').text()).toBe('No nickname was specified');
275 276 277 278
            }, converse));

            it("will show an error message if the user is not allowed to have created the room", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
279 280 281 282
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
283 284 285
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'cancel'})
                    .c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
286
                var view = this.chatboxviews.get('problematic@muc.localhost');
287
                spyOn(view, 'showErrorMessage').andCallThrough();
288
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
289
                expect(view.$el.find('.chat-body p').text()).toBe('You are not allowed to create new rooms');
290 291 292 293
            }, converse));

            it("will show an error message if the user's nickname doesn't conform to room policy", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
294 295 296 297
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
298 299 300
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'cancel'})
                    .c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
301
                var view = this.chatboxviews.get('problematic@muc.localhost');
302
                spyOn(view, 'showErrorMessage').andCallThrough();
303
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
304
                expect(view.$el.find('.chat-body p').text()).toBe("Your nickname doesn't conform to this room's policies");
305 306 307 308
            }, converse));

            it("will show an error message if the user's nickname is already taken", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
309 310 311 312
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
313 314 315
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'cancel'})
                    .c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
316
                var view = this.chatboxviews.get('problematic@muc.localhost');
317
                spyOn(view, 'showErrorMessage').andCallThrough();
318
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
319
                expect(view.$el.find('.chat-body p').text()).toBe("Your nickname is already taken");
320 321 322 323
            }, converse));

            it("will show an error message if the room doesn't yet exist", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
324 325 326 327
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
328 329 330
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'cancel'})
                    .c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
331
                var view = this.chatboxviews.get('problematic@muc.localhost');
332
                spyOn(view, 'showErrorMessage').andCallThrough();
333
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
334
                expect(view.$el.find('.chat-body p').text()).toBe("This room does not (yet) exist");
335 336 337 338
            }, converse));

            it("will show an error message if the room has reached it's maximum number of occupants", $.proxy(function () {
                var presence = $pres().attrs({
JC Brand's avatar
JC Brand committed
339 340 341 342
                    from:'coven@chat.shakespeare.lit/thirdwitch',
                        id:'n13mt3l',
                        to:'hag66@shakespeare.lit/pda',
                        type:'error'})
343 344 345
                .c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
                .c('error').attrs({by:'coven@chat.shakespeare.lit', type:'cancel'})
                    .c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
346
                var view = this.chatboxviews.get('problematic@muc.localhost');
347
                spyOn(view, 'showErrorMessage').andCallThrough();
348
                view.onChatRoomPresence(presence, {'nick': 'dummy'});
JC Brand's avatar
JC Brand committed
349
                expect(view.$el.find('.chat-body p').text()).toBe("This room has reached it's maximum number of occupants");
350 351
            }, converse));
        }, converse));
352
    }, converse, mock, utils));
353
}));