Repository: Yoctol/bottender
Pull request #132 (2017-12-28 03:03:50)

use createSubscription and refactor tests


Patch:
diff --git a/src/cli/providers/messenger/webhook.js b/src/cli/providers/messenger/webhook.js
index 2b760e75..e9c4d778 100644
--- a/src/cli/providers/messenger/webhook.js
+++ b/src/cli/providers/messenger/webhook.js
@@ -1,3 +1,4 @@
+import { MessengerClient } from 'messaging-api-messenger';
 import axios from 'axios';
 import get from 'lodash/get';
 import invariant from 'invariant';
@@ -8,39 +9,31 @@ import { print, error, bold, warn } from '../../shared/log';
 
 import help from './help';
 
-export const client = axios.create({
-  baseURL: 'https://graph.facebook.com/v2.9/',
-  headers: { 'Content-Type': 'application/json' },
-});
-
-export const localClient = axios.create({
+export const ngrokClient = axios.create({
   baseURL: 'http://localhost:4040',
 });
 
 const getWebhookFromNgrok = async () => {
-  const res = await localClient.get('/api/tunnels');
+  const res = await ngrokClient.get('/api/tunnels');
   return get(res, 'data.tunnels[1].public_url'); // tunnels[1] return `https` protocol
 };
 
-const _getClientToken = async (clientId, clientSecret) => {
-  const res = await client.get(
-    `/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`
-  );
-  return res.data.access_token;
-};
-
-export async function setWebhook(_webhook, _verifyToken) {
+export async function setWebhook(webhook, verifyToken) {
   try {
     const config = getConfig('bottender.config.js', 'messenger');
+
+    const client = MessengerClient.connect(config.accessToken);
+
     const defaultFields = [
       'messages',
       'messaging_postbacks',
+      'messaging_optins',
       'messaging_referrals',
+      'messaging_handovers',
+      'messaging_policy_enforcement',
     ];
 
-    let webhook = _webhook;
-
-    if (!_webhook) {
+    if (!webhook) {
       warn('We can not find the webhook callback url you provided.');
       const prompt = new Confirm(
         'Are you using ngrok (get url from ngrok server on http://127.0.0.1:4040)?'
@@ -51,7 +44,7 @@ export async function setWebhook(_webhook, _verifyToken) {
       }
     }
 
-    const verifyToken = _verifyToken || config.verifyToken;
+    verifyToken = verifyToken || config.verifyToken;
 
     invariant(config.appId, '`appId` is not found in config file');
     invariant(config.appSecret, '`appSecret` is not found in config file');
@@ -71,22 +64,21 @@ export async function setWebhook(_webhook, _verifyToken) {
         )} to setup.`
       );
       print(
-        'See more on: https://developers.facebook.com/docs/graph-api/reference/v2.9/app/subscriptions'
+        'See more on: https://developers.facebook.com/docs/graph-api/reference/app/subscriptions'
       );
     }
+
     const fields = config.fields || defaultFields;
 
-    const token = await _getClientToken(config.appId, config.appSecret);
-    const res = await client.post(
-      `/${config.appId}/subscriptions?access_token=${token}`,
-      {
-        object: 'page',
-        callback_url: webhook,
-        verify_token: verifyToken,
-        fields,
-      }
-    );
-    invariant(res.data.success, 'Setting for webhook is failed');
+    const { success } = await client.createSubscription({
+      app_id: config.appId,
+      object: 'page',
+      callback_url: webhook,
+      verify_token: verifyToken,
+      fields,
+      access_token: `${config.appId}|${config.appSecret}`,
+    });
+    invariant(success, 'Setting for webhook is failed');
 
     print('Successfully set Messenger webhook callback URL');
     print(


Test patch:
diff --git a/src/cache/__tests__/RedisCacheStore.spec.js b/src/cache/__tests__/RedisCacheStore.spec.js
index 64ebc633..595bc753 100644
--- a/src/cache/__tests__/RedisCacheStore.spec.js
+++ b/src/cache/__tests__/RedisCacheStore.spec.js
@@ -2,10 +2,6 @@ import Redis from 'ioredis';
 
 import RedisCacheStore from '../RedisCacheStore';
 
-beforeEach(() => {
-  jest.resetAllMocks();
-});
-
 describe('#constructor', () => {
   it('can call without any arguments', () => {
     const store = new RedisCacheStore(); // eslint-disable-line no-unused-vars
diff --git a/src/cli/providers/messenger/__tests__/checkMessengerProfile.spec.js b/src/cli/providers/messenger/__tests__/checkMessengerProfile.spec.js
index df2a96b5..30feab3d 100644
--- a/src/cli/providers/messenger/__tests__/checkMessengerProfile.spec.js
+++ b/src/cli/providers/messenger/__tests__/checkMessengerProfile.spec.js
@@ -10,7 +10,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 beforeEach(() => {
diff --git a/src/cli/providers/messenger/__tests__/deleteGetStarted.spec.js b/src/cli/providers/messenger/__tests__/deleteGetStarted.spec.js
index a80ebf4b..49107084 100644
--- a/src/cli/providers/messenger/__tests__/deleteGetStarted.spec.js
+++ b/src/cli/providers/messenger/__tests__/deleteGetStarted.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/deleteGreeting.spec.js b/src/cli/providers/messenger/__tests__/deleteGreeting.spec.js
index 06afd220..54c86d14 100644
--- a/src/cli/providers/messenger/__tests__/deleteGreeting.spec.js
+++ b/src/cli/providers/messenger/__tests__/deleteGreeting.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/deleteMessengerProfile.spec.js b/src/cli/providers/messenger/__tests__/deleteMessengerProfile.spec.js
index 6650c262..f4751953 100644
--- a/src/cli/providers/messenger/__tests__/deleteMessengerProfile.spec.js
+++ b/src/cli/providers/messenger/__tests__/deleteMessengerProfile.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/deletePersistentMenu.spec.js b/src/cli/providers/messenger/__tests__/deletePersistentMenu.spec.js
index ce49d9a3..0367b9db 100644
--- a/src/cli/providers/messenger/__tests__/deletePersistentMenu.spec.js
+++ b/src/cli/providers/messenger/__tests__/deletePersistentMenu.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/deleteWhitelistedDomains.spec.js b/src/cli/providers/messenger/__tests__/deleteWhitelistedDomains.spec.js
index d7d7ceae..cf6e10fb 100644
--- a/src/cli/providers/messenger/__tests__/deleteWhitelistedDomains.spec.js
+++ b/src/cli/providers/messenger/__tests__/deleteWhitelistedDomains.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/getGetStarted.spec.js b/src/cli/providers/messenger/__tests__/getGetStarted.spec.js
index 6517aab6..996540df 100644
--- a/src/cli/providers/messenger/__tests__/getGetStarted.spec.js
+++ b/src/cli/providers/messenger/__tests__/getGetStarted.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/getGreeting.spec.js b/src/cli/providers/messenger/__tests__/getGreeting.spec.js
index 420fbdd2..f5bb9dc7 100644
--- a/src/cli/providers/messenger/__tests__/getGreeting.spec.js
+++ b/src/cli/providers/messenger/__tests__/getGreeting.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/getMessengerProfile.spec.js b/src/cli/providers/messenger/__tests__/getMessengerProfile.spec.js
index 6e914fa0..fbfe2a81 100644
--- a/src/cli/providers/messenger/__tests__/getMessengerProfile.spec.js
+++ b/src/cli/providers/messenger/__tests__/getMessengerProfile.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/getPersistentMenu.spec.js b/src/cli/providers/messenger/__tests__/getPersistentMenu.spec.js
index d9274a6e..315dc792 100644
--- a/src/cli/providers/messenger/__tests__/getPersistentMenu.spec.js
+++ b/src/cli/providers/messenger/__tests__/getPersistentMenu.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/getWhitelistedDomains.spec.js b/src/cli/providers/messenger/__tests__/getWhitelistedDomains.spec.js
index d87162c9..f2d2efad 100644
--- a/src/cli/providers/messenger/__tests__/getWhitelistedDomains.spec.js
+++ b/src/cli/providers/messenger/__tests__/getWhitelistedDomains.spec.js
@@ -14,7 +14,6 @@ const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
     accessToken: '__FAKE_TOKEN__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/messenger/__tests__/setMessengerProfile.spec.js b/src/cli/providers/messenger/__tests__/setMessengerProfile.spec.js
index e033e35b..aa899761 100644
--- a/src/cli/providers/messenger/__tests__/setMessengerProfile.spec.js
+++ b/src/cli/providers/messenger/__tests__/setMessengerProfile.spec.js
@@ -33,7 +33,6 @@ const MOCK_FILE_WITH_PLATFORM = {
       ],
     },
   },
-  line: {},
 };
 
 let _client;
@@ -70,7 +69,6 @@ beforeEach(() => {
 
 afterEach(() => {
   process.exit = _exit;
-  jest.resetAllMocks();
 });
 
 it('be defined', () => {
diff --git a/src/cli/providers/messenger/__tests__/setWebhook.spec.js b/src/cli/providers/messenger/__tests__/setWebhook.spec.js
index 78a2514d..e7c9fa1c 100644
--- a/src/cli/providers/messenger/__tests__/setWebhook.spec.js
+++ b/src/cli/providers/messenger/__tests__/setWebhook.spec.js
@@ -1,65 +1,45 @@
 import MockAdapter from 'axios-mock-adapter';
 
-import {
-  setWebhook,
-  client as _client,
-  localClient as _localClient,
-} from '../webhook';
+import { setWebhook, ngrokClient } from '../webhook';
 
+jest.mock('messaging-api-messenger');
 jest.mock('prompt-confirm');
 
 jest.mock('../../../shared/log');
 jest.mock('../../../shared/getConfig');
 
 const Confirm = require('prompt-confirm');
+const { MessengerClient } = require('messaging-api-messenger');
 
 const log = require('../../../shared/log');
 const getConfig = require('../../../shared/getConfig');
 
+const APP_ID = '__APP_ID__';
+const APP_SECRET = '__APP_SECRET__';
+const VERIFY_TOKEN = '__VERIFY_TOKEN__';
+const WEBHOOK = 'http://example.com/webhook';
+
 const MOCK_FILE_WITH_PLATFORM = {
   messenger: {
-    appId: '__APP_ID__',
-    appSecret: '__APP_SECRET__',
-    verifyToken: '__verifyToken__',
+    appId: APP_ID,
+    appSecret: APP_SECRET,
+    verifyToken: VERIFY_TOKEN,
   },
-  line: {},
 };
-const configPath = 'bot.sample.json';
-
-let client;
-let localClient;
-
-const setup = (
-  {
-    clientId = MOCK_FILE_WITH_PLATFORM.messenger.appId,
-    clientSecret = MOCK_FILE_WITH_PLATFORM.messenger.appSecret,
-    accessToken = '__FAKE_TOKEN__',
-    webhook = 'http://example.com/webhook',
-  } = {
-    clientId: MOCK_FILE_WITH_PLATFORM.messenger.appId,
-    clientSecret: MOCK_FILE_WITH_PLATFORM.messenger.appSecret,
-    accessToken: '__FAKE_TOKEN__',
-    webhook: 'http://example.com/webhook',
-  }
-) => ({
-  getUrl: `/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&grant_type=client_credentials`,
-  postUrl: `/${clientId}/subscriptions?access_token=${accessToken}`,
-  webhook,
-  accessToken,
-});
 
-beforeEach(() => {
-  const { getUrl, postUrl, accessToken } = setup();
+function setup({ success = true } = {}) {
   getConfig.mockReturnValue(MOCK_FILE_WITH_PLATFORM.messenger);
 
-  client = new MockAdapter(_client);
-  client.onGet(getUrl).reply(200, {
-    access_token: accessToken,
-  });
-  client.onPost(postUrl).reply(200, { success: true });
+  const client = {
+    createSubscription: jest.fn(),
+  };
+
+  client.createSubscription.mockReturnValue(Promise.resolve({ success }));
+
+  MessengerClient.connect = jest.fn(() => client);
 
-  localClient = new MockAdapter(_localClient);
-  localClient.onGet('/api/tunnels').reply(200, {
+  const ngrokClientMock = new MockAdapter(ngrokClient);
+  ngrokClientMock.onGet('/api/tunnels').reply(200, {
     tunnels: [
       {
         public_url: 'http://fakeDomain.ngrok.io',
@@ -69,107 +49,119 @@ beforeEach(() => {
       },
     ],
   });
+
   Confirm.mockImplementation(() => ({
     run: jest.fn(() => Promise.resolve(true)),
   }));
+
   log.print = jest.fn();
   log.error = jest.fn();
   log.bold = jest.fn(s => s);
-});
 
-afterEach(() => {
-  jest.resetAllMocks();
-});
+  process.exit = jest.fn();
+
+  return {
+    client,
+    ngrokClientMock,
+  };
+}
 
 it('be defined', () => {
   expect(setWebhook).toBeDefined();
 });
 
 describe('resolve', () => {
-  it('successfully set webhook', async () => {
-    const { webhook } = setup();
+  it('successfully set webhook and show messages', async () => {
+    setup();
+
+    await setWebhook(WEBHOOK, VERIFY_TOKEN);
 
-    await setWebhook(webhook, configPath);
+    const logs = log.print.mock.calls.map(call => call[0]);
 
-    expect(log.print).toHaveBeenCalledTimes(5);
-    expect(log.print.mock.calls[2][0]).toMatch(/Successfully/);
+    expect(log.print).toBeCalled();
+    expect(logs.some(text => /Successfully/.test(text))).toBe(true);
   });
 
   it('use default fields to setup', async () => {
-    const { getUrl, postUrl, webhook, accessToken } = setup({
-      webhook: 'http://fakeurl.com',
-    });
-    client.onGet(getUrl).reply(200, {
-      access_token: accessToken,
+    const { client } = setup();
+
+    await setWebhook(WEBHOOK, VERIFY_TOKEN);
+
+    expect(client.createSubscription).toBeCalledWith({
+      app_id: '__APP_ID__',
+      access_token: '__APP_ID__|__APP_SECRET__',
+      callback_url: 'http://example.com/webhook',
+      fields: [
+        'messages',
+        'messaging_postbacks',
+        'messaging_optins',
+        'messaging_referrals',
+        'messaging_handovers',
+        'messaging_policy_enforcement',
+      ],
+      object: 'page',
+      verify_token: '__VERIFY_TOKEN__',
     });
-    client
-      .onPost(postUrl, {
-        object: 'page',
-        callback_url: 'http://fakeurl.com',
-        verify_token: '__verifyToken__',
-        fields: ['messages', 'messaging_postbacks', 'messaging_referrals'],
-      })
-      .reply(200, { success: true });
-
-    await setWebhook(webhook, configPath);
-
-    expect(log.print).toHaveBeenCalledTimes(5);
-    expect(log.print.mock.calls[0][0]).toMatch(/messages/);
-    expect(log.print.mock.calls[0][0]).toMatch(/messaging_postbacks/);
-    expect(log.print.mock.calls[0][0]).toMatch(/messaging_referrals/);
   });
 
   it('get ngrok webhook to setup', async () => {
-    const { postUrl } = setup();
-
-    client
-      .onPost(postUrl, {
-        object: 'page',
-        callback_url: 'https://fakeDomain.ngrok.io',
-        verify_token: '__verifyToken__',
-        fields: ['messages', 'messaging_postbacks', 'messaging_referrals'],
-      })
-      .reply(200, { success: true });
-
-    await setWebhook(undefined, configPath);
-
-    expect(log.print).toHaveBeenCalledTimes(5);
-    expect(log.print.mock.calls[0][0]).toMatch(/messages/);
-    expect(log.print.mock.calls[0][0]).toMatch(/messaging_postbacks/);
-    expect(log.print.mock.calls[0][0]).toMatch(/messaging_referrals/);
+    const { client } = setup();
+
+    await setWebhook(undefined, VERIFY_TOKEN);
+
+    expect(client.createSubscription).toBeCalledWith({
+      app_id: '__APP_ID__',
+      access_token: '__APP_ID__|__APP_SECRET__',
+      callback_url: 'https://fakeDomain.ngrok.io',
+      fields: [
+        'messages',
+        'messaging_postbacks',
+        'messaging_optins',
+        'messaging_referrals',
+        'messaging_handovers',
+        'messaging_policy_enforcement',
+      ],
+      object: 'page',
+      verify_token: '__VERIFY_TOKEN__',
+    });
   });
 });
 
 describe('reject', () => {
   it('reject when `appId` not found in config file', async () => {
-    const { webhook } = setup();
+    setup();
+
     getConfig.mockReturnValue({
       appSecret: '__APP_SECRET__',
       verifyToken: '__verifyToken__',
     });
-    process.exit = jest.fn();
 
-    await setWebhook(webhook, configPath);
+    await setWebhook(WEBHOOK, VERIFY_TOKEN);
 
+    expect(log.error).toBeCalled();
     expect(process.exit).toBeCalled();
   });
 
   it('reject when `appSecret` not found in config file', async () => {
-    const { webhook } = setup();
+    setup();
+
     getConfig.mockReturnValue({
       appId: '__APP_ID__',
       verifyToken: '__verifyToken__',
     });
-    process.exit = jest.fn();
 
-    await setWebhook(webhook, configPath);
+    await setWebhook(WEBHOOK, VERIFY_TOKEN);
 
+    expect(log.error).toBeCalled();
     expect(process.exit).toBeCalled();
   });
 
-  it('reject when messenger return not success', () => {
-    const { postUrl, webhook } = setup();
-    client.onPost(postUrl).reply(400, { success: false });
-    expect(setWebhook(webhook, configPath).then).toThrow();
+  it('reject when messenger return not success', async () => {
+    setup({ success: false });
+
+    await setWebhook(WEBHOOK, VERIFY_TOKEN);
+
+    expect(log.error).toBeCalled();
+    expect(process.exit).toBeCalled();
   });
 });
diff --git a/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js b/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js
index ea43d761..306c9d53 100644
--- a/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js
+++ b/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js
@@ -22,7 +22,6 @@ const MOCK_FILE_WITH_PLATFORM = {
     appSecret: '__APP_SECRET__',
     verifyToken: '__verifyToken__',
   },
-  line: {},
 };
 
 let _client;
diff --git a/src/cli/providers/telegram/__tests__/deleteWebhook.spec.js b/src/cli/providers/telegram/__tests__/deleteWebhook.spec.js
index ae4000b8..86b7c9a0 100644
--- a/src/cli/providers/telegram/__tests__/deleteWebhook.spec.js
+++ b/src/cli/providers/telegram/__tests__/deleteWebhook.spec.js
@@ -38,7 +38,6 @@ beforeEach(() => {
 
 afterEach(() => {
   process.exit = _exit;
-  jest.resetAllMocks();
 });
 
 it('be defined', () => {
diff --git a/src/cli/providers/telegram/__tests__/getWebhook.spec.js b/src/cli/providers/telegram/__tests__/getWebhook.spec.js
index 03effca9..b1cc1389 100644
--- a/src/cli/providers/telegram/__tests__/getWebhook.spec.js
+++ b/src/cli/providers/telegram/__tests__/getWebhook.spec.js
@@ -38,7 +38,6 @@ beforeEach(() => {
 
 afterEach(() => {
   process.exit = _exit;
-  jest.resetAllMocks();
 });
 
 it('be defined', () => {
diff --git a/src/cli/providers/telegram/__tests__/setWebhook.spec.js b/src/cli/providers/telegram/__tests__/setWebhook.spec.js
index 654fcfa1..98b661e6 100644
--- a/src/cli/providers/telegram/__tests__/setWebhook.spec.js
+++ b/src/cli/providers/telegram/__tests__/setWebhook.spec.js
@@ -62,7 +62,6 @@ beforeEach(() => {
 
 afterEach(() => {
   process.exit = _exit;
-  jest.resetAllMocks();
 });
 
 it('be defined', () => {
diff --git a/src/session/__tests__/MongoSessionStore.spec.js b/src/session/__tests__/MongoSessionStore.spec.js
index 4aebb625..feb8fe51 100644
--- a/src/session/__tests__/MongoSessionStore.spec.js
+++ b/src/session/__tests__/MongoSessionStore.spec.js
@@ -9,7 +9,6 @@ const { MongoClient } = require('mongodb');
 const MINUTES_IN_ONE_YEAR = 365 * 24 * 60;
 
 function setup(options = {}) {
-  jest.resetAllMocks();
   const sessions = {
     findOne: jest.fn(),
     updateOne: jest.fn(),