Repository: Yoctol/bottender (ts)

Issue:
support LINE leave room/group on context
in a room/group context, calling `context.leaveRoom();` `context.leaveGroup();` to leave
or `context.leave()` to automatically decide which API to call.

Pull request description:
add LINE context.leave() function
close #106 

Patch:
diff --git a/src/context/LineContext.js b/src/context/LineContext.js
index aa7a20f4..e4668ab6 100644
--- a/src/context/LineContext.js
+++ b/src/context/LineContext.js
@@ -73,6 +73,31 @@ class LineContext extends Context implements PlatformContext {
     return this._client.pushText(this._session[type].id, text);
   }
 
+  /**
+   * Leave room or group depending on type of the session.
+   *
+   */
+  async leave(): Promise<any> {
+    if (!this._session) {
+      warning(false, 'leave: should not be called in context without session');
+      return;
+    }
+
+    switch (this._session.type) {
+      case 'room':
+        this._isHandled = true;
+        return this._client.leaveRoom(this._session.room.id);
+      case 'group':
+        this._isHandled = true;
+        return this._client.leaveGroup(this._session.group.id);
+      default:
+        warning(
+          false,
+          'leave: should not be called in context which is not room or group session'
+        );
+    }
+  }
+
   /**
    * Gets the ID of the rich menu linked to the user.
    *


Test patch:
diff --git a/src/context/__tests__/LineContext.spec.js b/src/context/__tests__/LineContext.spec.js
index da1a668e..8fe44cf1 100644
--- a/src/context/__tests__/LineContext.spec.js
+++ b/src/context/__tests__/LineContext.spec.js
@@ -37,6 +37,21 @@ const userSession = {
     id: 'fakeUserId',
   },
 };
+
+const roomSession = {
+  type: 'room',
+  room: {
+    id: 'fakeRoomId',
+  },
+};
+
+const groupSession = {
+  type: 'group',
+  group: {
+    id: 'fakeGroupId',
+  },
+};
+
 const setup = ({ session } = { session: userSession }) => {
   const client = {
     reply: jest.fn(),
@@ -55,6 +70,8 @@ const setup = ({ session } = { session: userSession }) => {
     getLinkedRichMenu: jest.fn(),
     linkRichMenu: jest.fn(),
     unlinkRichMenu: jest.fn(),
+    leaveGroup: jest.fn(),
+    leaveRoom: jest.fn(),
   };
   const context = new LineContext({
     client,
@@ -98,6 +115,48 @@ it('get #client works', () => {
   expect(context.client).toBe(client);
 });
 
+describe('#leave', () => {
+  it('not leave no session', async () => {
+    const { context, client } = setup({ session: null });
+
+    await context.leave();
+
+    expect(client.leaveGroup).not.toBeCalled();
+    expect(client.leaveRoom).not.toBeCalled();
+    expect(warning).toBeCalled();
+    expect(context.isHandled).toBe(false);
+  });
+
+  it('leave group', async () => {
+    const { context, client } = setup({ session: groupSession });
+
+    await context.leave();
+
+    expect(client.leaveGroup).toBeCalledWith('fakeGroupId');
+    expect(context.isHandled).toBe(true);
+  });
+
+  it('leave room', async () => {
+    const { context, client } = setup({ session: roomSession });
+
+    await context.leave();
+
+    expect(client.leaveRoom).toBeCalledWith('fakeRoomId');
+    expect(context.isHandled).toBe(true);
+  });
+
+  it('not leave user', async () => {
+    const { context, client } = setup({ session: userSession });
+
+    await context.leave();
+
+    expect(client.leaveGroup).not.toBeCalled();
+    expect(client.leaveRoom).not.toBeCalled();
+    expect(warning).toBeCalled();
+    expect(context.isHandled).toBe(false);
+  });
+});
+
 describe('#reply', () => {
   it('#reply to call client.reply', async () => {
     const { context, client } = setup();