diff --git a/src/clientfactory.ts b/src/clientfactory.ts
index ec842ecc32a19ff3d92a34aae766e14ed9f0beb1..7055ccf0d03390aa6bec368e0744c2d846147e9a 100644
--- a/src/clientfactory.ts
+++ b/src/clientfactory.ts
@@ -17,7 +17,7 @@ export class DiscordClientFactory {
     this.store = store;
   }
 
-  public init(): Promise<null> {
+  public async init(): Promise<void> {
     if (this.config === undefined) {
       return Promise.reject("Client config not supplied.");
     }
@@ -28,12 +28,12 @@ export class DiscordClientFactory {
       sync: true,
       messageCacheLifetime: 5,
     }));
-    this.botClient.login(this.config.botToken);
-    return this.botClient.onAsync("ready")
-    .timeout(READY_TIMEOUT, "Bot timed out waiting for ready.")
-    .catch((err) => {
-      log.error("ClientFactory", "Could not login as the bot user. This is bad!", err);
-      throw err;
+    return Bluebird.all([
+        this.botClient.onAsync("ready").timeout(READY_TIMEOUT, "Bot timed out waiting for ready."),
+        this.botClient.login(this.config.botToken),
+    ]).then(() => { return; }).catch((err) => {
+        log.error("ClientFactory", "Could not login as the bot user. This is bad!", err);
+        throw err;
     });
   }
 
@@ -44,15 +44,15 @@ export class DiscordClientFactory {
       messageCacheLifetime: 5,
     });
     return new Bluebird<string>((resolve, reject) => {
-      client.login(token).catch(reject);
       client.on("ready", () => {
         const id = client.user.id;
         client.destroy();
         resolve(id);
       });
+      client.login(token).catch(reject);
     }).timeout(READY_TIMEOUT).catch((err: Error) => {
       log.warn("ClientFactory", "Could not login as a normal user. '%s'", err.message);
-      throw Error("Could not retrive ID");
+      throw Error("Could not retrieve ID");
     });
   }
 
@@ -81,7 +81,8 @@ export class DiscordClientFactory {
       this.clients.set(userId, client);
       return client;
     } catch (err) {
-      log.warn("ClientFactory", `Could not log ${userId} in.`, err);
+      log.warn("ClientFactory", `Could not log ${userId} in. Returning bot user for now.`, err);
+      return this.botClient;
     }
   }
 }
