diff --git a/lib/facebook/setup.js b/lib/facebook/setup.js index 1df238a..41a258c 100644 --- a/lib/facebook/setup.js +++ b/lib/facebook/setup.js @@ -47,7 +47,7 @@ module.exports = function fbSetup(api, bot, logError, optionalParser, optionalRe stageName: lambdaDetails.alias }).then(data => { if (options['configure-fb-bot']) { - let token, pageAccessToken; + let token, pageAccessToken, pageId, subscribedFields; return Promise.resolve().then(() => { if (data.variables && data.variables.facebookVerifyToken) @@ -71,11 +71,18 @@ module.exports = function fbSetup(api, bot, logError, optionalParser, optionalRe console.log(`\nYour webhook URL is: ${color.cyan}${lambdaDetails.apiUrl}/facebook${color.reset}\n`); console.log(`Your verify token is: ${color.cyan}${token}${color.reset}\n`); - return prompt(['Facebook page access token', 'Facebook App Secret']); + return prompt([ + 'Facebook page access token', + 'Facebook App Secret', + 'Facebook page ID', + 'Subscribed fields (comma separated)' + ]); }) .then(results => { console.log('\n'); pageAccessToken = results['Facebook page access token']; + pageId = results['Facebook page ID']; + subscribedFields = results['Subscribed fields (comma separated)'].split(',').map(field => `'${field.trim()}'`).join(','); const deployment = { restApiId: lambdaDetails.apiId, stageName: lambdaDetails.alias, @@ -90,7 +97,7 @@ module.exports = function fbSetup(api, bot, logError, optionalParser, optionalRe return utils.apiGatewayPromise.createDeploymentPromise(deployment); }) - .then(() => rp.post(`https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=${pageAccessToken}`)); + .then(() => rp.post(`https://graph.facebook.com/v4.0/${pageId}/subscribed_apps?access_token=${pageAccessToken}&subscribed_fields=[${subscribedFields}]`)); } }); }) diff --git a/spec/facebook/facebook-setup-spec.js b/spec/facebook/facebook-setup-spec.js index 84a066b..6c23e56 100644 --- a/spec/facebook/facebook-setup-spec.js +++ b/spec/facebook/facebook-setup-spec.js @@ -1,6 +1,7 @@ -/*global require, describe, it, expect, beforeEach, jasmine*/ +/*global require, describe, it, expect, beforeEach, jasmine, spyOn*/ 'use strict'; var underTest = require('../../lib/facebook/setup'); +var https = require('https'); describe('Facebook setup', () => { var api, bot, logError, parser, responder, botPromise, botResolve, botReject; beforeEach(() => { @@ -283,6 +284,91 @@ describe('Facebook setup', () => { }); }); }); - + }); + describe('post deploy step processor', () => { + it('is called once', () => { + expect(api.addPostDeployStep.calls.count()).toEqual(1); + expect(api.addPostDeployStep).toHaveBeenCalledWith('facebook', jasmine.any(Function)); + }); + describe('processing user input', () => { + const singleInput = (data) => { + return new Promise((resolve) => { + setTimeout(() => { + process.stdin.emit('data', data); + resolve(); + }, 500); + }); + }; + const emulateUserInputPromise = (accessToken, appSecret, pageId, subscribedField) => { + return new Promise((resolve) => { + singleInput(accessToken) + .then(() => singleInput(appSecret)) + .then(() => singleInput(pageId)) + .then(() => singleInput(subscribedField)) + .then(() => setTimeout(() => resolve()), 500); + }); + }; + let options = {'configure-fb-bot': true}; + let lambdaDetails = {apiUrl: 'https://testlambdafunction.com/latest'}; + let getStagePromise = () => Promise.resolve({variables: {}}); + let createDeploymentPromise = () => Promise.resolve(); + let utils = {apiGatewayPromise: {getStagePromise: getStagePromise, createDeploymentPromise: createDeploymentPromise}}; + var handler; + beforeEach(() => { + handler = api.addPostDeployStep.calls.argsFor(0)[1]; + }); + it('returns webhook URL if all parameters are valid', (done) => { + handler(options, lambdaDetails, utils).then(url => { + expect(url).toEqual(`${lambdaDetails.apiUrl}/facebook`); + done(); + }); + emulateUserInputPromise('accessToken\n', 'appSecret\n', 'pageId\n', 'messages, messaging_postbacks\n').then(() => { + https.request.calls[0].respond(200, 'OK'); + }); + }); + it('returns webhook URL if apiGateway already has facebookVerifyToken', (done) => { + getStagePromise = () => Promise.resolve({variables: {facebookVerifyToken: 'facebookVerityToken'}}); + utils = {apiGatewayPromise: {getStagePromise: getStagePromise, createDeploymentPromise: createDeploymentPromise}}; + handler(options, lambdaDetails, utils).then(url => { + expect(url).toEqual(`${lambdaDetails.apiUrl}/facebook`); + done(); + }); + emulateUserInputPromise('accessToken\n', 'appSecret\n', 'pageId\n', 'messages, messaging_postbacks\n').then(() => { + https.request.calls[0].respond(200, 'OK'); + }); + }); + it('shows deprecation warning and returns webhook URL if apiGateway does not return \'variables\' key', (done) => { + spyOn(console, 'log'); + getStagePromise = () => Promise.resolve({}); + utils = {apiGatewayPromise: {getStagePromise: getStagePromise, createDeploymentPromise: createDeploymentPromise}}; + handler(options, lambdaDetails, utils).then(url => { + expect(console.log.calls.mostRecent().args[0]).toMatch(/Deprecation warning/); + expect(url).toEqual(`${lambdaDetails.apiUrl}/facebook`); + done(); + }); + emulateUserInputPromise('accessToken\n', 'appSecret\n', 'pageId\n', 'messages, messaging_postbacks\n').then(() => { + https.request.calls[0].respond(200, 'OK'); + }); + }); + it('returns webhook URL even if \'configure-fb-bot\' option is not specified', (done) => { + options = { 'configure-fb-bot': false }; + handler(options, lambdaDetails, utils).then(url => { + expect(url).toEqual(`${lambdaDetails.apiUrl}/facebook`); + done(); + }); + emulateUserInputPromise('accessToken\n', 'appSecret\n', 'pageId\n', 'messages, messaging_postbacks\n').then(() => { + https.request.calls[0].respond(200, 'OK'); + }); + }); + it('returns webhook URL even if subscribed fields ended with comma and space', (done) => { + handler(options, lambdaDetails, utils).then(url => { + expect(url).toEqual(`${lambdaDetails.apiUrl}/facebook`); + done(); + }); + emulateUserInputPromise('accessToken\n', 'appSecret\n', 'pageId\n', 'messages, \n').then(() => { + https.request.calls[0].respond(200, 'OK'); + }); + }); + }); }); });