Parcourir la source

Move correections tests into a separate file

JC Brand il y a 4 ans
Parent
commit
ae7b29cb90
4 fichiers modifiés avec 625 ajouts et 612 suppressions
  1. 1 0
      karma.conf.js
  2. 624 0
      spec/corrections.js
  3. 0 344
      spec/messages.js
  4. 0 268
      spec/muc_messages.js

+ 1 - 0
karma.conf.js

@@ -46,6 +46,7 @@ module.exports = function(config) {
       { pattern: "spec/chatbox.js", type: 'module' },
       { pattern: "spec/user-details-modal.js", type: 'module' },
       { pattern: "spec/messages.js", type: 'module' },
+      { pattern: "spec/corrections.js", type: 'module' },
       { pattern: "spec/receipts.js", type: 'module' },
       { pattern: "spec/muc_messages.js", type: 'module' },
       { pattern: "spec/mentions.js", type: 'module' },

+ 624 - 0
spec/corrections.js

@@ -0,0 +1,624 @@
+/*global mock, converse */
+
+const { Promise, $msg, $pres, Strophe, sizzle } = converse.env;
+const u = converse.env.utils;
+
+describe("A Chat Message", function () {
+
+    it("can be sent as a correction by using the up arrow",
+        mock.initConverse(
+            ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+            async function (done, _converse) {
+
+        await mock.waitForRoster(_converse, 'current', 1);
+        await mock.openControlBox(_converse);
+        const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+        await mock.openChatBoxFor(_converse, contact_jid)
+        const view = _converse.api.chatviews.get(contact_jid);
+        const textarea = view.el.querySelector('textarea.chat-textarea');
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('');
+
+        textarea.value = 'But soft, what light through yonder airlock breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        expect(view.el.querySelector('.chat-msg__text').textContent)
+            .toBe('But soft, what light through yonder airlock breaks?');
+
+        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
+
+        spyOn(_converse.connection, 'send');
+        textarea.value = 'But soft, what light through yonder window breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        expect(_converse.connection.send).toHaveBeenCalled();
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+        const msg = _converse.connection.send.calls.all()[0].args[0];
+        expect(msg.toLocaleString())
+        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
+                `to="mercutio@montague.lit" type="chat" `+
+                `xmlns="jabber:client">`+
+                    `<body>But soft, what light through yonder window breaks?</body>`+
+                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
+                    `<request xmlns="urn:xmpp:receipts"/>`+
+                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
+                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
+            `</message>`);
+        expect(view.model.messages.models.length).toBe(1);
+        const corrected_message = view.model.messages.at(0);
+        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
+        expect(corrected_message.get('correcting')).toBe(false);
+
+        const older_versions = corrected_message.get('older_versions');
+        const keys = Object.keys(older_versions);
+        expect(keys.length).toBe(1);
+        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
+
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
+
+        // Test that pressing the down arrow cancels message correction
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 40 // Down arrow
+        });
+        expect(textarea.value).toBe('');
+        expect(view.model.messages.at(0).get('correcting')).toBe(false);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
+
+        textarea.value = 'It is the east, and Juliet is the one.';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+
+        textarea.value =  'Arise, fair sun, and kill the envious moon';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
+
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('Arise, fair sun, and kill the envious moon');
+        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
+        expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
+        expect(view.model.messages.at(2).get('correcting')).toBe(true);
+        await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg:last', view.el).pop()), 500);
+
+        textarea.selectionEnd = 0; // Happens by pressing up,
+                                // but for some reason not in tests, so we set it manually.
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('It is the east, and Juliet is the one.');
+        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
+        expect(view.model.messages.at(1).get('correcting')).toBe(true);
+        expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
+        await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg', view.el)[1]), 500);
+
+        textarea.value = 'It is the east, and Juliet is the sun.';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        await u.waitUntil(() => textarea.value === '');
+        const messages = view.el.querySelectorAll('.chat-msg');
+        expect(messages.length).toBe(3);
+        expect(messages[0].querySelector('.chat-msg__text').textContent)
+            .toBe('But soft, what light through yonder window breaks?');
+        expect(messages[1].querySelector('.chat-msg__text').textContent)
+            .toBe('It is the east, and Juliet is the sun.');
+        expect(messages[2].querySelector('.chat-msg__text').textContent)
+            .toBe('Arise, fair sun, and kill the envious moon');
+
+        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
+        expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
+        expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
+        done();
+    }));
+
+
+    it("can be sent as a correction by clicking the pencil icon",
+        mock.initConverse(
+            ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+            async function (done, _converse) {
+
+        await mock.waitForRoster(_converse, 'current', 1);
+        await mock.openControlBox(_converse);
+        const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+        await mock.openChatBoxFor(_converse, contact_jid);
+        const view = _converse.api.chatviews.get(contact_jid);
+        const textarea = view.el.querySelector('textarea.chat-textarea');
+
+        textarea.value = 'But soft, what light through yonder airlock breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        expect(view.el.querySelector('.chat-msg__text').textContent)
+            .toBe('But soft, what light through yonder airlock breaks?');
+        expect(textarea.value).toBe('');
+
+        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .chat-msg__action').length === 2);
+        let action = view.el.querySelector('.chat-msg .chat-msg__action');
+        expect(action.textContent.trim()).toBe('Edit');
+
+        action.style.opacity = 1;
+        action.click();
+
+        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
+
+        spyOn(_converse.connection, 'send');
+        textarea.value = 'But soft, what light through yonder window breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        expect(_converse.connection.send).toHaveBeenCalled();
+
+        const msg = _converse.connection.send.calls.all()[0].args[0];
+        expect(msg.toLocaleString())
+        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
+                `to="mercutio@montague.lit" type="chat" `+
+                `xmlns="jabber:client">`+
+                    `<body>But soft, what light through yonder window breaks?</body>`+
+                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
+                    `<request xmlns="urn:xmpp:receipts"/>`+
+                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
+                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
+            `</message>`);
+        expect(view.model.messages.models.length).toBe(1);
+        const corrected_message = view.model.messages.at(0);
+        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
+        expect(corrected_message.get('correcting')).toBe(false);
+
+        const older_versions = corrected_message.get('older_versions');
+        const keys = Object.keys(older_versions);
+        expect(keys.length).toBe(1);
+        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
+
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+
+        // Test that clicking the pencil icon a second time cancels editing.
+        action = view.el.querySelector('.chat-msg .chat-msg__action');
+        action.style.opacity = 1;
+        action.click();
+
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === true);
+
+        action = view.el.querySelector('.chat-msg .chat-msg__action');
+        action.style.opacity = 1;
+        action.click();
+        expect(textarea.value).toBe('');
+        expect(view.model.messages.at(0).get('correcting')).toBe(false);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
+
+        // Test that messages from other users don't have the pencil icon
+        _converse.handleMessageStanza(
+            $msg({
+                'from': contact_jid,
+                'to': _converse.connection.jid,
+                'type': 'chat',
+                'id': u.getUniqueId()
+            }).c('body').t('Hello').up()
+            .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()
+        );
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(2);
+
+        // Test confirmation dialog
+        spyOn(window, 'confirm').and.returnValue(true);
+        textarea.value = 'But soft, what light through yonder airlock breaks?';
+        action = view.el.querySelector('.chat-msg .chat-msg__action');
+        action.style.opacity = 1;
+        action.click();
+        expect(window.confirm).toHaveBeenCalledWith(
+            'You have an unsent message which will be lost if you continue. Are you sure?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+
+        textarea.value = 'But soft, what light through yonder airlock breaks?'
+        action.click();
+        expect(view.model.messages.at(0).get('correcting')).toBe(false);
+        expect(window.confirm.calls.count()).toBe(2);
+        expect(window.confirm.calls.argsFor(0)).toEqual(
+            ['You have an unsent message which will be lost if you continue. Are you sure?']);
+        expect(window.confirm.calls.argsFor(1)).toEqual(
+            ['You have an unsent message which will be lost if you continue. Are you sure?']);
+        done();
+    }));
+
+
+    describe("when received from someone else", function () {
+
+        it("can be replaced with a correction",
+            mock.initConverse(
+                ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+                async function (done, _converse) {
+
+            await mock.waitForRoster(_converse, 'current', 1);
+            await mock.openControlBox(_converse);
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const msg_id = u.getUniqueId();
+            const view = await mock.openChatBoxFor(_converse, sender_jid);
+            _converse.handleMessageStanza($msg({
+                    'from': sender_jid,
+                    'to': _converse.connection.jid,
+                    'type': 'chat',
+                    'id': msg_id,
+                }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
+            await new Promise(resolve => view.model.messages.once('rendered', resolve));
+            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+            expect(view.el.querySelector('.chat-msg__text').textContent)
+                .toBe('But soft, what light through yonder airlock breaks?');
+
+            _converse.handleMessageStanza($msg({
+                    'from': sender_jid,
+                    'to': _converse.connection.jid,
+                    'type': 'chat',
+                    'id': u.getUniqueId(),
+                }).c('body').t('But soft, what light through yonder chimney breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+            await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+            expect(view.el.querySelector('.chat-msg__text').textContent)
+                .toBe('But soft, what light through yonder chimney breaks?');
+            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+            expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
+            expect(view.model.messages.models.length).toBe(1);
+
+            _converse.handleMessageStanza($msg({
+                    'from': sender_jid,
+                    'to': _converse.connection.jid,
+                    'type': 'chat',
+                    'id': u.getUniqueId(),
+                }).c('body').t('But soft, what light through yonder window breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+            await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+            expect(view.el.querySelector('.chat-msg__text').textContent)
+                .toBe('But soft, what light through yonder window breaks?');
+            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+            expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
+            view.el.querySelector('.chat-msg__content .fa-edit').click();
+            const modal = await u.waitUntil(() => view.el.querySelector('converse-chat-message').message_versions_modal);
+            await u.waitUntil(() => u.isVisible(modal.el), 1000);
+            const older_msgs = modal.el.querySelectorAll('.older-msg');
+            expect(older_msgs.length).toBe(2);
+            expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
+            expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
+            expect(view.model.messages.models.length).toBe(1);
+            done();
+        }));
+    });
+});
+
+describe("A Groupchat Message", function () {
+
+    it("can be replaced with a correction",
+        mock.initConverse(
+            ['rosterGroupsFetched'], {},
+            async function (done, _converse) {
+
+        const muc_jid = 'lounge@montague.lit';
+        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+        const view = _converse.api.chatviews.get(muc_jid);
+        const stanza = $pres({
+                to: 'romeo@montague.lit/_converse.js-29092160',
+                from: 'coven@chat.shakespeare.lit/newguy'
+            })
+            .c('x', {xmlns: Strophe.NS.MUC_USER})
+            .c('item', {
+                'affiliation': 'none',
+                'jid': 'newguy@montague.lit/_converse.js-290929789',
+                'role': 'participant'
+            }).tree();
+        _converse.connection._dataRecv(mock.createRequest(stanza));
+        const msg_id = u.getUniqueId();
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': msg_id,
+            }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
+
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        expect(view.el.querySelector('.chat-msg__text').textContent)
+            .toBe('But soft, what light through yonder airlock breaks?');
+
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': u.getUniqueId(),
+            }).c('body').t('But soft, what light through yonder chimney breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
+            'But soft, what light through yonder chimney breaks?', 500);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
+
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': u.getUniqueId(),
+            }).c('body').t('But soft, what light through yonder window breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+
+        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
+            'But soft, what light through yonder window breaks?', 500);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
+        const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
+        edit.click();
+        const modal = await u.waitUntil(() => view.el.querySelector('converse-chat-message').message_versions_modal);
+        await u.waitUntil(() => u.isVisible(modal.el), 1000);
+        const older_msgs = modal.el.querySelectorAll('.older-msg');
+        expect(older_msgs.length).toBe(2);
+        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
+        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
+        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
+        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
+        done();
+    }));
+
+    it("keeps the same position in history after a correction",
+        mock.initConverse(
+            ['rosterGroupsFetched'], {},
+            async function (done, _converse) {
+
+        const muc_jid = 'lounge@montague.lit';
+        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+        const view = _converse.api.chatviews.get(muc_jid);
+        const stanza = $pres({
+                to: 'romeo@montague.lit/_converse.js-29092160',
+                from: 'coven@chat.shakespeare.lit/newguy'
+            })
+            .c('x', {xmlns: Strophe.NS.MUC_USER})
+            .c('item', {
+                'affiliation': 'none',
+                'jid': 'newguy@montague.lit/_converse.js-290929789',
+                'role': 'participant'
+            }).tree();
+        _converse.connection._dataRecv(mock.createRequest(stanza));
+        const msg_id = u.getUniqueId();
+
+        // Receiving the first message
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': msg_id,
+            }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
+
+        // Receiving own message to check order against
+        await view.model.handleMessageStanza($msg({
+            'from': 'lounge@montague.lit/romeo',
+            'to': _converse.connection.jid,
+            'type': 'groupchat',
+            'id': msg_id,
+        }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
+
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+        expect(view.el.querySelectorAll('.chat-msg__text')[0].textContent)
+            .toBe('But soft, what light through yonder airlock breaks?');
+        expect(view.el.querySelectorAll('.chat-msg__text')[1].textContent)
+        .toBe('But soft, what light through yonder airlock breaks?');
+
+        // First message correction
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': u.getUniqueId(),
+            }).c('body').t('But soft, what light through yonder chimney breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+
+        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
+            'But soft, what light through yonder chimney breaks?', 500);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+        await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
+
+        // Second message correction
+        await view.model.handleMessageStanza($msg({
+                'from': 'lounge@montague.lit/newguy',
+                'to': _converse.connection.jid,
+                'type': 'groupchat',
+                'id': u.getUniqueId(),
+            }).c('body').t('But soft, what light through yonder window breaks?').up()
+                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
+
+        // Second own message
+        await view.model.handleMessageStanza($msg({
+            'from': 'lounge@montague.lit/romeo',
+            'to': _converse.connection.jid,
+            'type': 'groupchat',
+            'id': u.getUniqueId(),
+        }).c('body').t('But soft, what light through yonder window breaks?').tree());
+
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[0].textContent ===
+            'But soft, what light through yonder window breaks?', 500);
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 3);
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[2].textContent ===
+            'But soft, what light through yonder window breaks?', 500);
+
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
+        expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
+        const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
+        edit.click();
+        const modal = await u.waitUntil(() => view.el.querySelectorAll('converse-chat-message')[0].message_versions_modal);
+        await u.waitUntil(() => u.isVisible(modal.el), 1000);
+        const older_msgs = modal.el.querySelectorAll('.older-msg');
+        expect(older_msgs.length).toBe(2);
+        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
+        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
+        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
+        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
+        done();
+    }));
+
+    it("can be sent as a correction by using the up arrow",
+        mock.initConverse(
+            ['rosterGroupsFetched'], {},
+            async function (done, _converse) {
+
+        const muc_jid = 'lounge@montague.lit';
+        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
+        const view = _converse.api.chatviews.get(muc_jid);
+        const textarea = view.el.querySelector('textarea.chat-textarea');
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('');
+
+        textarea.value = 'But soft, what light through yonder airlock breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
+        expect(view.el.querySelector('.chat-msg__text').textContent)
+            .toBe('But soft, what light through yonder airlock breaks?');
+
+        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
+
+        spyOn(_converse.connection, 'send');
+        textarea.value = 'But soft, what light through yonder window breaks?';
+        view.onKeyDown({
+            target: textarea,
+            preventDefault: function preventDefault () {},
+            keyCode: 13 // Enter
+        });
+        expect(_converse.connection.send).toHaveBeenCalled();
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+
+        const msg = _converse.connection.send.calls.all()[0].args[0];
+        expect(msg.toLocaleString())
+        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
+                `to="lounge@montague.lit" type="groupchat" `+
+                `xmlns="jabber:client">`+
+                    `<body>But soft, what light through yonder window breaks?</body>`+
+                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
+                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
+                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
+            `</message>`);
+
+        expect(view.model.messages.models.length).toBe(1);
+        const corrected_message = view.model.messages.at(0);
+        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
+        expect(corrected_message.get('correcting')).toBe(false);
+
+        const older_versions = corrected_message.get('older_versions');
+        const keys = Object.keys(older_versions);
+        expect(keys.length).toBe(1);
+        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
+
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
+        expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
+
+        // Check that messages from other users are skipped
+        await view.model.handleMessageStanza($msg({
+            'from': muc_jid+'/someone-else',
+            'id': u.getUniqueId(),
+            'to': 'romeo@montague.lit',
+            'type': 'groupchat'
+        }).c('body').t('Hello world').tree());
+        await new Promise(resolve => view.model.messages.once('rendered', resolve));
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+
+        // Test that pressing the down arrow cancels message correction
+        expect(textarea.value).toBe('');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 38 // Up arrow
+        });
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+        expect(view.model.messages.at(0).get('correcting')).toBe(true);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
+        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
+        view.onKeyDown({
+            target: textarea,
+            keyCode: 40 // Down arrow
+        });
+        expect(textarea.value).toBe('');
+        expect(view.model.messages.at(0).get('correcting')).toBe(false);
+        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
+        await u.waitUntil(() => !u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
+        done();
+    }));
+});

