Repository: Yoctol/bottender (ts)

Issue:
LINE -  Alias ButtonsTemplate to ButtonTemplate
Its name should be `Buttons template`
https://developers.line.me/en/docs/messaging-api/reference/#buttons

Pull request description:
alias LINE ButtonsTemplate to ButtonTemplate
Close #218

Patch:
diff --git a/src/context/LineContext.js b/src/context/LineContext.js
index 040db6e6..3a6e8baa 100644
--- a/src/context/LineContext.js
+++ b/src/context/LineContext.js
@@ -268,80 +268,87 @@ class LineContext extends Context implements PlatformContext {
   }
 }
 
-const types = [
-  '',
-  'Text',
-  'Image',
-  'Video',
-  'Audio',
-  'Location',
-  'Sticker',
-  'Imagemap',
-  'ButtonTemplate',
-  'ConfirmTemplate',
-  'CarouselTemplate',
-  'ImageCarouselTemplate',
+const types: Array<{ name: string, aliases?: Array<string> }> = [
+  { name: '' },
+  { name: 'Text' },
+  { name: 'Image' },
+  { name: 'Video' },
+  { name: 'Audio' },
+  { name: 'Location' },
+  { name: 'Sticker' },
+  { name: 'Imagemap' },
+  { name: 'ButtonTemplate', aliases: ['ButtonsTemplate'] },
+  { name: 'ConfirmTemplate' },
+  { name: 'CarouselTemplate' },
+  { name: 'ImageCarouselTemplate' },
 ];
-types.forEach(type => {
-  Object.defineProperty(LineContext.prototype, `reply${type}`, {
-    enumerable: false,
-    configurable: true,
-    writable: true,
-    async value(...args) {
-      invariant(!this._isReplied, 'Can not reply event mulitple times');
-
-      this._isReplied = true;
-      this._isHandled = true;
-
-      return this._client[`reply${type}`](this._event.replyToken, ...args);
-    },
-  });
 
-  Object.defineProperty(LineContext.prototype, `push${type}`, {
-    enumerable: false,
-    configurable: true,
-    writable: true,
-    async value(...args) {
-      if (!this._session) {
-        warning(
-          false,
-          `push${type}: should not be called in context without session`
+types.forEach(({ name, aliases }) => {
+  [name].concat(aliases || []).forEach(type => {
+    Object.defineProperty(LineContext.prototype, `reply${type}`, {
+      enumerable: false,
+      configurable: true,
+      writable: true,
+      async value(...args) {
+        invariant(!this._isReplied, 'Can not reply event mulitple times');
+
+        this._isReplied = true;
+        this._isHandled = true;
+
+        return this._client[`reply${name}`](this._event.replyToken, ...args);
+      },
+    });
+
+    Object.defineProperty(LineContext.prototype, `push${type}`, {
+      enumerable: false,
+      configurable: true,
+      writable: true,
+      async value(...args) {
+        if (!this._session) {
+          warning(
+            false,
+            `push${type}: should not be called in context without session`
+          );
+          return;
+        }
+
+        this._isHandled = true;
+        const sessionType = this._session.type;
+        return this._client[`push${name}`](
+          this._session[sessionType].id,
+          ...args
         );
-        return;
-      }
-
-      this._isHandled = true;
-      const sessionType = this._session.type;
-      return this._client[`push${type}`](
-        this._session[sessionType].id,
-        ...args
-      );
-    },
+      },
+    });
   });
 });
 
-types.filter(type => type !== 'Text' && type !== '').forEach(type => {
-  Object.defineProperty(LineContext.prototype, `send${type}`, {
-    enumerable: false,
-    configurable: true,
-    writable: true,
-    async value(...args) {
-      if (!this._session) {
-        warning(
-          false,
-          `send${type}: should not be called in context without session`
-        );
-        return;
-      }
-
-      this._isHandled = true;
-      const sessionType = this._session.type;
-      return this._client[`push${type}`](
-        this._session[sessionType].id,
-        ...args
-      );
-    },
+types
+  .filter(({ name }) => name !== 'Text' && name !== '')
+  .forEach(({ name, aliases }) => {
+    [name].concat(aliases || []).forEach(type => {
+      Object.defineProperty(LineContext.prototype, `send${type}`, {
+        enumerable: false,
+        configurable: true,
+        writable: true,
+        async value(...args) {
+          if (!this._session) {
+            warning(
+              false,
+              `send${type}: should not be called in context without session`
+            );
+            return;
+          }
+
+          this._isHandled = true;
+          const sessionType = this._session.type;
+          return this._client[`push${name}`](
+            this._session[sessionType].id,
+            ...args
+          );
+        },
+      });
+    });
   });
-});
 
 export default LineContext;


Test patch:
diff --git a/src/context/__tests__/LineContext.spec.js b/src/context/__tests__/LineContext.spec.js
index 71a07412..a36e7ab0 100644
--- a/src/context/__tests__/LineContext.spec.js
+++ b/src/context/__tests__/LineContext.spec.js
@@ -758,6 +758,18 @@ describe('send APIs', () => {
 
       expect(context.isHandled).toBe(true);
     });
+
+    it('should support sendButtonsTemplate alias', async () => {
+      const { context, client, session } = setup();
+
+      await context.sendButtonsTemplate('this is a button template', template);
+
+      expect(client.pushButtonTemplate).toBeCalledWith(
+        session.user.id,
+        'this is a button template',
+        template
+      );
+    });
   });
 
   describe('#sendConfirmTemplate', () => {