Repository: Yoctol/bottender (ts)

Issue:
Support Messenger webhook test button
![default](https://user-images.githubusercontent.com/1003146/34473843-8ed95d86-efb2-11e7-87e8-b32d29baca37.png)
```
  bottender/bot/Bot   "entry": [
  bottender/bot/Bot     {
  bottender/bot/Bot       "changes": [
  bottender/bot/Bot         {
  bottender/bot/Bot           "field": "messages",
  bottender/bot/Bot           "value": {
  bottender/bot/Bot             "page_id": "1067280970047460"
  bottender/bot/Bot           }
  bottender/bot/Bot         }
  bottender/bot/Bot       ],
  bottender/bot/Bot       "id": "0",
  bottender/bot/Bot       "time": 1514862760
  bottender/bot/Bot     }
  bottender/bot/Bot   ],
  bottender/bot/Bot   "object": "page"
  bottender/bot/Bot } +5s
```

This button will send a request which bottender can't parse.

Pull request description:
support Messenger webhook test requests
as well as other null `rawEvent` requests

fix #138

Patch:
diff --git a/src/bot/MessengerConnector.js b/src/bot/MessengerConnector.js
index 3d8ea779..e212a316 100644
--- a/src/bot/MessengerConnector.js
+++ b/src/bot/MessengerConnector.js
@@ -24,12 +24,14 @@ import type { Session } from '../session/Session';
 import type { Connector } from './Connector';
 
 type Entry = {
-  ['messaging' | 'standby']: Array<{
+  ['messaging' | 'standby' | 'changes']: Array<{
     sender: Sender,
     recipient: Recipient,
     timestamp: number,
     postback?: Postback,
     message?: Message,
+    field?: String,
+    value?: Object,
   }>,
 };
 
@@ -116,6 +118,12 @@ export default class MessengerConnector
           if (ent.standby) {
             return ((ent.standby[0]: any): MessengerRawEvent);
           }
+
+          // for Webhook Test button request and other page events
+          if (ent.changes) {
+            return ((ent.changes[0]: any): MessengerRawEvent);
+          }
+
           // $FlowExpectedError
           return null;
         })
@@ -155,10 +163,15 @@ export default class MessengerConnector
 
   getUniqueSessionKey(body: MessengerRequestBody): ?string {
     const rawEvent = this._getRawEventsFromRequest(body)[0];
-    if (rawEvent.message && rawEvent.message.is_echo && rawEvent.recipient) {
+    if (
+      rawEvent &&
+      rawEvent.message &&
+      rawEvent.message.is_echo &&
+      rawEvent.recipient
+    ) {
       return rawEvent.recipient.id;
     }
-    if (rawEvent.sender) {
+    if (rawEvent && rawEvent.sender) {
       return rawEvent.sender.id;
     }
     return null;


Test patch:
diff --git a/src/bot/__tests__/MessengerConnector.spec.js b/src/bot/__tests__/MessengerConnector.spec.js
index 5cc08672..e9757946 100644
--- a/src/bot/__tests__/MessengerConnector.spec.js
+++ b/src/bot/__tests__/MessengerConnector.spec.js
@@ -143,6 +143,26 @@ const standbyRequest = {
   },
 };
 
+const webhookTestRequest = {
+  body: {
+    entry: [
+      {
+        changes: [
+          {
+            field: 'messages',
+            value: {
+              page_id: '<PAGE_ID>',
+            },
+          },
+        ],
+        id: '0',
+        time: 1514862760,
+      },
+    ],
+    object: 'page',
+  },
+};
+
 function setup(
   { accessToken, appSecret, mapPageToAccessToken } = {
     accessToken: ACCESS_TOKEN,
@@ -209,6 +229,12 @@ describe('#getUniqueSessionKey', () => {
     const senderId = connector.getUniqueSessionKey({});
     expect(senderId).toBe(null);
   });
+
+  it('return null if is webhook test event or other null rawEvent requests', () => {
+    const { connector } = setup();
+    const senderId = connector.getUniqueSessionKey(webhookTestRequest.body);
+    expect(senderId).toBe(null);
+  });
 });
 
 describe('#updateSession', () => {