浏览代码

MUC: Queue messages received before we're ready

JC Brand 5 年之前
父节点
当前提交
49817a850f
共有 5 个文件被更改,包括 131 次插入20 次删除
  1. 81 8
      package-lock.json
  2. 12 4
      spec/muc.js
  3. 14 3
      spec/smacks.js
  4. 19 0
      src/headless/converse-muc.js
  5. 5 5
      tests/utils.js

+ 81 - 8
package-lock.json

@@ -9988,6 +9988,11 @@
 			"dev": true,
 			"dev": true,
 			"optional": true
 			"optional": true
 		},
 		},
+		"filesize": {
+			"version": "4.2.1",
+			"resolved": "https://registry.npmjs.org/filesize/-/filesize-4.2.1.tgz",
+			"integrity": "sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA=="
+		},
 		"fill-range": {
 		"fill-range": {
 			"version": "4.0.0",
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -10299,7 +10304,6 @@
 			"version": "8.1.0",
 			"version": "8.1.0",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
 			"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
 			"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
-			"dev": true,
 			"requires": {
 			"requires": {
 				"graceful-fs": "^4.2.0",
 				"graceful-fs": "^4.2.0",
 				"jsonfile": "^4.0.0",
 				"jsonfile": "^4.0.0",
@@ -10309,8 +10313,7 @@
 				"graceful-fs": {
 				"graceful-fs": {
 					"version": "4.2.3",
 					"version": "4.2.3",
 					"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
 					"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-					"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-					"dev": true
+					"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
 				}
 				}
 			}
 			}
 		},
 		},
@@ -11535,8 +11538,7 @@
 		"graceful-fs": {
 		"graceful-fs": {
 			"version": "4.1.11",
 			"version": "4.1.11",
 			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
 			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-			"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-			"dev": true
+			"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
 		},
 		},
 		"handle-thing": {
 		"handle-thing": {
 			"version": "2.0.0",
 			"version": "2.0.0",
@@ -12004,6 +12006,11 @@
 				"minimatch": "^3.0.4"
 				"minimatch": "^3.0.4"
 			}
 			}
 		},
 		},
+		"immediate": {
+			"version": "3.0.6",
+			"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+			"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
+		},
 		"import-cwd": {
 		"import-cwd": {
 			"version": "2.1.0",
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@@ -12567,6 +12574,11 @@
 			"integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=",
 			"integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=",
 			"dev": true
 			"dev": true
 		},
 		},
+		"jed": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz",
+			"integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ="
+		},
 		"jest-worker": {
 		"jest-worker": {
 			"version": "25.1.0",
 			"version": "25.1.0",
 			"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz",
 			"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz",
@@ -12726,7 +12738,6 @@
 			"version": "4.0.0",
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
 			"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
 			"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
-			"dev": true,
 			"requires": {
 			"requires": {
 				"graceful-fs": "^4.1.6"
 				"graceful-fs": "^4.1.6"
 			}
 			}
@@ -12963,6 +12974,14 @@
 				"type-check": "~0.3.2"
 				"type-check": "~0.3.2"
 			}
 			}
 		},
 		},
+		"lie": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
+			"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
+			"requires": {
+				"immediate": "~3.0.5"
+			}
+		},
 		"linkify-it": {
 		"linkify-it": {
 			"version": "2.2.0",
 			"version": "2.2.0",
 			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
 			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
@@ -13025,6 +13044,14 @@
 				"json5": "^0.5.0"
 				"json5": "^0.5.0"
 			}
 			}
 		},
 		},
+		"localforage": {
+			"version": "1.7.3",
+			"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz",
+			"integrity": "sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==",
+			"requires": {
+				"lie": "3.1.1"
+			}
+		},
 		"locate-path": {
 		"locate-path": {
 			"version": "3.0.0",
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@@ -19160,6 +19187,14 @@
 				}
 				}
 			}
 			}
 		},
 		},
+		"pluggable.js": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/pluggable.js/-/pluggable.js-2.0.1.tgz",
+			"integrity": "sha512-SBt6v6Tbp20Jf8hU0cpcc/+HBHGMY8/Q+yA6Ih0tBQE8tfdZ6U4PRG0iNvUUjLx/hVyOP53n0UfGBymlfaaXCg==",
+			"requires": {
+				"lodash": "^4.17.11"
+			}
+		},
 		"po-loader": {
 		"po-loader": {
 			"version": "0.5.0",
 			"version": "0.5.0",
 			"resolved": "https://registry.npmjs.org/po-loader/-/po-loader-0.5.0.tgz",
 			"resolved": "https://registry.npmjs.org/po-loader/-/po-loader-0.5.0.tgz",
@@ -21068,6 +21103,13 @@
 			"integrity": "sha512-Mf37VjirD7RqCVeYgI8jb5K0DymIho/jNJqDgIkMs4cgKbEkvsow8Q6hpvF7Zmys9iEif0oW41hgbeWVZwABJw==",
 			"integrity": "sha512-Mf37VjirD7RqCVeYgI8jb5K0DymIho/jNJqDgIkMs4cgKbEkvsow8Q6hpvF7Zmys9iEif0oW41hgbeWVZwABJw==",
 			"dev": true
 			"dev": true
 		},
 		},
