Repository: Yoctol/bottender (ts)

Issue:
CLI skip prompt for CI usage
Maybe `--skip-prompt` or `--no-prompt` ?

Pull request:
Add optional --yes for Messenger force upload attachment
close #119 

Patch:
diff --git a/examples/cross-platform/README.md b/examples/cross-platform/README.md
index 69d9ffac..0a6ab301 100644
--- a/examples/cross-platform/README.md
+++ b/examples/cross-platform/README.md
@@ -7,21 +7,50 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/cross-platform
 cd cross-platform
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put all needed information into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+You must set webhooks correspond to mounted paths properly:
+
+```
+<YOUR_BASE_URL>/messenger
+<YOUR_BASE_URL>/line
+<YOUR_BASE_URL>/slack
+<YOUR_BASE_URL>/telegram
+<YOUR_BASE_URL>/viber
+```
+
+> Note: See related examples to know how to set webhook on each platform
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
 ## Idea of this example
 
-This example shows the basic idea of building a cross-platform bot. You have
-better understand the concept of
-[handler](https://bottender.js.org/docs/APIReference-Handler) at first. The best
-feature of this example is that you can only develop one handler for four
+This example shows the basic idea of building a cross-platform bot. The best
+feature of this example is that you can only develop one handler for five
 different bots, instead of developing one handler for each platform.
 
 ## Related examples
 
-* [messenger-builder](../messenger-builder)
-* [line-builder](../line-builder)
-* [slack-builder](../slack-builder)
-* [telegram-builder](../telegram-builder)
+* [messenger-hello-world](../messenger-hello-world)
+* [line-hello-world](../line-hello-world)
+* [slack-hello-world](../slack-hello-world)
+* [telegram-hello-world](../telegram-hello-world)
+* [viber-hello-world](../viber-hello-world)
diff --git a/examples/cross-platform/bottender.config.js b/examples/cross-platform/bottender.config.js
new file mode 100644
index 00000000..e50b566f
--- /dev/null
+++ b/examples/cross-platform/bottender.config.js
@@ -0,0 +1,20 @@
+module.exports = {
+  messenger: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+    appSecret: '__FILL_YOUR_SECRET_HERE__',
+  },
+  line: {
+    channelSecret: '__FILL_YOUR_CHANNEL_SECRET_HERE__',
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+  telegram: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+  slack: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+    verificationToken: '__FILL_YOUR_VERIFICATION_TOKEN_HERE__',
+  },
+  viber: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/cross-platform/handler.js b/examples/cross-platform/handler.js
index 1c7dac66..a306309d 100644
--- a/examples/cross-platform/handler.js
+++ b/examples/cross-platform/handler.js
@@ -1,5 +1,5 @@
 const handler = async context => {
-  await context.sendText('Hello World');
+  await context.sendText(`Hello World. Platform: ${context.platform}`);
 };
 
 module.exports = handler;
diff --git a/examples/cross-platform/index.js b/examples/cross-platform/index.js
index d81515e4..a7299687 100644
--- a/examples/cross-platform/index.js
+++ b/examples/cross-platform/index.js
@@ -1,26 +1,16 @@
 const express = require('express');
 const bodyParser = require('body-parser');
-const { MessengerBot, LineBot, TelegramBot, SlackBot } = require('bottender');
+const {
+  MessengerBot,
+  LineBot,
+  TelegramBot,
+  SlackBot,
+  ViberBot,
+} = require('bottender');
 const { registerRoutes } = require('bottender/express');
 
 const handler = require('./handler');
-
-const config = {
-  messenger: {
-    accessToken: '__FILL_YOUR_TOKEN_HERE__',
-    appSecret: '__FILL_YOUR_SECRET_HERE__',
-  },
-  line: {
-    channelSecret: '__FILL_YOUR_CHANNEL_SECRET_HERE__',
-    accessToken: '__FILL_YOUR_TOKEN_HERE__',
-  },
-  telegram: {
-    accessToken: '__FILL_YOUR_TOKEN_HERE__',
-  },
-  slack: {
-    accessToken: '__FILL_YOUR_TOKEN_HERE__',
-  },
-};
+const config = require('./bottender.config');
 
 const server = express();
 
@@ -37,12 +27,14 @@ const bots = {
   line: new LineBot(config.line).onEvent(handler),
   slack: new SlackBot(config.slack).onEvent(handler),
   telegram: new TelegramBot(config.telegram).onEvent(handler),
+  viber: new ViberBot(config.viber).onEvent(handler),
 };
 
 registerRoutes(server, bots.messenger, { path: '/messenger' });
 registerRoutes(server, bots.line, { path: '/line' });
 registerRoutes(server, bots.slack, { path: '/slack' });
 registerRoutes(server, bots.telegram, { path: '/telegram' });
+registerRoutes(server, bots.viber, { path: '/viber' });
 
 server.listen(5000, () => {
   console.log('server is listening on 5000 port...');
diff --git a/examples/line-builder/README.md b/examples/line-builder/README.md
index eaffb835..74a6d6da 100644
--- a/examples/line-builder/README.md
+++ b/examples/line-builder/README.md
@@ -7,14 +7,34 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/line-builder
 cd line-builder
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` and `channelSecret` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+To set the webhook, go to [LINE developers console](https://developers.line.me/console/) and edit webhook information for your channel.
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
 ## Idea of this example
 
 This example shows how to combine
-[handler](https://bottender.js.org/docs/APIReference-Handler) with
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) with
 [LINE](https://line.me/) bot. For more information, check our
 [LINE guides](https://bottender.js.org/docs/Platforms-LINE).
 
diff --git a/examples/line-hello-world/README.md b/examples/line-hello-world/README.md
index 8da3ee0c..8dda9daf 100644
--- a/examples/line-hello-world/README.md
+++ b/examples/line-hello-world/README.md
@@ -7,14 +7,33 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/line-hello-world
 cd line-hello-world
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` and `channelSecret` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+To set the webhook, go to [LINE developers console](https://developers.line.me/console/) and edit webhook information for your channel.
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
 ## Idea of this example
 
-This example is a simple bot running on [LINE](https://line.me/). You have to
-get `channelSecret` and `accessToken` before running this bot.\
+This example is a simple bot running on [LINE](https://line.me/).
 For more information, check our [LINE guides](https://bottender.js.org/docs/Platforms-LINE).
 
 ## Related examples
diff --git a/examples/messenger-builder/README.md b/examples/messenger-builder/README.md
index b479cb22..7367a5de 100644
--- a/examples/messenger-builder/README.md
+++ b/examples/messenger-builder/README.md
@@ -14,7 +14,7 @@ npm run dev
 ## Idea of this example
 
 This example shows how to combine
-[handler](https://bottender.js.org/docs/APIReference-Handler) with
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) with
 [Messenger](https://www.messenger.com/) bot. You have to get `accessToken` and
 `appSecret` before running this bot.\
 For more information, check our [Messenger guides](https://bottender.js.org/docs/Platforms-Messenger).
diff --git a/examples/middleware/README.md b/examples/middleware/README.md
index a9e30171..37073199 100644
--- a/examples/middleware/README.md
+++ b/examples/middleware/README.md
@@ -14,7 +14,7 @@ npm run dev
 ## Idea of this example
 
 The feature of this example is using
-[handler](https://bottender.js.org/docs/APIReference-Handler) as middleware, so
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) as middleware, so
 you are able to combine two handlers into one.\
 For more information, check our [Middleware guides](https://bottender.js.org/docs/Guides-Middleware).
 
diff --git a/examples/slack-builder/README.md b/examples/slack-builder/README.md
index fb762038..fb7d56c0 100644
--- a/examples/slack-builder/README.md
+++ b/examples/slack-builder/README.md
@@ -7,16 +7,29 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/slack-builder
 cd slack-builder
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` and `verificationToken` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
 ## Idea of this example
 
 This example shows how to combine
-[handler](https://bottender.js.org/docs/APIReference-Handler) with
-[Slack](https://slack.com/) bot. You have to get `accessToken` and `verificationToken` before running
-this bot.\
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) with
+[Slack](https://slack.com/) bot.
 For more information, check our [Slack guides](https://bottender.js.org/docs/Platforms-Slack).
 
 ## Related examples
diff --git a/examples/slack-hello-world/README.md b/examples/slack-hello-world/README.md
index 187089a7..f84622ef 100644
--- a/examples/slack-hello-world/README.md
+++ b/examples/slack-hello-world/README.md
@@ -7,14 +7,27 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/slack-hello-world
 cd slack-hello-world
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` and `verificationToken` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
 ## Idea of this example
 
-This example is a simple bot running on [Slack](https://slack.com/). You have to
-get `accessToken` and `verificationToken` before running this bot.\
+This example is a simple bot running on [Slack](https://slack.com/).
 For more information, check our [Slack guides](https://bottender.js.org/docs/Platforms-Slack).
 
 ## Related examples
diff --git a/examples/slack-interactive-message/README.md b/examples/slack-interactive-message/README.md
index d0a5e132..3a9fcf0a 100644
--- a/examples/slack-interactive-message/README.md
+++ b/examples/slack-interactive-message/README.md
@@ -7,13 +7,27 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/slack-interactive-message
 cd slack-interactive-message
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` and `verificationToken` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
 ## Idea of this example
 
-This example shows how to send [messages with interactive components (button/menu)](https://api.slack.com/interactive-messages) and handle the event triggered by users clicking the button/menu. 
+This example shows how to send [messages with interactive components (button/menu)](https://api.slack.com/interactive-messages) and handle the event triggered by users clicking the button/menu.
 
 For more information, check our [Slack guides](https://bottender.js.org/docs/Platforms-Slack).
 
@@ -25,7 +39,6 @@ After that, type 'heyo' to the bot and it will respond you with buttons and menu
 
 ![default](https://user-images.githubusercontent.com/1003146/33164927-e2ec8da6-d06f-11e7-9378-e8a3e9b37257.png)
 
-
 ## Related examples
 
 * [slack-builder](../slack-builder)
diff --git a/examples/telegram-builder/README.md b/examples/telegram-builder/README.md
index 958616d0..3b0b95af 100644
--- a/examples/telegram-builder/README.md
+++ b/examples/telegram-builder/README.md
@@ -7,15 +7,41 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/telegram-builder
 cd telegram-builder
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+While the server running, you can run following command with global `bottender` to set up the webhook:
+
+```
+bottender telegram webhook set -w <YOUR_WEBHOOK_URL>
+```
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
+> Note: You must put `accessToken` into `bottender.config.js` before running this command.
+
 ## Idea of this example
 
 This example shows how to combine
-[handler](https://bottender.js.org/docs/APIReference-Handler) with
-[Telegram](https://telegram.org/) bot. You have to get `accessToken` before running this bot.\
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) with
+[Telegram](https://telegram.org/) bot.
 For more information, check our [Telegram guides](https://bottender.js.org/docs/Platforms-Telegram).
 
 ## Related examples
diff --git a/examples/telegram-builder/bottender.config.js b/examples/telegram-builder/bottender.config.js
new file mode 100644
index 00000000..b55afecf
--- /dev/null
+++ b/examples/telegram-builder/bottender.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+  telegram: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/telegram-builder/index.js b/examples/telegram-builder/index.js
index dc2435b0..a2eb1708 100644
--- a/examples/telegram-builder/index.js
+++ b/examples/telegram-builder/index.js
@@ -1,8 +1,10 @@
 const { TelegramBot, TelegramHandler } = require('bottender');
 const { createServer } = require('bottender/express');
 
+const config = require('./bottender.config').telegram;
+
 const bot = new TelegramBot({
-  accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  accessToken: config.accessToken,
 });
 
 const handler = new TelegramHandler()
diff --git a/examples/telegram-hello-world/README.md b/examples/telegram-hello-world/README.md
index 8deae23e..06d86b62 100644
--- a/examples/telegram-hello-world/README.md
+++ b/examples/telegram-hello-world/README.md
@@ -7,14 +7,39 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/telegram-hello-world
 cd telegram-hello-world
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+While the server running, you can run following command with global `bottender` to set up the webhook:
+
+```
+bottender telegram webhook set -w <YOUR_WEBHOOK_URL>
+```
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
+> Note: You must put `accessToken` into `bottender.config.js` before running this command.
+
 ## Idea of this example
 
-This example is a simple bot running on [Telegram](https://telegram.org/). You
-have to get `accessToken` before running this bot.\
+This example is a simple bot running on [Telegram](https://telegram.org/).
 For more information, check our [Telegram guides](https://bottender.js.org/docs/Platforms-Telegram).
 
 ## Related examples
diff --git a/examples/telegram-hello-world/bottender.config.js b/examples/telegram-hello-world/bottender.config.js
new file mode 100644
index 00000000..b55afecf
--- /dev/null
+++ b/examples/telegram-hello-world/bottender.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+  telegram: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/telegram-hello-world/index.js b/examples/telegram-hello-world/index.js
index 66e9f953..ae4663cc 100644
--- a/examples/telegram-hello-world/index.js
+++ b/examples/telegram-hello-world/index.js
@@ -1,8 +1,10 @@
 const { TelegramBot } = require('bottender');
 const { createServer } = require('bottender/express');
 
+const config = require('./bottender.config').telegram;
+
 const bot = new TelegramBot({
-  accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  accessToken: config.accessToken,
 });
 
 bot.onEvent(async context => {
diff --git a/examples/telegram-long-polling/README.md b/examples/telegram-long-polling/README.md
index 8c4dd5c0..b6885e74 100644
--- a/examples/telegram-long-polling/README.md
+++ b/examples/telegram-long-polling/README.md
@@ -7,14 +7,27 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/telegram-long-polling
 cd telegram-long-polling
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` into `index.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
 ## Idea of this example
 
-This example is a simple bot running on [Telegram](https://telegram.org/) using [getUpdates](https://core.telegram.org/bots/api#getupdates) API (long polling). You
-have to get `accessToken` before running this bot.\
+This example is a simple bot running on [Telegram](https://telegram.org/) using [getUpdates](https://core.telegram.org/bots/api#getupdates) API (long polling).
 For more information, check our [Telegram guides](https://bottender.js.org/docs/Platforms-Telegram).
 
 ## Related examples
diff --git a/examples/viber-builder/README.md b/examples/viber-builder/README.md
index f6ee594e..6460b4d4 100644
--- a/examples/viber-builder/README.md
+++ b/examples/viber-builder/README.md
@@ -7,15 +7,41 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/viber-builder
 cd viber-builder
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+While the server running, you can run following command with global `bottender` to set up the webhook:
+
+```
+bottender viber webhook set -w <YOUR_WEBHOOK_URL>
+```
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
+> Note: You must put `accessToken` into `bottender.config.js` before running this command.
+
 ## Idea of this example
 
 This example shows how to combine
-[handler](https://bottender.js.org/docs/APIReference-Handler) with
-[Viber](https://www.viber.com/) bot. You have to get `accessToken` before running this bot.\
+[`Handler`](https://bottender.js.org/docs/APIReference-Handler) with
+[Viber](https://www.viber.com/) bot.
 For more information, check our [Viber guides](https://bottender.js.org/docs/Platforms-Viber).
 
 ## Related examples
diff --git a/examples/viber-builder/bottender.config.js b/examples/viber-builder/bottender.config.js
new file mode 100644
index 00000000..c37cb1c8
--- /dev/null
+++ b/examples/viber-builder/bottender.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+  viber: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/viber-builder/index.js b/examples/viber-builder/index.js
index ae553554..b4fc5253 100644
--- a/examples/viber-builder/index.js
+++ b/examples/viber-builder/index.js
@@ -1,8 +1,10 @@
 const { ViberBot, ViberHandler } = require('bottender');
 const { createServer } = require('bottender/express');
 
+const config = require('./bottender.config').viber;
+
 const bot = new ViberBot({
-  accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  accessToken: config.accessToken,
 });
 
 const handler = new ViberHandler()
diff --git a/examples/viber-hello-world/README.md b/examples/viber-hello-world/README.md
index 2973ffc7..2f899f6e 100644
--- a/examples/viber-hello-world/README.md
+++ b/examples/viber-hello-world/README.md
@@ -7,14 +7,39 @@ Download this example or clone [bottender](https://github.com/Yoctol/bottender).
 ```
 curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/viber-hello-world
 cd viber-hello-world
+```
+
+Install dependencies:
+
+```
 npm install
+```
+
+You must put `accessToken` into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
 npm run dev
 ```
 
+This command will start server for bot developing at `http://localhost:5000`.
+
+## Set webhook
+
+While the server running, you can run following command with global `bottender` to set up the webhook:
+
+```
+bottender viber webhook set -w <YOUR_WEBHOOK_URL>
+```
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
+> Note: You must put `accessToken` into `bottender.config.js` before running this command.
+
 ## Idea of this example
 
 This example is a simple bot running on [Viber](https://www.viber.com/).
-You have to get `accessToken` before running this bot.\
 For more information, check our [Viber guides](https://bottender.js.org/docs/Platforms-Viber).
 
 ## Related examples
diff --git a/examples/viber-hello-world/bottender.config.js b/examples/viber-hello-world/bottender.config.js
new file mode 100644
index 00000000..c37cb1c8
--- /dev/null
+++ b/examples/viber-hello-world/bottender.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+  viber: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/viber-hello-world/index.js b/examples/viber-hello-world/index.js
index a7e81238..0d854b00 100644
--- a/examples/viber-hello-world/index.js
+++ b/examples/viber-hello-world/index.js
@@ -1,8 +1,10 @@
 const { ViberBot } = require('bottender');
 const { createServer } = require('bottender/express');
 
+const config = require('./bottender.config').viber;
+
 const bot = new ViberBot({
-  accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  accessToken: config.accessToken,
 });
 
 bot.onEvent(async context => {
diff --git a/src/cli/providers/messenger/attachment.js b/src/cli/providers/messenger/attachment.js
index 8b49d274..b70e10d3 100644
--- a/src/cli/providers/messenger/attachment.js
+++ b/src/cli/providers/messenger/attachment.js
@@ -25,7 +25,8 @@ const help = () => {
 
     ${chalk.dim('Options:')}
 
-      --force   Upload all assets and regenerate bottender-lock.json.
+      -f, --force   Upload all assets and regenerate bottender-lock.json.
+      -y, --yes     Skip prompt confirmation for uploading assets.
 
     ${chalk.dim('Examples:')}
 
@@ -81,7 +82,10 @@ const logUploadInfo = uploadInfo => {
 };
 
 export async function uploadAttachment(ctx) {
-  const { force } = ctx.argv;
+  const { f, force: _force, y, yes: _yes } = ctx.argv;
+  const force = f || _force;
+  const yes = y || _yes;
+
   try {
     warn(
       `${bold(
@@ -99,17 +103,21 @@ export async function uploadAttachment(ctx) {
 
     files.forEach(print);
 
-    const promptResult = await inquirer.prompt([
-      {
-        type: 'confirm',
-        message: force
-          ? 'Are you sure you want to force upload all assets?'
-          : 'Is it correct for uploading?',
-        name: 'confirm',
-      },
-    ]);
-
-    if (!promptResult.confirm) {
+    let confirm = true;
+    if (!yes) {
+      const promptResult = await inquirer.prompt([
+        {
+          type: 'confirm',
+          message: force
+            ? 'Are you sure you want to force upload all assets?'
+            : 'Is it correct for uploading?',
+          name: 'confirm',
+        },
+      ]);
+      confirm = promptResult.confirm;
+    }
+
+    if (!confirm) {
       print('bye');
       return process.exit(0);
     }
diff --git a/src/cli/providers/sh/init/template/README.md b/src/cli/providers/sh/init/template/README.md
index 35e810da..b07336d7 100644
--- a/src/cli/providers/sh/init/template/README.md
+++ b/src/cli/providers/sh/init/template/README.md
@@ -25,7 +25,7 @@ my-bot/
 
 All functionalities start from here.\
 Mainly it's a server which listen on port 5000. You are encouraged to add more [event listener](https://bottender.js.org/docs/APIReference-Event)
-and [handler](https://bottender.js.org/docs/APIReference-Handler) to enrich the bot.
+and [`Handler`](https://bottender.js.org/docs/APIReference-Handler) to enrich the bot.
 
 See more examples, please refer to
 [Bottender examples](https://github.com/Yoctol/bottender/tree/master/examples).


Test patch:
diff --git a/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js b/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js
new file mode 100644
index 00000000..ea43d761
--- /dev/null
+++ b/src/cli/providers/messenger/__tests__/uploadAttachment.spec.js
@@ -0,0 +1,126 @@
+import { uploadAttachment } from '../attachment';
+
+jest.mock('fs');
+jest.mock('inquirer');
+jest.mock('messaging-api-messenger');
+jest.mock('recursive-readdir');
+
+jest.mock('../../../shared/log');
+jest.mock('../../../shared/getConfig');
+
+const inquirer = require('inquirer');
+const { MessengerClient } = require('messaging-api-messenger');
+const readdir = require('recursive-readdir');
+
+const log = require('../../../shared/log');
+const getConfig = require('../../../shared/getConfig');
+
+const MOCK_FILE_WITH_PLATFORM = {
+  messenger: {
+    accessToken: '__PUT_YOUR_ACCESS_TOKEN_HERE__',
+    appId: '__APP_ID__',
+    appSecret: '__APP_SECRET__',
+    verifyToken: '__verifyToken__',
+  },
+  line: {},
+};
+
+let _client;
+
+describe('uploadAttachment', () => {
+  beforeEach(() => {
+    _client = {
+      getPageInfo: jest.fn(),
+      uploadAttachment: jest.fn(),
+    };
+    MessengerClient.connect = jest.fn(() => _client);
+    getConfig.mockReturnValue(MOCK_FILE_WITH_PLATFORM.messenger);
+    readdir.mockReturnValue(
+      Promise.resolve([
+        {
+          name: 'The X-Files',
+        },
+      ])
+    );
+    inquirer.prompt = jest.fn();
+    inquirer.prompt.mockReturnValue(
+      Promise.resolve({
+        confirm: true,
+      })
+    );
+    process.exit = jest.fn();
+  });
+
+  it('be defined', () => {
+    expect(uploadAttachment).toBeDefined();
+  });
+
+  describe('resolve', () => {
+    it('--yes should work', async () => {
+      const ctx = {
+        argv: { force: true, yes: true },
+      };
+
+      await uploadAttachment(ctx);
+
+      expect(inquirer.prompt).not.toBeCalled();
+      expect(log.print).not.toBeCalledWith('bye');
+    });
+
+    it('Abbreviational options should work', async () => {
+      const ctx = {
+        argv: { f: true, y: true },
+      };
+
+      await uploadAttachment(ctx);
+
+      expect(inquirer.prompt).not.toBeCalled();
+      expect(log.print).not.toBeCalledWith('bye');
+    });
+  });
+
+  describe('reject', () => {
+    it('reject when `accessToken` not found in config file', async () => {
+      const ctx = {
+        argv: {},
+      };
+
+      getConfig.mockReturnValueOnce({
+        appId: '__APP_ID__',
+        appSecret: '__APP_SECRET__',
+        verifyToken: '__verifyToken__',
+      });
+
+      await uploadAttachment(ctx);
+
+      expect(process.exit).toBeCalled();
+      expect(log.error).toBeCalledWith(
+        'accessToken is not found in config file'
+      );
+    });
+
+    it('exit when user does not confirm force upload', async () => {
+      const ctx = {
+        argv: {
+          force: true,
+        },
+      };
+      inquirer.prompt.mockReturnValueOnce(
+        Promise.resolve({
+          confirm: false,
+        })
+      );
+
+      await uploadAttachment(ctx);
+
+      expect(inquirer.prompt).toBeCalledWith([
+        {
+          type: 'confirm',
+          message: 'Are you sure you want to force upload all assets?',
+          name: 'confirm',
+        },
+      ]);
+      expect(process.exit).toBeCalled();
+    });
+  });
+});
diff --git a/src/test-utils/ContextSimulator.js b/src/test-utils/ContextSimulator.js
index 48f148ae..4fdff8aa 100644
--- a/src/test-utils/ContextSimulator.js
+++ b/src/test-utils/ContextSimulator.js
@@ -99,7 +99,7 @@ class ContextSimulator {
     }
   }
 
-  createContext({ event }: { event: Object }): Object {
+  createContext({ event, state }: { event: Object, state?: Object }): Object {
     const base = {
       platform: 'other',
 
@@ -111,7 +111,7 @@ class ContextSimulator {
       },
 
       event,
-      state: {},
+      state: state || {},
 
       isHandled: false,