diff --git a/test/mocks/discordclient.ts b/test/mocks/discordclient.ts
index 71ffef63a1f37141798c36b13941f90a4225c797..d431ebf1dd0b0a768d691aeeac08560148ef8a24 100644
--- a/test/mocks/discordclient.ts
+++ b/test/mocks/discordclient.ts
@@ -6,7 +6,7 @@ export class MockDiscordClient {
   public guilds = new MockCollection<string, MockGuild>();
   public user: MockUser;
   private testLoggedIn: boolean = false;
-  private testCallbacks: Array<() => void> = [];
+  private testCallbacks: Map<string, () => void> = new Map();
 
   constructor() {
     const channels = [
@@ -31,13 +31,19 @@ export class MockDiscordClient {
   }
 
   public on(event: string, callback: () => void) {
-    if (event === "ready") {
-      this.testCallbacks[0] = callback;
-    }
+      this.testCallbacks.set(event, callback);
   }
 
-  public login(token: string) {
+  public async login(token: string): Promise<void> {
+    if (token !== "passme") {
+        throw new Error("Mock Discord Client only logins with the token 'passme'");
+    }
     this.testLoggedIn = true;
-    this.testCallbacks[0]();
+    if (this.testCallbacks.has("ready")) {
+        this.testCallbacks.get("ready")();
+    }
+    return;
   }
+
+  public destroy() { } // no-op
 }
diff --git a/test/test_clientfactory.ts b/test/test_clientfactory.ts
new file mode 100644
index 0000000000000000000000000000000000000000..721962646a810a2b40af67b1e1a0551c75bc0d31
--- /dev/null
+++ b/test/test_clientfactory.ts
@@ -0,0 +1,110 @@
+import * as Chai from "chai";
+import * as ChaiAsPromised from "chai-as-promised";
+import * as Proxyquire from "proxyquire";
+import {DiscordBridgeConfigAuth} from "../src/config";
+import {MockDiscordClient} from "./mocks/discordclient";
+import * as log from "npmlog";
+
+Chai.use(ChaiAsPromised);
+const expect = Chai.expect;
+
+const DiscordClientFactory = Proxyquire("../src/clientfactory", {
+    "discord.js": { Client: require("./mocks/discordclient").MockDiscordClient },
+}).DiscordClientFactory;
+
+const STORE = {
+    get_user_discord_ids: (userid: string) => {
+        if (userid === "@valid:localhost") {
+            return Promise.resolve(["12345"]);
+        } else if (userid === "@invalid:localhost") {
+            return Promise.resolve(["1234555"]);
+        }
+        return Promise.resolve([]);
+    },
+    get_token: (discordid: string) => {
+        if (discordid === "12345") {
+            return Promise.resolve("passme");
+        } else if (discordid === "1234555") {
+            return Promise.resolve("failme");
+        }
+        return Promise.reject("Token not found");
+    },
+};
+
+describe("ClientFactory", () => {
+    describe("init", () => {
+       it ("should start successfully", () => {
+           const config = new DiscordBridgeConfigAuth();
+           config.botToken = "passme";
+           const cf = new DiscordClientFactory(null, config);
+           return expect(cf.init()).to.eventually.be.fulfilled;
+       });
+       it ("should fail if a config is not supplied", () => {
+           log.level = "silent";
+           const cf = new DiscordClientFactory(null);
+           return expect(cf.init()).to.eventually.be.rejected;
+       });
+       it ("should fail if the bot fails to connect", () => {
+           log.level = "silent";
+           const config = new DiscordBridgeConfigAuth();
+           config.botToken = "failme";
+           const cf = new DiscordClientFactory(null, config);
+           return expect(cf.init()).to.eventually.be.rejected;
+       });
+    });
+    describe("getDiscordId", () => {
+        it("should fetch id successfully", () => {
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(null);
+            return expect(cf.getDiscordId("passme")).to.eventually.equal("12345");
+        });
+        it("should fail if the token is not recognised", () => {
+            log.level = "silent";
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(null);
+            return expect(cf.getDiscordId("failme")).to.eventually.be.rejected;
+        });
+    });
+    describe("getClient", () => {
+        it("should fetch bot client successfully", () => {
+            const config = new DiscordBridgeConfigAuth();
+            config.botToken = "passme";
+            const cf = new DiscordClientFactory(null, config);
+            cf.botClient = 1;
+            return expect(cf.getClient()).to.eventually.equal(cf.botClient);
+        });
+        it("should return cached client", () => {
+            log.level = "silent";
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(null);
+            cf.clients.set("@user:localhost", "testclient");
+            return expect(cf.getClient("@user:localhost")).to.eventually.equal("testclient");
+        });
+        it("should fetch bot client if userid doesn't match", () => {
+            log.level = "silent";
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(STORE);
+            cf.botClient = 1;
+            return expect(cf.getClient("@user:localhost")).to.eventually.equal(cf.botClient);
+        });
+        it("should fetch user client if userid matches", () => {
+            log.level = "silent";
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(STORE);
+            return cf.getClient("@valid:localhost").then((client) => {
+                expect(client).is.not.null;
+                expect(cf.clients.has("@valid:localhost")).to.be.true;
+            });
+        });
+        it("should fail if the user client cannot log in", () => {
+            log.level = "silent";
+            const config = new DiscordBridgeConfigAuth();
+            const cf = new DiscordClientFactory(STORE);
+            cf.botClient = 1;
+            return cf.getClient("@invalid:localhost").then((client) => {
+                expect(client).to.equal(cf.botClient);
+                expect(cf.clients.has("@invalid:localhost")).to.be.false;
+            });
+        });
+    });
+});
diff --git a/test/test_discordbot.ts b/test/test_discordbot.ts
index c11d8a5e9e1e8fd86acfe93112805684347cd4a7..95855e72dd60790d02f1a5682af28348c05351e9 100644
--- a/test/test_discordbot.ts
+++ b/test/test_discordbot.ts
@@ -25,7 +25,7 @@ const mockBridge = {
     };
   },
   getIntentFromLocalpart: (localpart: string) => {
-    return{
+    return {
       sendTyping: (room: string, isTyping: boolean) => {
         return;
       },