+		"skeletor.js": {
+			"version": "github:skeletorjs/skeletor#dea2d5791ee894493e30b92662c953efec0e58f6",
+			"from": "github:skeletorjs/skeletor#dea2d5791ee894493e30b92662c953efec0e58f6",
+			"requires": {
+				"lodash": "^4.17.14"
+			}
+		},
 		"slash": {
 		"slash": {
 			"version": "2.0.0",
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
 			"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@@ -21742,6 +21784,11 @@
 				"through": "^2.3.4"
 				"through": "^2.3.4"
 			}
 			}
 		},
 		},
+		"strophe.js": {
+			"version": "1.3.4",
+			"resolved": "https://registry.npmjs.org/strophe.js/-/strophe.js-1.3.4.tgz",
+			"integrity": "sha512-jSLDG8jolhAwGOSgiJ7DTMSYK3wVoEJHKtpVRyEacQZ6CWA6z2WRPJpcFMjsIweq5aP9/XIvKUQqHBu/ZhvESA=="
+		},
 		"style-loader": {
 		"style-loader": {
 			"version": "0.23.1",
 			"version": "0.23.1",
 			"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
 			"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz",
@@ -22195,6 +22242,33 @@
 			"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
 			"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
 			"dev": true
 			"dev": true
 		},
 		},