+ 0 - 344
spec/messages.js

@@ -78,289 +78,6 @@ describe("A Chat Message", function () {
         done();
     }));
 
-    it("can be sent as a correction by clicking the pencil icon",
-        mock.initConverse(
-            ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-            async function (done, _converse) {
-
-        await mock.waitForRoster(_converse, 'current', 1);
-        await mock.openControlBox(_converse);
-        const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
-        await mock.openChatBoxFor(_converse, contact_jid);
-        const view = _converse.api.chatviews.get(contact_jid);
-        const textarea = view.el.querySelector('textarea.chat-textarea');
-
-        textarea.value = 'But soft, what light through yonder airlock breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        expect(view.el.querySelector('.chat-msg__text').textContent)
-            .toBe('But soft, what light through yonder airlock breaks?');
-        expect(textarea.value).toBe('');
-
-        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg .chat-msg__action').length === 2);
-        let action = view.el.querySelector('.chat-msg .chat-msg__action');
-        expect(action.textContent.trim()).toBe('Edit');
-
-        action.style.opacity = 1;
-        action.click();
-
-        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
-
-        spyOn(_converse.connection, 'send');
-        textarea.value = 'But soft, what light through yonder window breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        expect(_converse.connection.send).toHaveBeenCalled();
-
-        const msg = _converse.connection.send.calls.all()[0].args[0];
-        expect(msg.toLocaleString())
-        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
-                `to="mercutio@montague.lit" type="chat" `+
-                `xmlns="jabber:client">`+
-                    `<body>But soft, what light through yonder window breaks?</body>`+
-                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
-                    `<request xmlns="urn:xmpp:receipts"/>`+
-                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
-                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
-            `</message>`);
-        expect(view.model.messages.models.length).toBe(1);
-        const corrected_message = view.model.messages.at(0);
-        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
-        expect(corrected_message.get('correcting')).toBe(false);
-
-        const older_versions = corrected_message.get('older_versions');
-        const keys = Object.keys(older_versions);
-        expect(keys.length).toBe(1);
-        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
-
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-
-        // Test that clicking the pencil icon a second time cancels editing.
-        action = view.el.querySelector('.chat-msg .chat-msg__action');
-        action.style.opacity = 1;
-        action.click();
-
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')) === true);
-
-        action = view.el.querySelector('.chat-msg .chat-msg__action');
-        action.style.opacity = 1;
-        action.click();
-        expect(textarea.value).toBe('');
-        expect(view.model.messages.at(0).get('correcting')).toBe(false);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
-
-        // Test that messages from other users don't have the pencil icon
-        _converse.handleMessageStanza(
-            $msg({
-                'from': contact_jid,
-                'to': _converse.connection.jid,
-                'type': 'chat',
-                'id': u.getUniqueId()
-            }).c('body').t('Hello').up()
-            .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree()
-        );
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        expect(view.el.querySelectorAll('.chat-msg .chat-msg__action').length).toBe(2);
-
-        // Test confirmation dialog
-        spyOn(window, 'confirm').and.returnValue(true);
-        textarea.value = 'But soft, what light through yonder airlock breaks?';
-        action = view.el.querySelector('.chat-msg .chat-msg__action');
-        action.style.opacity = 1;
-        action.click();
-        expect(window.confirm).toHaveBeenCalledWith(
-            'You have an unsent message which will be lost if you continue. Are you sure?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-
-        textarea.value = 'But soft, what light through yonder airlock breaks?'
-        action.click();
-        expect(view.model.messages.at(0).get('correcting')).toBe(false);
-        expect(window.confirm.calls.count()).toBe(2);
-        expect(window.confirm.calls.argsFor(0)).toEqual(
-            ['You have an unsent message which will be lost if you continue. Are you sure?']);
-        expect(window.confirm.calls.argsFor(1)).toEqual(
-            ['You have an unsent message which will be lost if you continue. Are you sure?']);
-        done();
-    }));
-
-
-    it("can be sent as a correction by using the up arrow",
-        mock.initConverse(
-            ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-            async function (done, _converse) {
-
-        await mock.waitForRoster(_converse, 'current', 1);
-        await mock.openControlBox(_converse);
-        const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
-        await mock.openChatBoxFor(_converse, contact_jid)
-        const view = _converse.api.chatviews.get(contact_jid);
-        const textarea = view.el.querySelector('textarea.chat-textarea');
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('');
-
-        textarea.value = 'But soft, what light through yonder airlock breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        expect(view.el.querySelector('.chat-msg__text').textContent)
-            .toBe('But soft, what light through yonder airlock breaks?');
-
-        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
-
-        spyOn(_converse.connection, 'send');
-        textarea.value = 'But soft, what light through yonder window breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        expect(_converse.connection.send).toHaveBeenCalled();
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-
-        const msg = _converse.connection.send.calls.all()[0].args[0];
-        expect(msg.toLocaleString())
-        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
-                `to="mercutio@montague.lit" type="chat" `+
-                `xmlns="jabber:client">`+
-                    `<body>But soft, what light through yonder window breaks?</body>`+
-                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
-                    `<request xmlns="urn:xmpp:receipts"/>`+
-                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
-                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
-            `</message>`);
-        expect(view.model.messages.models.length).toBe(1);
-        const corrected_message = view.model.messages.at(0);
-        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
-        expect(corrected_message.get('correcting')).toBe(false);
-
-        const older_versions = corrected_message.get('older_versions');
-        const keys = Object.keys(older_versions);
-        expect(keys.length).toBe(1);
-        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
-
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
-
-        // Test that pressing the down arrow cancels message correction
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 40 // Down arrow
-        });
-        expect(textarea.value).toBe('');
-        expect(view.model.messages.at(0).get('correcting')).toBe(false);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => (u.hasClass('correcting', view.el.querySelector('.chat-msg')) === false), 500);
-
-        textarea.value = 'It is the east, and Juliet is the one.';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-
-        textarea.value =  'Arise, fair sun, and kill the envious moon';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
-
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('Arise, fair sun, and kill the envious moon');
-        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
-        expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
-        expect(view.model.messages.at(2).get('correcting')).toBe(true);
-        await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg:last', view.el).pop()), 500);
-
-        textarea.selectionEnd = 0; // Happens by pressing up,
-                                // but for some reason not in tests, so we set it manually.
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('It is the east, and Juliet is the one.');
-        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
-        expect(view.model.messages.at(1).get('correcting')).toBe(true);
-        expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
-        await u.waitUntil(() => u.hasClass('correcting', sizzle('.chat-msg', view.el)[1]), 500);
-
-        textarea.value = 'It is the east, and Juliet is the sun.';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        await u.waitUntil(() => textarea.value === '');
-        const messages = view.el.querySelectorAll('.chat-msg');
-        expect(messages.length).toBe(3);
-        expect(messages[0].querySelector('.chat-msg__text').textContent)
-            .toBe('But soft, what light through yonder window breaks?');
-        expect(messages[1].querySelector('.chat-msg__text').textContent)
-            .toBe('It is the east, and Juliet is the sun.');
-        expect(messages[2].querySelector('.chat-msg__text').textContent)
-            .toBe('Arise, fair sun, and kill the envious moon');
-
-        expect(view.model.messages.at(0).get('correcting')).toBeFalsy();
-        expect(view.model.messages.at(1).get('correcting')).toBeFalsy();
-        expect(view.model.messages.at(2).get('correcting')).toBeFalsy();
-        done();
-    }));
-
-
     it("can be received out of order, and will still be displayed in the right order",
         mock.initConverse(
             ['rosterGroupsFetched'], {},
@@ -1307,67 +1024,6 @@ describe("A Chat Message", function () {
         }));
 
 
-        it("can be replaced with a correction",
-            mock.initConverse(
-                ['rosterGroupsFetched', 'chatBoxesFetched'], {},
-                async function (done, _converse) {
-
-            await mock.waitForRoster(_converse, 'current', 1);
-            await mock.openControlBox(_converse);
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
-            const msg_id = u.getUniqueId();
-            const view = await mock.openChatBoxFor(_converse, sender_jid);
-            _converse.handleMessageStanza($msg({
-                    'from': sender_jid,
-                    'to': _converse.connection.jid,
-                    'type': 'chat',
-                    'id': msg_id,
-                }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
-            await new Promise(resolve => view.model.messages.once('rendered', resolve));
-            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-            expect(view.el.querySelector('.chat-msg__text').textContent)
-                .toBe('But soft, what light through yonder airlock breaks?');
-
-            _converse.handleMessageStanza($msg({
-                    'from': sender_jid,
-                    'to': _converse.connection.jid,
-                    'type': 'chat',
-                    'id': u.getUniqueId(),
-                }).c('body').t('But soft, what light through yonder chimney breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-            await new Promise(resolve => view.model.messages.once('rendered', resolve));
-
-            expect(view.el.querySelector('.chat-msg__text').textContent)
-                .toBe('But soft, what light through yonder chimney breaks?');
-            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-            expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
-            expect(view.model.messages.models.length).toBe(1);
-
-            _converse.handleMessageStanza($msg({
-                    'from': sender_jid,
-                    'to': _converse.connection.jid,
-                    'type': 'chat',
-                    'id': u.getUniqueId(),
-                }).c('body').t('But soft, what light through yonder window breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-            await new Promise(resolve => view.model.messages.once('rendered', resolve));
-
-            expect(view.el.querySelector('.chat-msg__text').textContent)
-                .toBe('But soft, what light through yonder window breaks?');
-            expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-            expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
-            view.el.querySelector('.chat-msg__content .fa-edit').click();
-            const modal = await u.waitUntil(() => view.el.querySelector('converse-chat-message').message_versions_modal);
-            await u.waitUntil(() => u.isVisible(modal.el), 1000);
-            const older_msgs = modal.el.querySelectorAll('.older-msg');
-            expect(older_msgs.length).toBe(2);
-            expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-            expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
-            expect(view.model.messages.models.length).toBe(1);
-            done();
-        }));
-
-
         describe("when a chatbox is opened for someone who is not in the roster", function () {
 
             it("the VCard for that user is fetched and the chatbox updated with the results",

+ 0 - 268
spec/muc_messages.js

@@ -523,274 +523,6 @@ describe("A Groupchat Message", function () {
         done();
     }));
 
-    it("can be replaced with a correction",
-        mock.initConverse(
-            ['rosterGroupsFetched'], {},
-            async function (done, _converse) {
-
-        const muc_jid = 'lounge@montague.lit';
-        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
-        const view = _converse.api.chatviews.get(muc_jid);
-        const stanza = $pres({
-                to: 'romeo@montague.lit/_converse.js-29092160',
-                from: 'coven@chat.shakespeare.lit/newguy'
-            })
-            .c('x', {xmlns: Strophe.NS.MUC_USER})
-            .c('item', {
-                'affiliation': 'none',
-                'jid': 'newguy@montague.lit/_converse.js-290929789',
-                'role': 'participant'
-            }).tree();
-        _converse.connection._dataRecv(mock.createRequest(stanza));
-        const msg_id = u.getUniqueId();
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': msg_id,
-            }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
-
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        expect(view.el.querySelector('.chat-msg__text').textContent)
-            .toBe('But soft, what light through yonder airlock breaks?');
-
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': u.getUniqueId(),
-            }).c('body').t('But soft, what light through yonder chimney breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
-            'But soft, what light through yonder chimney breaks?', 500);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
-
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': u.getUniqueId(),
-            }).c('body').t('But soft, what light through yonder window breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-
-        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
-            'But soft, what light through yonder window breaks?', 500);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
-        const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
-        edit.click();
-        const modal = await u.waitUntil(() => view.el.querySelector('converse-chat-message').message_versions_modal);
-        await u.waitUntil(() => u.isVisible(modal.el), 1000);
-        const older_msgs = modal.el.querySelectorAll('.older-msg');
-        expect(older_msgs.length).toBe(2);
-        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
-        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
-        done();
-    }));
-
-    it("keeps the same position in history after a correction",
-        mock.initConverse(
-            ['rosterGroupsFetched'], {},
-            async function (done, _converse) {
-
-        const muc_jid = 'lounge@montague.lit';
-        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
-        const view = _converse.api.chatviews.get(muc_jid);
-        const stanza = $pres({
-                to: 'romeo@montague.lit/_converse.js-29092160',
-                from: 'coven@chat.shakespeare.lit/newguy'
-            })
-            .c('x', {xmlns: Strophe.NS.MUC_USER})
-            .c('item', {
-                'affiliation': 'none',
-                'jid': 'newguy@montague.lit/_converse.js-290929789',
-                'role': 'participant'
-            }).tree();
-        _converse.connection._dataRecv(mock.createRequest(stanza));
-        const msg_id = u.getUniqueId();
-
-        // Receiving the first message
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': msg_id,
-            }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
-
-        // Receiving own message to check order against
-        await view.model.handleMessageStanza($msg({
-            'from': 'lounge@montague.lit/romeo',
-            'to': _converse.connection.jid,
-            'type': 'groupchat',
-            'id': msg_id,
-        }).c('body').t('But soft, what light through yonder airlock breaks?').tree());
-
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 2);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-        expect(view.el.querySelectorAll('.chat-msg__text')[0].textContent)
-            .toBe('But soft, what light through yonder airlock breaks?');
-        expect(view.el.querySelectorAll('.chat-msg__text')[1].textContent)
-        .toBe('But soft, what light through yonder airlock breaks?');
-
-        // First message correction
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': u.getUniqueId(),
-            }).c('body').t('But soft, what light through yonder chimney breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-
-        await u.waitUntil(() => view.el.querySelector('.chat-msg__text').textContent ===
-            'But soft, what light through yonder chimney breaks?', 500);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-        await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
-
-        // Second message correction
-        await view.model.handleMessageStanza($msg({
-                'from': 'lounge@montague.lit/newguy',
-                'to': _converse.connection.jid,
-                'type': 'groupchat',
-                'id': u.getUniqueId(),
-            }).c('body').t('But soft, what light through yonder window breaks?').up()
-                .c('replace', {'id': msg_id, 'xmlns': 'urn:xmpp:message-correct:0'}).tree());
-
-        // Second own message
-        await view.model.handleMessageStanza($msg({
-            'from': 'lounge@montague.lit/romeo',
-            'to': _converse.connection.jid,
-            'type': 'groupchat',
-            'id': u.getUniqueId(),
-        }).c('body').t('But soft, what light through yonder window breaks?').tree());
-
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[0].textContent ===
-            'But soft, what light through yonder window breaks?', 500);
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 3);
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text')[2].textContent ===
-            'But soft, what light through yonder window breaks?', 500);
-
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(3);
-        expect(view.el.querySelectorAll('.chat-msg__content .fa-edit').length).toBe(1);
-        const edit = await u.waitUntil(() => view.el.querySelector('.chat-msg__content .fa-edit'));
-        edit.click();
-        const modal = await u.waitUntil(() => view.el.querySelectorAll('converse-chat-message')[0].message_versions_modal);
-        await u.waitUntil(() => u.isVisible(modal.el), 1000);
-        const older_msgs = modal.el.querySelectorAll('.older-msg');
-        expect(older_msgs.length).toBe(2);
-        expect(older_msgs[0].childNodes[2].textContent).toBe('But soft, what light through yonder airlock breaks?');
-        expect(older_msgs[0].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[0].nodeName).toBe('TIME');
-        expect(older_msgs[1].childNodes[2].textContent).toBe('But soft, what light through yonder chimney breaks?');
-        done();
-    }));
-
-    it("can be sent as a correction by using the up arrow",
-        mock.initConverse(
-            ['rosterGroupsFetched'], {},
-            async function (done, _converse) {
-
-        const muc_jid = 'lounge@montague.lit';
-        await mock.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
-        const view = _converse.api.chatviews.get(muc_jid);
-        const textarea = view.el.querySelector('textarea.chat-textarea');
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('');
-
-        textarea.value = 'But soft, what light through yonder airlock breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
-        expect(view.el.querySelector('.chat-msg__text').textContent)
-            .toBe('But soft, what light through yonder airlock breaks?');
-
-        const first_msg = view.model.messages.findWhere({'message': 'But soft, what light through yonder airlock breaks?'});
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('But soft, what light through yonder airlock breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')));
-
-        spyOn(_converse.connection, 'send');
-        textarea.value = 'But soft, what light through yonder window breaks?';
-        view.onKeyDown({
-            target: textarea,
-            preventDefault: function preventDefault () {},
-            keyCode: 13 // Enter
-        });
-        expect(_converse.connection.send).toHaveBeenCalled();
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-
-        const msg = _converse.connection.send.calls.all()[0].args[0];
-        expect(msg.toLocaleString())
-        .toBe(`<message from="romeo@montague.lit/orchard" id="${msg.nodeTree.getAttribute("id")}" `+
-                `to="lounge@montague.lit" type="groupchat" `+
-                `xmlns="jabber:client">`+
-                    `<body>But soft, what light through yonder window breaks?</body>`+
-                    `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
-                    `<replace id="${first_msg.get("msgid")}" xmlns="urn:xmpp:message-correct:0"/>`+
-                    `<origin-id id="${msg.nodeTree.querySelector('origin-id').getAttribute("id")}" xmlns="urn:xmpp:sid:0"/>`+
-            `</message>`);
-
-        expect(view.model.messages.models.length).toBe(1);
-        const corrected_message = view.model.messages.at(0);
-        expect(corrected_message.get('msgid')).toBe(first_msg.get('msgid'));
-        expect(corrected_message.get('correcting')).toBe(false);
-
-        const older_versions = corrected_message.get('older_versions');
-        const keys = Object.keys(older_versions);
-        expect(keys.length).toBe(1);
-        expect(older_versions[keys[0]]).toBe('But soft, what light through yonder airlock breaks?');
-
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(1);
-        expect(u.hasClass('correcting', view.el.querySelector('.chat-msg'))).toBe(false);
-
-        // Check that messages from other users are skipped
-        await view.model.handleMessageStanza($msg({
-            'from': muc_jid+'/someone-else',
-            'id': u.getUniqueId(),
-            'to': 'romeo@montague.lit',
-            'type': 'groupchat'
-        }).c('body').t('Hello world').tree());
-        await new Promise(resolve => view.model.messages.once('rendered', resolve));
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-
-        // Test that pressing the down arrow cancels message correction
-        expect(textarea.value).toBe('');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 38 // Up arrow
-        });
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-        expect(view.model.messages.at(0).get('correcting')).toBe(true);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-        await u.waitUntil(() => u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
-        expect(textarea.value).toBe('But soft, what light through yonder window breaks?');
-        view.onKeyDown({
-            target: textarea,
-            keyCode: 40 // Down arrow
-        });
-        expect(textarea.value).toBe('');
-        expect(view.model.messages.at(0).get('correcting')).toBe(false);
-        expect(view.el.querySelectorAll('.chat-msg').length).toBe(2);
-        await u.waitUntil(() => !u.hasClass('correcting', view.el.querySelector('.chat-msg')), 500);
-        done();
-    }));
-
     it("will be shown as received upon MUC reflection",
         mock.initConverse(
             ['rosterGroupsFetched'], {},