소스 검색

fix tests

JC Brand 6 달 전
부모
커밋
ffc4b65068

+ 9 - 11
src/headless/plugins/roster/contact.js

@@ -146,25 +146,23 @@ class RosterContact extends ColorAwareModel(Model) {
 
 
     /**
     /**
      * Remove this contact from the roster
      * Remove this contact from the roster
+     * @async
      * @param {boolean} [unauthorize] - Whether to also unauthorize the
      * @param {boolean} [unauthorize] - Whether to also unauthorize the
+     * @returns {Promise<Error|Element>}
      */
      */
-    async remove (unauthorize) {
+    remove (unauthorize) {
         const subscription = this.get('subscription');
         const subscription = this.get('subscription');
         if (subscription === 'none' && this.get('ask') !== 'subscribe') {
         if (subscription === 'none' && this.get('ask') !== 'subscribe') {
             this.destroy();
             this.destroy();
             return;
             return;
         }
         }
-
-        try {
-            if (unauthorize && ['from', 'both'].includes(subscription)) {
-                this.unauthorize();
-            }
-            await this.sendRosterRemoveStanza();
-        } finally {
-            // The model might have already been removed as
-            // result of a roster push.
-            if (this.collection) this.destroy();
+        if (unauthorize && ['from', 'both'].includes(subscription)) {
+            this.unauthorize();
         }
         }
+        const promise = this.sendRosterRemoveStanza();
+        if (this.collection) this.destroy();
+
+        return promise;
     }
     }
 
 
     /**
     /**

+ 2 - 2
src/headless/plugins/roster/utils.js

@@ -212,8 +212,8 @@ export function onRosterContactsFetched () {
 /**
 /**
  * Reject or cancel another user's subscription to our presence updates.
  * Reject or cancel another user's subscription to our presence updates.
  * @function rejectPresenceSubscription
  * @function rejectPresenceSubscription
- * @param { String } jid - The Jabber ID of the user whose subscription is being canceled
- * @param { String } message - An optional message to the user
+ * @param {String} jid - The Jabber ID of the user whose subscription is being canceled
+ * @param {String} message - An optional message to the user
  */
  */
 export function rejectPresenceSubscription (jid, message) {
 export function rejectPresenceSubscription (jid, message) {
     const pres = $pres({to: jid, type: "unsubscribed"});
     const pres = $pres({to: jid, type: "unsubscribed"});

+ 3 - 1
src/headless/types/plugins/roster/contact.d.ts

@@ -118,9 +118,11 @@ declare class RosterContact extends RosterContact_base {
     authorize(message: string): this;
     authorize(message: string): this;
     /**
     /**
      * Remove this contact from the roster
      * Remove this contact from the roster
+     * @async
      * @param {boolean} [unauthorize] - Whether to also unauthorize the
      * @param {boolean} [unauthorize] - Whether to also unauthorize the
+     * @returns {Promise<Error|Element>}
      */
      */
-    remove(unauthorize?: boolean): Promise<void>;
+    remove(unauthorize?: boolean): Promise<Error | Element>;
     /**
     /**
      * Instruct the XMPP server to remove this contact from our roster
      * Instruct the XMPP server to remove this contact from our roster
      * @async
      * @async

+ 2 - 2
src/headless/types/plugins/roster/utils.d.ts

@@ -24,8 +24,8 @@ export function onRosterContactsFetched(): void;
 /**
 /**
  * Reject or cancel another user's subscription to our presence updates.
  * Reject or cancel another user's subscription to our presence updates.
  * @function rejectPresenceSubscription
  * @function rejectPresenceSubscription
- * @param { String } jid - The Jabber ID of the user whose subscription is being canceled
- * @param { String } message - An optional message to the user
+ * @param {String} jid - The Jabber ID of the user whose subscription is being canceled
+ * @param {String} message - An optional message to the user
  */
  */
 export function rejectPresenceSubscription(jid: string, message: string): void;
 export function rejectPresenceSubscription(jid: string, message: string): void;
 export type RosterContacts = import("./contacts").default;
 export type RosterContacts = import("./contacts").default;

+ 12 - 12
src/headless/types/shared/model-with-contact.d.ts

@@ -5,25 +5,25 @@
 export default function ModelWithContact<T extends import("./types").ModelExtender>(BaseModel: T): {
 export default function ModelWithContact<T extends import("./types").ModelExtender>(BaseModel: T): {
     new (...args: any[]): {
     new (...args: any[]): {
         /**
         /**
-        * @typedef {import('../plugins/vcard/vcard').default} VCard
-        * @typedef {import('../plugins/roster/contact').default} RosterContact
-        * @typedef {import('./_converse.js').XMPPStatus} XMPPStatus
-        */
+         * @typedef {import('../plugins/vcard/vcard').default} VCard
+         * @typedef {import('../plugins/roster/contact').default} RosterContact
+         * @typedef {import('./_converse.js').XMPPStatus} XMPPStatus
+         */
         initialize(): void;
         initialize(): void;
         rosterContactAdded: any;
         rosterContactAdded: any;
         /**
         /**
-        * @public
-        * @type {RosterContact|XMPPStatus}
-        */
+         * @public
+         * @type {RosterContact|XMPPStatus}
+         */
         contact: import("../plugins/roster/contact").default | import("../index.js").XMPPStatus;
         contact: import("../plugins/roster/contact").default | import("../index.js").XMPPStatus;
         /**
         /**
-        * @public
-        * @type {VCard}
-        */
+         * @public
+         * @type {VCard}
+         */
         vcard: import("../plugins/vcard/vcard").default;
         vcard: import("../plugins/vcard/vcard").default;
         /**
         /**
-        * @param {string} jid
-        */
+         * @param {string} jid
+         */
         setModelContact(jid: string): Promise<void>;
         setModelContact(jid: string): Promise<void>;
         cid: any;
         cid: any;
         attributes: {};
         attributes: {};

+ 1 - 0
src/plugins/chatview/tests/chatbox.js

@@ -102,6 +102,7 @@ describe("Chatboxes", function () {
                 async function (_converse) {
                 async function (_converse) {
 
 
             const { api } = _converse;
             const { api } = _converse;
+            await mock.waitUntilBlocklistInitialized(_converse);
             await mock.waitForRoster(_converse, 'current', 0);
             await mock.waitForRoster(_converse, 'current', 0);
             const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const stanza = u.toStanza(`
             const stanza = u.toStanza(`

+ 0 - 1
src/plugins/chatview/tests/messages.js

@@ -1050,7 +1050,6 @@ describe("A Chat Message", function () {
                 expect(view).not.toBeDefined();
                 expect(view).not.toBeDefined();
 
 
                 api.settings.set('allow_non_roster_messaging', true);
                 api.settings.set('allow_non_roster_messaging', true);
-                        debugger;
                 await _converse.handleMessageStanza(msg);
                 await _converse.handleMessageStanza(msg);
                 view = _converse.chatboxviews.get(sender_jid);
                 view = _converse.chatboxviews.get(sender_jid);
                 await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
                 await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);

+ 1 - 1
src/plugins/rosterview/templates/roster_item.js

@@ -11,7 +11,7 @@ export const tplRemoveLink = (el) => {
    const display_name = el.model.getDisplayName();
    const display_name = el.model.getDisplayName();
    const i18n_remove = __('Click to remove %1$s as a contact', display_name);
    const i18n_remove = __('Click to remove %1$s as a contact', display_name);
    return html`
    return html`
-      <a class="list-item-action remove-xmpp-contact" @click=${el.removeContact} title="${i18n_remove}" href="#">
+      <a class="list-item-action remove-xmpp-contact" @click="${el.removeContact}" title="${i18n_remove}" href="#">
          <converse-icon class="fa fa-trash-alt" size="1.5em"></converse-icon>
          <converse-icon class="fa fa-trash-alt" size="1.5em"></converse-icon>
       </a>
       </a>
    `;
    `;

+ 24 - 6
src/plugins/rosterview/tests/roster.js

@@ -763,17 +763,33 @@ describe("The Contacts Roster", function () {
         }));
         }));
 
 
         it("can be removed by the user",
         it("can be removed by the user",
-                mock.initConverse([], {'roster_groups': false}, async function (_converse) {
+                mock.initConverse(
+                    [],
+                    {'roster_groups': false},
+                    async function (_converse) {
 
 
+            spyOn(_converse.api, 'confirm').and.callFake(() => Promise.resolve(true));
             await mock.openControlBox(_converse);
             await mock.openControlBox(_converse);
-            await mock.waitForRoster(_converse, 'all');
+            await mock.waitForRoster(_converse, 'pending');
             await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
             await Promise.all(_converse.roster.map(contact => u.waitUntil(() => contact.vcard.get('fullname'))));
             await u.waitUntil(() => _converse.roster.at(0).vcard.get('fullname'))
             await u.waitUntil(() => _converse.roster.at(0).vcard.get('fullname'))
             const rosterview = document.querySelector('converse-roster');
             const rosterview = document.querySelector('converse-roster');
-            spyOn(_converse.api, 'confirm').and.returnValue(Promise.resolve(true));
+
+            const sent_IQs = _converse.api.connection.get().IQ_stanzas;
+
             for (let i=0; i<mock.pend_names.length; i++) {
             for (let i=0; i<mock.pend_names.length; i++) {
                 const name = mock.pend_names[i];
                 const name = mock.pend_names[i];
-                sizzle(`.remove-xmpp-contact[title="Click to remove ${name} as a contact"]`, rosterview).pop().click();
+                const jid = name.replace(/ /g,'.').toLowerCase() + '@montague.lit';
+                const el = rosterview.querySelector(`.remove-xmpp-contact[title="Click to remove ${name} as a contact"]`);
+                el.click();
+                const stanza = await u.waitUntil(() => sent_IQs.find(iq => iq.querySelector('iq item[subscription="remove"]')));
+                expect(stanza).toEqualStanza(
+                    stx`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">
+                        <query xmlns="jabber:iq:roster"><item jid="${jid}" subscription="remove"/></query>
+                    </iq>`);
+                _converse.api.connection.get()._dataRecv(mock.createRequest(
+                    stx`<iq id="${stanza.getAttribute('id')}" type="result" xmlns="jabber:client"></iq>`));
+                while (sent_IQs.length) sent_IQs.pop();
             }
             }
             await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null);
             await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`) === null);
         }));
         }));
@@ -1361,10 +1377,11 @@ describe("The Contacts Roster", function () {
                 async function (_converse) {
                 async function (_converse) {
 
 
             const { api } = _converse;
             const { api } = _converse;
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            await mock.waitUntilBlocklistInitialized(_converse);
             await mock.waitForRoster(_converse, "current", 0);
             await mock.waitForRoster(_converse, "current", 0);
             await mock.openControlBox(_converse);
             await mock.openControlBox(_converse);
 
 
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const msg = stx`
             const msg = stx`
                 <message xmlns='jabber:client'
                 <message xmlns='jabber:client'
                         id='${api.connection.get().getUniqueId()}'
                         id='${api.connection.get().getUniqueId()}'
@@ -1388,10 +1405,11 @@ describe("The Contacts Roster", function () {
                 async function (_converse) {
                 async function (_converse) {
 
 
             const { api } = _converse;
             const { api } = _converse;
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            await mock.waitUntilBlocklistInitialized(_converse);
             await mock.waitForRoster(_converse, "current", 1);
             await mock.waitForRoster(_converse, "current", 1);
             await mock.openControlBox(_converse);
             await mock.openControlBox(_converse);
 
 
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             let msg = stx`
             let msg = stx`
                 <message xmlns='jabber:client'
                 <message xmlns='jabber:client'
                         id='${api.connection.get().getUniqueId()}'
                         id='${api.connection.get().getUniqueId()}'

+ 7 - 5
src/plugins/rosterview/utils.js

@@ -11,10 +11,10 @@ const { STATUS_WEIGHTS } = constants;
 
 
 /**
 /**
  * @param {RosterContact} contact
  * @param {RosterContact} contact
- * @param {boolean} [unsubscribe]
+ * @param {boolean} [unauthorize]
  * @returns {Promise<boolean>}
  * @returns {Promise<boolean>}
  */
  */
-export async function removeContact(contact, unsubscribe = false) {
+export async function removeContact(contact, unauthorize = false) {
     if (!api.settings.get('allow_contact_removal')) return;
     if (!api.settings.get('allow_contact_removal')) return;
 
 
     const result = await api.confirm(__('Are you sure you want to remove this contact?'));
     const result = await api.confirm(__('Are you sure you want to remove this contact?'));
@@ -23,7 +23,7 @@ export async function removeContact(contact, unsubscribe = false) {
     const chat = await api.chats.get(contact.get('jid'));
     const chat = await api.chats.get(contact.get('jid'));
     chat?.close();
     chat?.close();
     try {
     try {
-        contact.remove(unsubscribe);
+        await contact.remove(unauthorize);
     } catch (e) {
     } catch (e) {
         log.error(e);
         log.error(e);
         api.alert('error', __('Error'), [
         api.alert('error', __('Error'), [
@@ -47,8 +47,10 @@ export async function blockContact(contact) {
     (await api.chats.get(contact.get('jid')))?.close();
     (await api.chats.get(contact.get('jid')))?.close();
 
 
     try {
     try {
-        contact.remove(true);
-        await api.blocklist.add(contact.get('jid'));
+        await Promise.all([
+            api.blocklist.add(contact.get('jid')),
+            contact.remove(true)
+        ]);
     } catch (e) {
     } catch (e) {
         log.error(e);
         log.error(e);
         api.alert('error', __('Error'), [
         api.alert('error', __('Error'), [

+ 1 - 1
src/shared/modals/user-details.js

@@ -45,7 +45,7 @@ export default class UserDetailsModal extends BaseModal {
         this.listenTo(this.model.contact.vcard, 'change', this.render);
         this.listenTo(this.model.contact.vcard, 'change', this.render);
         this.model.contact.on('destroy', () => {
         this.model.contact.on('destroy', () => {
             delete this.model.contact;
             delete this.model.contact;
-            this.render();
+            this.close();
         });
         });
 
 
         // Refresh the vcard
         // Refresh the vcard

+ 2 - 2
src/types/plugins/rosterview/utils.d.ts

@@ -1,9 +1,9 @@
 /**
 /**
  * @param {RosterContact} contact
  * @param {RosterContact} contact
- * @param {boolean} [unsubscribe]
+ * @param {boolean} [unauthorize]
  * @returns {Promise<boolean>}
  * @returns {Promise<boolean>}
  */
  */
-export function removeContact(contact: RosterContact, unsubscribe?: boolean): Promise<boolean>;
+export function removeContact(contact: RosterContact, unauthorize?: boolean): Promise<boolean>;
 /**
 /**
  * @param {RosterContact} contact
  * @param {RosterContact} contact
  * @returns {Promise<boolean>}
  * @returns {Promise<boolean>}