+		"twemoji": {
+			"version": "12.1.5",
+			"resolved": "https://registry.npmjs.org/twemoji/-/twemoji-12.1.5.tgz",
+			"integrity": "sha512-B0PBVy5xomwb1M/WZxf/IqPZfnoIYy1skXnlHjMwLwTNfZ9ljh8VgWQktAPcJXu8080WoEh6YwQGPVhDVqvrVQ==",
+			"requires": {
+				"fs-extra": "^8.0.1",
+				"jsonfile": "^5.0.0",
+				"twemoji-parser": "12.1.3",
+				"universalify": "^0.1.2"
+			},
+			"dependencies": {
+				"jsonfile": {
+					"version": "5.0.0",
+					"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz",
+					"integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==",
+					"requires": {
+						"graceful-fs": "^4.1.6",
+						"universalify": "^0.1.2"
+					}
+				}
+			}
+		},
+		"twemoji-parser": {
+			"version": "12.1.3",
+			"resolved": "https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-12.1.3.tgz",
+			"integrity": "sha512-ND4LZXF4X92/PFrzSgGkq6KPPg8swy/U0yRw1k/+izWRVmq1HYi3khPwV3XIB6FRudgVICAaBhJfW8e8G3HC7Q=="
+		},
 		"type-check": {
 		"type-check": {
 			"version": "0.3.2",
 			"version": "0.3.2",
 			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
 			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -22415,8 +22489,7 @@
 		"universalify": {
 		"universalify": {
 			"version": "0.1.2",
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
 			"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
-			"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
-			"dev": true
+			"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
 		},
 		},
 		"unpipe": {
 		"unpipe": {
 			"version": "1.0.0",
 			"version": "1.0.0",

+ 12 - 4
spec/muc.js

@@ -580,12 +580,15 @@
 
 
             it("shows join/leave messages when users enter or exit a groupchat",
             it("shows join/leave messages when users enter or exit a groupchat",
                 mock.initConverse(
                 mock.initConverse(
-                    ['rosterGroupsFetched', 'chatBoxesFetched'], {},
+                    ['rosterGroupsFetched', 'chatBoxesFetched'], {'muc_fetch_members': false},
                     async function (done, _converse) {
                     async function (done, _converse) {
 
 
                 const muc_jid = 'coven@chat.shakespeare.lit';
                 const muc_jid = 'coven@chat.shakespeare.lit';
-                await test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1');
+                const nick = 'some1';
+                const room_creation_promise = await _converse.api.rooms.open(muc_jid, {nick});
                 await test_utils.getRoomFeatures(_converse, muc_jid);
                 await test_utils.getRoomFeatures(_converse, muc_jid);
+                const sent_stanzas = _converse.connection.sent_stanzas;
+                await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
 
 
                 const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
                 const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
                 const chat_content = view.el.querySelector('.chat-content');
                 const chat_content = view.el.querySelector('.chat-content');
@@ -627,6 +630,10 @@
                 expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
                 expect(sizzle('div.chat-info:first', chat_content).pop().textContent.trim())
                     .toBe("some1 has entered the groupchat");
                     .toBe("some1 has entered the groupchat");
 
 
+                await room_creation_promise;
+                await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
+                await view.model.messages.fetched;
+
                 presence = $pres({
                 presence = $pres({
                         to: 'romeo@montague.lit/_converse.js-29092160',
                         to: 'romeo@montague.lit/_converse.js-29092160',
                         from: 'coven@chat.shakespeare.lit/newguy'
                         from: 'coven@chat.shakespeare.lit/newguy'
@@ -664,7 +671,7 @@
                         'role': 'participant'
                         'role': 'participant'
                     });
                     });
                 _converse.connection._dataRecv(test_utils.createRequest(presence));
                 _converse.connection._dataRecv(test_utils.createRequest(presence));
-                expect(chat_content.querySelectorAll('div.chat-info').length).toBe(3);
+                await u.waitUntil(() => chat_content.querySelectorAll('div.chat-info').length === 3);
                 expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
                 expect(sizzle('div.chat-info:last', chat_content).pop().textContent.trim())
                     .toBe("newgirl has entered the groupchat");
                     .toBe("newgirl has entered the groupchat");
 
 
@@ -5184,13 +5191,14 @@
             });
             });
 
 
             describe("A paused notification", function () {
             describe("A paused notification", function () {
+
                 it("will be shown if received",
                 it("will be shown if received",
                     mock.initConverse(
                     mock.initConverse(
                         ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                         ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                         async function (done, _converse) {
                         async function (done, _converse) {
 
 
-                    await test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1');
                     const muc_jid = 'coven@chat.shakespeare.lit';
                     const muc_jid = 'coven@chat.shakespeare.lit';
+                    await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'some1');
                     const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
                     const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
                     const chat_content = view.el.querySelector('.chat-content');
                     const chat_content = view.el.querySelector('.chat-content');
 
 

+ 14 - 3
spec/smacks.js

@@ -185,9 +185,10 @@
             mock.initConverse(
             mock.initConverse(
                 ['chatBoxesInitialized'],
                 ['chatBoxesInitialized'],
                 { 'auto_login': false,
                 { 'auto_login': false,
+                  'blacklisted_plugins': 'converse-mam',
                   'enable_smacks': true,
                   'enable_smacks': true,
+                  'muc_fetch_members': false,
                   'show_controlbox_by_default': true,
                   'show_controlbox_by_default': true,
-                  'blacklisted_plugins': 'converse-mam',
                   'smacks_max_unacked_stanzas': 2
                   'smacks_max_unacked_stanzas': 2
                 },
                 },
                 async function (done, _converse) {
                 async function (done, _converse) {
@@ -243,9 +244,11 @@
             _converse.connection._dataRecv(test_utils.createRequest(result));
             _converse.connection._dataRecv(test_utils.createRequest(result));
             expect(_converse.session.get('smacks_enabled')).toBe(true);
             expect(_converse.session.get('smacks_enabled')).toBe(true);
 
 
+
+            const nick = 'romeo';
             const func = _converse.chatboxes.onChatBoxesFetched;
             const func = _converse.chatboxes.onChatBoxesFetched;
             spyOn(_converse.chatboxes, 'onChatBoxesFetched').and.callFake(collection => {
             spyOn(_converse.chatboxes, 'onChatBoxesFetched').and.callFake(collection => {
-                const muc = new _converse.ChatRoom({'jid': muc_jid, 'id': muc_jid}, {'collection': _converse.chatboxes});
+                const muc = new _converse.ChatRoom({'jid': muc_jid, 'id': muc_jid, nick}, {'collection': _converse.chatboxes});
                 _converse.chatboxes.add(muc);
                 _converse.chatboxes.add(muc);
                 func.call(_converse.chatboxes, collection);
                 func.call(_converse.chatboxes, collection);
             });
             });
@@ -262,7 +265,15 @@
 
 
             await _converse.api.waitUntil('chatBoxesFetched');
             await _converse.api.waitUntil('chatBoxesFetched');
             const muc = _converse.chatboxes.get(muc_jid);
             const muc = _converse.chatboxes.get(muc_jid);
-            await u.waitUntil(() => muc.messages.length === 1);
+            await u.waitUntil(() => muc.message_queue.length === 1);
+
+            const view = _converse.chatboxviews.get(muc_jid);
+            await test_utils.getRoomFeatures(_converse, muc_jid);
+            await test_utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
+            await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
+            await view.model.messages.fetched;
+
+            await u.waitUntil(() => muc.messages.length);
             expect(muc.messages.at(0).get('message')).toBe('First message')
             expect(muc.messages.at(0).get('message')).toBe('First message')
             done();
             done();
         }));
         }));

+ 19 - 0
src/headless/converse-muc.js

@@ -384,6 +384,7 @@ converse.plugins.add('converse-muc', {
                     await new Promise(resolve => this.features.fetch({'success': resolve, 'error': resolve}));
                     await new Promise(resolve => this.features.fetch({'success': resolve, 'error': resolve}));
                     await this.fetchOccupants();
                     await this.fetchOccupants();
                     await this.fetchMessages();
                     await this.fetchMessages();
+                    await this.clearMessageQueue();
                     return true;
                     return true;
                 } else {
                 } else {
                     await this.clearCache();
                     await this.clearCache();
@@ -451,12 +452,23 @@ converse.plugins.add('converse-muc', {
                 return this.join();
                 return this.join();
             },
             },
 
 
+            initMessages () {
+                _converse.ChatBox.prototype.initMessages.call(this);
+                this.message_queue = [];
+            },
+
+            async clearMessageQueue () {
+                await Promise.all(this.message_queue.map(m => this.onMessage(m)));
+                this.message_queue = [];
+            },
+
             async onConnectionStatusChanged () {
             async onConnectionStatusChanged () {
                 if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
                 if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
                     if (_converse.muc_fetch_members) {
                     if (_converse.muc_fetch_members) {
                         await this.occupants.fetchMembers();
                         await this.occupants.fetchMembers();
                     }
                     }
                     await this.fetchMessages();
                     await this.fetchMessages();
+                    await this.clearMessageQueue();
                     /**
                     /**
                      * Triggered when the user has entered a new MUC
                      * Triggered when the user has entered a new MUC
                      * @event _converse#enteredNewRoom
                      * @event _converse#enteredNewRoom
@@ -1780,6 +1792,13 @@ converse.plugins.add('converse-muc', {
              * @param { XMLElement } stanza - The message stanza.
              * @param { XMLElement } stanza - The message stanza.
              */
              */
             async onMessage (stanza) {
             async onMessage (stanza) {
+                if (!this.messages.fetched || this.messages.fetched.isPending) {
+                    // We're not ready to accept messages before we've fetched
+                    // from our store, so we stuff them into a queue.
+                    this.message_queue.push(stanza);
+                    return;
+                }
+
                 if (sizzle(`message > forwarded[xmlns="${Strophe.NS.FORWARD}"]`, stanza).length) {
                 if (sizzle(`message > forwarded[xmlns="${Strophe.NS.FORWARD}"]`, stanza).length) {
                     return log.warn('onMessage: Ignoring unencapsulated forwarded groupchat message');
                     return log.warn('onMessage: Ignoring unencapsulated forwarded groupchat message');
                 }
                 }

+ 5 - 5
tests/utils.js

@@ -140,9 +140,7 @@
     };
     };
 
 
     utils.openChatRoom = async function (_converse, room, server) {
     utils.openChatRoom = async function (_converse, room, server) {
-        const model = await _converse.api.rooms.open(`${room}@${server}`);
-        await model.messages.fetched;
-        return model;
+        return _converse.api.rooms.open(`${room}@${server}`);
     };
     };
 
 
     utils.getRoomFeatures = async function (_converse, muc_jid, features=[]) {
     utils.getRoomFeatures = async function (_converse, muc_jid, features=[]) {
@@ -273,7 +271,9 @@
         return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
         return new Promise(resolve => _converse.api.listen.on('membersFetched', resolve));
     };
     };
 
 
-    utils.receiveOwnMUCPresence = function (_converse, muc_jid, nick) {
+    utils.receiveOwnMUCPresence = async function (_converse, muc_jid, nick) {
+        const sent_stanzas = _converse.connection.sent_stanzas;
+        await u.waitUntil(() => sent_stanzas.filter(iq => sizzle('presence history', iq).length).pop());
         const presence = $pres({
         const presence = $pres({
                 to: _converse.connection.jid,
                 to: _converse.connection.jid,
                 from: `${muc_jid}/${nick}`,
                 from: `${muc_jid}/${nick}`,
@@ -297,7 +297,7 @@
         // The user has just entered the room (because join was called)
         // The user has just entered the room (because join was called)
         // and receives their own presence from the server.
         // and receives their own presence from the server.
         // See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
         // See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
-        utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
+        await utils.receiveOwnMUCPresence(_converse, muc_jid, nick);
 
 
         await room_creation_promise;
         await room_creation_promise;
         const view = _converse.chatboxviews.get(muc_jid);
         const view = _converse.chatboxviews.get(muc_jid);