From 32206c05a0d52d9e14b69e576f96a534a045b46b Mon Sep 17 00:00:00 2001
From: Sonny Piers <sonny@fastmail.net>
Date: Wed, 8 Jan 2025 15:50:07 +0100
Subject: [PATCH] connection: Make disconnect a public function

See
* 2877a7b4c240150f66bceac5946d7d772c81f0e7
* 31bb31c5a9da70ac396cbe14cd108c7ab54cb15d
---
 packages/connection/index.js                  | 13 +++--
 .../connection/test/{end.js => disconnect.js} | 35 ++++++++++----
 packages/connection/test/onElement.js         |  4 +-
 packages/connection/test/stop.js              | 48 ++++++-------------
 packages/connection/test/streamError.js       |  4 +-
 test/client.js                                |  2 +-
 6 files changed, 54 insertions(+), 52 deletions(-)
 rename packages/connection/test/{end.js => disconnect.js} (61%)

diff --git a/packages/connection/index.js b/packages/connection/index.js
index cdc85215..c7e254ae 100644
--- a/packages/connection/index.js
+++ b/packages/connection/index.js
@@ -38,7 +38,7 @@ class Connection extends EventEmitter {
       );
     } catch {}
 
-    return this._end();
+    return this.disconnect();
   }
 
   _onData(data) {
@@ -107,7 +107,7 @@ class Connection extends EventEmitter {
     if (isStreamError) {
       // "Stream Errors Are Unrecoverable"
       // "The entity that receives the stream error then SHALL close the stream"
-      this._end();
+      this.disconnect();
     }
   }
 
@@ -211,15 +211,18 @@ class Connection extends EventEmitter {
     }
   }
 
-  async _end() {
+  async disconnect() {
     let el;
     try {
       el = await this._closeStream();
-    } catch {}
+    } catch (err) {
+      console.log(err);
+    }
 
     try {
       await this._closeSocket();
     } catch (err) {
+      console.log(err);
       this.#onSocketClosed(true, err);
     }
 
@@ -301,7 +304,7 @@ class Connection extends EventEmitter {
    * https://tools.ietf.org/html/rfc7395#section-3.6
    */
   async stop() {
-    const el = await this._end();
+    const el = await this.disconnect();
     this._status("offline", el);
     return el;
   }
diff --git a/packages/connection/test/end.js b/packages/connection/test/disconnect.js
similarity index 61%
rename from packages/connection/test/end.js
rename to packages/connection/test/disconnect.js
index 87ada10b..4c50d349 100644
--- a/packages/connection/test/end.js
+++ b/packages/connection/test/disconnect.js
@@ -1,18 +1,21 @@
 import Connection from "../index.js";
 
-test("#_end", async () => {
+test("disconnect", async () => {
   const conn = new Connection();
 
-  const spy_closeStream = jest.spyOn(conn, "_closeStream");
+  const el = {};
+  const spy_closeStream = jest
+    .spyOn(conn, "_closeStream")
+    .mockImplementation(async () => el);
   const spy_closeSocket = jest.spyOn(conn, "_closeSocket");
 
-  await conn._end();
+  expect(await conn.disconnect()).toBe(el);
 
   expect(spy_closeStream).toHaveBeenCalledTimes(1);
   expect(spy_closeSocket).toHaveBeenCalledTimes(1);
 });
 
-test("#_end with close rejection", async () => {
+test("disconnect with _closeStream rejection", async () => {
   const conn = new Connection();
 
   const spy_closeStream = jest
@@ -22,13 +25,13 @@ test("#_end with close rejection", async () => {
     });
   const spy_closeSocket = jest.spyOn(conn, "_closeSocket");
 
-  await conn._end();
+  await conn.disconnect();
 
   expect(spy_closeStream).toHaveBeenCalledTimes(1);
   expect(spy_closeSocket).toHaveBeenCalledTimes(1);
 });
 
-test("#_end with disconnect rejection", async () => {
+test("disconnect with _closeSocket rejection", async () => {
   const conn = new Connection();
 
   const spy_closeStream = jest.spyOn(conn, "_closeStream");
@@ -38,13 +41,13 @@ test("#_end with disconnect rejection", async () => {
       return Promise.reject();
     });
 
-  await conn._end();
+  await conn.disconnect();
 
   expect(spy_closeStream).toHaveBeenCalledTimes(1);
   expect(spy_closeSocket).toHaveBeenCalledTimes(1);
 });
 
-test("#_end with close and disconnect rejection", async () => {
+test("disconnect with _closeStream and _closeSocket rejections", async () => {
   const conn = new Connection();
 
   const spy_closeStream = jest
@@ -58,8 +61,22 @@ test("#_end with close and disconnect rejection", async () => {
       return Promise.reject();
     });
 
-  await conn._end();
+  await conn.disconnect();
 
   expect(spy_closeStream).toHaveBeenCalledTimes(1);
   expect(spy_closeSocket).toHaveBeenCalledTimes(1);
 });
+
+test("resolves if socket property is undefined", async () => {
+  const conn = new Connection();
+  conn.footerElement = () => <foo />;
+  conn.socket = undefined;
+  await conn.disconnect();
+  expect().pass();
+});
+
+test("does not reject if connection is not established", async () => {
+  const conn = new Connection();
+  await conn.disconnect();
+  expect().pass();
+});
diff --git a/packages/connection/test/onElement.js b/packages/connection/test/onElement.js
index c6e558a3..e0001fb2 100644
--- a/packages/connection/test/onElement.js
+++ b/packages/connection/test/onElement.js
@@ -27,10 +27,10 @@ test("#_onElement stream:error", (done) => {
     application,
   ]);
   const conn = new Connection();
-  conn._end = () => {
+  jest.spyOn(conn, "disconnect").mockImplementation(() => {
     done();
     return Promise.resolve();
-  };
+  });
 
   conn.on("element", (el) => {
     expect(el).toBe(foo);
diff --git a/packages/connection/test/stop.js b/packages/connection/test/stop.js
index 28c376d1..8a94a49a 100644
--- a/packages/connection/test/stop.js
+++ b/packages/connection/test/stop.js
@@ -1,43 +1,25 @@
-import Connection from "../index.js";
 import { EventEmitter } from "@xmpp/events";
+import Connection from "../index.js";
 
-test("resolves if socket property is undefined", async () => {
+test("stop", async () => {
   const conn = new Connection();
-  conn.footerElement = () => <foo />;
-  conn.socket = undefined;
-  await conn.stop();
-  expect().pass();
-});
 
-test("resolves if _closeStream rejects", async () => {
-  const conn = new Connection();
-  conn._closeStream = () => Promise.reject();
-  conn._closeSocket = () => Promise.resolve();
-  await conn.stop();
-  expect().pass();
-});
+  const close_el = {};
+  const spy_disconnect = jest
+    .spyOn(conn, "disconnect")
+    .mockImplementation(async () => {
+      return close_el;
+    });
+  const spy_status = jest.spyOn(conn, "_status");
 
-test("resolves if _closeSocket rejects", async () => {
-  const conn = new Connection();
-  conn._closeStream = () => Promise.resolve();
-  conn._closeSocket = () => Promise.reject();
-  await conn.stop();
-  expect().pass();
-});
+  conn.status = "online";
 
-test("resolves with the result of close", async () => {
-  const conn = new Connection();
-  conn.socket = {};
-  const el = {};
-  conn._closeStream = () => Promise.resolve(el);
-  conn._closeSocket = () => Promise.resolve();
-  expect(await conn.stop()).toBe(el);
-});
-
-test("does not throw if connection is not established", async () => {
-  const conn = new Connection();
   await conn.stop();
-  expect().pass();
+
+  expect(spy_disconnect).toHaveBeenCalledTimes(1);
+  expect(spy_status).toHaveBeenCalledTimes(1);
+  expect(spy_status).toHaveBeenCalledWith("offline", close_el);
+  expect(conn.status).toBe("offline");
 });
 
 // https://github.com/xmppjs/xmpp.js/issues/956
diff --git a/packages/connection/test/streamError.js b/packages/connection/test/streamError.js
index 79d8967a..5b0fc3e9 100644
--- a/packages/connection/test/streamError.js
+++ b/packages/connection/test/streamError.js
@@ -4,12 +4,12 @@ import xml from "@xmpp/xml";
 test("#_streamError", async () => {
   const conn = new Connection();
 
-  const spy_end = jest.spyOn(conn, "_end");
+  const spy_disconnect = jest.spyOn(conn, "disconnect");
   const spy_send = jest.spyOn(conn, "send");
 
   await conn._streamError("foo-bar");
 
-  expect(spy_end).toHaveBeenCalled();
+  expect(spy_disconnect).toHaveBeenCalled();
 
   expect(spy_send).toHaveBeenCalledWith(
     xml("stream:error", {}, [
diff --git a/test/client.js b/test/client.js
index 5adf4786..2b6f3c4e 100644
--- a/test/client.js
+++ b/test/client.js
@@ -169,7 +169,7 @@ test("statuses", async () => {
   ]);
 
   // trigger reconnect
-  await xmpp._closeSocket();
+  await xmpp.disconnect();
 
   statuses = [xmpp.status];
   await promise(xmpp, "open");