From 778fd3e367fdc5470c654106588e8f956c8e38b9 Mon Sep 17 00:00:00 2001 From: curbengh <43627182+curbengh@users.noreply.github.com> Date: Wed, 11 Sep 2019 05:27:09 +0100 Subject: [PATCH] (WIP) style: prettier --- .eslintrc.json | 15 +- lib/box/index.js | 219 ++-- lib/extend/console.js | 8 +- lib/extend/filter.js | 12 +- lib/extend/tag.js | 51 +- lib/hexo/default_config.js | 1 - lib/hexo/index.js | 207 ++-- lib/hexo/load_config.js | 62 +- lib/hexo/load_database.js | 24 +- lib/hexo/load_plugins.js | 91 +- lib/hexo/multi_config_path.js | 117 +- lib/hexo/post.js | 277 +++-- lib/hexo/render.js | 52 +- lib/hexo/router.js | 52 +- lib/hexo/scaffold.js | 57 +- lib/models/asset.js | 8 +- lib/models/cache.js | 80 +- lib/models/category.js | 25 +- lib/models/data.js | 2 +- lib/models/page.js | 20 +- lib/models/post.js | 188 +-- lib/models/post_asset.js | 10 +- lib/models/post_category.js | 4 +- lib/models/post_tag.js | 4 +- lib/models/tag.js | 12 +- lib/plugins/console/clean.js | 2 +- lib/plugins/console/config.js | 28 +- lib/plugins/console/deploy.js | 46 +- lib/plugins/console/generate.js | 197 ++-- lib/plugins/console/index.js | 213 ++-- lib/plugins/console/list/category.js | 4 +- lib/plugins/console/list/index.js | 6 +- lib/plugins/console/list/page.js | 2 +- lib/plugins/console/list/post.js | 6 +- lib/plugins/console/list/tag.js | 6 +- lib/plugins/console/migrate.js | 6 +- lib/plugins/console/new.js | 2 +- lib/plugins/console/publish.js | 19 +- lib/plugins/console/render.js | 41 +- .../filter/after_post_render/external_link.js | 39 +- .../filter/before_generate/render_post.js | 2 +- .../before_post_render/backtick_code_block.js | 75 +- lib/plugins/filter/meta_generator.js | 11 +- lib/plugins/filter/new_post_path.js | 10 +- lib/plugins/filter/post_permalink.js | 8 +- lib/plugins/filter/template_locals/i18n.js | 5 +- lib/plugins/generator/asset.js | 34 +- lib/plugins/helper/date.js | 7 +- lib/plugins/helper/fragment_cache.js | 2 +- lib/plugins/helper/gravatar.js | 7 +- lib/plugins/helper/image_tag.js | 9 +- lib/plugins/helper/link_to.js | 13 +- lib/plugins/helper/list_archives.js | 4 +- lib/plugins/helper/list_categories.js | 37 +- lib/plugins/helper/list_posts.js | 13 +- lib/plugins/helper/list_tags.js | 17 +- lib/plugins/helper/mail_to.js | 11 +- lib/plugins/helper/number_format.js | 3 +- lib/plugins/helper/open_graph.js | 45 +- lib/plugins/helper/paginator.js | 64 +- lib/plugins/helper/partial.js | 63 +- lib/plugins/helper/render.js | 16 +- lib/plugins/helper/search_form.js | 10 +- lib/plugins/helper/tagcloud.js | 11 +- lib/plugins/helper/toc.js | 22 +- lib/plugins/helper/url_for.js | 9 +- lib/plugins/processor/asset.js | 26 +- lib/plugins/processor/post.js | 258 ++-- lib/plugins/renderer/swig.js | 31 +- lib/plugins/tag/asset_img.js | 2 +- lib/plugins/tag/asset_link.js | 2 +- lib/plugins/tag/asset_path.js | 2 +- lib/plugins/tag/blockquote.js | 31 +- lib/plugins/tag/code.js | 52 +- lib/plugins/tag/gist.js | 10 +- lib/plugins/tag/iframe.js | 10 +- lib/plugins/tag/img.js | 14 +- lib/plugins/tag/include_code.js | 147 +-- lib/plugins/tag/index.js | 4 +- lib/plugins/tag/jsfiddle.js | 13 +- lib/plugins/tag/link.js | 10 +- lib/plugins/tag/post_link.js | 2 +- lib/plugins/tag/post_path.js | 2 +- lib/plugins/tag/pullquote.js | 25 +- lib/plugins/tag/vimeo.js | 10 +- lib/plugins/tag/youtube.js | 10 +- lib/theme/index.js | 11 +- lib/theme/processors/config.js | 17 +- lib/theme/processors/source.js | 11 +- lib/theme/view.js | 28 +- test/fixtures/post_render.js | 9 +- test/scripts/box/box.js | 430 ++++--- test/scripts/box/file.js | 34 +- test/scripts/console/clean.js | 32 +- test/scripts/console/config.js | 140 ++- test/scripts/console/deploy.js | 40 +- test/scripts/console/generate.js | 308 +++-- test/scripts/console/list_categories.js | 25 +- test/scripts/console/list_page.js | 16 +- test/scripts/console/list_post.js | 22 +- test/scripts/console/list_tags.js | 21 +- test/scripts/console/migrate.js | 4 +- test/scripts/console/new.js | 193 +-- test/scripts/console/publish.js | 164 +-- test/scripts/console/render.js | 147 +-- test/scripts/extend/console.js | 6 +- test/scripts/extend/deployer.js | 4 +- test/scripts/extend/filter.js | 48 +- test/scripts/extend/migrator.js | 4 +- test/scripts/extend/tag.js | 73 +- test/scripts/extend/tag_errors.js | 45 +- test/scripts/filters/backtick_code_block.js | 144 +-- test/scripts/filters/excerpt.js | 85 +- test/scripts/filters/external_link.js | 60 +- test/scripts/filters/i18n_locals.js | 4 +- test/scripts/filters/meta_generator.js | 33 +- test/scripts/filters/new_post_path.js | 151 ++- test/scripts/filters/post_permalink.js | 30 +- test/scripts/filters/render_post.js | 65 +- test/scripts/filters/save_database.js | 22 +- test/scripts/filters/titlecase.js | 8 +- test/scripts/generators/asset.js | 91 +- test/scripts/generators/page.js | 82 +- test/scripts/generators/post.js | 106 +- test/scripts/helpers/css.js | 21 +- test/scripts/helpers/date.js | 103 +- test/scripts/helpers/debug.js | 12 +- test/scripts/helpers/favicon_tag.js | 4 +- test/scripts/helpers/feed_tag.js | 12 +- test/scripts/helpers/fragment_cache.js | 6 +- test/scripts/helpers/gravatar.js | 13 +- test/scripts/helpers/image_tag.js | 19 +- test/scripts/helpers/is.js | 111 +- test/scripts/helpers/link_to.js | 33 +- test/scripts/helpers/list_archives.js | 193 +-- test/scripts/helpers/list_categories.js | 459 ++++---- test/scripts/helpers/list_posts.js | 163 +-- test/scripts/helpers/list_tags.js | 196 ++-- test/scripts/helpers/mail_to.js | 73 +- test/scripts/helpers/markdown.js | 10 +- test/scripts/helpers/number_format.js | 16 +- test/scripts/helpers/open_graph.js | 515 +++++--- test/scripts/helpers/paginator.js | 115 +- test/scripts/helpers/partial.js | 38 +- test/scripts/helpers/relative_url.js | 12 +- test/scripts/helpers/render.js | 6 +- test/scripts/helpers/search_form.js | 56 +- test/scripts/helpers/tagcloud.js | 274 +++-- test/scripts/helpers/toc.js | 81 +- test/scripts/helpers/url_for.js | 9 +- test/scripts/hexo/hexo.js | 328 ++++-- test/scripts/hexo/load_config.js | 171 ++- test/scripts/hexo/load_database.js | 57 +- test/scripts/hexo/load_plugins.js | 146 ++- test/scripts/hexo/locals.js | 2 +- test/scripts/hexo/multi_config_path.js | 42 +- test/scripts/hexo/post.js | 1039 ++++++++++------- test/scripts/hexo/render.js | 142 ++- test/scripts/hexo/router.js | 36 +- test/scripts/hexo/scaffold.js | 64 +- test/scripts/hexo/update_package.js | 57 +- test/scripts/models/asset.js | 46 +- test/scripts/models/cache.js | 8 +- test/scripts/models/category.js | 337 +++--- test/scripts/models/moment.js | 63 +- test/scripts/models/page.js | 46 +- test/scripts/models/post.js | 566 +++++---- test/scripts/models/post_asset.js | 128 +- test/scripts/models/tag.js | 268 +++-- test/scripts/processors/asset.js | 392 +++---- test/scripts/processors/common.js | 26 +- test/scripts/processors/data.js | 65 +- test/scripts/processors/post.js | 738 ++++++------ test/scripts/renderers/json.js | 2 +- test/scripts/renderers/plain.js | 2 +- test/scripts/renderers/swig.js | 25 +- test/scripts/renderers/yaml.js | 10 +- test/scripts/tags/asset_img.js | 62 +- test/scripts/tags/asset_link.js | 54 +- test/scripts/tags/asset_path.js | 46 +- test/scripts/tags/blockquote.js | 30 +- test/scripts/tags/code.js | 73 +- test/scripts/tags/gist.js | 8 +- test/scripts/tags/iframe.js | 60 +- test/scripts/tags/img.js | 218 +++- test/scripts/tags/include_code.js | 48 +- test/scripts/tags/jsfiddle.js | 48 +- test/scripts/tags/link.js | 108 +- test/scripts/tags/post_link.js | 24 +- test/scripts/tags/post_path.js | 14 +- test/scripts/tags/pullquote.js | 10 +- test/scripts/tags/vimeo.js | 12 +- test/scripts/tags/youtube.js | 12 +- test/scripts/theme/theme.js | 16 +- test/scripts/theme/view.js | 270 ++--- test/scripts/theme_processors/config.js | 49 +- test/scripts/theme_processors/i18n.js | 34 +- test/scripts/theme_processors/source.js | 80 +- test/scripts/theme_processors/view.js | 48 +- test/util/stream.js | 13 +- 200 files changed, 8628 insertions(+), 6162 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 57bd13b4a0..2cf72c2756 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,17 +1,4 @@ { "extends": "hexo", - "root": true, - "rules": { - "one-var": 0, - "operator-linebreak": [ - 2, - "after" - ], - "comma-spacing": [ - 2, - { - "after": true - } - ] - } + "root": true } diff --git a/lib/box/index.js b/lib/box/index.js index edd6459556..faf7ace4db 100644 --- a/lib/box/index.js +++ b/lib/box/index.js @@ -14,9 +14,12 @@ const defaultPattern = new Pattern(() => ({})); function Box(ctx, base, options) { Reflect.apply(EventEmitter, this, []); - this.options = Object.assign({ - persistent: true - }, options); + this.options = Object.assign( + { + persistent: true + }, + options + ); if (!base.endsWith(sep)) { base += sep; @@ -44,7 +47,8 @@ function getHash(path) { const src = fs.createReadStream(path); const hasher = new HashStream(); - src.pipe(hasher) + src + .pipe(hasher) .on('finish', () => { resolve(hasher.read().toString('hex')); }) @@ -69,15 +73,23 @@ Box.prototype._createFileClass = function() { options = {}; } - return ctx.render.render({ - path: this.source - }, options).asCallback(callback); + return ctx.render + .render( + { + path: this.source + }, + options + ) + .asCallback(callback); }; _File.prototype.renderSync = function(options) { - return ctx.render.renderSync({ - path: this.source - }, options); + return ctx.render.renderSync( + { + path: this.source + }, + options + ); }; return _File; @@ -105,16 +117,24 @@ Box.prototype._readDir = function(base, fn, prefix = '') { return Promise.resolve('Ignoring dir.'); } - return fs.readdir(base).map(path => fs.stat(join(base, path)).then(stats => { - if (stats.isDirectory()) { - return this._readDir(join(base, path), fn, `${prefix + path}/`); - } - - return this._checkFileStatus(prefix + path).then(file => fn(file).thenReturn(file)); - })).catch(err => { - if (err.cause && err.cause.code === 'ENOENT') return; - throw err; - }).reduce((files, item) => files.concat(item), []); + return fs + .readdir(base) + .map(path => + fs.stat(join(base, path)).then(stats => { + if (stats.isDirectory()) { + return this._readDir(join(base, path), fn, `${prefix + path}/`); + } + + return this._checkFileStatus(prefix + path).then(file => + fn(file).thenReturn(file) + ); + }) + ) + .catch(err => { + if (err.cause && err.cause.code === 'ENOENT') return; + throw err; + }) + .reduce((files, item) => files.concat(item), []); }; Box.prototype._checkFileStatus = function(path) { @@ -135,19 +155,34 @@ Box.prototype._checkFileStatus = function(path) { Box.prototype.process = function(callback) { const { base, Cache, context: ctx } = this; - return fs.stat(base).then(stats => { - if (!stats.isDirectory()) return; - - // Check existing files in cache - const relativeBase = escapeBackslash(base.substring(ctx.base_dir.length)); - const cacheFiles = Cache.filter(item => item._id.startsWith(relativeBase)).map(item => item._id.substring(relativeBase.length)); - - // Read files from directory - return this._readDir(base, file => this._processFile(file.type, file.path)).map(file => file.path).then(files => // Handle deleted files - Promise.filter(cacheFiles, path => !files.includes(path)).map(path => this._processFile(File.TYPE_DELETE, path))); - }).catch(err => { - if (err.cause && err.cause.code !== 'ENOENT') throw err; - }).asCallback(callback); + return fs + .stat(base) + .then(stats => { + if (!stats.isDirectory()) return; + + // Check existing files in cache + const relativeBase = escapeBackslash(base.substring(ctx.base_dir.length)); + const cacheFiles = Cache.filter(item => + item._id.startsWith(relativeBase) + ).map(item => item._id.substring(relativeBase.length)); + + // Read files from directory + return this._readDir(base, file => + this._processFile(file.type, file.path) + ) + .map(file => file.path) + .then(( + files // Handle deleted files + ) => + Promise.filter(cacheFiles, path => !files.includes(path)).map(path => + this._processFile(File.TYPE_DELETE, path) + ) + ); + }) + .catch(err => { + if (err.cause && err.cause.code !== 'ENOENT') throw err; + }) + .asCallback(callback); }; Box.prototype.load = Box.prototype.process; @@ -166,38 +201,49 @@ Box.prototype._processFile = function(type, path) { path }); - return Promise.reduce(this.processors, (count, processor) => { - const params = processor.pattern.match(path); - if (!params) return count; - - const file = new File({ - source: join(base, path), - path, - params, - type - }); - - return Reflect.apply(Promise.method(processor.process), ctx, [file]) - .thenReturn(count + 1); - }, 0).then(count => { - if (count) { - ctx.log.debug('Processed: %s', chalk.magenta(path)); - } - - this.emit('processAfter', { - type, - path - }); - }).catch(err => { - ctx.log.error({err}, 'Process failed: %s', chalk.magenta(path)); - }).finally(() => { - this._processingFiles[path] = false; - }).thenReturn(path); + return Promise.reduce( + this.processors, + (count, processor) => { + const params = processor.pattern.match(path); + if (!params) return count; + + const file = new File({ + source: join(base, path), + path, + params, + type + }); + + return Reflect.apply(Promise.method(processor.process), ctx, [ + file + ]).thenReturn(count + 1); + }, + 0 + ) + .then(count => { + if (count) { + ctx.log.debug('Processed: %s', chalk.magenta(path)); + } + + this.emit('processAfter', { + type, + path + }); + }) + .catch(err => { + ctx.log.error({ err }, 'Process failed: %s', chalk.magenta(path)); + }) + .finally(() => { + this._processingFiles[path] = false; + }) + .thenReturn(path); }; Box.prototype.watch = function(callback) { if (this.isWatching()) { - return Promise.reject(new Error('Watcher has already started.')).asCallback(callback); + return Promise.reject(new Error('Watcher has already started.')).asCallback( + callback + ); } const { base } = this; @@ -206,28 +252,35 @@ Box.prototype.watch = function(callback) { return escapeBackslash(path.substring(base.length)); } - return this.process().then(() => fs.watch(base, this.options)).then(watcher => { - this.watcher = watcher; - - watcher.on('add', path => { - this._processFile(File.TYPE_CREATE, getPath(path)); - }); - - watcher.on('change', path => { - this._processFile(File.TYPE_UPDATE, getPath(path)); - }); - - watcher.on('unlink', path => { - this._processFile(File.TYPE_DELETE, getPath(path)); - }); - - watcher.on('addDir', path => { - let prefix = getPath(path); - if (prefix) prefix += '/'; - - this._readDir(path, file => this._processFile(file.type, file.path), prefix); - }); - }).asCallback(callback); + return this.process() + .then(() => fs.watch(base, this.options)) + .then(watcher => { + this.watcher = watcher; + + watcher.on('add', path => { + this._processFile(File.TYPE_CREATE, getPath(path)); + }); + + watcher.on('change', path => { + this._processFile(File.TYPE_UPDATE, getPath(path)); + }); + + watcher.on('unlink', path => { + this._processFile(File.TYPE_DELETE, getPath(path)); + }); + + watcher.on('addDir', path => { + let prefix = getPath(path); + if (prefix) prefix += '/'; + + this._readDir( + path, + file => this._processFile(file.type, file.path), + prefix + ); + }); + }) + .asCallback(callback); }; Box.prototype.unwatch = function() { diff --git a/lib/extend/console.js b/lib/extend/console.js index fd72b4d60f..bcbdc6ec4f 100644 --- a/lib/extend/console.js +++ b/lib/extend/console.js @@ -25,10 +25,12 @@ Console.prototype.register = function(name, desc, options, fn) { if (typeof options === 'function') { fn = options; - if (typeof desc === 'object') { // name, options, fn + if (typeof desc === 'object') { + // name, options, fn options = desc; desc = ''; - } else { // name, desc, fn + } else { + // name, desc, fn options = {}; } } else { @@ -52,7 +54,7 @@ Console.prototype.register = function(name, desc, options, fn) { fn = Promise.method(fn); } - const c = this.store[name.toLowerCase()] = fn; + const c = (this.store[name.toLowerCase()] = fn); c.options = options; c.desc = desc; diff --git a/lib/extend/filter.js b/lib/extend/filter.js index 962a5431dc..1d229f5f59 100644 --- a/lib/extend/filter.js +++ b/lib/extend/filter.js @@ -30,7 +30,7 @@ Filter.prototype.register = function(type, fn, priority) { type = typeAlias[type] || type; priority = priority == null ? 10 : priority; - const store = this.store[type] = this.store[type] || []; + const store = (this.store[type] = this.store[type] || []); fn.priority = priority; store.push(fn); @@ -57,10 +57,12 @@ Filter.prototype.exec = function(type, data, options = {}) { args.unshift(data); - return Promise.each(filters, filter => Reflect.apply(Promise.method(filter), ctx, args).then(result => { - args[0] = result == null ? args[0] : result; - return args[0]; - })).then(() => args[0]); + return Promise.each(filters, filter => + Reflect.apply(Promise.method(filter), ctx, args).then(result => { + args[0] = result == null ? args[0] : result; + return args[0]; + }) + ).then(() => args[0]); }; Filter.prototype.execSync = function(type, data, options = {}) { diff --git a/lib/extend/tag.js b/lib/extend/tag.js index df66add124..7135b7325a 100644 --- a/lib/extend/tag.js +++ b/lib/extend/tag.js @@ -17,7 +17,7 @@ Tag.prototype.register = function(name, fn, options) { if (typeof fn !== 'function') throw new TypeError('fn must be a function'); if (options == null || typeof options === 'boolean') { - options = {ends: options}; + options = { ends: options }; } let tag; @@ -66,20 +66,23 @@ function getContext(lines, errLine, location, type) { colorize(' === (line number probably different from source) ===') ]; - Array.prototype.push.apply(message, + Array.prototype.push.apply( + message, // get LINES_OF_CONTEXT lines surrounding `errLine` - getContextLineNums(1, lines.length, errLine, LINES_OF_CONTEXT) - .map(function(lnNum) { - const line = ' ' + lnNum + ' | ' + lines[lnNum - 1]; - if (lnNum === errLine) { - return colorize.bold(line); - } - - return colorize(line); - }) + getContextLineNums(1, lines.length, errLine, LINES_OF_CONTEXT).map(function( + lnNum + ) { + const line = ' ' + lnNum + ' | ' + lines[lnNum - 1]; + if (lnNum === errLine) { + return colorize.bold(line); + } + + return colorize(line); + }) + ); + message.push( + colorize(' ===== Context Dump Ends =====') ); - message.push(colorize( - ' ===== Context Dump Ends =====')); return message; } @@ -104,7 +107,12 @@ function formatNunjucksError(err, input) { e.line = errLine; e.location = splited[0]; e.type = splited[1].trim(); - e.message = getContext(input.split(/\r?\n/), errLine, e.location, e.type).join('\n'); + e.message = getContext( + input.split(/\r?\n/), + errLine, + e.location, + e.type + ).join('\n'); return e; } @@ -120,7 +128,9 @@ Tag.prototype.render = function(str, options, callback) { str = str.replace(/
[\s\S]*?<\/code><\/pre>/gm, escapeContent);
 
-  return Promise.fromCallback(cb => { this.env.renderString(str, options, cb); })
+  return Promise.fromCallback(cb => {
+    this.env.renderString(str, options, cb);
+  })
     .catch(err => Promise.reject(formatNunjucksError(err, str)))
     .then(result => result.replace(rPlaceholder, (_, index) => cache[index]));
 };
@@ -145,9 +155,16 @@ NunjucksTag.prototype._parseArgs = (parser, nodes, lexer) => {
   let argitem = '';
 
   while ((token = parser.nextToken(true))) {
-    if (token.type === lexer.TOKEN_WHITESPACE || token.type === lexer.TOKEN_BLOCK_END) {
+    if (
+      token.type === lexer.TOKEN_WHITESPACE ||
+      token.type === lexer.TOKEN_BLOCK_END
+    ) {
       if (argitem !== '') {
-        const argnode = new nodes.Literal(tag.lineno, tag.colno, argitem.trim());
+        const argnode = new nodes.Literal(
+          tag.lineno,
+          tag.colno,
+          argitem.trim()
+        );
         argarray.addChild(argnode);
         argitem = '';
       }
diff --git a/lib/hexo/default_config.js b/lib/hexo/default_config.js
index 710e764586..9f72dbdea1 100644
--- a/lib/hexo/default_config.js
+++ b/lib/hexo/default_config.js
@@ -59,4 +59,3 @@ module.exports = {
   // Category & Tag
   meta_generator: true
 };
-
diff --git a/lib/hexo/index.js b/lib/hexo/index.js
index d98c187e6f..4aceb60da1 100644
--- a/lib/hexo/index.js
+++ b/lib/hexo/index.js
@@ -94,8 +94,9 @@ function Hexo(base = process.cwd(), args = {}) {
 
   const mcp = multiConfigPath(this);
 
-  this.config_path = args.config ? mcp(base, args.config, args.output) :
-    join(base, '_config.yml');
+  this.config_path = args.config
+    ? mcp(base, args.config, args.output)
+    : join(base, '_config.yml');
 
   registerModels(this);
 
@@ -115,7 +116,7 @@ Hexo.prototype._bindLocals = function() {
     const query = {};
 
     if (!this.config.future) {
-      query.date = {$lte: Date.now()};
+      query.date = { $lte: Date.now() };
     }
 
     if (!this._showDrafts()) {
@@ -129,7 +130,7 @@ Hexo.prototype._bindLocals = function() {
     const query = {};
 
     if (!this.config.future) {
-      query.date = {$lte: Date.now()};
+      query.date = { $lte: Date.now() };
     }
 
     return db.model('Page').find(query);
@@ -152,7 +153,10 @@ Hexo.prototype._bindLocals = function() {
 
 Hexo.prototype.init = function() {
   this.log.debug('Hexo version: %s', chalk.magenta(this.version));
-  this.log.debug('Working directory: %s', chalk.magenta(tildify(this.base_dir)));
+  this.log.debug(
+    'Working directory: %s',
+    chalk.magenta(tildify(this.base_dir))
+  );
 
   // Load internal plugins
   require('../plugins/console')(this);
@@ -164,14 +168,19 @@ Hexo.prototype.init = function() {
   require('../plugins/tag')(this);
 
   // Load config
-  return Promise.each([
-    'update_package', // Update package.json
-    'load_config', // Load config
-    'load_plugins' // Load external plugins & scripts
-  ], name => require(`./${name}`)(this)).then(() => this.execFilter('after_init', null, {context: this})).then(() => {
-    // Ready to go!
-    this.emit('ready');
-  });
+  return Promise.each(
+    [
+      'update_package', // Update package.json
+      'load_config', // Load config
+      'load_plugins' // Load external plugins & scripts
+    ],
+    name => require(`./${name}`)(this)
+  )
+    .then(() => this.execFilter('after_init', null, { context: this }))
+    .then(() => {
+      // Ready to go!
+      this.emit('ready');
+    });
 };
 
 Hexo.prototype.call = function(name, args, callback) {
@@ -209,28 +218,31 @@ Hexo.prototype.resolvePlugin = function(name) {
 };
 
 Hexo.prototype.loadPlugin = function(path, callback) {
-  return fs.readFile(path).then(script => {
-    // Based on: https://github.com/joyent/node/blob/v0.10.33/src/node.js#L516
-    const module = new Module(path);
-    module.filename = path;
-    module.paths = Module._nodeModulePaths(path);
-
-    function require(path) {
-      return module.require(path);
-    }
+  return fs
+    .readFile(path)
+    .then(script => {
+      // Based on: https://github.com/joyent/node/blob/v0.10.33/src/node.js#L516
+      const module = new Module(path);
+      module.filename = path;
+      module.paths = Module._nodeModulePaths(path);
+
+      function require(path) {
+        return module.require(path);
+      }
 
-    require.resolve = request => Module._resolveFilename(request, module);
+      require.resolve = request => Module._resolveFilename(request, module);
 
-    require.main = process.mainModule;
-    require.extensions = Module._extensions;
-    require.cache = Module._cache;
+      require.main = process.mainModule;
+      require.extensions = Module._extensions;
+      require.cache = Module._cache;
 
-    script = `(function(exports, require, module, __filename, __dirname, hexo){${script}});`;
+      script = `(function(exports, require, module, __filename, __dirname, hexo){${script}});`;
 
-    const fn = vm.runInThisContext(script, path);
+      const fn = vm.runInThisContext(script, path);
 
-    return fn(module.exports, require, module, path, dirname(path), this);
-  }).asCallback(callback);
+      return fn(module.exports, require, module, path, dirname(path), this);
+    })
+    .asCallback(callback);
 };
 
 Hexo.prototype._showDrafts = function() {
@@ -239,32 +251,32 @@ Hexo.prototype._showDrafts = function() {
 };
 
 Hexo.prototype.load = function(callback) {
-  return loadDatabase(this).then(() => {
-    this.log.info('Start processing');
-
-    return Promise.all([
-      this.source.process(),
-      this.theme.process()
-    ]);
-  }).then(() => this._generate({cache: true})).asCallback(callback);
+  return loadDatabase(this)
+    .then(() => {
+      this.log.info('Start processing');
+
+      return Promise.all([this.source.process(), this.theme.process()]);
+    })
+    .then(() => this._generate({ cache: true }))
+    .asCallback(callback);
 };
 
 Hexo.prototype.watch = function(callback) {
-  this._watchBox = debounce(() => this._generate({cache: false}), 100);
+  this._watchBox = debounce(() => this._generate({ cache: false }), 100);
 
-  return loadDatabase(this).then(() => {
-    this.log.info('Start processing');
+  return loadDatabase(this)
+    .then(() => {
+      this.log.info('Start processing');
 
-    return Promise.all([
-      this.source.watch(),
-      this.theme.watch()
-    ]);
-  }).then(() => {
-    this.source.on('processAfter', this._watchBox);
-    this.theme.on('processAfter', this._watchBox);
+      return Promise.all([this.source.watch(), this.theme.watch()]);
+    })
+    .then(() => {
+      this.source.on('processAfter', this._watchBox);
+      this.theme.on('processAfter', this._watchBox);
 
-    return this._generate({cache: false});
-  }).asCallback(callback);
+      return this._generate({ cache: false });
+    })
+    .asCallback(callback);
 };
 
 Hexo.prototype.unwatch = function() {
@@ -295,7 +307,12 @@ Hexo.prototype._generateLocals = function() {
   }
 
   Locals.prototype.config = config;
-  Locals.prototype.theme = Object.assign({}, config, theme.config, config.theme_config);
+  Locals.prototype.theme = Object.assign(
+    {},
+    config,
+    theme.config,
+    config.theme_config
+  );
   Locals.prototype._ = _;
   Locals.prototype.layout = 'layout';
   Locals.prototype.env = this.env;
@@ -326,9 +343,12 @@ Hexo.prototype._runGenerators = function() {
 
 const routeCache = new WeakMap();
 
-const unique = array => array.filter((item, index, self) => self.indexOf(item) === index);
+const unique = array =>
+  array.filter((item, index, self) => self.indexOf(item) === index);
 
-const castArray = obj => { return Array.isArray(obj) ? obj : [obj]; };
+const castArray = obj => {
+  return Array.isArray(obj) ? obj : [obj];
+};
 
 const createLoadThemeRoute = function(generatorResult, locals, ctx) {
   const { log, theme } = ctx;
@@ -338,7 +358,8 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) {
   const layoutLength = layout.length;
 
   return () => {
-    if (useCache && routeCache.has(generatorResult)) return routeCache.get(generatorResult);
+    if (useCache && routeCache.has(generatorResult))
+      return routeCache.get(generatorResult);
 
     for (let i = 0; i < layoutLength; i++) {
       const name = layout[i];
@@ -346,11 +367,14 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) {
 
       if (view) {
         log.debug(`Rendering HTML ${name}: ${chalk.magenta(path)}`);
-        return view.render(locals).tap(result => {
-          routeCache.set(generatorResult, result);
-        }).tapCatch(err => {
-          log.error({ err }, `Render HTML failed: ${chalk.magenta(path)}`);
-        });
+        return view
+          .render(locals)
+          .tap(result => {
+            routeCache.set(generatorResult, result);
+          })
+          .tapCatch(err => {
+            log.error({ err }, `Render HTML failed: ${chalk.magenta(path)}`);
+          });
       }
     }
 
@@ -364,29 +388,36 @@ Hexo.prototype._routerReflesh = function(runningGenerators, useCache) {
   const Locals = this._generateLocals();
   Locals.prototype.cache = useCache;
 
-  return runningGenerators.map(generatorResult => {
-    if (typeof generatorResult !== 'object' || generatorResult.path == null) return undefined;
+  return runningGenerators
+    .map(generatorResult => {
+      if (typeof generatorResult !== 'object' || generatorResult.path == null)
+        return undefined;
 
-    // add Route
-    const path = route.format(generatorResult.path);
-    const { data, layout } = generatorResult;
+      // add Route
+      const path = route.format(generatorResult.path);
+      const { data, layout } = generatorResult;
 
-    if (!layout) {
-      route.set(path, data);
-      return path;
-    }
-
-    return this.execFilter('template_locals', new Locals(path, data), {context: this})
-      .then(locals => { route.set(path, createLoadThemeRoute(generatorResult, locals, this)); })
-      .thenReturn(path);
-  }).then(newRouteList => {
-    // Remove old routes
-    const removed = routeList.filter(item => !newRouteList.includes(item));
+      if (!layout) {
+        route.set(path, data);
+        return path;
+      }
 
-    for (let i = 0, len = removed.length; i < len; i++) {
-      route.remove(removed[i]);
-    }
-  });
+      return this.execFilter('template_locals', new Locals(path, data), {
+        context: this
+      })
+        .then(locals => {
+          route.set(path, createLoadThemeRoute(generatorResult, locals, this));
+        })
+        .thenReturn(path);
+    })
+    .then(newRouteList => {
+      // Remove old routes
+      const removed = routeList.filter(item => !newRouteList.includes(item));
+
+      for (let i = 0, len = removed.length; i < len; i++) {
+        route.remove(removed[i]);
+      }
+    });
 };
 
 Hexo.prototype._generate = function(options = {}) {
@@ -399,13 +430,17 @@ Hexo.prototype._generate = function(options = {}) {
   this.emit('generateBefore');
 
   // Run before_generate filters
-  return this.execFilter('before_generate', this.locals.get('data'), {context: this})
-    .then(() => this._routerReflesh(this._runGenerators(), useCache)).then(() => {
+  return this.execFilter('before_generate', this.locals.get('data'), {
+    context: this
+  })
+    .then(() => this._routerReflesh(this._runGenerators(), useCache))
+    .then(() => {
       this.emit('generateAfter');
 
       // Run after_generate filters
-      return this.execFilter('after_generate', null, {context: this});
-    }).finally(() => {
+      return this.execFilter('after_generate', null, { context: this });
+    })
+    .finally(() => {
       this._isGenerating = false;
     });
 };
@@ -413,13 +448,13 @@ Hexo.prototype._generate = function(options = {}) {
 Hexo.prototype.exit = function(err) {
   if (err) {
     this.log.fatal(
-      {err},
-      'Something\'s wrong. Maybe you can find the solution here: %s',
+      { err },
+      "Something's wrong. Maybe you can find the solution here: %s",
       chalk.underline('https://hexo.io/docs/troubleshooting.html')
     );
   }
 
-  return this.execFilter('before_exit', null, {context: this}).then(() => {
+  return this.execFilter('before_exit', null, { context: this }).then(() => {
     this.emit('exit', err);
   });
 };
diff --git a/lib/hexo/load_config.js b/lib/hexo/load_config.js
index 6d9d3f890b..fead9661e9 100644
--- a/lib/hexo/load_config.js
+++ b/lib/hexo/load_config.js
@@ -14,35 +14,39 @@ module.exports = ctx => {
   const baseDir = ctx.base_dir;
   let configPath = ctx.config_path;
 
-  return fs.exists(configPath).then(exist => {
-    return exist ? configPath : findConfigPath(configPath);
-  }).then(path => {
-    if (!path) return;
-
-    configPath = path;
-    return ctx.render.render({path});
-  }).then(config => {
-    if (!config || typeof config !== 'object') return;
-
-    ctx.log.debug('Config loaded: %s', chalk.magenta(tildify(configPath)));
-
-    config = merge(ctx.config, config);
-    ctx.config_path = configPath;
-
-    config.root = config.root.replace(/\/*$/, '/');
-    config.url = config.url.replace(/\/+$/, '');
-
-    ctx.public_dir = resolve(baseDir, config.public_dir) + sep;
-    ctx.source_dir = resolve(baseDir, config.source_dir) + sep;
-    ctx.source = new Source(ctx);
-
-    if (!config.theme) return;
-
-    config.theme = config.theme.toString();
-    ctx.theme_dir = join(baseDir, 'themes', config.theme) + sep;
-    ctx.theme_script_dir = join(ctx.theme_dir, 'scripts') + sep;
-    ctx.theme = new Theme(ctx);
-  });
+  return fs
+    .exists(configPath)
+    .then(exist => {
+      return exist ? configPath : findConfigPath(configPath);
+    })
+    .then(path => {
+      if (!path) return;
+
+      configPath = path;
+      return ctx.render.render({ path });
+    })
+    .then(config => {
+      if (!config || typeof config !== 'object') return;
+
+      ctx.log.debug('Config loaded: %s', chalk.magenta(tildify(configPath)));
+
+      config = merge(ctx.config, config);
+      ctx.config_path = configPath;
+
+      config.root = config.root.replace(/\/*$/, '/');
+      config.url = config.url.replace(/\/+$/, '');
+
+      ctx.public_dir = resolve(baseDir, config.public_dir) + sep;
+      ctx.source_dir = resolve(baseDir, config.source_dir) + sep;
+      ctx.source = new Source(ctx);
+
+      if (!config.theme) return;
+
+      config.theme = config.theme.toString();
+      ctx.theme_dir = join(baseDir, 'themes', config.theme) + sep;
+      ctx.theme_script_dir = join(ctx.theme_dir, 'scripts') + sep;
+      ctx.theme = new Theme(ctx);
+    });
 };
 
 function findConfigPath(path) {
diff --git a/lib/hexo/load_database.js b/lib/hexo/load_database.js
index b3d59a036e..037e4eefc5 100644
--- a/lib/hexo/load_database.js
+++ b/lib/hexo/load_database.js
@@ -10,15 +10,19 @@ module.exports = ctx => {
   const { path } = db.options;
   const { log } = ctx;
 
-  return fs.exists(path).then(exist => {
-    if (!exist) return;
+  return fs
+    .exists(path)
+    .then(exist => {
+      if (!exist) return;
 
-    log.debug('Loading database.');
-    return db.load();
-  }).then(() => {
-    ctx._dbLoaded = true;
-  }).catch(() => {
-    log.error('Database load failed. Deleting database.');
-    return fs.unlink(path);
-  });
+      log.debug('Loading database.');
+      return db.load();
+    })
+    .then(() => {
+      ctx._dbLoaded = true;
+    })
+    .catch(() => {
+      log.error('Database load failed. Deleting database.');
+      return fs.unlink(path);
+    });
 };
diff --git a/lib/hexo/load_plugins.js b/lib/hexo/load_plugins.js
index d6e2c6105c..80b1cb5709 100644
--- a/lib/hexo/load_plugins.js
+++ b/lib/hexo/load_plugins.js
@@ -13,34 +13,39 @@ module.exports = ctx => {
 
 function loadModuleList(ctx) {
   if (ctx.config && Array.isArray(ctx.config.plugins)) {
-    return Promise.resolve(ctx.config.plugins).filter(item => typeof item === 'string');
+    return Promise.resolve(ctx.config.plugins).filter(
+      item => typeof item === 'string'
+    );
   }
 
   const packagePath = join(ctx.base_dir, 'package.json');
 
   // Make sure package.json exists
-  return fs.exists(packagePath).then(exist => {
-    if (!exist) return [];
-
-    // Read package.json and find dependencies
-    return fs.readFile(packagePath).then(content => {
-      const json = JSON.parse(content);
-      const deps = Object.keys(json.dependencies || {});
-      const devDeps = Object.keys(json.devDependencies || {});
-
-      return deps.concat(devDeps);
+  return fs
+    .exists(packagePath)
+    .then(exist => {
+      if (!exist) return [];
+
+      // Read package.json and find dependencies
+      return fs.readFile(packagePath).then(content => {
+        const json = JSON.parse(content);
+        const deps = Object.keys(json.dependencies || {});
+        const devDeps = Object.keys(json.devDependencies || {});
+
+        return deps.concat(devDeps);
+      });
+    })
+    .filter(name => {
+      // Ignore plugins whose name is not started with "hexo-"
+      if (!/^hexo-|^@[^/]+\/hexo-/.test(name)) return false;
+
+      // Ignore typescript definition file that is started with "@types/"
+      if (/^@types\//.test(name)) return false;
+
+      // Make sure the plugin exists
+      const path = ctx.resolvePlugin(name);
+      return fs.exists(path);
     });
-  }).filter(name => {
-    // Ignore plugins whose name is not started with "hexo-"
-    if (!/^hexo-|^@[^/]+\/hexo-/.test(name)) return false;
-
-    // Ignore typescript definition file that is started with "@types/"
-    if (/^@types\//.test(name)) return false;
-
-    // Make sure the plugin exists
-    const path = ctx.resolvePlugin(name);
-    return fs.exists(path);
-  });
 }
 
 function loadModules(ctx) {
@@ -48,11 +53,14 @@ function loadModules(ctx) {
     const path = ctx.resolvePlugin(name);
 
     // Load plugins
-    return ctx.loadPlugin(path).then(() => {
-      ctx.log.debug('Plugin loaded: %s', chalk.magenta(name));
-    }).catch(err => {
-      ctx.log.error({err}, 'Plugin load failed: %s', chalk.magenta(name));
-    });
+    return ctx
+      .loadPlugin(path)
+      .then(() => {
+        ctx.log.debug('Plugin loaded: %s', chalk.magenta(name));
+      })
+      .catch(err => {
+        ctx.log.error({ err }, 'Plugin load failed: %s', chalk.magenta(name));
+      });
   });
 }
 
@@ -63,18 +71,21 @@ function loadScripts(ctx) {
     return chalk.magenta(path.substring(baseDirLength));
   }
 
-  return Promise.filter([
-    ctx.theme_script_dir,
-    ctx.script_dir
-  ], scriptDir => { // Ignore the directory if it does not exist
+  return Promise.filter([ctx.theme_script_dir, ctx.script_dir], scriptDir => {
+    // Ignore the directory if it does not exist
     return scriptDir ? fs.exists(scriptDir) : false;
-  }).map(scriptDir => fs.listDir(scriptDir).map(name => {
-    const path = join(scriptDir, name);
-
-    return ctx.loadPlugin(path).then(() => {
-      ctx.log.debug('Script loaded: %s', displayPath(path));
-    }).catch(err => {
-      ctx.log.error({err}, 'Script load failed: %s', displayPath(path));
-    });
-  }));
+  }).map(scriptDir =>
+    fs.listDir(scriptDir).map(name => {
+      const path = join(scriptDir, name);
+
+      return ctx
+        .loadPlugin(path)
+        .then(() => {
+          ctx.log.debug('Script loaded: %s', displayPath(path));
+        })
+        .catch(err => {
+          ctx.log.error({ err }, 'Script load failed: %s', displayPath(path));
+        });
+    })
+  );
 }
diff --git a/lib/hexo/multi_config_path.js b/lib/hexo/multi_config_path.js
index afc3b40b00..6924616e81 100644
--- a/lib/hexo/multi_config_path.js
+++ b/lib/hexo/multi_config_path.js
@@ -5,73 +5,76 @@ const fs = require('hexo-fs');
 const merge = require('lodash/merge');
 const yml = require('js-yaml');
 
-module.exports = ctx => function multiConfigPath(base, configPaths, outputDir) {
-  const { log } = ctx;
-  const defaultPath = join(base, '_config.yml');
-
-  if (!configPaths) {
-    log.w('No config file entered.');
-    return join(base, '_config.yml');
-  }
-
-  let paths;
-  // determine if comma or space separated
-  if (configPaths.includes(',')) {
-    paths = configPaths.replace(' ', '').split(',');
-  } else {
-    // only one config
-    let configPath = isAbsolute(configPaths) ? configPaths : resolve(base, configPaths);
-
-    if (!fs.existsSync(configPath)) {
-      log.w(`Config file ${configPaths} not found, using default.`);
-      configPath = defaultPath;
+module.exports = ctx =>
+  function multiConfigPath(base, configPaths, outputDir) {
+    const { log } = ctx;
+    const defaultPath = join(base, '_config.yml');
+
+    if (!configPaths) {
+      log.w('No config file entered.');
+      return join(base, '_config.yml');
     }
 
-    return configPath;
-  }
-
-  const numPaths = paths.length;
+    let paths;
+    // determine if comma or space separated
+    if (configPaths.includes(',')) {
+      paths = configPaths.replace(' ', '').split(',');
+    } else {
+      // only one config
+      let configPath = isAbsolute(configPaths)
+        ? configPaths
+        : resolve(base, configPaths);
 
-  // combine files
-  const combinedConfig = {};
-  let count = 0;
-  for (let i = 0; i < numPaths; i++) {
-    const configPath = isAbsolute(paths[i]) ? paths[i] : join(base, paths[i]);
+      if (!fs.existsSync(configPath)) {
+        log.w(`Config file ${configPaths} not found, using default.`);
+        configPath = defaultPath;
+      }
 
-    if (!fs.existsSync(configPath)) {
-      log.w(`Config file ${paths[i]} not found.`);
-      continue;
+      return configPath;
     }
 
-    // files read synchronously to ensure proper overwrite order
-    const file = fs.readFileSync(configPath);
-    const ext = extname(paths[i]).toLowerCase();
-
-    if (ext === '.yml') {
-      merge(combinedConfig, yml.load(file));
-      count++;
-    } else if (ext === '.json') {
-      merge(combinedConfig, yml.safeLoad(file, {json: true}));
-      count++;
-    } else {
-      log.w(`Config file ${paths[i]} not supported type.`);
+    const numPaths = paths.length;
+
+    // combine files
+    const combinedConfig = {};
+    let count = 0;
+    for (let i = 0; i < numPaths; i++) {
+      const configPath = isAbsolute(paths[i]) ? paths[i] : join(base, paths[i]);
+
+      if (!fs.existsSync(configPath)) {
+        log.w(`Config file ${paths[i]} not found.`);
+        continue;
+      }
+
+      // files read synchronously to ensure proper overwrite order
+      const file = fs.readFileSync(configPath);
+      const ext = extname(paths[i]).toLowerCase();
+
+      if (ext === '.yml') {
+        merge(combinedConfig, yml.load(file));
+        count++;
+      } else if (ext === '.json') {
+        merge(combinedConfig, yml.safeLoad(file, { json: true }));
+        count++;
+      } else {
+        log.w(`Config file ${paths[i]} not supported type.`);
+      }
     }
-  }
 
-  if (count === 0) {
-    log.e('No config files found. Using _config.yml.');
-    return defaultPath;
-  }
+    if (count === 0) {
+      log.e('No config files found. Using _config.yml.');
+      return defaultPath;
+    }
 
-  log.i('Config based on', count, 'files');
+    log.i('Config based on', count, 'files');
 
-  const multiconfigRoot = outputDir || base;
-  const outputPath = join(multiconfigRoot, '_multiconfig.yml');
+    const multiconfigRoot = outputDir || base;
+    const outputPath = join(multiconfigRoot, '_multiconfig.yml');
 
-  log.d(`Writing _multiconfig.yml to ${outputPath}`);
+    log.d(`Writing _multiconfig.yml to ${outputPath}`);
 
-  fs.writeFileSync(outputPath, yml.dump(combinedConfig));
+    fs.writeFileSync(outputPath, yml.dump(combinedConfig));
 
-  // write file and return path
-  return outputPath;
-};
+    // write file and return path
+    return outputPath;
+  };
diff --git a/lib/hexo/post.js b/lib/hexo/post.js
index de2ded5b14..8e4ce09e85 100644
--- a/lib/hexo/post.js
+++ b/lib/hexo/post.js
@@ -24,7 +24,9 @@ const _escapeContent = (cache, str) => {
 
 PostRenderCache.prototype.escapeContent = function(str) {
   const rEscapeContent = /]*)>([\s\S]*?)<\/escape>/g;
-  return str.replace(rEscapeContent, (_, content) => _escapeContent(this.cache, content));
+  return str.replace(rEscapeContent, (_, content) =>
+    _escapeContent(this.cache, content)
+  );
 };
 
 PostRenderCache.prototype.loadContent = function(str) {
@@ -39,7 +41,8 @@ PostRenderCache.prototype.escapeAllSwigTags = function(str) {
   const rSwigFullBlock = /\{% *(.+?)(?: *| +.*)%\}[\s\S]+?\{% *end\1 *%\}/g;
 
   const escape = _str => _escapeContent(this.cache, _str);
-  return str.replace(rSwigFullBlock, escape)
+  return str
+    .replace(rSwigFullBlock, escape)
     .replace(rSwigBlock, escape)
     .replace(rSwigComment, '')
     .replace(rSwigVar, escape);
@@ -58,7 +61,9 @@ Post.prototype.create = function(data, replace, callback) {
   const ctx = this.context;
   const { config } = ctx;
 
-  data.slug = slugize((data.slug || data.title).toString(), {transform: config.filename_case});
+  data.slug = slugize((data.slug || data.title).toString(), {
+    transform: config.filename_case
+  });
   data.layout = (data.layout || config.default_layout).toLowerCase();
   data.date = data.date ? moment(data.date) : moment();
 
@@ -69,18 +74,22 @@ Post.prototype.create = function(data, replace, callback) {
       context: ctx
     }),
     this._renderScaffold(data)
-  ]).spread((path, content) => {
-    const result = { path, content };
-
-    return Promise.all([
-      // Write content to file
-      fs.writeFile(path, content),
-      // Create asset folder
-      createAssetFolder(path, config.post_asset_folder)
-    ]).then(() => {
-      ctx.emit('new', result);
-    }).thenReturn(result);
-  }).asCallback(callback);
+  ])
+    .spread((path, content) => {
+      const result = { path, content };
+
+      return Promise.all([
+        // Write content to file
+        fs.writeFile(path, content),
+        // Create asset folder
+        createAssetFolder(path, config.post_asset_folder)
+      ])
+        .then(() => {
+          ctx.emit('new', result);
+        })
+        .thenReturn(result);
+    })
+    .asCallback(callback);
 };
 
 function prepareFrontMatter(data) {
@@ -112,42 +121,46 @@ Post.prototype._renderScaffold = function(data) {
   const { tag } = this.context.extend;
   let yfmSplit;
 
-  return this._getScaffold(data.layout).then(scaffold => {
-    const frontMatter = prepareFrontMatter(clone(data));
-    yfmSplit = yfm.split(scaffold);
-
-    return tag.render(yfmSplit.data, frontMatter);
-  }).then(frontMatter => {
-    const { separator } = yfmSplit;
-    const jsonMode = separator[0] === ';';
-
-    // Parse front-matter
-    const obj = jsonMode ? JSON.parse(`{${frontMatter}}`) : yaml.load(frontMatter);
-
-    // Add data which are not in the front-matter
-    for (const key of Object.keys(data)) {
-      if (!preservedKeys.includes(key) && obj[key] == null) {
-        obj[key] = data[key];
+  return this._getScaffold(data.layout)
+    .then(scaffold => {
+      const frontMatter = prepareFrontMatter(clone(data));
+      yfmSplit = yfm.split(scaffold);
+
+      return tag.render(yfmSplit.data, frontMatter);
+    })
+    .then(frontMatter => {
+      const { separator } = yfmSplit;
+      const jsonMode = separator[0] === ';';
+
+      // Parse front-matter
+      const obj = jsonMode
+        ? JSON.parse(`{${frontMatter}}`)
+        : yaml.load(frontMatter);
+
+      // Add data which are not in the front-matter
+      for (const key of Object.keys(data)) {
+        if (!preservedKeys.includes(key) && obj[key] == null) {
+          obj[key] = data[key];
+        }
       }
-    }
 
-    let content = '';
-    // Prepend the separator
-    if (yfmSplit.prefixSeparator) content += `${separator}\n`;
+      let content = '';
+      // Prepend the separator
+      if (yfmSplit.prefixSeparator) content += `${separator}\n`;
 
-    content += yfm.stringify(obj, {
-      mode: jsonMode ? 'json' : ''
-    });
+      content += yfm.stringify(obj, {
+        mode: jsonMode ? 'json' : ''
+      });
 
-    // Concat content
-    content += yfmSplit.content;
+      // Concat content
+      content += yfmSplit.content;
 
-    if (data.content) {
-      content += `\n${data.content}`;
-    }
+      if (data.content) {
+        content += `\n${data.content}`;
+      }
 
-    return content;
-  });
+      return content;
+    });
 };
 
 function createAssetFolder(path, assetFolder) {
@@ -175,7 +188,9 @@ Post.prototype.publish = function(data, replace, callback) {
   const ctx = this.context;
   const { config } = ctx;
   const draftDir = join(ctx.source_dir, '_drafts');
-  const slug = data.slug = slugize(data.slug.toString(), {transform: config.filename_case});
+  const slug = (data.slug = slugize(data.slug.toString(), {
+    transform: config.filename_case
+  }));
   const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\/\\\\]+)`);
   let src = '';
   const result = {};
@@ -183,38 +198,48 @@ Post.prototype.publish = function(data, replace, callback) {
   data.layout = (data.layout || config.default_layout).toLowerCase();
 
   // Find the draft
-  return fs.listDir(draftDir).then(list => {
-    return list.find(item => regex.test(item));
-  }).then(item => {
-    if (!item) throw new Error(`Draft "${slug}" does not exist.`);
-
-    // Read the content
-    src = join(draftDir, item);
-    return fs.readFile(src);
-  }).then(content => {
-    // Create post
-    assignIn(data, yfm(content));
-    data.content = data._content;
-    delete data._content;
-
-    return this.create(data, replace).then(post => {
-      result.path = post.path;
-      result.content = post.content;
-    });
-  }).then(() => // Remove the original draft file
-    fs.unlink(src)).then(() => {
-    if (!config.post_asset_folder) return;
-
-    // Copy assets
-    const assetSrc = removeExtname(src);
-    const assetDest = removeExtname(result.path);
-
-    return fs.exists(assetSrc).then(exist => {
-      if (!exist) return;
-
-      return fs.copyDir(assetSrc, assetDest).then(() => fs.rmdir(assetSrc));
-    });
-  }).thenReturn(result).asCallback(callback);
+  return fs
+    .listDir(draftDir)
+    .then(list => {
+      return list.find(item => regex.test(item));
+    })
+    .then(item => {
+      if (!item) throw new Error(`Draft "${slug}" does not exist.`);
+
+      // Read the content
+      src = join(draftDir, item);
+      return fs.readFile(src);
+    })
+    .then(content => {
+      // Create post
+      assignIn(data, yfm(content));
+      data.content = data._content;
+      delete data._content;
+
+      return this.create(data, replace).then(post => {
+        result.path = post.path;
+        result.content = post.content;
+      });
+    })
+    .then(() =>
+      // Remove the original draft file
+      fs.unlink(src)
+    )
+    .then(() => {
+      if (!config.post_asset_folder) return;
+
+      // Copy assets
+      const assetSrc = removeExtname(src);
+      const assetDest = removeExtname(result.path);
+
+      return fs.exists(assetSrc).then(exist => {
+        if (!exist) return;
+
+        return fs.copyDir(assetSrc, assetDest).then(() => fs.rmdir(assetSrc));
+      });
+    })
+    .thenReturn(result)
+    .asCallback(callback);
 };
 
 Post.prototype.render = function(source, data = {}, callback) {
@@ -231,61 +256,73 @@ Post.prototype.render = function(source, data = {}, callback) {
     // Read content from files
     promise = fs.readFile(source);
   } else {
-    return Promise.reject(new Error('No input file or string!')).asCallback(callback);
+    return Promise.reject(new Error('No input file or string!')).asCallback(
+      callback
+    );
   }
 
   const isSwig = ext === 'swig';
 
   // disable Nunjucks when the renderer spcify that.
-  const disableNunjucks = ext && ctx.render.renderer.get(ext) && !!ctx.render.renderer.get(ext).disableNunjucks;
+  const disableNunjucks =
+    ext &&
+    ctx.render.renderer.get(ext) &&
+    !!ctx.render.renderer.get(ext).disableNunjucks;
 
   const cacheObj = new PostRenderCache();
 
-  return promise.then(content => {
-    data.content = content;
-
-    // Run "before_post_render" filters
-    return ctx.execFilter('before_post_render', data, {context: ctx});
-  }).then(() => {
-    data.content = cacheObj.escapeContent(data.content);
-
-    if (isSwig) {
-      // Render with Nunjucks if this is a swig file
-      return tag.render(data.content, data);
-    }
-
-    // Escape all Swig tags
-    if (!disableNunjucks) {
-      data.content = cacheObj.escapeAllSwigTags(data.content);
-    }
-
-    const options = data.markdown || {};
-    if (!config.highlight.enable) options.highlight = null;
+  return promise
+    .then(content => {
+      data.content = content;
 
-    ctx.log.debug('Rendering post: %s', chalk.magenta(source));
-    // Render with markdown or other renderer
-    return ctx.render.render({
-      text: data.content,
-      path: source,
-      engine: data.engine,
-      toString: true,
-      onRenderEnd(content) {
-        // Replace cache data with real contents
-        data.content = cacheObj.loadContent(content);
+      // Run "before_post_render" filters
+      return ctx.execFilter('before_post_render', data, { context: ctx });
+    })
+    .then(() => {
+      data.content = cacheObj.escapeContent(data.content);
 
-        // Return content after replace the placeholders
-        if (disableNunjucks) return data.content;
-
-        // Render with Nunjucks
+      if (isSwig) {
+        // Render with Nunjucks if this is a swig file
         return tag.render(data.content, data);
       }
-    }, options);
-  }).then(content => {
-    data.content = content;
 
-    // Run "after_post_render" filters
-    return ctx.execFilter('after_post_render', data, {context: ctx});
-  }).asCallback(callback);
+      // Escape all Swig tags
+      if (!disableNunjucks) {
+        data.content = cacheObj.escapeAllSwigTags(data.content);
+      }
+
+      const options = data.markdown || {};
+      if (!config.highlight.enable) options.highlight = null;
+
+      ctx.log.debug('Rendering post: %s', chalk.magenta(source));
+      // Render with markdown or other renderer
+      return ctx.render.render(
+        {
+          text: data.content,
+          path: source,
+          engine: data.engine,
+          toString: true,
+          onRenderEnd(content) {
+            // Replace cache data with real contents
+            data.content = cacheObj.loadContent(content);
+
+            // Return content after replace the placeholders
+            if (disableNunjucks) return data.content;
+
+            // Render with Nunjucks
+            return tag.render(data.content, data);
+          }
+        },
+        options
+      );
+    })
+    .then(content => {
+      data.content = content;
+
+      // Run "after_post_render" filters
+      return ctx.execFilter('after_post_render', data, { context: ctx });
+    })
+    .asCallback(callback);
 };
 
 module.exports = Post;
diff --git a/lib/hexo/render.js b/lib/hexo/render.js
index 40029d46e0..e10e922c06 100644
--- a/lib/hexo/render.js
+++ b/lib/hexo/render.js
@@ -51,27 +51,31 @@ Render.prototype.render = function(data, options, callback) {
     if (!data.path) return reject(new TypeError('No input file or string!'));
 
     fs.readFile(data.path).then(resolve, reject);
-  }).then(text => {
-    data.text = text;
-    ext = data.engine || getExtname(data.path);
-    if (!ext || !this.isRenderable(ext)) return text;
-
-    const renderer = this.getRenderer(ext);
-    return Reflect.apply(renderer, ctx, [data, options]);
-  }).then(result => {
-    result = toString(result, data);
-    if (data.onRenderEnd) {
-      return data.onRenderEnd(result);
-    }
-
-    return result;
-  }).then(result => {
-    const output = this.getOutput(ext) || ext;
-    return ctx.execFilter(`after_render:${output}`, result, {
-      context: ctx,
-      args: [data]
-    });
-  }).asCallback(callback);
+  })
+    .then(text => {
+      data.text = text;
+      ext = data.engine || getExtname(data.path);
+      if (!ext || !this.isRenderable(ext)) return text;
+
+      const renderer = this.getRenderer(ext);
+      return Reflect.apply(renderer, ctx, [data, options]);
+    })
+    .then(result => {
+      result = toString(result, data);
+      if (data.onRenderEnd) {
+        return data.onRenderEnd(result);
+      }
+
+      return result;
+    })
+    .then(result => {
+      const output = this.getOutput(ext) || ext;
+      return ctx.execFilter(`after_render:${output}`, result, {
+        context: ctx,
+        args: [data]
+      });
+    })
+    .asCallback(callback);
 };
 
 Render.prototype.renderSync = function(data, options) {
@@ -112,7 +116,11 @@ Render.prototype.renderSync = function(data, options) {
 };
 
 function toString(result, options) {
-  if (!Object.prototype.hasOwnProperty.call(options, 'toString') || typeof result === 'string') return result;
+  if (
+    !Object.prototype.hasOwnProperty.call(options, 'toString') ||
+    typeof result === 'string'
+  )
+    return result;
 
   if (typeof options.toString === 'function') {
     return options.toString(result);
diff --git a/lib/hexo/router.js b/lib/hexo/router.js
index 54ccf47481..c3c424be65 100644
--- a/lib/hexo/router.js
+++ b/lib/hexo/router.js
@@ -98,7 +98,7 @@ Router.prototype.remove = function(path) {
 };
 
 function RouteStream(data) {
-  Reflect.apply(Readable, this, [{objectMode: true}]);
+  Reflect.apply(Readable, this, [{ objectMode: true }]);
 
   this._data = data.data;
   this._ended = false;
@@ -120,32 +120,34 @@ RouteStream.prototype._read = function() {
   if (this._ended) return false;
   this._ended = true;
 
-  data().then(data => {
-    if (data instanceof Stream && data.readable) {
-      data.on('data', d => {
-        this.push(d);
-      });
-
-      data.on('end', () => {
+  data()
+    .then(data => {
+      if (data instanceof Stream && data.readable) {
+        data.on('data', d => {
+          this.push(d);
+        });
+
+        data.on('end', () => {
+          this.push(null);
+        });
+
+        data.on('error', err => {
+          this.emit('error', err);
+        });
+      } else if (data instanceof Buffer || typeof data === 'string') {
+        this.push(data);
         this.push(null);
-      });
-
-      data.on('error', err => {
-        this.emit('error', err);
-      });
-    } else if (data instanceof Buffer || typeof data === 'string') {
-      this.push(data);
-      this.push(null);
-    } else if (typeof data === 'object') {
-      this.push(JSON.stringify(data));
-      this.push(null);
-    } else {
+      } else if (typeof data === 'object') {
+        this.push(JSON.stringify(data));
+        this.push(null);
+      } else {
+        this.push(null);
+      }
+    })
+    .catch(err => {
+      this.emit('error', err);
       this.push(null);
-    }
-  }).catch(err => {
-    this.emit('error', err);
-    this.push(null);
-  });
+    });
 };
 
 module.exports = Router;
diff --git a/lib/hexo/scaffold.js b/lib/hexo/scaffold.js
index 5a9acdb888..2ed45678dd 100644
--- a/lib/hexo/scaffold.js
+++ b/lib/hexo/scaffold.js
@@ -22,16 +22,19 @@ Scaffold.prototype.defaults = {
 Scaffold.prototype._listDir = function() {
   const { scaffoldDir } = this;
 
-  return fs.exists(scaffoldDir).then(exist => {
-    if (!exist) return [];
+  return fs
+    .exists(scaffoldDir)
+    .then(exist => {
+      if (!exist) return [];
 
-    return fs.listDir(scaffoldDir, {
-      ignoreFilesRegex: /^_|\/_/
-    });
-  }).map(item => ({
-    name: item.substring(0, item.length - extname(item).length),
-    path: join(scaffoldDir, item)
-  }));
+      return fs.listDir(scaffoldDir, {
+        ignoreFilesRegex: /^_|\/_/
+      });
+    })
+    .map(item => ({
+      name: item.substring(0, item.length - extname(item).length),
+      path: join(scaffoldDir, item)
+    }));
 };
 
 Scaffold.prototype._getScaffold = function(name) {
@@ -39,32 +42,38 @@ Scaffold.prototype._getScaffold = function(name) {
 };
 
 Scaffold.prototype.get = function(name, callback) {
-  return this._getScaffold(name).then(item => {
-    if (item) {
-      return fs.readFile(item.path);
-    }
+  return this._getScaffold(name)
+    .then(item => {
+      if (item) {
+        return fs.readFile(item.path);
+      }
 
-    return this.defaults[name];
-  }).asCallback(callback);
+      return this.defaults[name];
+    })
+    .asCallback(callback);
 };
 
 Scaffold.prototype.set = function(name, content, callback) {
   const { scaffoldDir } = this;
 
-  return this._getScaffold(name).then(item => {
-    let path = item ? item.path : join(scaffoldDir, name);
-    if (!extname(path)) path += '.md';
+  return this._getScaffold(name)
+    .then(item => {
+      let path = item ? item.path : join(scaffoldDir, name);
+      if (!extname(path)) path += '.md';
 
-    return fs.writeFile(path, content);
-  }).asCallback(callback);
+      return fs.writeFile(path, content);
+    })
+    .asCallback(callback);
 };
 
 Scaffold.prototype.remove = function(name, callback) {
-  return this._getScaffold(name).then(item => {
-    if (!item) return;
+  return this._getScaffold(name)
+    .then(item => {
+      if (!item) return;
 
-    return fs.unlink(item.path);
-  }).asCallback(callback);
+      return fs.unlink(item.path);
+    })
+    .asCallback(callback);
 };
 
 module.exports = Scaffold;
diff --git a/lib/models/asset.js b/lib/models/asset.js
index 30320d9417..ee9865a74f 100644
--- a/lib/models/asset.js
+++ b/lib/models/asset.js
@@ -5,10 +5,10 @@ const { join } = require('path');
 
 module.exports = ctx => {
   const Asset = new Schema({
-    _id: {type: String, required: true},
-    path: {type: String, required: true},
-    modified: {type: Boolean, default: true},
-    renderable: {type: Boolean, default: true}
+    _id: { type: String, required: true },
+    path: { type: String, required: true },
+    modified: { type: Boolean, default: true },
+    renderable: { type: Boolean, default: true }
   });
 
   Asset.virtual('source').get(function() {
diff --git a/lib/models/cache.js b/lib/models/cache.js
index 1e3c9cd39d..00e9bb34ce 100644
--- a/lib/models/cache.js
+++ b/lib/models/cache.js
@@ -5,9 +5,9 @@ const Promise = require('bluebird');
 
 module.exports = ctx => {
   const Cache = new Schema({
-    _id: {type: String, required: true},
-    hash: {type: String, default: ''},
-    modified: {type: Number, default: Date.now}
+    _id: { type: String, required: true },
+    hash: { type: String, default: '' },
+    modified: { type: Number, default: Date.now }
   });
 
   Cache.static('compareFile', function(id, hashFn, statFn) {
@@ -16,52 +16,58 @@ module.exports = ctx => {
     // If cache does not exist, then it must be a new file. We have to get both
     // file hash and stats.
     if (!cache) {
-      return Promise.all([hashFn(id), statFn(id)]).spread((hash, stats) => this.insert({
-        _id: id,
-        hash,
-        modified: stats.mtime
-      })).thenReturn({
-        type: 'create'
-      });
+      return Promise.all([hashFn(id), statFn(id)])
+        .spread((hash, stats) =>
+          this.insert({
+            _id: id,
+            hash,
+            modified: stats.mtime
+          })
+        )
+        .thenReturn({
+          type: 'create'
+        });
     }
 
     let mtime;
 
     // Get file stats
-    return statFn(id).then(stats => {
-      mtime = stats.mtime;
+    return statFn(id)
+      .then(stats => {
+        mtime = stats.mtime;
 
-      // Skip the file if the modified time is unchanged
-      if (cache.modified === mtime) {
-        return {
-          type: 'skip'
-        };
-      }
+        // Skip the file if the modified time is unchanged
+        if (cache.modified === mtime) {
+          return {
+            type: 'skip'
+          };
+        }
 
-      // Get file hash
-      return hashFn(id);
-    }).then(result => {
-      // If the result is an object, skip the following steps because it's an
-      // unchanged file
-      if (typeof result === 'object') return result;
+        // Get file hash
+        return hashFn(id);
+      })
+      .then(result => {
+        // If the result is an object, skip the following steps because it's an
+        // unchanged file
+        if (typeof result === 'object') return result;
 
-      const hash = result;
+        const hash = result;
 
-      // Skip the file if the hash is unchanged
-      if (cache.hash === hash) {
-        return {
-          type: 'skip'
-        };
-      }
+        // Skip the file if the hash is unchanged
+        if (cache.hash === hash) {
+          return {
+            type: 'skip'
+          };
+        }
 
-      // Update cache info
-      cache.hash = hash;
-      cache.modified = mtime;
+        // Update cache info
+        cache.hash = hash;
+        cache.modified = mtime;
 
-      return cache.save().thenReturn({
-        type: 'update'
+        return cache.save().thenReturn({
+          type: 'update'
+        });
       });
-    });
   });
 
   return Cache;
diff --git a/lib/models/category.js b/lib/models/category.js
index a025b5316a..ea6d3023b9 100644
--- a/lib/models/category.js
+++ b/lib/models/category.js
@@ -5,8 +5,8 @@ const { slugize } = require('hexo-util');
 
 module.exports = ctx => {
   const Category = new Schema({
-    name: {type: String, required: true},
-    parent: {type: Schema.Types.CUID, ref: 'Category'}
+    name: { type: String, required: true },
+    parent: { type: Schema.Types.CUID, ref: 'Category' }
   });
 
   Category.virtual('slug').get(function() {
@@ -24,7 +24,7 @@ module.exports = ctx => {
     const map = ctx.config.category_map || {};
 
     name = map[name] || name;
-    str += slugize(name, {transform: ctx.config.filename_case});
+    str += slugize(name, { transform: ctx.config.filename_case });
 
     return str;
   });
@@ -44,10 +44,12 @@ module.exports = ctx => {
   Category.virtual('posts').get(function() {
     const PostCategory = ctx.model('PostCategory');
 
-    const ids = PostCategory.find({category_id: this._id}).map(item => item.post_id);
+    const ids = PostCategory.find({ category_id: this._id }).map(
+      item => item.post_id
+    );
 
     return ctx.locals.get('posts').find({
-      _id: {$in: ids}
+      _id: { $in: ids }
     });
   });
 
@@ -61,10 +63,13 @@ module.exports = ctx => {
     if (!name) return;
 
     const Category = ctx.model('Category');
-    const cat = Category.findOne({
-      name,
-      parent: parent || {$exists: false}
-    }, {lean: true});
+    const cat = Category.findOne(
+      {
+        name,
+        parent: parent || { $exists: false }
+      },
+      { lean: true }
+    );
 
     if (cat) {
       throw new Error(`Category \`${name}\` has already existed!`);
@@ -74,7 +79,7 @@ module.exports = ctx => {
   // Remove PostCategory references
   Category.pre('remove', data => {
     const PostCategory = ctx.model('PostCategory');
-    return PostCategory.remove({category_id: data._id});
+    return PostCategory.remove({ category_id: data._id });
   });
 
   return Category;
diff --git a/lib/models/data.js b/lib/models/data.js
index c4eaccd126..20b2466c3d 100644
--- a/lib/models/data.js
+++ b/lib/models/data.js
@@ -4,7 +4,7 @@ const { Schema } = require('warehouse');
 
 module.exports = ctx => {
   const Data = new Schema({
-    _id: {type: String, required: true},
+    _id: { type: String, required: true },
     data: Object
   });
 
diff --git a/lib/models/page.js b/lib/models/page.js
index f946abb25d..de8e6c3da9 100644
--- a/lib/models/page.js
+++ b/lib/models/page.js
@@ -7,7 +7,7 @@ const moment = require('moment');
 
 module.exports = ctx => {
   const Page = new Schema({
-    title: {type: String, default: ''},
+    title: { type: String, default: '' },
     date: {
       type: Moment,
       default: moment,
@@ -20,15 +20,15 @@ module.exports = ctx => {
       language: ctx.config.languages,
       timezone: ctx.config.timezone
     },
-    comments: {type: Boolean, default: true},
-    layout: {type: String, default: 'page'},
-    _content: {type: String, default: ''},
-    source: {type: String, required: true},
-    path: {type: String, required: true},
-    raw: {type: String, default: ''},
-    content: {type: String},
-    excerpt: {type: String},
-    more: {type: String}
+    comments: { type: Boolean, default: true },
+    layout: { type: String, default: 'page' },
+    _content: { type: String, default: '' },
+    source: { type: String, required: true },
+    path: { type: String, required: true },
+    raw: { type: String, default: '' },
+    content: { type: String },
+    excerpt: { type: String },
+    more: { type: String }
   });
 
   Page.virtual('permalink').get(function() {
diff --git a/lib/models/post.js b/lib/models/post.js
index 27fc275a0d..e7f7c22a95 100644
--- a/lib/models/post.js
+++ b/lib/models/post.js
@@ -17,7 +17,7 @@ function removeEmptyTag(tags) {
 module.exports = ctx => {
   const Post = new Schema({
     id: String,
-    title: {type: String, default: ''},
+    title: { type: String, default: '' },
     date: {
       type: Moment,
       default: moment,
@@ -30,22 +30,22 @@ module.exports = ctx => {
       language: ctx.config.languages,
       timezone: ctx.config.timezone
     },
-    comments: {type: Boolean, default: true},
-    layout: {type: String, default: 'post'},
-    _content: {type: String, default: ''},
-    source: {type: String, required: true},
-    slug: {type: String, required: true},
+    comments: { type: Boolean, default: true },
+    layout: { type: String, default: 'post' },
+    _content: { type: String, default: '' },
+    source: { type: String, required: true },
+    slug: { type: String, required: true },
     photos: [String],
-    link: {type: String, default: ''},
-    raw: {type: String, default: ''},
-    published: {type: Boolean, default: true},
-    content: {type: String},
-    excerpt: {type: String},
-    more: {type: String}
+    link: { type: String, default: '' },
+    raw: { type: String, default: '' },
+    published: { type: Boolean, default: true },
+    content: { type: String },
+    excerpt: { type: String },
+    more: { type: String }
   });
 
   Post.virtual('path').get(function() {
-    const path = ctx.execFilterSync('post_permalink', this, {context: ctx});
+    const path = ctx.execFilterSync('post_permalink', this, { context: ctx });
     return typeof path === 'string' ? path : '';
   });
 
@@ -70,9 +70,11 @@ module.exports = ctx => {
     const PostTag = ctx.model('PostTag');
     const Tag = ctx.model('Tag');
 
-    const ids = PostTag.find({post_id: this._id}, {lean: true}).map(item => item.tag_id);
+    const ids = PostTag.find({ post_id: this._id }, { lean: true }).map(
+      item => item.tag_id
+    );
 
-    return Tag.find({_id: {$in: ids}});
+    return Tag.find({ _id: { $in: ids } });
   });
 
   Post.method('setTags', function(tags) {
@@ -81,60 +83,74 @@ module.exports = ctx => {
     const PostTag = ctx.model('PostTag');
     const Tag = ctx.model('Tag');
     const id = this._id;
-    const existed = PostTag.find({post_id: id}, {lean: true}).map(pickID);
+    const existed = PostTag.find({ post_id: id }, { lean: true }).map(pickID);
 
     return Promise.map(tags, tag => {
       // Find the tag by name
-      const data = Tag.findOne({name: tag}, {lean: true});
+      const data = Tag.findOne({ name: tag }, { lean: true });
       if (data) return data;
 
       // Insert the tag if not exist
-      return Tag.insert({name: tag}).catch(err => {
+      return Tag.insert({ name: tag }).catch(err => {
         // Try to find the tag again. Throw the error if not found
-        const data = Tag.findOne({name: tag}, {lean: true});
+        const data = Tag.findOne({ name: tag }, { lean: true });
 
         if (data) return data;
         throw err;
       });
-    }).map(tag => {
-      // Find the reference
-      const ref = PostTag.findOne({post_id: id, tag_id: tag._id}, {lean: true});
-      if (ref) return ref;
-
-      // Insert the reference if not exist
-      return PostTag.insert({
-        post_id: id,
-        tag_id: tag._id
-      });
-    }).then(tags => {
-      // Remove old tags
-      const deleted = existed.filter(item => !tags.map(pickID).includes(item));
-      return deleted;
-    }).map(tag => PostTag.removeById(tag));
+    })
+      .map(tag => {
+        // Find the reference
+        const ref = PostTag.findOne(
+          { post_id: id, tag_id: tag._id },
+          { lean: true }
+        );
+        if (ref) return ref;
+
+        // Insert the reference if not exist
+        return PostTag.insert({
+          post_id: id,
+          tag_id: tag._id
+        });
+      })
+      .then(tags => {
+        // Remove old tags
+        const deleted = existed.filter(
+          item => !tags.map(pickID).includes(item)
+        );
+        return deleted;
+      })
+      .map(tag => PostTag.removeById(tag));
   });
 
   Post.virtual('categories').get(function() {
     const PostCategory = ctx.model('PostCategory');
     const Category = ctx.model('Category');
 
-    const ids = PostCategory.find({post_id: this._id}, {lean: true}).map(item => item.category_id);
+    const ids = PostCategory.find({ post_id: this._id }, { lean: true }).map(
+      item => item.category_id
+    );
 
-    return Category.find({_id: {$in: ids}});
+    return Category.find({ _id: { $in: ids } });
   });
 
   Post.method('setCategories', function(cats) {
     // Remove empty categories, preserving hierarchies
-    cats = cats.filter(cat => {
-      return Array.isArray(cat) || (cat != null && cat !== '');
-    }).map(cat => {
-      return Array.isArray(cat) ? removeEmptyTag(cat) : `${cat}`;
-    });
+    cats = cats
+      .filter(cat => {
+        return Array.isArray(cat) || (cat != null && cat !== '');
+      })
+      .map(cat => {
+        return Array.isArray(cat) ? removeEmptyTag(cat) : `${cat}`;
+      });
 
     const PostCategory = ctx.model('PostCategory');
     const Category = ctx.model('Category');
     const id = this._id;
     const allIds = [];
-    const existed = PostCategory.find({post_id: id}, {lean: true}).map(pickID);
+    const existed = PostCategory.find({ post_id: id }, { lean: true }).map(
+      pickID
+    );
     const hasHierarchy = cats.filter(Array.isArray).length > 0;
 
     // Add a hierarchy of categories
@@ -145,10 +161,13 @@ module.exports = ctx => {
       // MUST USE "Promise.each".
       return Promise.each(catHierarchy, (cat, i) => {
         // Find the category by name
-        const data = Category.findOne({
-          name: cat,
-          parent: i ? parentIds[i - 1] : {$exists: false}
-        }, {lean: true});
+        const data = Category.findOne(
+          {
+            name: cat,
+            parent: i ? parentIds[i - 1] : { $exists: false }
+          },
+          { lean: true }
+        );
 
         if (data) {
           allIds.push(data._id);
@@ -157,57 +176,72 @@ module.exports = ctx => {
         }
 
         // Insert the category if not exist
-        const obj = {name: cat};
+        const obj = { name: cat };
         if (i) obj.parent = parentIds[i - 1];
 
-        return Category.insert(obj).catch(err => {
-          // Try to find the category again. Throw the error if not found
-          const data = Category.findOne({
-            name: cat,
-            parent: i ? parentIds[i - 1] : {$exists: false}
-          }, {lean: true});
-
-          if (data) return data;
-          throw err;
-        }).then(data => {
-          allIds.push(data._id);
-          parentIds.push(data._id);
-          return data;
-        });
+        return Category.insert(obj)
+          .catch(err => {
+            // Try to find the category again. Throw the error if not found
+            const data = Category.findOne(
+              {
+                name: cat,
+                parent: i ? parentIds[i - 1] : { $exists: false }
+              },
+              { lean: true }
+            );
+
+            if (data) return data;
+            throw err;
+          })
+          .then(data => {
+            allIds.push(data._id);
+            parentIds.push(data._id);
+            return data;
+          });
       });
     };
 
-    return (hasHierarchy ? Promise.each(cats, addHierarchy) : Promise.resolve(addHierarchy(cats))
-    ).then(() => allIds).map(catId => {
-      // Find the reference
-      const ref = PostCategory.findOne({post_id: id, category_id: catId}, {lean: true});
-      if (ref) return ref;
-
-      // Insert the reference if not exist
-      return PostCategory.insert({
-        post_id: id,
-        category_id: catId
-      });
-    }).then(postCats => // Remove old categories
-      existed.filter(item => !postCats.map(pickID).includes(item))).map(cat => PostCategory.removeById(cat));
+    return (hasHierarchy
+      ? Promise.each(cats, addHierarchy)
+      : Promise.resolve(addHierarchy(cats))
+    )
+      .then(() => allIds)
+      .map(catId => {
+        // Find the reference
+        const ref = PostCategory.findOne(
+          { post_id: id, category_id: catId },
+          { lean: true }
+        );
+        if (ref) return ref;
+
+        // Insert the reference if not exist
+        return PostCategory.insert({
+          post_id: id,
+          category_id: catId
+        });
+      })
+      .then((
+        postCats // Remove old categories
+      ) => existed.filter(item => !postCats.map(pickID).includes(item)))
+      .map(cat => PostCategory.removeById(cat));
   });
 
   // Remove PostTag references
   Post.pre('remove', data => {
     const PostTag = ctx.model('PostTag');
-    return PostTag.remove({post_id: data._id});
+    return PostTag.remove({ post_id: data._id });
   });
 
   // Remove PostCategory references
   Post.pre('remove', data => {
     const PostCategory = ctx.model('PostCategory');
-    return PostCategory.remove({post_id: data._id});
+    return PostCategory.remove({ post_id: data._id });
   });
 
   // Remove assets
   Post.pre('remove', data => {
     const PostAsset = ctx.model('PostAsset');
-    return PostAsset.remove({post: data._id});
+    return PostAsset.remove({ post: data._id });
   });
 
   return Post;
diff --git a/lib/models/post_asset.js b/lib/models/post_asset.js
index 316178e53e..6f690b6b28 100644
--- a/lib/models/post_asset.js
+++ b/lib/models/post_asset.js
@@ -5,11 +5,11 @@ const { join } = require('path');
 
 module.exports = ctx => {
   const PostAsset = new Schema({
-    _id: {type: String, required: true},
-    slug: {type: String, required: true},
-    modified: {type: Boolean, default: true},
-    post: {type: Schema.Types.CUID, ref: 'Post'},
-    renderable: {type: Boolean, default: true}
+    _id: { type: String, required: true },
+    slug: { type: String, required: true },
+    modified: { type: Boolean, default: true },
+    post: { type: Schema.Types.CUID, ref: 'Post' },
+    renderable: { type: Boolean, default: true }
   });
 
   PostAsset.virtual('path').get(function() {
diff --git a/lib/models/post_category.js b/lib/models/post_category.js
index fa28d33880..1fcd86aa44 100644
--- a/lib/models/post_category.js
+++ b/lib/models/post_category.js
@@ -4,8 +4,8 @@ const { Schema } = require('warehouse');
 
 module.exports = ctx => {
   const PostCategory = new Schema({
-    post_id: {type: Schema.Types.CUID, ref: 'Post'},
-    category_id: {type: Schema.Types.CUID, ref: 'Category'}
+    post_id: { type: Schema.Types.CUID, ref: 'Post' },
+    category_id: { type: Schema.Types.CUID, ref: 'Category' }
   });
 
   return PostCategory;
diff --git a/lib/models/post_tag.js b/lib/models/post_tag.js
index fac9ef98b0..322a16c0ec 100644
--- a/lib/models/post_tag.js
+++ b/lib/models/post_tag.js
@@ -4,8 +4,8 @@ const { Schema } = require('warehouse');
 
 module.exports = ctx => {
   const PostTag = new Schema({
-    post_id: {type: Schema.Types.CUID, ref: 'Post'},
-    tag_id: {type: Schema.Types.CUID, ref: 'Tag'}
+    post_id: { type: Schema.Types.CUID, ref: 'Post' },
+    tag_id: { type: Schema.Types.CUID, ref: 'Tag' }
   });
 
   return PostTag;
diff --git a/lib/models/tag.js b/lib/models/tag.js
index 22491f1fd9..afefb6f236 100644
--- a/lib/models/tag.js
+++ b/lib/models/tag.js
@@ -6,7 +6,7 @@ const { hasOwnProperty: hasOwn } = Object.prototype;
 
 module.exports = ctx => {
   const Tag = new Schema({
-    name: {type: String, required: true}
+    name: { type: String, required: true }
   });
 
   Tag.virtual('slug').get(function() {
@@ -18,7 +18,7 @@ module.exports = ctx => {
       name = map[name] || name;
     }
 
-    return slugize(name, {transform: ctx.config.filename_case});
+    return slugize(name, { transform: ctx.config.filename_case });
   });
 
   Tag.virtual('path').get(function() {
@@ -35,10 +35,10 @@ module.exports = ctx => {
   Tag.virtual('posts').get(function() {
     const PostTag = ctx.model('PostTag');
 
-    const ids = PostTag.find({tag_id: this._id}).map(item => item.post_id);
+    const ids = PostTag.find({ tag_id: this._id }).map(item => item.post_id);
 
     return ctx.locals.get('posts').find({
-      _id: {$in: ids}
+      _id: { $in: ids }
     });
   });
 
@@ -52,7 +52,7 @@ module.exports = ctx => {
     if (!name) return;
 
     const Tag = ctx.model('Tag');
-    const tag = Tag.findOne({name}, {lean: true});
+    const tag = Tag.findOne({ name }, { lean: true });
 
     if (tag) {
       throw new Error(`Tag \`${name}\` has already existed!`);
@@ -62,7 +62,7 @@ module.exports = ctx => {
   // Remove PostTag references
   Tag.pre('remove', data => {
     const PostTag = ctx.model('PostTag');
-    return PostTag.remove({tag_id: data._id});
+    return PostTag.remove({ tag_id: data._id });
   });
 
   return Tag;
diff --git a/lib/plugins/console/clean.js b/lib/plugins/console/clean.js
index ab6895f165..4914025155 100644
--- a/lib/plugins/console/clean.js
+++ b/lib/plugins/console/clean.js
@@ -7,7 +7,7 @@ function cleanConsole(args) {
   return Promise.all([
     deleteDatabase(this),
     deletePublicDir(this),
-    this.execFilter('after_clean', null, {context: this})
+    this.execFilter('after_clean', null, { context: this })
   ]);
 }
 
diff --git a/lib/plugins/console/config.js b/lib/plugins/console/config.js
index a8b1828dc4..4e1af71513 100644
--- a/lib/plugins/console/config.js
+++ b/lib/plugins/console/config.js
@@ -23,18 +23,22 @@ function configConsole(args) {
   const configPath = this.config_path;
   const ext = extname(configPath);
 
-  return fs.exists(configPath).then(exist => {
-    if (!exist) return {};
-    return this.render.render({path: configPath});
-  }).then(config => {
-    if (!config) config = {};
-
-    setProperty(config, key, castValue(value));
-
-    const result = ext === '.json' ? JSON.stringify(config) : yaml.dump(config);
-
-    return fs.writeFile(configPath, result);
-  });
+  return fs
+    .exists(configPath)
+    .then(exist => {
+      if (!exist) return {};
+      return this.render.render({ path: configPath });
+    })
+    .then(config => {
+      if (!config) config = {};
+
+      setProperty(config, key, castValue(value));
+
+      const result =
+        ext === '.json' ? JSON.stringify(config) : yaml.dump(config);
+
+      return fs.writeFile(configPath, result);
+    });
 }
 
 function getProperty(obj, key) {
diff --git a/lib/plugins/console/deploy.js b/lib/plugins/console/deploy.js
index 433f0f272f..4f553b4c19 100644
--- a/lib/plugins/console/deploy.js
+++ b/lib/plugins/console/deploy.js
@@ -13,10 +13,13 @@ function deployConsole(args) {
   if (!config) {
     let help = '';
 
-    help += 'You should configure deployment settings in _config.yml first!\n\n';
+    help +=
+      'You should configure deployment settings in _config.yml first!\n\n';
     help += 'Available deployer plugins:\n';
     help += `  ${Object.keys(deployers).join(', ')}\n\n`;
-    help += `For more help, you can check the online docs: ${chalk.underline('https://hexo.io/')}`;
+    help += `For more help, you can check the online docs: ${chalk.underline(
+      'https://hexo.io/'
+    )}`;
 
     console.log(help);
     return;
@@ -35,29 +38,34 @@ function deployConsole(args) {
         this.call('generate', args).then(resolve, reject);
       });
     }
-  }).then(() => {
-    this.emit('deployBefore');
+  })
+    .then(() => {
+      this.emit('deployBefore');
 
-    if (!Array.isArray(config)) config = [config];
-    return config;
-  }).each(item => {
-    if (!item.type) return;
+      if (!Array.isArray(config)) config = [config];
+      return config;
+    })
+    .each(item => {
+      if (!item.type) return;
 
-    const { type } = item;
+      const { type } = item;
 
-    if (!deployers[type]) {
-      this.log.error('Deployer not found: %s', chalk.magenta(type));
-      return;
-    }
+      if (!deployers[type]) {
+        this.log.error('Deployer not found: %s', chalk.magenta(type));
+        return;
+      }
 
-    this.log.info('Deploying: %s', chalk.magenta(type));
+      this.log.info('Deploying: %s', chalk.magenta(type));
 
-    return Reflect.apply(deployers[type], this, [assignIn({}, item, args)]).then(() => {
-      this.log.info('Deploy done: %s', chalk.magenta(type));
+      return Reflect.apply(deployers[type], this, [
+        assignIn({}, item, args)
+      ]).then(() => {
+        this.log.info('Deploy done: %s', chalk.magenta(type));
+      });
+    })
+    .then(() => {
+      this.emit('deployAfter');
     });
-  }).then(() => {
-    this.emit('deployAfter');
-  });
 }
 
 module.exports = deployConsole;
diff --git a/lib/plugins/console/generate.js b/lib/plugins/console/generate.js
index ff7e9440cd..c14b76aa17 100644
--- a/lib/plugins/console/generate.js
+++ b/lib/plugins/console/generate.js
@@ -28,57 +28,69 @@ function generateConsole(args = {}) {
 
     const dest = join(publicDir, path);
 
-    return fs.exists(dest).then(exist => {
-      if (force || !exist) return writeFile(path, true);
-      if (route.isModified(path)) return writeFile(path);
-    }).finally(() => {
-      // Unlock the file
-      generatingFiles[path] = false;
-    });
+    return fs
+      .exists(dest)
+      .then(exist => {
+        if (force || !exist) return writeFile(path, true);
+        if (route.isModified(path)) return writeFile(path);
+      })
+      .finally(() => {
+        // Unlock the file
+        generatingFiles[path] = false;
+      });
   }
 
   function writeFile(path, force) {
     const dest = join(publicDir, path);
     const cacheId = `public/${path}`;
-    const dataStream = wrapDataStream(route.get(path), {bail});
+    const dataStream = wrapDataStream(route.get(path), { bail });
     const cacheStream = new CacheStream();
     const hashStream = new HashStream();
 
     // Get data => Cache data => Calculate hash
-    return pipeStream(dataStream, cacheStream, hashStream).then(() => {
-      const cache = Cache.findById(cacheId);
-      const hash = hashStream.read().toString('hex');
-
-      // Skip generating if hash is unchanged
-      if (!force && cache && cache.hash === hash) {
-        return;
-      }
-
-      // Save new hash to cache
-      return Cache.save({
-        _id: cacheId,
-        hash
-      }).then(() => // Write cache data to public folder
-        fs.writeFile(dest, cacheStream.getCache())).then(() => {
-        log.info('Generated: %s', chalk.magenta(path));
-        return true;
+    return pipeStream(dataStream, cacheStream, hashStream)
+      .then(() => {
+        const cache = Cache.findById(cacheId);
+        const hash = hashStream.read().toString('hex');
+
+        // Skip generating if hash is unchanged
+        if (!force && cache && cache.hash === hash) {
+          return;
+        }
+
+        // Save new hash to cache
+        return Cache.save({
+          _id: cacheId,
+          hash
+        })
+          .then(() =>
+            // Write cache data to public folder
+            fs.writeFile(dest, cacheStream.getCache())
+          )
+          .then(() => {
+            log.info('Generated: %s', chalk.magenta(path));
+            return true;
+          });
+      })
+      .finally(() => {
+        // Destroy cache
+        cacheStream.destroy();
       });
-    }).finally(() => {
-      // Destroy cache
-      cacheStream.destroy();
-    });
   }
 
   function deleteFile(path) {
     const dest = join(publicDir, path);
 
-    return fs.unlink(dest).then(() => {
-      log.info('Deleted: %s', chalk.magenta(path));
-    }, err => {
-      // Skip ENOENT errors (file was deleted)
-      if (err.cause && err.cause.code === 'ENOENT') return;
-      throw err;
-    });
+    return fs.unlink(dest).then(
+      () => {
+        log.info('Deleted: %s', chalk.magenta(path));
+      },
+      err => {
+        // Skip ENOENT errors (file was deleted)
+        if (err.cause && err.cause.code === 'ENOENT') return;
+        throw err;
+      }
+    );
   }
 
   function wrapDataStream(dataStream, options) {
@@ -106,58 +118,79 @@ function generateConsole(args = {}) {
     start = process.hrtime();
 
     // Check the public folder
-    return fs.stat(publicDir).then(stats => {
-      if (!stats.isDirectory()) {
-        throw new Error('%s is not a directory', chalk.magenta(tildify(publicDir)));
-      }
-    }).catch(err => {
-      // Create public folder if not exists
-      if (err.cause && err.cause.code === 'ENOENT') {
-        return fs.mkdirs(publicDir);
-      }
-
-      throw err;
-    }).then(() => {
-      const task = (fn, path) => () => fn(path);
-      const doTask = fn => fn();
-      const routeList = route.list();
-      const publicFiles = Cache.filter(item => item._id.startsWith('public/')).map(item => item._id.substring(7));
-      const tasks = publicFiles.filter(path => !routeList.includes(path))
-        // Clean files
-        .map(path => task(deleteFile, path))
-        // Generate files
-        .concat(routeList.map(path => task(generateFile, path)));
-
-      return Promise.all(Promise.map(tasks, doTask, { concurrency: parseFloat(concurrency || 'Infinity') }));
-    }).then(result => {
-      const interval = prettyHrtime(process.hrtime(start));
-      const count = result.filter(Boolean).length;
-
-      log.info('%d files generated in %s', count, chalk.cyan(interval));
-    });
+    return fs
+      .stat(publicDir)
+      .then(stats => {
+        if (!stats.isDirectory()) {
+          throw new Error(
+            '%s is not a directory',
+            chalk.magenta(tildify(publicDir))
+          );
+        }
+      })
+      .catch(err => {
+        // Create public folder if not exists
+        if (err.cause && err.cause.code === 'ENOENT') {
+          return fs.mkdirs(publicDir);
+        }
+
+        throw err;
+      })
+      .then(() => {
+        const task = (fn, path) => () => fn(path);
+        const doTask = fn => fn();
+        const routeList = route.list();
+        const publicFiles = Cache.filter(item =>
+          item._id.startsWith('public/')
+        ).map(item => item._id.substring(7));
+        const tasks = publicFiles
+          .filter(path => !routeList.includes(path))
+          // Clean files
+          .map(path => task(deleteFile, path))
+          // Generate files
+          .concat(routeList.map(path => task(generateFile, path)));
+
+        return Promise.all(
+          Promise.map(tasks, doTask, {
+            concurrency: parseFloat(concurrency || 'Infinity')
+          })
+        );
+      })
+      .then(result => {
+        const interval = prettyHrtime(process.hrtime(start));
+        const count = result.filter(Boolean).length;
+
+        log.info('%d files generated in %s', count, chalk.cyan(interval));
+      });
   }
 
   if (args.w || args.watch) {
-    return this.watch().then(firstGenerate).then(() => {
-      log.info('Hexo is watching for file changes. Press Ctrl+C to exit.');
-
-      // Watch changes of the route
-      route.on('update', path => {
-        const modified = route.isModified(path);
-        if (!modified) return;
-
-        generateFile(path);
-      }).on('remove', path => {
-        deleteFile(path);
+    return this.watch()
+      .then(firstGenerate)
+      .then(() => {
+        log.info('Hexo is watching for file changes. Press Ctrl+C to exit.');
+
+        // Watch changes of the route
+        route
+          .on('update', path => {
+            const modified = route.isModified(path);
+            if (!modified) return;
+
+            generateFile(path);
+          })
+          .on('remove', path => {
+            deleteFile(path);
+          });
       });
-    });
   }
 
-  return this.load().then(firstGenerate).then(() => {
-    if (args.d || args.deploy) {
-      return this.call('deploy', args);
-    }
-  });
+  return this.load()
+    .then(firstGenerate)
+    .then(() => {
+      if (args.d || args.deploy) {
+        return this.call('deploy', args);
+      }
+    });
 }
 
 // Pipe a stream from one to another
diff --git a/lib/plugins/console/index.js b/lib/plugins/console/index.js
index 3a34b7b0fb..23ec68c7a9 100644
--- a/lib/plugins/console/index.js
+++ b/lib/plugins/console/index.js
@@ -3,78 +3,159 @@
 module.exports = function(ctx) {
   const { console } = ctx.extend;
 
-  console.register('clean', 'Remove generated files and cache.', require('./clean'));
+  console.register(
+    'clean',
+    'Remove generated files and cache.',
+    require('./clean')
+  );
 
-  console.register('config', 'Get or set configurations.', {
-    usage: '[name] [value]',
-    arguments: [
-      {name: 'name', desc: 'Setting name. Leave it blank if you want to show all configurations.'},
-      {name: 'value', desc: 'New value of a setting. Leave it blank if you just want to show a single configuration.'}
-    ]
-  }, require('./config'));
+  console.register(
+    'config',
+    'Get or set configurations.',
+    {
+      usage: '[name] [value]',
+      arguments: [
+        {
+          name: 'name',
+          desc:
+            'Setting name. Leave it blank if you want to show all configurations.'
+        },
+        {
+          name: 'value',
+          desc:
+            'New value of a setting. Leave it blank if you just want to show a single configuration.'
+        }
+      ]
+    },
+    require('./config')
+  );
 
-  console.register('deploy', 'Deploy your website.', {
-    options: [
-      {name: '--setup', desc: 'Setup without deployment'},
-      {name: '-g, --generate', desc: 'Generate before deployment'}
-    ]
-  }, require('./deploy'));
+  console.register(
+    'deploy',
+    'Deploy your website.',
+    {
+      options: [
+        { name: '--setup', desc: 'Setup without deployment' },
+        { name: '-g, --generate', desc: 'Generate before deployment' }
+      ]
+    },
+    require('./deploy')
+  );
 
-  console.register('generate', 'Generate static files.', {
-    options: [
-      {name: '-d, --deploy', desc: 'Deploy after generated'},
-      {name: '-f, --force', desc: 'Force regenerate'},
-      {name: '-w, --watch', desc: 'Watch file changes'},
-      {name: '-b, --bail', desc: 'Raise an error if any unhandled exception is thrown during generation'},
-      {name: '-c, --concurrency', desc: 'Maximum number of files to be generated in parallel. Default is infinity'}
-    ]
-  }, require('./generate'));
+  console.register(
+    'generate',
+    'Generate static files.',
+    {
+      options: [
+        { name: '-d, --deploy', desc: 'Deploy after generated' },
+        { name: '-f, --force', desc: 'Force regenerate' },
+        { name: '-w, --watch', desc: 'Watch file changes' },
+        {
+          name: '-b, --bail',
+          desc:
+            'Raise an error if any unhandled exception is thrown during generation'
+        },
+        {
+          name: '-c, --concurrency',
+          desc:
+            'Maximum number of files to be generated in parallel. Default is infinity'
+        }
+      ]
+    },
+    require('./generate')
+  );
 
-  console.register('list', 'List the information of the site', {
-    desc: 'List the information of the site.',
-    usage: '',
-    arguments: [
-      {name: 'type', desc: 'Available types: page, post, route, tag, category'}
-    ]
-  }, require('./list'));
+  console.register(
+    'list',
+    'List the information of the site',
+    {
+      desc: 'List the information of the site.',
+      usage: '',
+      arguments: [
+        {
+          name: 'type',
+          desc: 'Available types: page, post, route, tag, category'
+        }
+      ]
+    },
+    require('./list')
+  );
 
-  console.register('migrate', 'Migrate your site from other system to Hexo.', {
-    init: true,
-    usage: '',
-    arguments: [
-      {name: 'type', desc: 'Migrator type.'}
-    ]
-  }, require('./migrate'));
+  console.register(
+    'migrate',
+    'Migrate your site from other system to Hexo.',
+    {
+      init: true,
+      usage: '',
+      arguments: [{ name: 'type', desc: 'Migrator type.' }]
+    },
+    require('./migrate')
+  );
 
-  console.register('new', 'Create a new post.', {
-    usage: '[layout] ',
-    arguments: [
-      {name: 'layout', desc: 'Post layout. Use post, page, draft or whatever you want.'},
-      {name: 'title', desc: 'Post title. Wrap it with quotations to escape.'}
-    ],
-    options: [
-      {name: '-r, --replace', desc: 'Replace the current post if existed.'},
-      {name: '-s, --slug', desc: 'Post slug. Customize the URL of the post.'},
-      {name: '-p, --path', desc: 'Post path. Customize the path of the post.'}
-    ]
-  }, require('./new'));
+  console.register(
+    'new',
+    'Create a new post.',
+    {
+      usage: '[layout] <title>',
+      arguments: [
+        {
+          name: 'layout',
+          desc: 'Post layout. Use post, page, draft or whatever you want.'
+        },
+        {
+          name: 'title',
+          desc: 'Post title. Wrap it with quotations to escape.'
+        }
+      ],
+      options: [
+        { name: '-r, --replace', desc: 'Replace the current post if existed.' },
+        {
+          name: '-s, --slug',
+          desc: 'Post slug. Customize the URL of the post.'
+        },
+        {
+          name: '-p, --path',
+          desc: 'Post path. Customize the path of the post.'
+        }
+      ]
+    },
+    require('./new')
+  );
 
-  console.register('publish', 'Moves a draft post from _drafts to _posts folder.', {
-    usage: '[layout] <filename>',
-    arguments: [
-      {name: 'layout', desc: 'Post layout. Use post, page, draft or whatever you want.'},
-      {name: 'filename', desc: 'Draft filename. "hello-world" for example.'}
-    ]
-  }, require('./publish'));
+  console.register(
+    'publish',
+    'Moves a draft post from _drafts to _posts folder.',
+    {
+      usage: '[layout] <filename>',
+      arguments: [
+        {
+          name: 'layout',
+          desc: 'Post layout. Use post, page, draft or whatever you want.'
+        },
+        { name: 'filename', desc: 'Draft filename. "hello-world" for example.' }
+      ]
+    },
+    require('./publish')
+  );
 
-  console.register('render', 'Render files with renderer plugins.', {
-    init: true,
-    desc: 'Render files with renderer plugins (e.g. Markdown) and save them at the specified path.',
-    usage: '<file1> [file2] ...',
-    options: [
-      {name: '--output', desc: 'Output destination. Result will be printed in the terminal if the output destination is not set.'},
-      {name: '--engine', desc: 'Specify render engine'},
-      {name: '--pretty', desc: 'Prettify JSON output'}
-    ]
-  }, require('./render'));
+  console.register(
+    'render',
+    'Render files with renderer plugins.',
+    {
+      init: true,
+      desc:
+        'Render files with renderer plugins (e.g. Markdown) and save them at the specified path.',
+      usage: '<file1> [file2] ...',
+      options: [
+        {
+          name: '--output',
+          desc:
+            'Output destination. Result will be printed in the terminal if the output destination is not set.'
+        },
+        { name: '--engine', desc: 'Specify render engine' },
+        { name: '--pretty', desc: 'Prettify JSON output' }
+      ]
+    },
+    require('./render')
+  );
 };
diff --git a/lib/plugins/console/list/category.js b/lib/plugins/console/list/category.js
index 85b9045df2..3e52a8b0a2 100644
--- a/lib/plugins/console/list/category.js
+++ b/lib/plugins/console/list/category.js
@@ -7,7 +7,9 @@ const common = require('./common');
 function listCategory() {
   const categories = this.model('Category');
 
-  const data = categories.sort({name: 1}).map(cate => [cate.name, String(cate.length)]);
+  const data = categories
+    .sort({ name: 1 })
+    .map(cate => [cate.name, String(cate.length)]);
 
   // Table header
   const header = ['Name', 'Posts'].map(str => chalk.underline(str));
diff --git a/lib/plugins/console/list/index.js b/lib/plugins/console/list/index.js
index 4ab6fba1d0..172e688c5a 100644
--- a/lib/plugins/console/list/index.js
+++ b/lib/plugins/console/list/index.js
@@ -17,10 +17,12 @@ function listConsole(args) {
 
   // Display help message if user didn't input any arguments
   if (!type || !alias[type]) {
-    return this.call('help', {_: ['list']});
+    return this.call('help', { _: ['list'] });
   }
 
-  return this.load().then(() => Reflect.apply(store[alias[type]], this, [args]));
+  return this.load().then(() =>
+    Reflect.apply(store[alias[type]], this, [args])
+  );
 }
 
 module.exports = listConsole;
diff --git a/lib/plugins/console/list/page.js b/lib/plugins/console/list/page.js
index 230853c016..8b2e298cf3 100644
--- a/lib/plugins/console/list/page.js
+++ b/lib/plugins/console/list/page.js
@@ -7,7 +7,7 @@ const common = require('./common');
 function listPage() {
   const Page = this.model('Page');
 
-  const data = Page.sort({date: 1}).map(page => {
+  const data = Page.sort({ date: 1 }).map(page => {
     const date = page.date.format('YYYY-MM-DD');
     return [chalk.gray(date), page.title, chalk.magenta(page.source)];
   });
diff --git a/lib/plugins/console/list/post.js b/lib/plugins/console/list/post.js
index 8a4a368144..1f29b5e092 100644
--- a/lib/plugins/console/list/post.js
+++ b/lib/plugins/console/list/post.js
@@ -11,7 +11,7 @@ function mapName(item) {
 function listPost() {
   const Post = this.model('Post');
 
-  const data = Post.sort({published: -1, date: 1}).map(post => {
+  const data = Post.sort({ published: -1, date: 1 }).map(post => {
     const date = post.published ? post.date.format('YYYY-MM-DD') : 'Draft';
     const tags = post.tags.map(mapName);
     const categories = post.categories.map(mapName);
@@ -26,7 +26,9 @@ function listPost() {
   });
 
   // Table header
-  const header = ['Date', 'Title', 'Path', 'Category', 'Tags'].map(str => chalk.underline(str));
+  const header = ['Date', 'Title', 'Path', 'Category', 'Tags'].map(str =>
+    chalk.underline(str)
+  );
 
   data.unshift(header);
 
diff --git a/lib/plugins/console/list/tag.js b/lib/plugins/console/list/tag.js
index f01453b679..ed3ccae9f2 100644
--- a/lib/plugins/console/list/tag.js
+++ b/lib/plugins/console/list/tag.js
@@ -7,7 +7,11 @@ const common = require('./common');
 function listTag() {
   const Tag = this.model('Tag');
 
-  const data = Tag.sort({name: 1}).map(tag => [tag.name, String(tag.length), chalk.magenta(tag.path)]);
+  const data = Tag.sort({ name: 1 }).map(tag => [
+    tag.name,
+    String(tag.length),
+    chalk.magenta(tag.path)
+  ]);
 
   // Table header
   const header = ['Name', 'Posts', 'Path'].map(str => chalk.underline(str));
diff --git a/lib/plugins/console/migrate.js b/lib/plugins/console/migrate.js
index 9592525805..d4db6f4c58 100644
--- a/lib/plugins/console/migrate.js
+++ b/lib/plugins/console/migrate.js
@@ -5,7 +5,7 @@ const chalk = require('chalk');
 function migrateConsole(args) {
   // Display help message if user didn't input any arguments
   if (!args._.length) {
-    return this.call('help', {_: ['migrate']});
+    return this.call('help', { _: ['migrate'] });
   }
 
   const type = args._.shift();
@@ -17,7 +17,9 @@ function migrateConsole(args) {
     help += `${type.magenta} migrator plugin is not installed.\n\n`;
     help += 'Installed migrator plugins:\n';
     help += `  ${Object.keys(migrators).join(', ')}\n\n`;
-    help += `For more help, you can check the online docs: ${chalk.underline('https://hexo.io/')}`;
+    help += `For more help, you can check the online docs: ${chalk.underline(
+      'https://hexo.io/'
+    )}`;
 
     console.log(help);
     return;
diff --git a/lib/plugins/console/new.js b/lib/plugins/console/new.js
index ace8d996ec..e41020707c 100644
--- a/lib/plugins/console/new.js
+++ b/lib/plugins/console/new.js
@@ -20,7 +20,7 @@ const reservedKeys = {
 function newConsole(args) {
   // Display help message if user didn't input any arguments
   if (!args._.length) {
-    return this.call('help', {_: ['new']});
+    return this.call('help', { _: ['new'] });
   }
 
   const data = {
diff --git a/lib/plugins/console/publish.js b/lib/plugins/console/publish.js
index 030063e9f9..fa1d6a6aef 100644
--- a/lib/plugins/console/publish.js
+++ b/lib/plugins/console/publish.js
@@ -6,15 +6,20 @@ const chalk = require('chalk');
 function publishConsole(args) {
   // Display help message if user didn't input any arguments
   if (!args._.length) {
-    return this.call('help', {_: ['publish']});
+    return this.call('help', { _: ['publish'] });
   }
 
-  return this.post.publish({
-    slug: args._.pop(),
-    layout: args._.length ? args._[0] : this.config.default_layout
-  }, args.r || args.replace).then(post => {
-    this.log.info('Published: %s', chalk.magenta(tildify(post.path)));
-  });
+  return this.post
+    .publish(
+      {
+        slug: args._.pop(),
+        layout: args._.length ? args._[0] : this.config.default_layout
+      },
+      args.r || args.replace
+    )
+    .then(post => {
+      this.log.info('Published: %s', chalk.magenta(tildify(post.path)));
+    });
 }
 
 module.exports = publishConsole;
diff --git a/lib/plugins/console/render.js b/lib/plugins/console/render.js
index 937c2d1b03..51133cb4fc 100644
--- a/lib/plugins/console/render.js
+++ b/lib/plugins/console/render.js
@@ -9,7 +9,7 @@ const chalk = require('chalk');
 function renderConsole(args) {
   // Display help message if user didn't input any arguments
   if (!args._.length) {
-    return this.call('help', {_: 'render'});
+    return this.call('help', { _: 'render' });
   }
 
   const baseDir = this.base_dir;
@@ -18,26 +18,33 @@ function renderConsole(args) {
   const start = process.hrtime();
   const { log } = this;
 
-  return this.render.render({
-    path: src,
-    engine: args.engine
-  }).then(result => {
-    if (typeof result === 'object') {
-      if (args.pretty) {
-        result = JSON.stringify(result, null, '  ');
-      } else {
-        result = JSON.stringify(result);
+  return this.render
+    .render({
+      path: src,
+      engine: args.engine
+    })
+    .then(result => {
+      if (typeof result === 'object') {
+        if (args.pretty) {
+          result = JSON.stringify(result, null, '  ');
+        } else {
+          result = JSON.stringify(result);
+        }
       }
-    }
 
-    if (!output) return console.log(result);
+      if (!output) return console.log(result);
 
-    const dest = resolve(baseDir, output);
-    const interval = prettyHrtime(process.hrtime(start));
+      const dest = resolve(baseDir, output);
+      const interval = prettyHrtime(process.hrtime(start));
 
-    log.info('Rendered in %s: %s -> %s', chalk.cyan(interval), chalk.magenta(tildify(src)), chalk.magenta(tildify(dest)));
-    return fs.writeFile(dest, result);
-  });
+      log.info(
+        'Rendered in %s: %s -> %s',
+        chalk.cyan(interval),
+        chalk.magenta(tildify(src)),
+        chalk.magenta(tildify(dest))
+      );
+      return fs.writeFile(dest, result);
+    });
 }
 
 module.exports = renderConsole;
diff --git a/lib/plugins/filter/after_post_render/external_link.js b/lib/plugins/filter/after_post_render/external_link.js
index 229f3a3f41..17edfe979c 100644
--- a/lib/plugins/filter/after_post_render/external_link.js
+++ b/lib/plugins/filter/after_post_render/external_link.js
@@ -8,25 +8,28 @@ function externalLinkFilter(data) {
 
   const siteHost = url.parse(config.url).hostname || config.url;
 
-  data.content = data.content.replace(/<a.*?(href=['"](.*?)['"]).*?>/gi, (str, hrefStr, href) => {
-    if (/target=/gi.test(str)) return str;
-
-    const data = url.parse(href);
-    // Exit if the link doesn't have protocol, which means it's a internal link
-    // Exit if the url has same host with config.url
-    if (!data.protocol || data.hostname === siteHost) return str;
-
-    if (/rel=/gi.test(str)) {
-      str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
-        if (!rel.includes('noopenner')) relStr = relStr.replace(rel, `${rel} noopener`);
-        return relStr;
-      });
-      return str.replace(hrefStr, `${hrefStr} target="_blank"`);
+  data.content = data.content.replace(
+    /<a.*?(href=['"](.*?)['"]).*?>/gi,
+    (str, hrefStr, href) => {
+      if (/target=/gi.test(str)) return str;
+
+      const data = url.parse(href);
+      // Exit if the link doesn't have protocol, which means it's a internal link
+      // Exit if the url has same host with config.url
+      if (!data.protocol || data.hostname === siteHost) return str;
+
+      if (/rel=/gi.test(str)) {
+        str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
+          if (!rel.includes('noopenner'))
+            relStr = relStr.replace(rel, `${rel} noopener`);
+          return relStr;
+        });
+        return str.replace(hrefStr, `${hrefStr} target="_blank"`);
+      }
+
+      return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
     }
-
-    return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
-  });
-
+  );
 }
 
 module.exports = externalLinkFilter;
diff --git a/lib/plugins/filter/before_generate/render_post.js b/lib/plugins/filter/before_generate/render_post.js
index 100450004a..4a874835fb 100644
--- a/lib/plugins/filter/before_generate/render_post.js
+++ b/lib/plugins/filter/before_generate/render_post.js
@@ -8,7 +8,7 @@ function renderPostFilter(data) {
 
     return Promise.map(posts, post => {
       post.content = post._content;
-      post.site = {data};
+      post.site = { data };
 
       return this.post.render(post.full_source, post).then(() => post.save());
     });
diff --git a/lib/plugins/filter/before_post_render/backtick_code_block.js b/lib/plugins/filter/before_post_render/backtick_code_block.js
index 06dec6739a..57d4a9b3a8 100644
--- a/lib/plugins/filter/before_post_render/backtick_code_block.js
+++ b/lib/plugins/filter/before_post_render/backtick_code_block.js
@@ -10,52 +10,55 @@ const rLangCaption = /([^\s]+)\s*(.+)?/;
 function backtickCodeBlock(data) {
   const config = this.config.highlight || {};
   if (!config.enable) return;
-  data.content = data.content.replace(rBacktick, ($0, start, $2, _args, content, end) => {
-    const args = _args.split('=').shift();
-
-    const options = {
-      hljs: config.hljs,
-      autoDetect: config.auto_detect,
-      gutter: config.line_number,
-      tab: config.tab_replace
-    };
-
-    if (options.gutter) {
-      config.first_line_number = config.first_line_number || 'always1';
-      if (config.first_line_number === 'inline') {
-
-        // setup line number by inline
-        _args = _args.replace('=+', '=');
-        options.gutter = _args.includes('=');
-
-        // setup fiestLineNumber;
-        options.firstLine = options.gutter ? _args.split('=')[1] || 1 : 0;
-      }
-    }
+  data.content = data.content.replace(
+    rBacktick,
+    ($0, start, $2, _args, content, end) => {
+      const args = _args.split('=').shift();
+
+      const options = {
+        hljs: config.hljs,
+        autoDetect: config.auto_detect,
+        gutter: config.line_number,
+        tab: config.tab_replace
+      };
+
+      if (options.gutter) {
+        config.first_line_number = config.first_line_number || 'always1';
+        if (config.first_line_number === 'inline') {
+          // setup line number by inline
+          _args = _args.replace('=+', '=');
+          options.gutter = _args.includes('=');
 
-    if (args) {
-      const match = rAllOptions.exec(args) || rLangCaption.exec(args);
+          // setup fiestLineNumber;
+          options.firstLine = options.gutter ? _args.split('=')[1] || 1 : 0;
+        }
+      }
 
+      if (args) {
+        const match = rAllOptions.exec(args) || rLangCaption.exec(args);
 
-      if (match) {
-        options.lang = match[1];
+        if (match) {
+          options.lang = match[1];
 
-        if (match[2]) {
-          options.caption = `<span>${match[2]}</span>`;
+          if (match[2]) {
+            options.caption = `<span>${match[2]}</span>`;
 
-          if (match[3]) {
-            options.caption += `<a href="${match[3]}">${match[4] ? match[4] : 'link'}</a>`;
+            if (match[3]) {
+              options.caption += `<a href="${match[3]}">${
+                match[4] ? match[4] : 'link'
+              }</a>`;
+            }
           }
         }
       }
-    }
 
-    content = highlight(stripIndent(content), options)
-      .replace(/{/g, '{')
-      .replace(/}/g, '}');
+      content = highlight(stripIndent(content), options)
+        .replace(/{/g, '{')
+        .replace(/}/g, '}');
 
-    return `${start}<escape>${content}</escape>${end ? '\n\n' : ''}`;
-  });
+      return `${start}<escape>${content}</escape>${end ? '\n\n' : ''}`;
+    }
+  );
 }
 
 module.exports = backtickCodeBlock;
diff --git a/lib/plugins/filter/meta_generator.js b/lib/plugins/filter/meta_generator.js
index 8440b9b0fe..af23b91faa 100644
--- a/lib/plugins/filter/meta_generator.js
+++ b/lib/plugins/filter/meta_generator.js
@@ -2,12 +2,17 @@
 
 function hexoMetaGeneratorInject(data) {
   const { config } = this;
-  if (!config.meta_generator ||
-  data.match(/<meta\s+name=['|"]?generator['|"]?/i)) return;
+  if (
+    !config.meta_generator ||
+    data.match(/<meta\s+name=['|"]?generator['|"]?/i)
+  )
+    return;
 
   const hexoGeneratorTag = `<meta name="generator" content="Hexo ${this.version}">`;
 
-  return data.replace(/<head>(?!<\/head>).+?<\/head>/, (str) => str.replace('</head>', `${hexoGeneratorTag}</head>`));
+  return data.replace(/<head>(?!<\/head>).+?<\/head>/, str =>
+    str.replace('</head>', `${hexoGeneratorTag}</head>`)
+  );
 }
 
 module.exports = hexoMetaGeneratorInject;
diff --git a/lib/plugins/filter/new_post_path.js b/lib/plugins/filter/new_post_path.js
index 4773c0cca1..76fd438243 100644
--- a/lib/plugins/filter/new_post_path.js
+++ b/lib/plugins/filter/new_post_path.js
@@ -73,12 +73,16 @@ function newPostPathFilter(data = {}, replace) {
           if (!reservedKeys[key]) filenameData[key] = data[key];
         }
 
-        target = join(postDir, permalink.stringify(
-          defaults(filenameData, permalinkDefaults)));
+        target = join(
+          postDir,
+          permalink.stringify(defaults(filenameData, permalinkDefaults))
+        );
       }
     }
   } else {
-    return Promise.reject(new TypeError('Either data.path or data.slug is required!'));
+    return Promise.reject(
+      new TypeError('Either data.path or data.slug is required!')
+    );
   }
 
   if (!extname(target)) {
diff --git a/lib/plugins/filter/post_permalink.js b/lib/plugins/filter/post_permalink.js
index 9fc519c933..ce5bea213d 100644
--- a/lib/plugins/filter/post_permalink.js
+++ b/lib/plugins/filter/post_permalink.js
@@ -11,7 +11,7 @@ function postPermalinkFilter(data) {
     id: data.id || data._id,
     title: data.slug,
     name: typeof data.slug === 'string' ? basename(data.slug) : '',
-    post_title: slugize(data.title, {transform: 1}),
+    post_title: slugize(data.title, { transform: 1 }),
     year: data.date.format('YYYY'),
     month: data.date.format('MM'),
     day: data.date.format('DD'),
@@ -39,7 +39,11 @@ function postPermalinkFilter(data) {
 
     // Use Object.getOwnPropertyDescriptor to copy getters to avoid "Maximum call
     // stack size exceeded" error
-    Object.defineProperty(meta, key, Object.getOwnPropertyDescriptor(data, key));
+    Object.defineProperty(
+      meta,
+      key,
+      Object.getOwnPropertyDescriptor(data, key)
+    );
   }
 
   return permalink.stringify(defaults(meta, config.permalink_defaults));
diff --git a/lib/plugins/filter/template_locals/i18n.js b/lib/plugins/filter/template_locals/i18n.js
index 7348a3d580..74b7165985 100644
--- a/lib/plugins/filter/template_locals/i18n.js
+++ b/lib/plugins/filter/template_locals/i18n.js
@@ -29,7 +29,10 @@ function i18nLocalsFilter(locals) {
 
   page.canonical_path = page.canonical_path || locals.path;
 
-  const languages = _([].concat(lang, i18nConfigLanguages, i18nLanguages)).compact().uniq().value();
+  const languages = _([].concat(lang, i18nConfigLanguages, i18nLanguages))
+    .compact()
+    .uniq()
+    .value();
 
   locals.__ = i18n.__(languages);
   locals._p = i18n._p(languages);
diff --git a/lib/plugins/generator/asset.js b/lib/plugins/generator/asset.js
index b24ad1a3e2..d3a16a47f2 100644
--- a/lib/plugins/generator/asset.js
+++ b/lib/plugins/generator/asset.js
@@ -6,9 +6,11 @@ const { extname } = require('path');
 const chalk = require('chalk');
 
 const process = (name, ctx) => {
-  return Promise.filter(ctx.model(name).toArray(), asset => fs.exists(asset.source).tap(exist => {
-    if (!exist) return asset.remove();
-  })).map(asset => {
+  return Promise.filter(ctx.model(name).toArray(), asset =>
+    fs.exists(asset.source).tap(exist => {
+      if (!exist) return asset.remove();
+    })
+  ).map(asset => {
     const { source } = asset;
     let { path } = asset;
     const data = {
@@ -21,12 +23,19 @@ const process = (name, ctx) => {
 
       path = `${filename}.${ctx.render.getOutput(path)}`;
 
-      data.data = () => ctx.render.render({
-        path: source,
-        toString: true
-      }).catch(err => {
-        ctx.log.error({err}, 'Asset render failed: %s', chalk.magenta(path));
-      });
+      data.data = () =>
+        ctx.render
+          .render({
+            path: source,
+            toString: true
+          })
+          .catch(err => {
+            ctx.log.error(
+              { err },
+              'Asset render failed: %s',
+              chalk.magenta(path)
+            );
+          });
     } else {
       data.data = () => fs.createReadStream(source);
     }
@@ -36,10 +45,9 @@ const process = (name, ctx) => {
 };
 
 function assetGenerator(locals) {
-  return Promise.all([
-    process('Asset', this),
-    process('PostAsset', this)
-  ]).then(data => [].concat(...data));
+  return Promise.all([process('Asset', this), process('PostAsset', this)]).then(
+    data => [].concat(...data)
+  );
 }
 
 module.exports = assetGenerator;
diff --git a/lib/plugins/helper/date.js b/lib/plugins/helper/date.js
index 8bad844b9d..0bd54d39f6 100644
--- a/lib/plugins/helper/date.js
+++ b/lib/plugins/helper/date.js
@@ -55,7 +55,12 @@ function relativeDateHelper(date) {
 
 function timeTagHelper(date, format) {
   const { config } = this;
-  return `<time datetime="${toISOString(date)}">${this.date(date, format, getLanguage(this), config.timezone)}</time>`;
+  return `<time datetime="${toISOString(date)}">${this.date(
+    date,
+    format,
+    getLanguage(this),
+    config.timezone
+  )}</time>`;
 }
 
 function getLanguage(ctx) {
diff --git a/lib/plugins/helper/fragment_cache.js b/lib/plugins/helper/fragment_cache.js
index 95c1a9a5fe..d220dc5c16 100644
--- a/lib/plugins/helper/fragment_cache.js
+++ b/lib/plugins/helper/fragment_cache.js
@@ -6,7 +6,7 @@ module.exports = ctx => {
   return function fragmentCache(id, fn) {
     if (this.cache && cache[id] != null) return cache[id];
 
-    const result = cache[id] = fn();
+    const result = (cache[id] = fn());
     return result;
   };
 };
diff --git a/lib/plugins/helper/gravatar.js b/lib/plugins/helper/gravatar.js
index 184a1df38d..a0eb86f36a 100644
--- a/lib/plugins/helper/gravatar.js
+++ b/lib/plugins/helper/gravatar.js
@@ -4,12 +4,15 @@ const crypto = require('crypto');
 const querystring = require('querystring');
 
 function md5(str) {
-  return crypto.createHash('md5').update(str).digest('hex');
+  return crypto
+    .createHash('md5')
+    .update(str)
+    .digest('hex');
 }
 
 function gravatarHelper(email, options) {
   if (typeof options === 'number') {
-    options = {s: options};
+    options = { s: options };
   }
 
   let str = `https://www.gravatar.com/avatar/${md5(email.toLowerCase())}`;
diff --git a/lib/plugins/helper/image_tag.js b/lib/plugins/helper/image_tag.js
index 8fc8d92da9..8f67666e58 100644
--- a/lib/plugins/helper/image_tag.js
+++ b/lib/plugins/helper/image_tag.js
@@ -3,9 +3,12 @@
 const { htmlTag } = require('hexo-util');
 
 function imageTagHelper(path, options = {}) {
-  const attrs = Object.assign({
-    src: this.url_for(path)
-  }, options);
+  const attrs = Object.assign(
+    {
+      src: this.url_for(path)
+    },
+    options
+  );
 
   if (attrs.class && Array.isArray(attrs.class)) {
     attrs.class = attrs.class.join(' ');
diff --git a/lib/plugins/helper/link_to.js b/lib/plugins/helper/link_to.js
index ed9605c9f6..bc89da2338 100644
--- a/lib/plugins/helper/link_to.js
+++ b/lib/plugins/helper/link_to.js
@@ -3,14 +3,17 @@
 const { htmlTag } = require('hexo-util');
 
 function linkToHelper(path, text, options = {}) {
-  if (typeof options === 'boolean') options = {external: options};
+  if (typeof options === 'boolean') options = { external: options };
 
   if (!text) text = path.replace(/^https?:\/\/|\/$/g, '');
 
-  const attrs = Object.assign({
-    href: this.url_for(path),
-    title: text
-  }, options);
+  const attrs = Object.assign(
+    {
+      href: this.url_for(path),
+      title: text
+    },
+    options
+  );
 
   if (attrs.external) {
     attrs.target = '_blank';
diff --git a/lib/plugins/helper/list_archives.js b/lib/plugins/helper/list_archives.js
index 861e92fa15..35ba3d03ca 100644
--- a/lib/plugins/helper/list_archives.js
+++ b/lib/plugins/helper/list_archives.js
@@ -8,7 +8,9 @@ function listArchivesHelper(options = {}) {
   let { format } = options;
   const type = options.type || 'monthly';
   const { style = 'list', transform, separator = ', ' } = options;
-  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true;
+  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count')
+    ? options.show_count
+    : true;
   const className = options.class || 'archive';
   const order = options.order || -1;
   let result = '';
diff --git a/lib/plugins/helper/list_categories.js b/lib/plugins/helper/list_categories.js
index f867ed6903..de184ef1d1 100644
--- a/lib/plugins/helper/list_categories.js
+++ b/lib/plugins/helper/list_categories.js
@@ -1,7 +1,10 @@
 'use strict';
 
 function listCategoriesHelper(categories, options) {
-  if (!options && (!categories || !Object.prototype.hasOwnProperty.call(categories, 'length'))) {
+  if (
+    !options &&
+    (!categories || !Object.prototype.hasOwnProperty.call(categories, 'length'))
+  ) {
     options = categories;
     categories = this.site.categories;
   }
@@ -10,13 +13,20 @@ function listCategoriesHelper(categories, options) {
   options = options || {};
 
   const { style = 'list', transform, separator = ', ', suffix = '' } = options;
-  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true;
+  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count')
+    ? options.show_count
+    : true;
   const className = options.class || 'category';
   const depth = options.depth ? parseInt(options.depth, 10) : 0;
   const orderby = options.orderby || 'name';
   const order = options.order || 1;
   const showCurrent = options.show_current || false;
-  const childrenIndicator = Object.prototype.hasOwnProperty.call(options, 'children_indicator') ? options.children_indicator : false;
+  const childrenIndicator = Object.prototype.hasOwnProperty.call(
+    options,
+    'children_indicator'
+  )
+    ? options.children_indicator
+    : false;
 
   const prepareQuery = parent => {
     const query = {};
@@ -24,10 +34,13 @@ function listCategoriesHelper(categories, options) {
     if (parent) {
       query.parent = parent;
     } else {
-      query.parent = {$exists: false};
+      query.parent = { $exists: false };
     }
 
-    return categories.find(query).sort(orderby, order).filter(cat => cat.length);
+    return categories
+      .find(query)
+      .sort(orderby, order)
+      .filter(cat => cat.length);
   };
 
   const hierarchicalList = (level, parent) => {
@@ -50,14 +63,18 @@ function listCategoriesHelper(categories, options) {
         }
 
         // special case: category page
-        isCurrent = isCurrent || (this.page.base && this.page.base.startsWith(cat.path));
+        isCurrent =
+          isCurrent || (this.page.base && this.page.base.startsWith(cat.path));
       }
 
-      const additionalClassName = child && childrenIndicator ? ` ${childrenIndicator}` : '';
+      const additionalClassName =
+        child && childrenIndicator ? ` ${childrenIndicator}` : '';
 
       result += `<li class="${className}-list-item${additionalClassName}">`;
 
-      result += `<a class="${className}-list-link${isCurrent ? ' current' : ''}" href="${this.url_for(cat.path)}${suffix}">`;
+      result += `<a class="${className}-list-link${
+        isCurrent ? ' current' : ''
+      }" href="${this.url_for(cat.path)}${suffix}">`;
       result += transform ? transform(cat.name) : cat.name;
       result += '</a>';
 
@@ -81,7 +98,9 @@ function listCategoriesHelper(categories, options) {
     prepareQuery(parent).forEach((cat, i) => {
       if (i || level) result += separator;
 
-      result += `<a class="${className}-link" href="${this.url_for(cat.path)}${suffix}">`;
+      result += `<a class="${className}-link" href="${this.url_for(
+        cat.path
+      )}${suffix}">`;
       result += transform ? transform(cat.name) : cat.name;
 
       if (showCount) {
diff --git a/lib/plugins/helper/list_posts.js b/lib/plugins/helper/list_posts.js
index 3161edd71b..66e8727d82 100644
--- a/lib/plugins/helper/list_posts.js
+++ b/lib/plugins/helper/list_posts.js
@@ -1,7 +1,10 @@
 'use strict';
 
 function listPostsHelper(posts, options) {
-  if (!options && (!posts || !Object.prototype.hasOwnProperty.call(posts, 'length'))) {
+  if (
+    !options &&
+    (!posts || !Object.prototype.hasOwnProperty.call(posts, 'length'))
+  ) {
     options = posts;
     posts = this.site.posts;
   }
@@ -30,7 +33,9 @@ function listPostsHelper(posts, options) {
 
       result += `<li class="${className}-list-item">`;
 
-      result += `<a class="${className}-list-link" href="${this.url_for(post.path)}">`;
+      result += `<a class="${className}-list-link" href="${this.url_for(
+        post.path
+      )}">`;
       result += transform ? transform(title) : title;
       result += '</a>';
 
@@ -44,7 +49,9 @@ function listPostsHelper(posts, options) {
 
       const title = post.title || post.slug;
 
-      result += `<a class="${className}-link" href="${this.url_for(post.path)}">`;
+      result += `<a class="${className}-link" href="${this.url_for(
+        post.path
+      )}">`;
       result += transform ? transform(title) : title;
       result += '</a>';
     });
diff --git a/lib/plugins/helper/list_tags.js b/lib/plugins/helper/list_tags.js
index 881bfa506c..81c9717cef 100644
--- a/lib/plugins/helper/list_tags.js
+++ b/lib/plugins/helper/list_tags.js
@@ -1,7 +1,10 @@
 'use strict';
 
 function listTagsHelper(tags, options) {
-  if (!options && (!tags || !Object.prototype.hasOwnProperty.call(tags, 'length'))) {
+  if (
+    !options &&
+    (!tags || !Object.prototype.hasOwnProperty.call(tags, 'length'))
+  ) {
     options = tags;
     tags = this.site.tags;
   }
@@ -10,7 +13,9 @@ function listTagsHelper(tags, options) {
   options = options || {};
 
   const { style = 'list', transform, separator = ', ', suffix = '' } = options;
-  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count') ? options.show_count : true;
+  const showCount = Object.prototype.hasOwnProperty.call(options, 'show_count')
+    ? options.show_count
+    : true;
   const className = options.class || 'tag';
   const orderby = options.orderby || 'name';
   const order = options.order || 1;
@@ -31,7 +36,9 @@ function listTagsHelper(tags, options) {
     tags.forEach(tag => {
       result += `<li class="${className}-list-item">`;
 
-      result += `<a class="${className}-list-link" href="${this.url_for(tag.path)}${suffix}" rel="tag">`;
+      result += `<a class="${className}-list-link" href="${this.url_for(
+        tag.path
+      )}${suffix}" rel="tag">`;
       result += transform ? transform(tag.name) : tag.name;
       result += '</a>';
 
@@ -47,7 +54,9 @@ function listTagsHelper(tags, options) {
     tags.forEach((tag, i) => {
       if (i) result += separator;
 
-      result += `<a class="${className}-link" href="${this.url_for(tag.path)}${suffix}" rel="tag">`;
+      result += `<a class="${className}-link" href="${this.url_for(
+        tag.path
+      )}${suffix}" rel="tag">`;
       result += transform ? transform(tag.name) : tag.name;
 
       if (showCount) {
diff --git a/lib/plugins/helper/mail_to.js b/lib/plugins/helper/mail_to.js
index 5443388106..09a7bca472 100644
--- a/lib/plugins/helper/mail_to.js
+++ b/lib/plugins/helper/mail_to.js
@@ -7,10 +7,13 @@ function mailToHelper(path, text, options = {}) {
   if (Array.isArray(path)) path = path.join(',');
   if (!text) text = path;
 
-  const attrs = Object.assign({
-    href: `mailto:${path}`,
-    title: text
-  }, options);
+  const attrs = Object.assign(
+    {
+      href: `mailto:${path}`,
+      title: text
+    },
+    options
+  );
 
   if (attrs.class && Array.isArray(attrs.class)) {
     attrs.class = attrs.class.join(' ');
diff --git a/lib/plugins/helper/number_format.js b/lib/plugins/helper/number_format.js
index 0db807eb76..bbedd0362e 100644
--- a/lib/plugins/helper/number_format.js
+++ b/lib/plugins/helper/number_format.js
@@ -30,7 +30,8 @@ function numberFormatHelper(num, options = {}) {
       const afterLast = after[precision];
       const last = parseInt(after[precision - 1], 10);
 
-      afterResult = after.substr(0, precision - 1) + (afterLast < 5 ? last : last + 1);
+      afterResult =
+        after.substr(0, precision - 1) + (afterLast < 5 ? last : last + 1);
     } else {
       afterResult = after;
       for (let i = 0, len = precision - afterLength; i < len; i++) {
diff --git a/lib/plugins/helper/open_graph.js b/lib/plugins/helper/open_graph.js
index 279f1db908..eb1b358433 100644
--- a/lib/plugins/helper/open_graph.js
+++ b/lib/plugins/helper/open_graph.js
@@ -27,24 +27,34 @@ function og(name, content, escape) {
 }
 
 function openGraphHelper(options = {}) {
-
   const { config, page } = this;
   const { content } = page;
   let images = options.image || options.images || page.photos || [];
-  let description = options.description || page.description || page.excerpt || content || config.description;
-  const keywords = page.keywords || (page.tags && page.tags.length ? page.tags : undefined) || config.keywords;
+  let description =
+    options.description ||
+    page.description ||
+    page.excerpt ||
+    content ||
+    config.description;
+  const keywords =
+    page.keywords ||
+    (page.tags && page.tags.length ? page.tags : undefined) ||
+    config.keywords;
   const title = options.title || page.title || config.title;
   const type = options.type || (this.is_post() ? 'article' : 'website');
   const url = options.url || this.url;
   const siteName = options.site_name || config.title;
   const twitterCard = options.twitter_card || 'summary';
-  const updated = options.updated !== false ? options.updated || page.updated : false;
-  const language = options.language || page.lang || page.language || config.language;
+  const updated =
+    options.updated !== false ? options.updated || page.updated : false;
+  const language =
+    options.language || page.lang || page.language || config.language;
 
   if (!Array.isArray(images)) images = [images];
 
   if (description) {
-    description = stripHTML(description).substring(0, 200)
+    description = stripHTML(description)
+      .substring(0, 200)
       .trim() // Remove prefixing/trailing spaces
       .replace(/</g, '<')
       .replace(/>/g, '>')
@@ -64,7 +74,6 @@ function openGraphHelper(options = {}) {
         images.push(img[1]);
       }
     }
-
   }
 
   let result = '';
@@ -77,9 +86,15 @@ function openGraphHelper(options = {}) {
     if (typeof keywords === 'string') {
       result += meta('keywords', keywords);
     } else if (keywords.length) {
-      result += meta('keywords', keywords.map(tag => {
-        return tag.name ? tag.name : tag;
-      }).filter(keyword => !!keyword).join());
+      result += meta(
+        'keywords',
+        keywords
+          .map(tag => {
+            return tag.name ? tag.name : tag;
+          })
+          .filter(keyword => !!keyword)
+          .join()
+      );
     }
   }
 
@@ -110,7 +125,10 @@ function openGraphHelper(options = {}) {
   });
 
   if (updated) {
-    if ((moment.isMoment(updated) || moment.isDate(updated)) && !isNaN(updated.valueOf())) {
+    if (
+      (moment.isMoment(updated) || moment.isDate(updated)) &&
+      !isNaN(updated.valueOf())
+    ) {
       result += og('og:updated_time', updated.toISOString());
     }
   }
@@ -133,7 +151,10 @@ function openGraphHelper(options = {}) {
   }
 
   if (options.google_plus) {
-    result += `${htmlTag('link', {rel: 'publisher', href: options.google_plus})}\n`;
+    result += `${htmlTag('link', {
+      rel: 'publisher',
+      href: options.google_plus
+    })}\n`;
   }
 
   if (options.fb_admins) {
diff --git a/lib/plugins/helper/paginator.js b/lib/plugins/helper/paginator.js
index 622251c63a..55a9e12fe0 100644
--- a/lib/plugins/helper/paginator.js
+++ b/lib/plugins/helper/paginator.js
@@ -14,9 +14,17 @@ const createPageTag = (options, ctx) => {
 
   return i => {
     if (i === current) {
-      return htmlTag('span', { class: 'page-number current' }, transform ? transform(i) : i);
+      return htmlTag(
+        'span',
+        { class: 'page-number current' },
+        transform ? transform(i) : i
+      );
     }
-    return htmlTag('a', { class: 'page-number', href: link(i) }, transform ? transform(i) : i);
+    return htmlTag(
+      'a',
+      { class: 'page-number', href: link(i) },
+      transform ? transform(i) : i
+    );
   };
 };
 
@@ -41,9 +49,12 @@ const pagenasionPartShow = (tags, options, ctx) => {
   } = options;
 
   const leftEnd = current <= endSize ? current - 1 : endSize;
-  const rightEnd = total - current <= endSize ? current + 1 : total - endSize + 1;
-  const leftMid = current - midSize <= endSize ? leftEnd + 1 : current - midSize;
-  const rightMid = current + midSize + endSize > total ? rightEnd - 1 : current + midSize;
+  const rightEnd =
+    total - current <= endSize ? current + 1 : total - endSize + 1;
+  const leftMid =
+    current - midSize <= endSize ? leftEnd + 1 : current - midSize;
+  const rightMid =
+    current + midSize + endSize > total ? rightEnd - 1 : current + midSize;
   const spaceHtml = htmlTag('span', { class: 'space' }, space);
 
   const pageTag = createPageTag(options, ctx);
@@ -87,18 +98,21 @@ const pagenasionPartShow = (tags, options, ctx) => {
 };
 
 function paginatorHelper(options = {}) {
-  options = Object.assign({
-    base: this.page.base || '',
-    current: this.page.current || 0,
-    format: `${this.config.pagination_dir}/%d/`,
-    total: this.page.total || 1,
-    end_size: 1,
-    mid_size: 2,
-    space: '…',
-    next_text: 'Next',
-    prev_text: 'Prev',
-    prev_next: true
-  }, options);
+  options = Object.assign(
+    {
+      base: this.page.base || '',
+      current: this.page.current || 0,
+      format: `${this.config.pagination_dir}/%d/`,
+      total: this.page.total || 1,
+      end_size: 1,
+      mid_size: 2,
+      space: '…',
+      next_text: 'Next',
+      prev_text: 'Prev',
+      prev_next: true
+    },
+    options
+  );
 
   const {
     current,
@@ -116,7 +130,13 @@ function paginatorHelper(options = {}) {
 
   // Display the link to the previous page
   if (prevNext && current > 1) {
-    tags.push(htmlTag('a', { class: 'extend prev', rel: 'prev', href: link(current - 1)}, prevText));
+    tags.push(
+      htmlTag(
+        'a',
+        { class: 'extend prev', rel: 'prev', href: link(current - 1) },
+        prevText
+      )
+    );
   }
 
   if (options.show_all) {
@@ -127,7 +147,13 @@ function paginatorHelper(options = {}) {
 
   // Display the link to the next page
   if (prevNext && current < total) {
-    tags.push(htmlTag('a', { class: 'extend next', rel: 'next', href: link(current + 1) }, nextText));
+    tags.push(
+      htmlTag(
+        'a',
+        { class: 'extend next', rel: 'next', href: link(current + 1) },
+        nextText
+      )
+    );
   }
 
   return tags.join('');
diff --git a/lib/plugins/helper/partial.js b/lib/plugins/helper/partial.js
index bc3994189c..0b4d4573b9 100644
--- a/lib/plugins/helper/partial.js
+++ b/lib/plugins/helper/partial.js
@@ -2,34 +2,35 @@
 
 const { dirname, join } = require('path');
 
-module.exports = ctx => function partial(name, locals, options = {}) {
-  if (typeof name !== 'string') throw new TypeError('name must be a string!');
-
-  const { cache } = options;
-  const viewDir = this.view_dir;
-  const currentView = this.filename.substring(viewDir.length);
-  const path = join(dirname(currentView), name);
-  const view = ctx.theme.getView(path) || ctx.theme.getView(name);
-  const viewLocals = { layout: false };
-
-  if (!view) {
-    throw new Error(`Partial ${name} does not exist. (in ${currentView})`);
-  }
-
-  if (options.only) {
-    Object.assign(viewLocals, locals);
-  } else {
-    Object.assign(viewLocals, this, locals);
-  }
-
-  // Partial don't need layout
-  viewLocals.layout = false;
-
-  if (cache) {
-    const cacheId = typeof cache === 'string' ? cache : view.path;
-
-    return this.fragment_cache(cacheId, () => view.renderSync(viewLocals));
-  }
-
-  return view.renderSync(viewLocals);
-};
+module.exports = ctx =>
+  function partial(name, locals, options = {}) {
+    if (typeof name !== 'string') throw new TypeError('name must be a string!');
+
+    const { cache } = options;
+    const viewDir = this.view_dir;
+    const currentView = this.filename.substring(viewDir.length);
+    const path = join(dirname(currentView), name);
+    const view = ctx.theme.getView(path) || ctx.theme.getView(name);
+    const viewLocals = { layout: false };
+
+    if (!view) {
+      throw new Error(`Partial ${name} does not exist. (in ${currentView})`);
+    }
+
+    if (options.only) {
+      Object.assign(viewLocals, locals);
+    } else {
+      Object.assign(viewLocals, this, locals);
+    }
+
+    // Partial don't need layout
+    viewLocals.layout = false;
+
+    if (cache) {
+      const cacheId = typeof cache === 'string' ? cache : view.path;
+
+      return this.fragment_cache(cacheId, () => view.renderSync(viewLocals));
+    }
+
+    return view.renderSync(viewLocals);
+  };
diff --git a/lib/plugins/helper/render.js b/lib/plugins/helper/render.js
index f71bdb2917..d7f9c5d8b0 100644
--- a/lib/plugins/helper/render.js
+++ b/lib/plugins/helper/render.js
@@ -1,8 +1,12 @@
 'use strict';
 
-module.exports = ctx => function render(text, engine, options) {
-  return ctx.render.renderSync({
-    text,
-    engine
-  }, options);
-};
+module.exports = ctx =>
+  function render(text, engine, options) {
+    return ctx.render.renderSync(
+      {
+        text,
+        engine
+      },
+      options
+    );
+  };
diff --git a/lib/plugins/helper/search_form.js b/lib/plugins/helper/search_form.js
index ea81c2c4c4..2ab6c413b5 100644
--- a/lib/plugins/helper/search_form.js
+++ b/lib/plugins/helper/search_form.js
@@ -5,7 +5,15 @@ function searchFormHelper(options = {}) {
   const className = options.class || 'search-form';
   const { text = 'Search', button } = options;
 
-  return `<form action="//google.com/search" method="get" accept-charset="UTF-8" class="${className}"><input type="search" name="q" class="${className}-input"${text ? ` placeholder="${text}"` : ''}>${button ? `<button type="submit" class="${className}-submit">${typeof button === 'string' ? button : text}</button>` : ''}<input type="hidden" name="sitesearch" value="${config.url}"></form>`;
+  return `<form action="//google.com/search" method="get" accept-charset="UTF-8" class="${className}"><input type="search" name="q" class="${className}-input"${
+    text ? ` placeholder="${text}"` : ''
+  }>${
+    button
+      ? `<button type="submit" class="${className}-submit">${
+          typeof button === 'string' ? button : text
+        }</button>`
+      : ''
+  }<input type="hidden" name="sitesearch" value="${config.url}"></form>`;
 }
 
 module.exports = searchFormHelper;
diff --git a/lib/plugins/helper/tagcloud.js b/lib/plugins/helper/tagcloud.js
index 9fd5bda421..dd18572c2a 100644
--- a/lib/plugins/helper/tagcloud.js
+++ b/lib/plugins/helper/tagcloud.js
@@ -3,7 +3,10 @@
 const Color = require('hexo-util').Color;
 
 function tagcloudHelper(tags, options) {
-  if (!options && (!tags || !Object.prototype.hasOwnProperty.call(tags, 'length'))) {
+  if (
+    !options &&
+    (!tags || !Object.prototype.hasOwnProperty.call(tags, 'length'))
+  ) {
     options = tags;
     tags = this.site.tags;
   }
@@ -57,7 +60,7 @@ function tagcloudHelper(tags, options) {
 
   tags.forEach(tag => {
     const ratio = length ? sizes.indexOf(tag.length) / length : 0;
-    const size = min + ((max - min) * ratio);
+    const size = min + (max - min) * ratio;
     let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};`;
 
     if (color) {
@@ -66,7 +69,9 @@ function tagcloudHelper(tags, options) {
     }
 
     result.push(
-      `<a href="${this.url_for(tag.path)}" style="${style}">${transform ? transform(tag.name) : tag.name}</a>`
+      `<a href="${this.url_for(tag.path)}" style="${style}">${
+        transform ? transform(tag.name) : tag.name
+      }</a>`
     );
   });
 
diff --git a/lib/plugins/helper/toc.js b/lib/plugins/helper/toc.js
index ddf4023816..81dd1f852a 100644
--- a/lib/plugins/helper/toc.js
+++ b/lib/plugins/helper/toc.js
@@ -7,14 +7,26 @@ function tocHelper(str, options = {}) {
   if (!cheerio) cheerio = require('cheerio');
 
   const $ = cheerio.load(str);
-  const headingsMaxDepth = Object.prototype.hasOwnProperty.call(options, 'max_depth') ? options.max_depth : 6;
-  const headingsSelector = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].slice(0, headingsMaxDepth).join(',');
+  const headingsMaxDepth = Object.prototype.hasOwnProperty.call(
+    options,
+    'max_depth'
+  )
+    ? options.max_depth
+    : 6;
+  const headingsSelector = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
+    .slice(0, headingsMaxDepth)
+    .join(',');
   const headings = $(headingsSelector);
 
   if (!headings.length) return '';
 
   const className = options.class || 'toc';
-  const listNumber = Object.prototype.hasOwnProperty.call(options, 'list_number') ? options.list_number : true;
+  const listNumber = Object.prototype.hasOwnProperty.call(
+    options,
+    'list_number'
+  )
+    ? options.list_number
+    : true;
   let result = `<ol class="${className}">`;
   const lastNumber = [0, 0, 0, 0, 0, 0];
   let firstLevel = 0;
@@ -23,9 +35,7 @@ function tocHelper(str, options = {}) {
   function getId(ele) {
     const id = $(ele).attr('id');
     const $parent = $(ele).parent();
-    return id ||
-    ($parent.length < 1 ? null :
-      getId($parent));
+    return id || ($parent.length < 1 ? null : getId($parent));
   }
 
   headings.each(function() {
diff --git a/lib/plugins/helper/url_for.js b/lib/plugins/helper/url_for.js
index 868dd56b3c..1810465a04 100644
--- a/lib/plugins/helper/url_for.js
+++ b/lib/plugins/helper/url_for.js
@@ -11,9 +11,12 @@ function urlForHelper(path = '/', options) {
   const { root } = config;
   const data = url.parse(path);
 
-  options = Object.assign({
-    relative: config.relative_link
-  }, options);
+  options = Object.assign(
+    {
+      relative: config.relative_link
+    },
+    options
+  );
 
   // Exit if this is an external path
   if (data.protocol) {
diff --git a/lib/plugins/processor/asset.js b/lib/plugins/processor/asset.js
index ee39ade154..1239075c93 100644
--- a/lib/plugins/processor/asset.js
+++ b/lib/plugins/processor/asset.js
@@ -10,7 +10,7 @@ module.exports = ctx => {
   function processPage(file) {
     const Page = ctx.model('Page');
     const { path } = file;
-    const doc = Page.findOne({source: path});
+    const doc = Page.findOne({ source: path });
     const { config } = ctx;
     const { timezone } = config;
 
@@ -26,10 +26,7 @@ module.exports = ctx => {
       return;
     }
 
-    return Promise.all([
-      file.stat(),
-      file.read()
-    ]).spread((stats, content) => {
+    return Promise.all([file.stat(), file.read()]).spread((stats, content) => {
       const data = yfm(content);
       const output = ctx.render.getOutput(path);
 
@@ -64,7 +61,10 @@ module.exports = ctx => {
           data.path += `.${output}`;
         }
       } else {
-        data.path = `${path.substring(0, path.length - extname(path).length)}.${output}`;
+        data.path = `${path.substring(
+          0,
+          path.length - extname(path).length
+        )}.${output}`;
       }
 
       if (!data.layout && output !== 'html' && output !== 'htm') {
@@ -73,7 +73,7 @@ module.exports = ctx => {
 
       // FIXME: Data may be inserted when reading files. Load it again to prevent
       // race condition. We have to solve this in warehouse.
-      const doc = Page.findOne({source: path});
+      const doc = Page.findOne({ source: path });
 
       if (doc) {
         return doc.replace(data);
@@ -106,14 +106,20 @@ module.exports = ctx => {
 
   return {
     pattern: new Pattern(path => {
-      if (common.isTmpFile(path) || common.isMatch(path, ctx.config.exclude)) return;
+      if (common.isTmpFile(path) || common.isMatch(path, ctx.config.exclude))
+        return;
 
-      if (common.isHiddenFile(path) && !common.isMatch(path, ctx.config.include)) {
+      if (
+        common.isHiddenFile(path) &&
+        !common.isMatch(path, ctx.config.include)
+      ) {
         return;
       }
 
       return {
-        renderable: ctx.render.isRenderable(path) && !common.isMatch(path, ctx.config.skip_render)
+        renderable:
+          ctx.render.isRenderable(path) &&
+          !common.isMatch(path, ctx.config.skip_render)
       };
     }),
 
diff --git a/lib/plugins/processor/post.js b/lib/plugins/processor/post.js
index 6518e504b6..62495d4583 100644
--- a/lib/plugins/processor/post.js
+++ b/lib/plugins/processor/post.js
@@ -24,7 +24,7 @@ module.exports = ctx => {
   function processPost(file) {
     const Post = ctx.model('Post');
     const { path } = file.params;
-    const doc = Post.findOne({source: file.path});
+    const doc = Post.findOne({ source: file.path });
     const { config } = ctx;
     const { timezone } = config;
     let categories, tags;
@@ -41,105 +41,112 @@ module.exports = ctx => {
       return;
     }
 
-    return Promise.all([
-      file.stat(),
-      file.read()
-    ]).spread((stats, content) => {
-      const data = yfm(content);
-      const info = parseFilename(config.new_post_name, path);
-      const keys = Object.keys(info);
-
-      data.source = file.path;
-      data.raw = content;
-      data.slug = info.title;
-
-      if (file.params.published) {
-        if (!Object.prototype.hasOwnProperty.call(data, 'published')) data.published = true;
-      } else {
-        data.published = false;
-      }
-
-      for (let i = 0, len = keys.length; i < len; i++) {
-        const key = keys[i];
-        if (!preservedKeys[key]) data[key] = info[key];
-      }
-
-      if (data.date) {
-        data.date = common.toDate(data.date);
-      } else if (info && info.year && (info.month || info.i_month) && (info.day || info.i_day)) {
-        data.date = new Date(
-          info.year,
-          parseInt(info.month || info.i_month, 10) - 1,
-          parseInt(info.day || info.i_day, 10)
-        );
-      }
-
-      if (data.date) {
-        if (timezone) data.date = common.timezone(data.date, timezone);
-      } else {
-        data.date = stats.birthtime;
-      }
-
-      data.updated = common.toDate(data.updated);
-
-      if (data.updated) {
-        if (timezone) data.updated = common.timezone(data.updated, timezone);
-      } else {
-        data.updated = stats.mtime;
-      }
-
-      if (data.category && !data.categories) {
-        data.categories = data.category;
-        delete data.category;
-      }
-
-      if (data.tag && !data.tags) {
-        data.tags = data.tag;
-        delete data.tag;
-      }
-
-      categories = data.categories || [];
-      tags = data.tags || [];
-
-      if (!Array.isArray(categories)) categories = [categories];
-      if (!Array.isArray(tags)) tags = [tags];
-
-      if (data.photo && !data.photos) {
-        data.photos = data.photo;
-        delete data.photo;
-      }
-
-      if (data.photos && !Array.isArray(data.photos)) {
-        data.photos = [data.photos];
-      }
-
-      if (data.link && !data.title) {
-        data.title = data.link.replace(/^https?:\/\/|\/$/g, '');
-      }
-
-      if (!data.title) {
-        data.title = data.slug;
-      }
-
-      if (data.permalink) {
-        data.slug = data.permalink;
-        delete data.permalink;
-      }
-
-      // FIXME: Data may be inserted when reading files. Load it again to prevent
-      // race condition. We have to solve this in warehouse.
-      const doc = Post.findOne({source: file.path});
-
-      if (doc) {
-        return doc.replace(data);
-      }
-
-      return Post.insert(data);
-    }).then(doc => Promise.all([
-      doc.setCategories(categories),
-      doc.setTags(tags),
-      scanAssetDir(doc)
-    ]));
+    return Promise.all([file.stat(), file.read()])
+      .spread((stats, content) => {
+        const data = yfm(content);
+        const info = parseFilename(config.new_post_name, path);
+        const keys = Object.keys(info);
+
+        data.source = file.path;
+        data.raw = content;
+        data.slug = info.title;
+
+        if (file.params.published) {
+          if (!Object.prototype.hasOwnProperty.call(data, 'published'))
+            data.published = true;
+        } else {
+          data.published = false;
+        }
+
+        for (let i = 0, len = keys.length; i < len; i++) {
+          const key = keys[i];
+          if (!preservedKeys[key]) data[key] = info[key];
+        }
+
+        if (data.date) {
+          data.date = common.toDate(data.date);
+        } else if (
+          info &&
+          info.year &&
+          (info.month || info.i_month) &&
+          (info.day || info.i_day)
+        ) {
+          data.date = new Date(
+            info.year,
+            parseInt(info.month || info.i_month, 10) - 1,
+            parseInt(info.day || info.i_day, 10)
+          );
+        }
+
+        if (data.date) {
+          if (timezone) data.date = common.timezone(data.date, timezone);
+        } else {
+          data.date = stats.birthtime;
+        }
+
+        data.updated = common.toDate(data.updated);
+
+        if (data.updated) {
+          if (timezone) data.updated = common.timezone(data.updated, timezone);
+        } else {
+          data.updated = stats.mtime;
+        }
+
+        if (data.category && !data.categories) {
+          data.categories = data.category;
+          delete data.category;
+        }
+
+        if (data.tag && !data.tags) {
+          data.tags = data.tag;
+          delete data.tag;
+        }
+
+        categories = data.categories || [];
+        tags = data.tags || [];
+
+        if (!Array.isArray(categories)) categories = [categories];
+        if (!Array.isArray(tags)) tags = [tags];
+
+        if (data.photo && !data.photos) {
+          data.photos = data.photo;
+          delete data.photo;
+        }
+
+        if (data.photos && !Array.isArray(data.photos)) {
+          data.photos = [data.photos];
+        }
+
+        if (data.link && !data.title) {
+          data.title = data.link.replace(/^https?:\/\/|\/$/g, '');
+        }
+
+        if (!data.title) {
+          data.title = data.slug;
+        }
+
+        if (data.permalink) {
+          data.slug = data.permalink;
+          delete data.permalink;
+        }
+
+        // FIXME: Data may be inserted when reading files. Load it again to prevent
+        // race condition. We have to solve this in warehouse.
+        const doc = Post.findOne({ source: file.path });
+
+        if (doc) {
+          return doc.replace(data);
+        }
+
+        return Post.insert(data);
+      })
+      .then(doc =>
+        Promise.all([
+          doc.setCategories(categories),
+          doc.setTags(tags),
+          scanAssetDir(doc)
+        ])
+      );
   }
 
   function scanAssetDir(post) {
@@ -150,25 +157,32 @@ module.exports = ctx => {
     const baseDirLength = baseDir.length;
     const PostAsset = ctx.model('PostAsset');
 
-    return fs.stat(assetDir).then(stats => {
-      if (!stats.isDirectory()) return [];
-
-      return fs.listDir(assetDir);
-    }).catch(err => {
-      if (err.cause && err.cause.code === 'ENOENT') return [];
-      throw err;
-    }).filter(item => !common.isTmpFile(item) && !common.isHiddenFile(item)).map(item => {
-      const id = join(assetDir, item).substring(baseDirLength).replace(/\\/g, '/');
-      const asset = PostAsset.findById(id);
-      if (asset) return undefined;
-
-      return PostAsset.save({
-        _id: id,
-        post: post._id,
-        slug: item,
-        modified: true
+    return fs
+      .stat(assetDir)
+      .then(stats => {
+        if (!stats.isDirectory()) return [];
+
+        return fs.listDir(assetDir);
+      })
+      .catch(err => {
+        if (err.cause && err.cause.code === 'ENOENT') return [];
+        throw err;
+      })
+      .filter(item => !common.isTmpFile(item) && !common.isHiddenFile(item))
+      .map(item => {
+        const id = join(assetDir, item)
+          .substring(baseDirLength)
+          .replace(/\\/g, '/');
+        const asset = PostAsset.findById(id);
+        if (asset) return undefined;
+
+        return PostAsset.save({
+          _id: id,
+          post: post._id,
+          slug: item,
+          modified: true
+        });
       });
-    });
   }
 
   function processAsset(file) {
@@ -186,7 +200,9 @@ module.exports = ctx => {
     }
 
     // TODO: Better post searching
-    const post = Post.toArray().find(post => file.source.startsWith(post.asset_dir));
+    const post = Post.toArray().find(post =>
+      file.source.startsWith(post.asset_dir)
+    );
 
     if (post != null) {
       return PostAsset.save({
@@ -223,7 +239,9 @@ module.exports = ctx => {
 
       if (!result || common.isHiddenFile(result.path)) return;
 
-      result.renderable = ctx.render.isRenderable(path) && !common.isMatch(path, ctx.config.skip_render);
+      result.renderable =
+        ctx.render.isRenderable(path) &&
+        !common.isMatch(path, ctx.config.skip_render);
       return result;
     }),
 
diff --git a/lib/plugins/renderer/swig.js b/lib/plugins/renderer/swig.js
index d272df7a0c..a1afca8ee7 100644
--- a/lib/plugins/renderer/swig.js
+++ b/lib/plugins/renderer/swig.js
@@ -23,13 +23,23 @@ swig.setDefaults({
 });
 
 // Hack: Override for tag of Swig
-swig.setTag('for', forTag.parse, (...args) => {
-  const compile = forTag.compile(...args).split('\n');
-
-  compile.splice(3, 0, '  if (!Array.isArray(__l) && typeof __l.toArray === "function") { __l = __l.toArray(); }');
-
-  return compile.join('\n');
-}, forTag.ends, true);
+swig.setTag(
+  'for',
+  forTag.parse,
+  (...args) => {
+    const compile = forTag.compile(...args).split('\n');
+
+    compile.splice(
+      3,
+      0,
+      '  if (!Array.isArray(__l) && typeof __l.toArray === "function") { __l = __l.toArray(); }'
+    );
+
+    return compile.join('\n');
+  },
+  forTag.ends,
+  true
+);
 
 function swigRenderer(data, locals) {
   return swig.render(data.text, {
@@ -38,8 +48,9 @@ function swigRenderer(data, locals) {
   });
 }
 
-swigRenderer.compile = (data, locals) => swig.compile(data.text, {
-  filename: data.path
-});
+swigRenderer.compile = (data, locals) =>
+  swig.compile(data.text, {
+    filename: data.path
+  });
 
 module.exports = swigRenderer;
diff --git a/lib/plugins/tag/asset_img.js b/lib/plugins/tag/asset_img.js
index 752d0deb05..a2dc5f24a3 100644
--- a/lib/plugins/tag/asset_img.js
+++ b/lib/plugins/tag/asset_img.js
@@ -17,7 +17,7 @@ module.exports = ctx => {
 
     // Find image URL
     for (let i = 0; i < len; i++) {
-      const asset = PostAsset.findOne({post: this._id, slug: args[i]});
+      const asset = PostAsset.findOne({ post: this._id, slug: args[i] });
       if (asset) {
         args[i] = url.resolve('/', asset.path);
         return img(ctx)(args);
diff --git a/lib/plugins/tag/asset_link.js b/lib/plugins/tag/asset_link.js
index 8cf335c30b..47760e7437 100644
--- a/lib/plugins/tag/asset_link.js
+++ b/lib/plugins/tag/asset_link.js
@@ -15,7 +15,7 @@ module.exports = ctx => {
     const slug = args.shift();
     if (!slug) return;
 
-    const asset = PostAsset.findOne({post: this._id, slug});
+    const asset = PostAsset.findOne({ post: this._id, slug });
     if (!asset) return;
 
     const title = args.length ? args.join(' ') : asset.slug;
diff --git a/lib/plugins/tag/asset_path.js b/lib/plugins/tag/asset_path.js
index 81babf2297..0d233278ca 100644
--- a/lib/plugins/tag/asset_path.js
+++ b/lib/plugins/tag/asset_path.js
@@ -15,7 +15,7 @@ module.exports = ctx => {
     const slug = args.shift();
     if (!slug) return;
 
-    const asset = PostAsset.findOne({post: this._id, slug});
+    const asset = PostAsset.findOne({ post: this._id, slug });
     if (!asset) return;
 
     return url.resolve(ctx.config.root, asset.path);
diff --git a/lib/plugins/tag/blockquote.js b/lib/plugins/tag/blockquote.js
index 847727da92..8a41de03da 100644
--- a/lib/plugins/tag/blockquote.js
+++ b/lib/plugins/tag/blockquote.js
@@ -49,21 +49,22 @@ const parseFooter = (args, ctx) => {
 };
 
 /**
-* Blockquote tag
-*
-* Syntax:
-*   {% blockquote [author[, source]] [link] [source_link_title] %}
-*   Quote string
-*   {% endblockquote %}
-*/
+ * Blockquote tag
+ *
+ * Syntax:
+ *   {% blockquote [author[, source]] [link] [source_link_title] %}
+ *   Quote string
+ *   {% endblockquote %}
+ */
 
-module.exports = ctx => function blockquoteTag(args, content) {
-  const footer = parseFooter(args, ctx);
+module.exports = ctx =>
+  function blockquoteTag(args, content) {
+    const footer = parseFooter(args, ctx);
 
-  let result = '<blockquote>';
-  result += ctx.render.renderSync({text: content, engine: 'markdown'});
-  if (footer) result += `<footer>${footer}</footer>`;
-  result += '</blockquote>';
+    let result = '<blockquote>';
+    result += ctx.render.renderSync({ text: content, engine: 'markdown' });
+    if (footer) result += `<footer>${footer}</footer>`;
+    result += '</blockquote>';
 
-  return result;
-};
+    return result;
+  };
diff --git a/lib/plugins/tag/code.js b/lib/plugins/tag/code.js
index e7cfd8a614..c4b5690391 100644
--- a/lib/plugins/tag/code.js
+++ b/lib/plugins/tag/code.js
@@ -24,7 +24,6 @@ const rMark = /\s*mark:([0-9,-]+)/i;
  */
 
 function getHighlightOptions(config, arg) {
-
   let lang = '';
   if (rLang.test(arg)) {
     arg = arg.replace(rLang, (match, _lang) => {
@@ -56,7 +55,8 @@ function getHighlightOptions(config, arg) {
         if (/-/.test(cur)) {
           let a = Number(cur.substr(0, cur.indexOf('-')));
           let b = Number(cur.substr(cur.indexOf('-') + 1));
-          if (b < a) { // switch a & b
+          if (b < a) {
+            // switch a & b
             const temp = a;
             a = b;
             b = temp;
@@ -80,10 +80,14 @@ function getHighlightOptions(config, arg) {
   let caption = '';
   if (rCaptionUrlTitle.test(arg)) {
     const match = arg.match(rCaptionUrlTitle);
-    caption = `<span>${match[1]}</span><a href="${match[2]}${match[3]}">${match[4]}</a>`;
+    caption = `<span>${match[1]}</span><a href="${match[2]}${match[3]}">${
+      match[4]
+    }</a>`;
   } else if (rCaptionUrl.test(arg)) {
     const match = arg.match(rCaptionUrl);
-    caption = `<span>${match[1]}</span><a href="${match[2]}${match[3]}">link</a>`;
+    caption = `<span>${match[1]}</span><a href="${match[2]}${
+      match[3]
+    }">link</a>`;
   } else if (rCaption.test(arg)) {
     const match = arg.match(rCaption);
     caption = `<span>${match[1]}</span>`;
@@ -101,29 +105,29 @@ function getHighlightOptions(config, arg) {
   };
 }
 
-module.exports = ctx => function codeTag(args, content) {
-  let arg = args.join(' ');
-  const config = ctx.config.highlight || {};
-  let enable = config.enable;
+module.exports = ctx =>
+  function codeTag(args, content) {
+    let arg = args.join(' ');
+    const config = ctx.config.highlight || {};
+    let enable = config.enable;
 
-  if (rHighlight.test(arg)) {
-    arg = arg.replace(rHighlight, (match, _enable) => {
-      enable = _enable === 'true';
-      return '';
-    });
-  }
+    if (rHighlight.test(arg)) {
+      arg = arg.replace(rHighlight, (match, _enable) => {
+        enable = _enable === 'true';
+        return '';
+      });
+    }
 
-  if (!enable) {
-    content = escapeHTML(content);
-    return `<pre><code>${content}</code></pre>`;
-  }
+    if (!enable) {
+      content = escapeHTML(content);
+      return `<pre><code>${content}</code></pre>`;
+    }
 
-  content = stripIndent(content);
+    content = stripIndent(content);
 
-  content = highlight(content, getHighlightOptions(config, arg));
+    content = highlight(content, getHighlightOptions(config, arg));
 
-  content = content.replace(/{/g, '{')
-    .replace(/}/g, '}');
+    content = content.replace(/{/g, '{').replace(/}/g, '}');
 
-  return content;
-};
+    return content;
+  };
diff --git a/lib/plugins/tag/gist.js b/lib/plugins/tag/gist.js
index f4a11fb2d1..b79cd3a1e2 100644
--- a/lib/plugins/tag/gist.js
+++ b/lib/plugins/tag/gist.js
@@ -1,11 +1,11 @@
 'use strict';
 
 /**
-* Gist tag
-*
-* Syntax:
-*   {% gist gist_id [filename] %}
-*/
+ * Gist tag
+ *
+ * Syntax:
+ *   {% gist gist_id [filename] %}
+ */
 
 function gistTag(args, content) {
   const id = args.shift();
diff --git a/lib/plugins/tag/iframe.js b/lib/plugins/tag/iframe.js
index 03fed9a4a6..e05f841c83 100644
--- a/lib/plugins/tag/iframe.js
+++ b/lib/plugins/tag/iframe.js
@@ -1,11 +1,11 @@
 'use strict';
 
 /**
-* Iframe tag
-*
-* Syntax:
-*   {% iframe url [width] [height] %}
-*/
+ * Iframe tag
+ *
+ * Syntax:
+ *   {% iframe url [width] [height] %}
+ */
 
 function iframeTag(args, content) {
   const url = args[0];
diff --git a/lib/plugins/tag/img.js b/lib/plugins/tag/img.js
index 99aeccf7b9..e68caf6791 100644
--- a/lib/plugins/tag/img.js
+++ b/lib/plugins/tag/img.js
@@ -7,11 +7,11 @@ const rUrl = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:ww
 const rMeta = /["']?([^"']+)?["']?\s*["']?([^"']+)?["']?/;
 
 /**
-* Image tag
-*
-* Syntax:
-*   {% img [class names] /path/to/image [width] [height] [title text [alt text]] %}
-*/
+ * Image tag
+ *
+ * Syntax:
+ *   {% img [class names] /path/to/image [width] [height] [title text [alt text]] %}
+ */
 module.exports = ctx => {
   const { config } = ctx;
 
@@ -33,7 +33,7 @@ module.exports = ctx => {
 
   return function imgTag(args, content) {
     const classes = [];
-    let src;
+    let src, width, height, title, alt;
 
     // Find image URL and class name
     while (args.length > 0) {
@@ -46,8 +46,6 @@ module.exports = ctx => {
       }
     }
 
-    let width, height, title, alt;
-
     // Find image width and height
     if (args && args.length) {
       if (!/\D+/.test(args[0])) {
diff --git a/lib/plugins/tag/include_code.js b/lib/plugins/tag/include_code.js
index f249c14797..f776e1aaa1 100644
--- a/lib/plugins/tag/include_code.js
+++ b/lib/plugins/tag/include_code.js
@@ -11,74 +11,81 @@ const rFrom = /\s*from:(\d+)/i;
 const rTo = /\s*to:(\d+)/i;
 
 /**
-* Include code tag
-*
-* Syntax:
-*   {% include_code [title] [lang:language] path/to/file %}
-*/
-
-module.exports = ctx => function includeCodeTag(args) {
-  const config = ctx.config.highlight || {};
-  let codeDir = ctx.config.code_dir;
-  let arg = args.join(' ');
-
-  // Add trailing slash to codeDir
-  if (codeDir[codeDir.length - 1] !== '/') codeDir += '/';
-
-  let lang = '';
-  arg = arg.replace(rLang, (match, _lang) => {
-    lang = _lang;
-    return '';
-  });
-  let from = 0;
-  arg = arg.replace(rFrom, (match, _from) => {
-    from = _from - 1;
-    return '';
-  });
-  let to = Number.MAX_VALUE;
-  arg = arg.replace(rTo, (match, _to) => {
-    to = _to;
-    return '';
-  });
-
-  const match = arg.match(rCaptionTitleFile);
-
-  // Exit if path is not defined
-  if (!match) return;
-
-  const path = match[2];
-
-  // If the title is not defined, use file name instead
-  const title = match[1] || basename(path);
-
-  // If the language is not defined, use file extension instead
-  lang = lang || extname(path).substring(1);
-
-  const src = join(ctx.source_dir, codeDir, path);
-
-  const caption = `<span>${title}</span><a href="${ctx.config.root}${codeDir}${path}">view raw</a>`;
-
-  const options = {
-    lang,
-    caption,
-    gutter: config.line_number,
-    hljs: config.hljs,
-    tab: config.tab_replace
+ * Include code tag
+ *
+ * Syntax:
+ *   {% include_code [title] [lang:language] path/to/file %}
+ */
+
+module.exports = ctx =>
+  function includeCodeTag(args) {
+    const config = ctx.config.highlight || {};
+    let codeDir = ctx.config.code_dir;
+    let arg = args.join(' ');
+
+    // Add trailing slash to codeDir
+    if (codeDir[codeDir.length - 1] !== '/') codeDir += '/';
+
+    let lang = '';
+    arg = arg.replace(rLang, (match, _lang) => {
+      lang = _lang;
+      return '';
+    });
+    let from = 0;
+    arg = arg.replace(rFrom, (match, _from) => {
+      from = _from - 1;
+      return '';
+    });
+    let to = Number.MAX_VALUE;
+    arg = arg.replace(rTo, (match, _to) => {
+      to = _to;
+      return '';
+    });
+
+    const match = arg.match(rCaptionTitleFile);
+
+    // Exit if path is not defined
+    if (!match) return;
+
+    const path = match[2];
+
+    // If the title is not defined, use file name instead
+    const title = match[1] || basename(path);
+
+    // If the language is not defined, use file extension instead
+    lang = lang || extname(path).substring(1);
+
+    const src = join(ctx.source_dir, codeDir, path);
+
+    const caption = `<span>${title}</span><a href="${ctx.config.root}${codeDir}${path}">view raw</a>`;
+
+    const options = {
+      lang,
+      caption,
+      gutter: config.line_number,
+      hljs: config.hljs,
+      tab: config.tab_replace
+    };
+
+    return fs
+      .exists(src)
+      .then(exist => {
+        if (exist) return fs.readFile(src);
+      })
+      .then(code => {
+        if (!code) return;
+
+        code = stripIndent(code);
+        const lines = code.split('\n');
+        code = lines
+          .slice(from, to)
+          .join('\n')
+          .trim();
+
+        if (!config.enable) {
+          return `<pre><code>${code}</code></pre>`;
+        }
+
+        return highlight(code, options);
+      });
   };
-
-  return fs.exists(src).then(exist => {
-    if (exist) return fs.readFile(src);
-  }).then(code => {
-    if (!code) return;
-
-    code = stripIndent(code);
-    const lines = code.split('\n');
-    code = lines.slice(from, to).join('\n').trim();
-
-    if (!config.enable) {
-      return `<pre><code>${code}</code></pre>`;
-    }
-
-    return highlight(code, options);
-  });
-};
diff --git a/lib/plugins/tag/index.js b/lib/plugins/tag/index.js
index 57e73aca15..3c8f81686f 100644
--- a/lib/plugins/tag/index.js
+++ b/lib/plugins/tag/index.js
@@ -24,8 +24,8 @@ module.exports = ctx => {
 
   const includeCode = require('./include_code')(ctx);
 
-  tag.register('include_code', includeCode, {async: true});
-  tag.register('include-code', includeCode, {async: true});
+  tag.register('include_code', includeCode, { async: true });
+  tag.register('include-code', includeCode, { async: true });
 
   tag.register('jsfiddle', require('./jsfiddle'));
 
diff --git a/lib/plugins/tag/jsfiddle.js b/lib/plugins/tag/jsfiddle.js
index 57fde79c93..e3afe4557b 100644
--- a/lib/plugins/tag/jsfiddle.js
+++ b/lib/plugins/tag/jsfiddle.js
@@ -1,15 +1,16 @@
 'use strict';
 
 /**
-* jsFiddle tag
-*
-* Syntax:
-*   {% jsfiddle shorttag [tabs] [skin] [height] [width] %}
-*/
+ * jsFiddle tag
+ *
+ * Syntax:
+ *   {% jsfiddle shorttag [tabs] [skin] [height] [width] %}
+ */
 
 function jsfiddleTag(args, content) {
   const id = args[0];
-  const tabs = args[1] && args[1] !== 'default' ? args[1] : 'js,resources,html,css,result';
+  const tabs =
+    args[1] && args[1] !== 'default' ? args[1] : 'js,resources,html,css,result';
   const skin = args[2] && args[2] !== 'default' ? args[2] : 'light';
   const width = args[3] && args[3] !== 'default' ? args[3] : '100%';
   const height = args[4] && args[4] !== 'default' ? args[4] : '300';
diff --git a/lib/plugins/tag/link.js b/lib/plugins/tag/link.js
index 744f874f88..ed3c30e62e 100644
--- a/lib/plugins/tag/link.js
+++ b/lib/plugins/tag/link.js
@@ -5,11 +5,11 @@ const { htmlTag } = require('hexo-util');
 const rUrl = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\w]*))?)/;
 
 /**
-* Link tag
-*
-* Syntax:
-*   {% link text url [external] [title] %}
-*/
+ * Link tag
+ *
+ * Syntax:
+ *   {% link text url [external] [title] %}
+ */
 
 function linkTag(args, content) {
   let url = '';
diff --git a/lib/plugins/tag/post_link.js b/lib/plugins/tag/post_link.js
index 87cf248ceb..bc752d74df 100644
--- a/lib/plugins/tag/post_link.js
+++ b/lib/plugins/tag/post_link.js
@@ -13,7 +13,7 @@ module.exports = ctx => {
     const slug = args.shift();
     if (!slug) return;
 
-    const post = Post.findOne({slug});
+    const post = Post.findOne({ slug });
     if (!post) return;
 
     const title = args.length ? args.join(' ') : post.title;
diff --git a/lib/plugins/tag/post_path.js b/lib/plugins/tag/post_path.js
index defe0b265f..4de33683c1 100644
--- a/lib/plugins/tag/post_path.js
+++ b/lib/plugins/tag/post_path.js
@@ -13,7 +13,7 @@ module.exports = ctx => {
     const slug = args.shift();
     if (!slug) return;
 
-    const post = Post.findOne({slug});
+    const post = Post.findOne({ slug });
     if (!post) return;
 
     return ctx.config.root + post.path;
diff --git a/lib/plugins/tag/pullquote.js b/lib/plugins/tag/pullquote.js
index 8a2f945d4a..df7fdbd3d9 100644
--- a/lib/plugins/tag/pullquote.js
+++ b/lib/plugins/tag/pullquote.js
@@ -1,17 +1,18 @@
 'use strict';
 
 /**
-* Pullquote tag
-*
-* Syntax:
-*   {% pullquote [class] %}
-*   Quote string
-*   {% endpullquote %}
-*/
-module.exports = ctx => function pullquoteTag(args, content) {
-  args.unshift('pullquote');
+ * Pullquote tag
+ *
+ * Syntax:
+ *   {% pullquote [class] %}
+ *   Quote string
+ *   {% endpullquote %}
+ */
+module.exports = ctx =>
+  function pullquoteTag(args, content) {
+    args.unshift('pullquote');
 
-  const result = ctx.render.renderSync({text: content, engine: 'markdown'});
+    const result = ctx.render.renderSync({ text: content, engine: 'markdown' });
 
-  return `<blockquote class="${args.join(' ')}">${result}</blockquote>`;
-};
+    return `<blockquote class="${args.join(' ')}">${result}</blockquote>`;
+  };
diff --git a/lib/plugins/tag/vimeo.js b/lib/plugins/tag/vimeo.js
index 11f6058e57..c395e36360 100644
--- a/lib/plugins/tag/vimeo.js
+++ b/lib/plugins/tag/vimeo.js
@@ -1,11 +1,11 @@
 'use strict';
 
 /**
-* Vimeo tag
-*
-* Syntax:
-*   {% vimeo video_id %}
-*/
+ * Vimeo tag
+ *
+ * Syntax:
+ *   {% vimeo video_id %}
+ */
 
 function vimeoTag(args, content) {
   const id = args[0];
diff --git a/lib/plugins/tag/youtube.js b/lib/plugins/tag/youtube.js
index 19ceed8554..e83c2d3380 100644
--- a/lib/plugins/tag/youtube.js
+++ b/lib/plugins/tag/youtube.js
@@ -1,11 +1,11 @@
 'use strict';
 
 /**
-* Youtube tag
-*
-* Syntax:
-*   {% youtube video_id %}
-*/
+ * Youtube tag
+ *
+ * Syntax:
+ *   {% youtube video_id %}
+ */
 
 function youtubeTag(args, content) {
   const id = args[0];
diff --git a/lib/theme/index.js b/lib/theme/index.js
index 79a1861fca..cede1939c0 100644
--- a/lib/theme/index.js
+++ b/lib/theme/index.js
@@ -30,12 +30,15 @@ function Theme(ctx) {
   languages.push('default');
 
   this.i18n = new I18n({
-    languages: _(languages).compact().uniq().value()
+    languages: _(languages)
+      .compact()
+      .uniq()
+      .value()
   });
 
-  const _View = this.View = function(path, data) {
+  const _View = (this.View = function(path, data) {
     Reflect.apply(View, this, [path, data]);
-  };
+  });
 
   util.inherits(_View, View);
 
@@ -66,7 +69,7 @@ Theme.prototype.getView = function(path) {
 Theme.prototype.setView = function(path, data) {
   const ext = extname(path);
   const name = path.substring(0, path.length - ext.length);
-  const views = this.views[name] = this.views[name] || {};
+  const views = (this.views[name] = this.views[name] || {});
 
   views[ext] = new this.View(path, data);
 };
diff --git a/lib/theme/processors/config.js b/lib/theme/processors/config.js
index 53ce70ff09..83466fb119 100644
--- a/lib/theme/processors/config.js
+++ b/lib/theme/processors/config.js
@@ -8,13 +8,16 @@ exports.process = function(file) {
     return;
   }
 
-  return file.render().then(result => {
-    file.box.config = result;
-    this.log.debug('Theme config loaded.');
-  }).catch(err => {
-    this.log.error('Theme config load failed.');
-    throw err;
-  });
+  return file
+    .render()
+    .then(result => {
+      file.box.config = result;
+      this.log.debug('Theme config loaded.');
+    })
+    .catch(err => {
+      this.log.error('Theme config load failed.');
+      throw err;
+    });
 };
 
 exports.pattern = new Pattern(/^_config\.\w+$/);
diff --git a/lib/theme/processors/source.js b/lib/theme/processors/source.js
index 826b6a109e..b25a712835 100644
--- a/lib/theme/processors/source.js
+++ b/lib/theme/processors/source.js
@@ -28,7 +28,12 @@ exports.pattern = new Pattern(path => {
   if (!path.startsWith('source/')) return false;
 
   path = path.substring(7);
-  if (common.isHiddenFile(path) || common.isTmpFile(path) || path.includes('node_modules')) return false;
-
-  return {path};
+  if (
+    common.isHiddenFile(path) ||
+    common.isTmpFile(path) ||
+    path.includes('node_modules')
+  )
+    return false;
+
+  return { path };
 });
diff --git a/lib/theme/view.js b/lib/theme/view.js
index 9eb720b695..9f4190548f 100644
--- a/lib/theme/view.js
+++ b/lib/theme/view.js
@@ -26,19 +26,21 @@ View.prototype.render = function(options, callback) {
   const { layout = options.layout } = data;
   const locals = this._buildLocals(options);
 
-  return this._compiled(this._bindHelpers(locals)).then(result => {
-    if (result == null || !layout) return result;
+  return this._compiled(this._bindHelpers(locals))
+    .then(result => {
+      if (result == null || !layout) return result;
 
-    const layoutView = this._resolveLayout(layout);
-    if (!layoutView) return result;
+      const layoutView = this._resolveLayout(layout);
+      if (!layoutView) return result;
 
-    const layoutLocals = Object.assign({}, locals, {
-      body: result,
-      layout: false
-    });
+      const layoutLocals = Object.assign({}, locals, {
+        body: result,
+        layout: false
+      });
 
-    return layoutView.render(layoutLocals, callback);
-  }).asCallback(callback);
+      return layoutView.render(layoutLocals, callback);
+    })
+    .asCallback(callback);
 };
 
 View.prototype.renderSync = function(options = {}) {
@@ -120,8 +122,10 @@ View.prototype._precompile = function() {
       return ctx.execFilterSync(...buildFilterArguments(result));
     };
 
-    this._compiled = locals => Promise.resolve(compiled(locals))
-      .then(result => ctx.execFilter(...buildFilterArguments(result)));
+    this._compiled = locals =>
+      Promise.resolve(compiled(locals)).then(result =>
+        ctx.execFilter(...buildFilterArguments(result))
+      );
   } else {
     this._compiledSync = locals => render.renderSync(data, locals);
 
diff --git a/test/fixtures/post_render.js b/test/fixtures/post_render.js
index 829c64b48c..2f75ea660c 100644
--- a/test/fixtures/post_render.js
+++ b/test/fixtures/post_render.js
@@ -2,10 +2,7 @@
 
 const util = require('hexo-util');
 
-const code = [
-  'if tired && night:',
-  '  sleep()'
-].join('\n');
+const code = ['if tired && night:', '  sleep()'].join('\n');
 
 const content = [
   '# Title',
@@ -28,7 +25,7 @@ exports.content = content;
 
 exports.expected = [
   '<h1 id="Title"><a href="#Title" class="headerlink" title="Title"></a>Title</h1>',
-  util.highlight(code, {lang: 'python'}),
+  util.highlight(code, { lang: 'python' }),
   '\n\n<p>some content</p>\n',
   '<h2 id="Another-title"><a href="#Another-title" class="headerlink" title="Another title"></a>Another title</h2>',
   '<blockquote>',
@@ -40,7 +37,7 @@ exports.expected = [
 
 exports.expected_disable_nunjucks = [
   '<h1 id="Title"><a href="#Title" class="headerlink" title="Title"></a>Title</h1>',
-  util.highlight(code, {lang: 'python'}),
+  util.highlight(code, { lang: 'python' }),
   '\n\n<p>some content</p>\n',
   '<h2 id="Another-title"><a href="#Another-title" class="headerlink" title="Another title"></a>Another title</h2>',
   '<p>{% blockquote %}<br>',
diff --git a/test/scripts/box/box.js b/test/scripts/box/box.js
index 025c05bce3..4956d33738 100644
--- a/test/scripts/box/box.js
+++ b/test/scripts/box/box.js
@@ -13,7 +13,7 @@ describe('Box', () => {
   const Box = require('../../../lib/box');
 
   function newBox(path, config) {
-    const hexo = new Hexo(baseDir, {silent: true});
+    const hexo = new Hexo(baseDir, { silent: true });
     hexo.config = Object.assign(hexo.config, config);
     const base = path ? pathFn.join(baseDir, path) : baseDir;
     return new Box(hexo, base);
@@ -89,20 +89,23 @@ describe('Box', () => {
     return Promise.all([
       fs.writeFile(pathFn.join(box.base, 'a.txt'), 'a'),
       fs.writeFile(pathFn.join(box.base, 'b', 'c.js'), 'c')
-    ]).then(() => box.process()).then(() => {
-      const keys = Object.keys(data);
-      let key, item;
-
-      for (let i = 0, len = keys.length; i < len; i++) {
-        key = keys[i];
-        item = data[key];
-
-        item.path.should.eql(key);
-        item.source.should.eql(pathFn.join(box.base, key));
-        item.type.should.eql('create');
-        item.params.should.eql({});
-      }
-    }).finally(() => fs.rmdir(box.base));
+    ])
+      .then(() => box.process())
+      .then(() => {
+        const keys = Object.keys(data);
+        let key, item;
+
+        for (let i = 0, len = keys.length; i < len; i++) {
+          key = keys[i];
+          item = data[key];
+
+          item.path.should.eql(key);
+          item.source.should.eql(pathFn.join(box.base, key));
+          item.type.should.eql('create');
+          item.params.should.eql({});
+        }
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - do nothing if target does not exist', () => {
@@ -119,11 +122,15 @@ describe('Box', () => {
     const processor = sinon.spy();
     box.addProcessor(processor);
 
-    return fs.writeFile(path, 'a').then(() => box.process()).then(() => {
-      const file = processor.args[0][0];
-      file.type.should.eql('create');
-      file.path.should.eql(name);
-    }).finally(() => fs.rmdir(box.base));
+    return fs
+      .writeFile(path, 'a')
+      .then(() => box.process())
+      .then(() => {
+        const file = processor.args[0][0];
+        file.type.should.eql('create');
+        file.path.should.eql(name);
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - mtime changed', () => {
@@ -141,11 +148,14 @@ describe('Box', () => {
         _id: cacheId,
         modified: 0
       })
-    ]).then(() => box.process()).then(() => {
-      const file = processor.args[0][0];
-      file.type.should.eql('update');
-      file.path.should.eql(name);
-    }).finally(() => fs.rmdir(box.base));
+    ])
+      .then(() => box.process())
+      .then(() => {
+        const file = processor.args[0][0];
+        file.type.should.eql('update');
+        file.path.should.eql(name);
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - hash changed', () => {
@@ -157,14 +167,22 @@ describe('Box', () => {
     const processor = sinon.spy();
     box.addProcessor(processor);
 
-    return fs.writeFile(path, 'a').then(() => fs.stat(path)).then(stats => box.Cache.insert({
-      _id: cacheId,
-      modified: stats.mtime
-    })).then(() => box.process()).then(() => {
-      const file = processor.args[0][0];
-      file.type.should.eql('update');
-      file.path.should.eql(name);
-    }).finally(() => fs.rmdir(box.base));
+    return fs
+      .writeFile(path, 'a')
+      .then(() => fs.stat(path))
+      .then(stats =>
+        box.Cache.insert({
+          _id: cacheId,
+          modified: stats.mtime
+        })
+      )
+      .then(() => box.process())
+      .then(() => {
+        const file = processor.args[0][0];
+        file.type.should.eql('update');
+        file.path.should.eql(name);
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - skip', () => {
@@ -176,15 +194,23 @@ describe('Box', () => {
     const processor = sinon.spy();
     box.addProcessor(processor);
 
-    return fs.writeFile(path, 'a').then(() => fs.stat(path)).then(stats => box.Cache.insert({
-      _id: cacheId,
-      modified: stats.mtime,
-      hash: util.hash('a').toString('hex')
-    })).then(() => box.process()).then(() => {
-      const file = processor.args[0][0];
-      file.type.should.eql('skip');
-      file.path.should.eql(name);
-    }).finally(() => fs.rmdir(box.base));
+    return fs
+      .writeFile(path, 'a')
+      .then(() => fs.stat(path))
+      .then(stats =>
+        box.Cache.insert({
+          _id: cacheId,
+          modified: stats.mtime,
+          hash: util.hash('a').toString('hex')
+        })
+      )
+      .then(() => box.process())
+      .then(() => {
+        const file = processor.args[0][0];
+        file.type.should.eql('skip');
+        file.path.should.eql(name);
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - delete', () => {
@@ -202,9 +228,12 @@ describe('Box', () => {
       box.Cache.insert({
         _id: cacheId
       })
-    ]).then(() => box.process()).then(() => {
-      processor.calledOnce.should.be.true;
-    }).finally(() => fs.rmdir(box.base));
+    ])
+      .then(() => box.process())
+      .then(() => {
+        processor.calledOnce.should.be.true;
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - params', () => {
@@ -217,13 +246,17 @@ describe('Box', () => {
 
     box.addProcessor('posts/:id', processor);
 
-    return fs.writeFile(path, 'a').then(() => box.process()).then(() => {
-      processor.calledOnce.should.be.true;
-    }).finally(() => fs.rmdir(box.base));
+    return fs
+      .writeFile(path, 'a')
+      .then(() => box.process())
+      .then(() => {
+        processor.calledOnce.should.be.true;
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - skip files if they match a glob epression in ignore', () => {
-    const box = newBox('test', {ignore: '**/ignore_me'});
+    const box = newBox('test', { ignore: '**/ignore_me' });
     const data = {};
 
     box.addProcessor(file => {
@@ -233,16 +266,21 @@ describe('Box', () => {
     return Promise.all([
       fs.writeFile(pathFn.join(box.base, 'foo.txt'), 'foo'),
       fs.writeFile(pathFn.join(box.base, 'ignore_me', 'bar.txt'), 'ignore_me')
-    ]).then(() => box.process()).then(() => {
-      const keys = Object.keys(data);
+    ])
+      .then(() => box.process())
+      .then(() => {
+        const keys = Object.keys(data);
 
-      keys.length.should.eql(1);
-      keys[0].should.eql('foo.txt');
-    }).finally(() => fs.rmdir(box.base));
+        keys.length.should.eql(1);
+        keys[0].should.eql('foo.txt');
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('process() - skip files if they match any of the glob expressions in ignore', () => {
-    const box = newBox('test', {ignore: ['**/ignore_me', '**/ignore_me_too']});
+    const box = newBox('test', {
+      ignore: ['**/ignore_me', '**/ignore_me_too']
+    });
     const data = {};
 
     box.addProcessor(file => {
@@ -252,12 +290,15 @@ describe('Box', () => {
     return Promise.all([
       fs.writeFile(pathFn.join(box.base, 'foo.txt'), 'foo'),
       fs.writeFile(pathFn.join(box.base, 'ignore_me', 'bar.txt'), 'ignore_me')
-    ]).then(() => box.process()).then(() => {
-      const keys = Object.keys(data);
+    ])
+      .then(() => box.process())
+      .then(() => {
+        const keys = Object.keys(data);
 
-      keys.length.should.eql(1);
-      keys[0].should.eql('foo.txt');
-    }).finally(() => fs.rmdir(box.base));
+        keys.length.should.eql(1);
+        keys[0].should.eql('foo.txt');
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 
   it('watch() - create', () => {
@@ -271,14 +312,16 @@ describe('Box', () => {
     return Promise.all([fs.writeFile(src, 'a')])
       .then(() => box.watch())
       .then(() => box.isWatching().should.be.true)
-      .delay(500).then(() => {
+      .delay(500)
+      .then(() => {
         const file = processor.args[0][0];
 
         file.source.should.eql(src);
         file.path.should.eql(path);
         file.type.should.eql('create');
         file.params.should.eql({});
-      }).finally(() => {
+      })
+      .finally(() => {
         box.unwatch();
         return fs.rmdir(box.base);
       });
@@ -294,20 +337,22 @@ describe('Box', () => {
 
     box.addProcessor(processor);
 
-    return Promise.all([
-      fs.writeFile(src, 'a'),
-      Cache.insert({_id: cacheId})
-    ]).then(() => box.watch()).then(() => fs.appendFile(src, 'b')).delay(500).then(() => {
-      const file = processor.lastCall.args[0];
-
-      file.source.should.eql(src);
-      file.path.should.eql(path);
-      file.type.should.eql('update');
-      file.params.should.eql({});
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
+    return Promise.all([fs.writeFile(src, 'a'), Cache.insert({ _id: cacheId })])
+      .then(() => box.watch())
+      .then(() => fs.appendFile(src, 'b'))
+      .delay(500)
+      .then(() => {
+        const file = processor.lastCall.args[0];
+
+        file.source.should.eql(src);
+        file.path.should.eql(path);
+        file.type.should.eql('update');
+        file.params.should.eql({});
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
+      });
   });
 
   it('watch() - delete', () => {
@@ -320,20 +365,22 @@ describe('Box', () => {
 
     box.addProcessor(processor);
 
-    return Promise.all([
-      fs.writeFile(src, 'a'),
-      Cache.insert({_id: cacheId})
-    ]).then(() => box.watch()).then(() => fs.unlink(src)).delay(500).then(() => {
-      const file = processor.lastCall.args[0];
+    return Promise.all([fs.writeFile(src, 'a'), Cache.insert({ _id: cacheId })])
+      .then(() => box.watch())
+      .then(() => fs.unlink(src))
+      .delay(500)
+      .then(() => {
+        const file = processor.lastCall.args[0];
 
-      file.source.should.eql(src);
-      file.path.should.eql(path);
-      file.type.should.eql('delete');
-      file.params.should.eql({});
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
+        file.source.should.eql(src);
+        file.path.should.eql(path);
+        file.type.should.eql('delete');
+        file.params.should.eql({});
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
+      });
   });
 
   it('watch() - rename file', () => {
@@ -348,31 +395,36 @@ describe('Box', () => {
 
     box.addProcessor(processor);
 
-    return Promise.all([
-      fs.writeFile(src, 'a'),
-      Cache.insert({_id: cacheId})
-    ]).then(() => box.watch()).then(() => fs.rename(src, newSrc)).delay(500).then(() => {
-      const lastTwoCalls = processor.args.slice(processor.args.length - 2, processor.args.length);
-
-      lastTwoCalls.forEach(args => {
-        const file = args[0];
-
-        switch (file.type) {
-          case 'create':
-            file.source.should.eql(newSrc);
-            file.path.should.eql(newPath);
-            break;
-
-          case 'delete':
-            file.source.should.eql(src);
-            file.path.should.eql(path);
-            break;
-        }
+    return Promise.all([fs.writeFile(src, 'a'), Cache.insert({ _id: cacheId })])
+      .then(() => box.watch())
+      .then(() => fs.rename(src, newSrc))
+      .delay(500)
+      .then(() => {
+        const lastTwoCalls = processor.args.slice(
+          processor.args.length - 2,
+          processor.args.length
+        );
+
+        lastTwoCalls.forEach(args => {
+          const file = args[0];
+
+          switch (file.type) {
+            case 'create':
+              file.source.should.eql(newSrc);
+              file.path.should.eql(newPath);
+              break;
+
+            case 'delete':
+              file.source.should.eql(src);
+              file.path.should.eql(path);
+              break;
+          }
+        });
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
       });
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
   });
 
   it('watch() - rename folder', () => {
@@ -387,47 +439,60 @@ describe('Box', () => {
 
     box.addProcessor(processor);
 
-    return Promise.all([
-      fs.writeFile(src, 'a'),
-      Cache.insert({_id: cacheId})
-    ]).then(() => box.watch()).then(() => fs.rename(pathFn.join(box.base, 'a'), pathFn.join(box.base, 'b'))).delay(500).then(() => {
-      const lastTwoCalls = processor.args.slice(processor.args.length - 2, processor.args.length);
-
-      lastTwoCalls.forEach(args => {
-        const file = args[0];
-
-        switch (file.type) {
-          case 'create':
-            file.source.should.eql(newSrc);
-            file.path.should.eql(newPath);
-            break;
-
-          case 'delete':
-            file.source.should.eql(src);
-            file.path.should.eql(path);
-            break;
-        }
+    return Promise.all([fs.writeFile(src, 'a'), Cache.insert({ _id: cacheId })])
+      .then(() => box.watch())
+      .then(() =>
+        fs.rename(pathFn.join(box.base, 'a'), pathFn.join(box.base, 'b'))
+      )
+      .delay(500)
+      .then(() => {
+        const lastTwoCalls = processor.args.slice(
+          processor.args.length - 2,
+          processor.args.length
+        );
+
+        lastTwoCalls.forEach(args => {
+          const file = args[0];
+
+          switch (file.type) {
+            case 'create':
+              file.source.should.eql(newSrc);
+              file.path.should.eql(newPath);
+              break;
+
+            case 'delete':
+              file.source.should.eql(src);
+              file.path.should.eql(path);
+              break;
+          }
+        });
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
       });
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
   });
 
   it('watch() - watcher has started', () => {
     const box = newBox();
 
-    return box.watch().then(() => {
-      const errorCallback = sinon.spy(err => {
-        err.should.have.property('message', 'Watcher has already started.');
-      });
-
-      return box.watch().catch(errorCallback).then(() => {
-        errorCallback.calledOnce.should.be.true;
+    return box
+      .watch()
+      .then(() => {
+        const errorCallback = sinon.spy(err => {
+          err.should.have.property('message', 'Watcher has already started.');
+        });
+
+        return box
+          .watch()
+          .catch(errorCallback)
+          .then(() => {
+            errorCallback.calledOnce.should.be.true;
+          });
+      })
+      .finally(() => {
+        box.unwatch();
       });
-    }).finally(() => {
-      box.unwatch();
-    });
   });
 
   it('watch() - run process() before start watching', () => {
@@ -441,29 +506,36 @@ describe('Box', () => {
     return Promise.all([
       fs.writeFile(pathFn.join(box.base, 'a.txt'), 'a'),
       fs.writeFile(pathFn.join(box.base, 'b', 'c.js'), 'c')
-    ]).then(() => box.watch()).then(() => {
-      data.should.have.members(['a.txt', 'b/c.js']);
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
+    ])
+      .then(() => box.watch())
+      .then(() => {
+        data.should.have.members(['a.txt', 'b/c.js']);
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
+      });
   });
 
   it('unwatch()', () => {
     const box = newBox('test');
     const processor = sinon.spy();
 
-    return box.watch().then(() => {
-      box.addProcessor(processor);
-      box.unwatch();
+    return box
+      .watch()
+      .then(() => {
+        box.addProcessor(processor);
+        box.unwatch();
 
-      return fs.writeFile(pathFn.join(box.base, 'a.txt'), 'a');
-    }).then(() => {
-      processor.called.should.be.false;
-    }).finally(() => {
-      box.unwatch();
-      return fs.rmdir(box.base);
-    });
+        return fs.writeFile(pathFn.join(box.base, 'a.txt'), 'a');
+      })
+      .then(() => {
+        processor.called.should.be.false;
+      })
+      .finally(() => {
+        box.unwatch();
+        return fs.rmdir(box.base);
+      });
   });
 
   it('isWatching()', () => {
@@ -471,14 +543,18 @@ describe('Box', () => {
 
     box.isWatching().should.be.false;
 
-    return box.watch().then(() => {
-      box.isWatching().should.be.true;
-      return box.unwatch();
-    }).then(() => {
-      box.isWatching().should.be.false;
-    }).finally(() => {
-      box.unwatch();
-    });
+    return box
+      .watch()
+      .then(() => {
+        box.isWatching().should.be.true;
+        return box.unwatch();
+      })
+      .then(() => {
+        box.isWatching().should.be.false;
+      })
+      .finally(() => {
+        box.unwatch();
+      });
   });
 
   it('processBefore & processAfter events', () => {
@@ -497,9 +573,13 @@ describe('Box', () => {
     box.on('processBefore', beforeSpy);
     box.on('processAfter', afterSpy);
 
-    return fs.writeFile(pathFn.join(box.base, 'a.txt'), 'a').then(() => box.process()).then(() => {
-      beforeSpy.calledOnce.should.be.true;
-      afterSpy.calledOnce.should.be.true;
-    }).finally(() => fs.rmdir(box.base));
+    return fs
+      .writeFile(pathFn.join(box.base, 'a.txt'), 'a')
+      .then(() => box.process())
+      .then(() => {
+        beforeSpy.calledOnce.should.be.true;
+        afterSpy.calledOnce.should.be.true;
+      })
+      .finally(() => fs.rmdir(box.base));
   });
 });
diff --git a/test/scripts/box/file.js b/test/scripts/box/file.js
index 70e15abe0b..75383bf34f 100644
--- a/test/scripts/box/file.js
+++ b/test/scripts/box/file.js
@@ -28,23 +28,29 @@ describe('File', () => {
   const path = 'test.yml';
 
   function makeFile(path, props) {
-    return new File(Object.assign({
-      source: pathFn.join(box.base, path),
-      path
-    }, props));
+    return new File(
+      Object.assign(
+        {
+          source: pathFn.join(box.base, path),
+          path
+        },
+        props
+      )
+    );
   }
 
   const file = makeFile(path, {
     source: pathFn.join(box.base, path),
     path,
     type: 'create',
-    params: {foo: 'bar'}
+    params: { foo: 'bar' }
   });
 
-  before(() => Promise.all([
-    fs.writeFile(file.source, body),
-    hexo.init()
-  ]).then(() => fs.stat(file.source)));
+  before(() =>
+    Promise.all([fs.writeFile(file.source, body), hexo.init()]).then(() =>
+      fs.stat(file.source)
+    )
+  );
 
   after(() => fs.rmdir(box.base));
 
@@ -62,12 +68,10 @@ describe('File', () => {
     file.readSync().should.eql(body);
   });
 
-  it('stat()', () => Promise.all([
-    fs.stat(file.source),
-    file.stat()
-  ]).then(stats => {
-    stats[0].should.eql(stats[1]);
-  }));
+  it('stat()', () =>
+    Promise.all([fs.stat(file.source), file.stat()]).then(stats => {
+      stats[0].should.eql(stats[1]);
+    }));
 
   it('stat() - callback', callback => {
     file.stat((err, fileStats) => {
diff --git a/test/scripts/console/clean.js b/test/scripts/console/clean.js
index 711ddbcd5a..f7a0f516fa 100644
--- a/test/scripts/console/clean.js
+++ b/test/scripts/console/clean.js
@@ -7,24 +7,32 @@ describe('clean', () => {
   let hexo, clean;
 
   beforeEach(() => {
-    hexo = new Hexo(__dirname, {silent: true});
+    hexo = new Hexo(__dirname, { silent: true });
     clean = require('../../../lib/plugins/console/clean').bind(hexo);
   });
 
   it('delete database', () => {
     const dbPath = hexo.database.options.path;
 
-    return fs.writeFile(dbPath, '').then(() => clean()).then(() => fs.exists(dbPath)).then(exist => {
-      exist.should.be.false;
-    });
+    return fs
+      .writeFile(dbPath, '')
+      .then(() => clean())
+      .then(() => fs.exists(dbPath))
+      .then(exist => {
+        exist.should.be.false;
+      });
   });
 
   it('delete public folder', () => {
     const publicDir = hexo.public_dir;
 
-    return fs.mkdirs(publicDir).then(() => clean()).then(() => fs.exists(publicDir)).then(exist => {
-      exist.should.be.false;
-    });
+    return fs
+      .mkdirs(publicDir)
+      .then(() => clean())
+      .then(() => fs.exists(publicDir))
+      .then(exist => {
+        exist.should.be.false;
+      });
   });
 
   it('execute corresponding filter', () => {
@@ -34,8 +42,12 @@ describe('clean', () => {
       return fs.unlink(extraDbPath);
     });
 
-    return fs.writeFile(extraDbPath, '').then(() => clean()).then(() => fs.exists(extraDbPath)).then(exist => {
-      exist.should.be.false;
-    });
+    return fs
+      .writeFile(extraDbPath, '')
+      .then(() => clean())
+      .then(() => fs.exists(extraDbPath))
+      .then(exist => {
+        exist.should.be.false;
+      });
   });
 });
diff --git a/test/scripts/console/config.js b/test/scripts/console/config.js
index 928c164cb5..9b1471b2a9 100644
--- a/test/scripts/console/config.js
+++ b/test/scripts/console/config.js
@@ -8,7 +8,9 @@ const sinon = require('sinon');
 
 describe('config', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {
+    silent: true
+  });
   const config = require('../../../lib/plugins/console/config').bind(hexo);
   const configModule = rewire('../../../lib/plugins/console/config');
 
@@ -21,25 +23,29 @@ describe('config', () => {
   it('read all config', () => {
     const spy = sinon.spy();
 
-    return configModule.__with__({
-      console: {
-        log: spy
-      }
-    })(() => configModule.call(hexo, {_: []})).then(() => {
-      spy.args[0][0].should.eql(hexo.config);
-    });
+    return configModule
+      .__with__({
+        console: {
+          log: spy
+        }
+      })(() => configModule.call(hexo, { _: [] }))
+      .then(() => {
+        spy.args[0][0].should.eql(hexo.config);
+      });
   });
 
   it('read config', () => {
     const spy = sinon.spy();
 
-    return configModule.__with__({
-      console: {
-        log: spy
-      }
-    })(() => configModule.call(hexo, {_: ['title']})).then(() => {
-      spy.args[0][0].should.eql(hexo.config.title);
-    });
+    return configModule
+      .__with__({
+        console: {
+          log: spy
+        }
+      })(() => configModule.call(hexo, { _: ['title'] }))
+      .then(() => {
+        spy.args[0][0].should.eql(hexo.config.title);
+      });
   });
 
   it('read nested config', () => {
@@ -49,61 +55,83 @@ describe('config', () => {
       port: 12345
     };
 
-    return configModule.__with__({
-      console: {
-        log: spy
-      }
-    })(() => configModule.call(hexo, {_: ['server.port']})).then(() => {
-      spy.args[0][0].should.eql(hexo.config.server.port);
-    }).finally(() => {
-      delete hexo.config.server;
-    });
+    return configModule
+      .__with__({
+        console: {
+          log: spy
+        }
+      })(() => configModule.call(hexo, { _: ['server.port'] }))
+      .then(() => {
+        spy.args[0][0].should.eql(hexo.config.server.port);
+      })
+      .finally(() => {
+        delete hexo.config.server;
+      });
   });
 
   function writeConfig() {
     const args = Array.from(arguments);
 
-    return config({_: args}).then(() => fs.readFile(hexo.config_path)).then(content => yaml.load(content));
+    return config({ _: args })
+      .then(() => fs.readFile(hexo.config_path))
+      .then(content => yaml.load(content));
   }
 
-  it('write config', () => writeConfig('title', 'My Blog').then(config => {
-    config.title.should.eql('My Blog');
-  }));
+  it('write config', () =>
+    writeConfig('title', 'My Blog').then(config => {
+      config.title.should.eql('My Blog');
+    }));
 
-  it('write config: number', () => writeConfig('server.port', '5000').then(config => {
-    config.server.port.should.eql(5000);
-  }));
+  it('write config: number', () =>
+    writeConfig('server.port', '5000').then(config => {
+      config.server.port.should.eql(5000);
+    }));
 
-  it('write config: false', () => writeConfig('post_asset_folder', 'false').then(config => {
-    config.post_asset_folder.should.be.false;
-  }));
+  it('write config: false', () =>
+    writeConfig('post_asset_folder', 'false').then(config => {
+      config.post_asset_folder.should.be.false;
+    }));
 
-  it('write config: true', () => writeConfig('post_asset_folder', 'true').then(config => {
-    config.post_asset_folder.should.be.true;
-  }));
+  it('write config: true', () =>
+    writeConfig('post_asset_folder', 'true').then(config => {
+      config.post_asset_folder.should.be.true;
+    }));
 
-  it('write config: null', () => writeConfig('language', 'null').then(config => {
-    should.not.exist(config.language);
-  }));
+  it('write config: null', () =>
+    writeConfig('language', 'null').then(config => {
+      should.not.exist(config.language);
+    }));
 
-  it('write config: regex', () => writeConfig('include', /^pattern$/gim).then(config => {
-    config.include.should.eql(/^pattern$/gim);
-  }));
+  it('write config: regex', () =>
+    writeConfig('include', /^pattern$/gim).then(config => {
+      config.include.should.eql(/^pattern$/gim);
+    }));
 
   it('write config: json', () => {
-    const configPath = hexo.config_path = pathFn.join(hexo.base_dir, '_config.json');
-
-    return fs.writeFile(configPath, '{}').then(() => config({_: ['title', 'My Blog']})).then(() => fs.readFile(configPath)).then(content => {
-      const json = JSON.parse(content);
-
-      json.title.should.eql('My Blog');
-
-      hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
-      return fs.unlink(configPath);
-    });
+    const configPath = (hexo.config_path = pathFn.join(
+      hexo.base_dir,
+      '_config.json'
+    ));
+
+    return fs
+      .writeFile(configPath, '{}')
+      .then(() => config({ _: ['title', 'My Blog'] }))
+      .then(() => fs.readFile(configPath))
+      .then(content => {
+        const json = JSON.parse(content);
+
+        json.title.should.eql('My Blog');
+
+        hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
+        return fs.unlink(configPath);
+      });
   });
 
-  it('create config if not exist', () => fs.unlink(hexo.config_path).then(() => writeConfig('subtitle', 'Hello world')).then(config => {
-    config.subtitle.should.eql('Hello world');
-  }));
+  it('create config if not exist', () =>
+    fs
+      .unlink(hexo.config_path)
+      .then(() => writeConfig('subtitle', 'Hello world'))
+      .then(config => {
+        config.subtitle.should.eql('Hello world');
+      }));
 });
diff --git a/test/scripts/console/deploy.js b/test/scripts/console/deploy.js
index 8b0d9bd4a7..396e86fea8 100644
--- a/test/scripts/console/deploy.js
+++ b/test/scripts/console/deploy.js
@@ -6,13 +6,15 @@ const sinon = require('sinon');
 
 describe('deploy', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'deploy_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'deploy_test'), {
+    silent: true
+  });
   const deploy = require('../../../lib/plugins/console/deploy').bind(hexo);
 
   before(() => fs.mkdirs(hexo.public_dir).then(() => hexo.init()));
 
   beforeEach(() => {
-    hexo.config.deploy = {type: 'foo'};
+    hexo.config.deploy = { type: 'foo' };
     hexo.extend.deployer.register('foo', () => {});
   });
 
@@ -39,7 +41,7 @@ describe('deploy', () => {
     hexo.once('deployAfter', afterListener);
     hexo.extend.deployer.register('foo', deployer);
 
-    return deploy({foo: 'foo', bar: 'bar'}).then(() => {
+    return deploy({ foo: 'foo', bar: 'bar' }).then(() => {
       deployer.calledOnce.should.be.true;
       beforeListener.calledOnce.should.be.true;
       afterListener.calledOnce.should.be.true;
@@ -64,14 +66,14 @@ describe('deploy', () => {
     });
 
     hexo.config.deploy = [
-      {type: 'foo', foo: 'foo'},
-      {type: 'bar', bar: 'bar'}
+      { type: 'foo', foo: 'foo' },
+      { type: 'bar', bar: 'bar' }
     ];
 
     hexo.extend.deployer.register('foo', deployer1);
     hexo.extend.deployer.register('bar', deployer2);
 
-    return deploy({test: true}).then(() => {
+    return deploy({ test: true }).then(() => {
       deployer1.calledOnce.should.be.true;
       deployer2.calledOnce.should.be.true;
     });
@@ -79,12 +81,22 @@ describe('deploy', () => {
 
   it('deployer not found');
 
-  it('generate', () => fs.writeFile(pathFn.join(hexo.source_dir, 'test.txt'), 'test').then(() => deploy({generate: true})).then(() => fs.readFile(pathFn.join(hexo.public_dir, 'test.txt'))).then(content => {
-    content.should.eql('test');
-    return fs.rmdir(hexo.source_dir);
-  }));
-
-  it('run generate if public directory not exist', () => fs.rmdir(hexo.public_dir).then(() => deploy({})).then(() => fs.exists(hexo.public_dir)).then(exist => {
-    exist.should.be.true;
-  }));
+  it('generate', () =>
+    fs
+      .writeFile(pathFn.join(hexo.source_dir, 'test.txt'), 'test')
+      .then(() => deploy({ generate: true }))
+      .then(() => fs.readFile(pathFn.join(hexo.public_dir, 'test.txt')))
+      .then(content => {
+        content.should.eql('test');
+        return fs.rmdir(hexo.source_dir);
+      }));
+
+  it('run generate if public directory not exist', () =>
+    fs
+      .rmdir(hexo.public_dir)
+      .then(() => deploy({}))
+      .then(() => fs.exists(hexo.public_dir))
+      .then(exist => {
+        exist.should.be.true;
+      }));
 });
diff --git a/test/scripts/console/generate.js b/test/scripts/console/generate.js
index 4755e87a00..2dd6a35298 100644
--- a/test/scripts/console/generate.js
+++ b/test/scripts/console/generate.js
@@ -11,7 +11,7 @@ describe('generate', () => {
   let hexo, generate;
 
   beforeEach(() => {
-    hexo = new Hexo(pathFn.join(__dirname, 'generate_test'), {silent: true});
+    hexo = new Hexo(pathFn.join(__dirname, 'generate_test'), { silent: true });
     generate = generateConsole.bind(hexo);
 
     return fs.mkdirs(hexo.base_dir).then(() => hexo.init());
@@ -20,7 +20,6 @@ describe('generate', () => {
   afterEach(() => fs.rmdir(hexo.base_dir));
 
   function testGenerate(options) {
-
     return Promise.all([
       // Add some source files
       fs.writeFile(pathFn.join(hexo.source_dir, 'test.txt'), 'test'),
@@ -29,22 +28,27 @@ describe('generate', () => {
       fs.writeFile(pathFn.join(hexo.public_dir, 'foo.txt'), 'foo'),
       fs.writeFile(pathFn.join(hexo.public_dir, 'bar', 'boo.txt'), 'boo'),
       fs.writeFile(pathFn.join(hexo.public_dir, 'faz', 'yo.txt'), 'yo')
-    ]).then(() => generate(options)).then(() => Promise.all([
-      fs.readFile(pathFn.join(hexo.public_dir, 'test.txt')),
-      fs.readFile(pathFn.join(hexo.public_dir, 'faz', 'yo.txt')),
-      fs.exists(pathFn.join(hexo.public_dir, 'foo.txt')),
-      fs.exists(pathFn.join(hexo.public_dir, 'bar', 'boo.txt'))
-    ])).then(result => {
-      // Check the new file
-      result[0].should.eql('test');
-
-      // Check the updated file
-      result[1].should.eql('yoooo');
-
-      // Old files should not be deleted
-      result[2].should.be.true;
-      result[3].should.be.true;
-    });
+    ])
+      .then(() => generate(options))
+      .then(() =>
+        Promise.all([
+          fs.readFile(pathFn.join(hexo.public_dir, 'test.txt')),
+          fs.readFile(pathFn.join(hexo.public_dir, 'faz', 'yo.txt')),
+          fs.exists(pathFn.join(hexo.public_dir, 'foo.txt')),
+          fs.exists(pathFn.join(hexo.public_dir, 'bar', 'boo.txt'))
+        ])
+      )
+      .then(result => {
+        // Check the new file
+        result[0].should.eql('test');
+
+        // Check the updated file
+        result[1].should.eql('yoooo');
+
+        // Old files should not be deleted
+        result[2].should.be.true;
+        result[3].should.be.true;
+      });
   }
 
   it('default', () => testGenerate());
@@ -55,41 +59,61 @@ describe('generate', () => {
     const content = 'test';
 
     // Add some source files
-    return fs.writeFile(src, content).then(() => // First generation
-      generate()).then(() => // Delete generated files
-      fs.unlink(dest)).then(() => // Second generation
-      generate()).then(() => fs.readFile(dest)).then(result => {
-      result.should.eql(content);
-
-      // Remove source files and generated files
-      return Promise.all([
-        fs.unlink(src),
+    return fs
+      .writeFile(src, content)
+      .then(() =>
+        // First generation
+        generate()
+      )
+      .then(() =>
+        // Delete generated files
         fs.unlink(dest)
-      ]);
-    });
+      )
+      .then(() =>
+        // Second generation
+        generate()
+      )
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        result.should.eql(content);
+
+        // Remove source files and generated files
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
+      });
   });
 
-  it('don\'t write if file unchanged', () => {
+  it("don't write if file unchanged", () => {
     const src = pathFn.join(hexo.source_dir, 'test.txt');
     const dest = pathFn.join(hexo.public_dir, 'test.txt');
     const content = 'test';
     const newContent = 'newtest';
 
     // Add some source files
-    return fs.writeFile(src, content).then(() => // First generation
-      generate()).then(() => // Change the generated file
-      fs.writeFile(dest, newContent)).then(() => // Second generation
-      generate()).then(() => // Read the generated file
-      fs.readFile(dest)).then(result => {
-      // Make sure the generated file didn't changed
-      result.should.eql(newContent);
-
-      // Remove source files and generated files
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
+    return fs
+      .writeFile(src, content)
+      .then(() =>
+        // First generation
+        generate()
+      )
+      .then(() =>
+        // Change the generated file
+        fs.writeFile(dest, newContent)
+      )
+      .then(() =>
+        // Second generation
+        generate()
+      )
+      .then(() =>
+        // Read the generated file
+        fs.readFile(dest)
+      )
+      .then(result => {
+        // Make sure the generated file didn't changed
+        result.should.eql(newContent);
+
+        // Remove source files and generated files
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
+      });
   });
 
   it('force regenerate', () => {
@@ -98,20 +122,31 @@ describe('generate', () => {
     const content = 'test';
     let mtime;
 
-    return fs.writeFile(src, content).then(() => // First generation
-      generate()).then(() => // Read file status
-      fs.stat(dest)).then(stats => {
-      mtime = stats.mtime.getTime();
-    }).delay(1000).then(() => // Force regenerate
-      generate({force: true})).then(() => fs.stat(dest)).then(stats => {
-      stats.mtime.getTime().should.be.above(mtime);
-
-      // Remove source files and generated files
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
+    return fs
+      .writeFile(src, content)
+      .then(() =>
+        // First generation
+        generate()
+      )
+      .then(() =>
+        // Read file status
+        fs.stat(dest)
+      )
+      .then(stats => {
+        mtime = stats.mtime.getTime();
+      })
+      .delay(1000)
+      .then(() =>
+        // Force regenerate
+        generate({ force: true })
+      )
+      .then(() => fs.stat(dest))
+      .then(stats => {
+        stats.mtime.getTime().should.be.above(mtime);
+
+        // Remove source files and generated files
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
+      });
   });
 
   it('watch - update', () => {
@@ -119,22 +154,35 @@ describe('generate', () => {
     const dest = pathFn.join(hexo.public_dir, 'test.txt');
     const content = 'test';
 
-    return testGenerate({watch: true}).then(() => // Update the file
-      fs.writeFile(src, content)).delay(300).then(() => fs.readFile(dest)).then(result => {
-      // Check the updated file
-      result.should.eql(content);
-    }).finally(() => {
-      // Stop watching
-      hexo.unwatch();
-    });
+    return testGenerate({ watch: true })
+      .then(() =>
+        // Update the file
+        fs.writeFile(src, content)
+      )
+      .delay(300)
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        // Check the updated file
+        result.should.eql(content);
+      })
+      .finally(() => {
+        // Stop watching
+        hexo.unwatch();
+      });
   });
 
-  it('watch - delete', () => testGenerate({watch: true}).then(() => fs.unlink(pathFn.join(hexo.source_dir, 'test.txt'))).delay(300).then(() => fs.exists(pathFn.join(hexo.public_dir, 'test.txt'))).then(exist => {
-    exist.should.be.false;
-  }).finally(() => {
-    // Stop watching
-    hexo.unwatch();
-  }));
+  it('watch - delete', () =>
+    testGenerate({ watch: true })
+      .then(() => fs.unlink(pathFn.join(hexo.source_dir, 'test.txt')))
+      .delay(300)
+      .then(() => fs.exists(pathFn.join(hexo.public_dir, 'test.txt')))
+      .then(exist => {
+        exist.should.be.false;
+      })
+      .finally(() => {
+        // Stop watching
+        hexo.unwatch();
+      }));
 
   it('deploy', () => {
     const deployer = sinon.spy();
@@ -145,41 +193,53 @@ describe('generate', () => {
       type: 'test'
     };
 
-    return generate({deploy: true}).then(() => {
+    return generate({ deploy: true }).then(() => {
       deployer.calledOnce.should.be.true;
     });
   });
 
-  it('update theme source files', () => Promise.all([
-    // Add some source files
-    fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'a.txt'), 'a'),
-    fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'b.txt'), 'b'),
-    fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'c.swig'), 'c')
-  ]).then(() => generate()).then(() => // Update source file
+  it('update theme source files', () =>
     Promise.all([
-      fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'b.txt'), 'bb'),
-      fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'c.swig'), 'cc')
-    ])).then(() => // Generate again
-    generate()).then(() => // Read the updated source file
-    Promise.all([
-      fs.readFile(pathFn.join(hexo.public_dir, 'b.txt')),
-      fs.readFile(pathFn.join(hexo.public_dir, 'c.html'))
-    ])).then(result => {
-    result[0].should.eql('bb');
-    result[1].should.eql('cc');
-  }));
+      // Add some source files
+      fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'a.txt'), 'a'),
+      fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'b.txt'), 'b'),
+      fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'c.swig'), 'c')
+    ])
+      .then(() => generate())
+      .then(() =>
+        // Update source file
+        Promise.all([
+          fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'b.txt'), 'bb'),
+          fs.writeFile(pathFn.join(hexo.theme_dir, 'source', 'c.swig'), 'cc')
+        ])
+      )
+      .then(() =>
+        // Generate again
+        generate()
+      )
+      .then(() =>
+        // Read the updated source file
+        Promise.all([
+          fs.readFile(pathFn.join(hexo.public_dir, 'b.txt')),
+          fs.readFile(pathFn.join(hexo.public_dir, 'c.html'))
+        ])
+      )
+      .then(result => {
+        result[0].should.eql('bb');
+        result[1].should.eql('cc');
+      }));
 
   it('proceeds after error when bail option is not set', () => {
-    hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception')));
-    hexo.extend.generator.register('test_page', () =>
-      [
-        {
-          path: 'testing-path',
-          layout: 'post',
-          data: {}
-        }
-      ]
+    hexo.extend.renderer.register('err', 'html', () =>
+      Promise.reject(new Error('Testing unhandled exception'))
     );
+    hexo.extend.generator.register('test_page', () => [
+      {
+        path: 'testing-path',
+        layout: 'post',
+        data: {}
+      }
+    ]);
 
     return Promise.all([
       fs.writeFile(pathFn.join(hexo.theme_dir, 'layout', 'post.err'), 'post')
@@ -189,35 +249,35 @@ describe('generate', () => {
   });
 
   it('proceeds after error when bail option is set to false', () => {
-    hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception')));
-    hexo.extend.generator.register('test_page', () =>
-      [
-        {
-          path: 'testing-path',
-          layout: 'post',
-          data: {}
-        }
-      ]
+    hexo.extend.renderer.register('err', 'html', () =>
+      Promise.reject(new Error('Testing unhandled exception'))
     );
+    hexo.extend.generator.register('test_page', () => [
+      {
+        path: 'testing-path',
+        layout: 'post',
+        data: {}
+      }
+    ]);
 
     return Promise.all([
       fs.writeFile(pathFn.join(hexo.theme_dir, 'layout', 'post.err'), 'post')
     ]).then(() => {
-      return generate({bail: false});
+      return generate({ bail: false });
     });
   });
 
   it('breaks after error when bail option is set to true', () => {
-    hexo.extend.renderer.register('err', 'html', () => Promise.reject(new Error('Testing unhandled exception')));
-    hexo.extend.generator.register('test_page', () =>
-      [
-        {
-          path: 'testing-path',
-          layout: 'post',
-          data: {}
-        }
-      ]
+    hexo.extend.renderer.register('err', 'html', () =>
+      Promise.reject(new Error('Testing unhandled exception'))
     );
+    hexo.extend.generator.register('test_page', () => [
+      {
+        path: 'testing-path',
+        layout: 'post',
+        data: {}
+      }
+    ]);
 
     const errorCallback = sinon.spy(err => {
       err.should.have.property('message', 'Testing unhandled exception');
@@ -226,13 +286,17 @@ describe('generate', () => {
     return Promise.all([
       fs.writeFile(pathFn.join(hexo.theme_dir, 'layout', 'post.err'), 'post')
     ]).then(() => {
-      return generate({bail: true}).catch(errorCallback).finally(() => {
-        errorCallback.calledOnce.should.be.true;
-      });
+      return generate({ bail: true })
+        .catch(errorCallback)
+        .finally(() => {
+          errorCallback.calledOnce.should.be.true;
+        });
     });
   });
 
   it('should generate all files even when concurrency is set', () => {
-    return generate({ concurrency: 1 }).then(() => generate({ concurrency: 2 }));
+    return generate({ concurrency: 1 }).then(() =>
+      generate({ concurrency: 2 })
+    );
   });
 });
diff --git a/test/scripts/console/list_categories.js b/test/scripts/console/list_categories.js
index 822bc312a1..2d43a499be 100644
--- a/test/scripts/console/list_categories.js
+++ b/test/scripts/console/list_categories.js
@@ -9,7 +9,9 @@ describe('Console list', () => {
   const hexo = new Hexo(__dirname);
   const Post = hexo.model('Post');
 
-  const listCategories = require('../../../lib/plugins/console/list/category').bind(hexo);
+  const listCategories = require('../../../lib/plugins/console/list/category').bind(
+    hexo
+  );
 
   before(() => {
     const log = console.log;
@@ -31,16 +33,19 @@ describe('Console list', () => {
 
   it('categories', () => {
     const posts = [
-      {source: 'foo', slug: 'foo', title: 'Its', date: 1e8},
-      {source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1},
-      {source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1}
+      { source: 'foo', slug: 'foo', title: 'Its', date: 1e8 },
+      { source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1 },
+      { source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1 }
     ];
-    return hexo.init()
-      .then(() => Post.insert(posts)).then(posts => Promise.each([
-        ['foo'],
-        ['baz'],
-        ['baz']
-      ], (tags, i) => posts[i].setCategories(tags))).then(() => {
+    return hexo
+      .init()
+      .then(() => Post.insert(posts))
+      .then(posts =>
+        Promise.each([['foo'], ['baz'], ['baz']], (tags, i) =>
+          posts[i].setCategories(tags)
+        )
+      )
+      .then(() => {
         hexo.locals.invalidate();
       })
       .then(() => {
diff --git a/test/scripts/console/list_page.js b/test/scripts/console/list_page.js
index d4f2afd1c5..b9709f4770 100644
--- a/test/scripts/console/list_page.js
+++ b/test/scripts/console/list_page.js
@@ -7,7 +7,9 @@ describe('Console list', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
   const Page = hexo.model('Page');
-  const listPages = require('../../../lib/plugins/console/list/page').bind(hexo);
+  const listPages = require('../../../lib/plugins/console/list/page').bind(
+    hexo
+  );
 
   hexo.config.permalink = ':title/';
   before(() => {
@@ -29,12 +31,12 @@ describe('Console list', () => {
     expect(console.log.calledWith(sinon.match('No pages.'))).to.be.true;
   });
 
-  it('page', () => Page.insert({
-    source: 'foo',
-    title: 'Hello World',
-    path: 'bar'
-  })
-    .then(() => {
+  it('page', () =>
+    Page.insert({
+      source: 'foo',
+      title: 'Hello World',
+      path: 'bar'
+    }).then(() => {
       listPages();
       expect(console.log.calledWith(sinon.match('Date'))).to.be.true;
       expect(console.log.calledWith(sinon.match('Title'))).to.be.true;
diff --git a/test/scripts/console/list_post.js b/test/scripts/console/list_post.js
index 96f424fdfb..0c514b96ec 100644
--- a/test/scripts/console/list_post.js
+++ b/test/scripts/console/list_post.js
@@ -8,7 +8,9 @@ describe('Console list', () => {
   const hexo = new Hexo(__dirname);
   const Post = hexo.model('Post');
 
-  const listPosts = require('../../../lib/plugins/console/list/post').bind(hexo);
+  const listPosts = require('../../../lib/plugins/console/list/post').bind(
+    hexo
+  );
 
   before(() => {
     const log = console.log;
@@ -33,12 +35,14 @@ describe('Console list', () => {
 
   it('post', () => {
     const posts = [
-      {source: 'foo', slug: 'foo', title: 'Its', date: 1e8},
-      {source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1},
-      {source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1}
+      { source: 'foo', slug: 'foo', title: 'Its', date: 1e8 },
+      { source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1 },
+      { source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1 }
     ];
-    return hexo.init()
-      .then(() => Post.insert(posts)).then(() => {
+    return hexo
+      .init()
+      .then(() => Post.insert(posts))
+      .then(() => {
         hexo.locals.invalidate();
       })
       .then(() => {
@@ -49,9 +53,11 @@ describe('Console list', () => {
         expect(console.log.calledWith(sinon.match('Category'))).to.be.true;
         expect(console.log.calledWith(sinon.match('Tags'))).to.be.true;
         for (let i = 0; i < posts.length; i++) {
-          expect(console.log.calledWith(sinon.match(posts[i].source))).to.be.true;
+          expect(console.log.calledWith(sinon.match(posts[i].source))).to.be
+            .true;
           expect(console.log.calledWith(sinon.match(posts[i].slug))).to.be.true;
-          expect(console.log.calledWith(sinon.match(posts[i].title))).to.be.true;
+          expect(console.log.calledWith(sinon.match(posts[i].title))).to.be
+            .true;
         }
       });
   });
diff --git a/test/scripts/console/list_tags.js b/test/scripts/console/list_tags.js
index 50b38419f1..01f2abc1c9 100644
--- a/test/scripts/console/list_tags.js
+++ b/test/scripts/console/list_tags.js
@@ -33,16 +33,19 @@ describe('Console list', () => {
 
   it('tags', () => {
     const posts = [
-      {source: 'foo', slug: 'foo', title: 'Its', date: 1e8},
-      {source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1},
-      {source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1}
+      { source: 'foo', slug: 'foo', title: 'Its', date: 1e8 },
+      { source: 'bar', slug: 'bar', title: 'Math', date: 1e8 + 1 },
+      { source: 'baz', slug: 'baz', title: 'Dude', date: 1e8 - 1 }
     ];
-    return hexo.init()
-      .then(() => Post.insert(posts)).then(posts => Promise.each([
-        ['foo'],
-        ['baz'],
-        ['baz']
-      ], (tags, i) => posts[i].setTags(tags))).then(() => {
+    return hexo
+      .init()
+      .then(() => Post.insert(posts))
+      .then(posts =>
+        Promise.each([['foo'], ['baz'], ['baz']], (tags, i) =>
+          posts[i].setTags(tags)
+        )
+      )
+      .then(() => {
         hexo.locals.invalidate();
       })
       .then(() => {
diff --git a/test/scripts/console/migrate.js b/test/scripts/console/migrate.js
index a029b50fd8..37f51897c2 100644
--- a/test/scripts/console/migrate.js
+++ b/test/scripts/console/migrate.js
@@ -4,7 +4,7 @@ const sinon = require('sinon');
 
 describe('migrate', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(__dirname, {silent: true});
+  const hexo = new Hexo(__dirname, { silent: true });
   const migrate = require('../../../lib/plugins/console/migrate').bind(hexo);
 
   it('default', () => {
@@ -15,7 +15,7 @@ describe('migrate', () => {
 
     hexo.extend.migrator.register('test', migrator);
 
-    return migrate({_: ['test'], foo: 1, bar: 2}).then(() => {
+    return migrate({ _: ['test'], foo: 1, bar: 2 }).then(() => {
       migrator.calledOnce.should.be.true;
     });
   });
diff --git a/test/scripts/console/new.js b/test/scripts/console/new.js
index 2ed1a11326..ed59db2643 100644
--- a/test/scripts/console/new.js
+++ b/test/scripts/console/new.js
@@ -8,7 +8,7 @@ const sinon = require('sinon');
 
 describe('new', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'new_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'new_test'), { silent: true });
   const n = require('../../../lib/plugins/console/new').bind(hexo);
   const post = hexo.post;
   const now = Date.now();
@@ -17,16 +17,21 @@ describe('new', () => {
   before(() => {
     clock = sinon.useFakeTimers(now);
 
-    return fs.mkdirs(hexo.base_dir).then(() => hexo.init()).then(() => hexo.scaffold.set('post', [
-      'title: {{ title }}',
-      'date: {{ date }}',
-      'tags:',
-      '---'
-    ].join('\n'))).then(() => hexo.scaffold.set('draft', [
-      'title: {{ title }}',
-      'tags:',
-      '---'
-    ].join('\n')));
+    return fs
+      .mkdirs(hexo.base_dir)
+      .then(() => hexo.init())
+      .then(() =>
+        hexo.scaffold.set(
+          'post',
+          ['title: {{ title }}', 'date: {{ date }}', 'tags:', '---'].join('\n')
+        )
+      )
+      .then(() =>
+        hexo.scaffold.set(
+          'draft',
+          ['title: {{ title }}', 'tags:', '---'].join('\n')
+        )
+      );
   });
 
   after(() => {
@@ -37,124 +42,148 @@ describe('new', () => {
   it('title', () => {
     const date = moment(now);
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
-    const body = [
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const body =
+      [
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return n({
       _: ['Hello World']
-    }).then(() => fs.readFile(path)).then(content => {
-      content.should.eql(body);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(content => {
+        content.should.eql(body);
+        return fs.unlink(path);
+      });
   });
 
   it('layout', () => {
     const path = pathFn.join(hexo.source_dir, '_drafts', 'Hello-World.md');
-    const body = [
-      'title: Hello World',
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const body = ['title: Hello World', 'tags:', '---'].join('\n') + '\n';
 
     return n({
       _: ['draft', 'Hello World']
-    }).then(() => fs.readFile(path)).then(content => {
-      content.should.eql(body);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(content => {
+        content.should.eql(body);
+        return fs.unlink(path);
+      });
   });
 
   it('slug', () => {
     const date = moment(now);
     const path = pathFn.join(hexo.source_dir, '_posts', 'foo.md');
-    const body = [
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const body =
+      [
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return n({
       _: ['Hello World'],
       slug: 'foo'
-    }).then(() => fs.readFile(path)).then(content => {
-      content.should.eql(body);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(content => {
+        content.should.eql(body);
+        return fs.unlink(path);
+      });
   });
 
   it('path', () => {
     const date = moment(now);
     const path = pathFn.join(hexo.source_dir, '_posts', 'bar.md');
-    const body = [
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const body =
+      [
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return n({
       _: ['Hello World'],
       slug: 'foo',
       path: 'bar'
-    }).then(() => fs.readFile(path)).then(content => {
-      content.should.eql(body);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(content => {
+        content.should.eql(body);
+        return fs.unlink(path);
+      });
   });
 
   it('rename if target existed', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => n({
-      _: ['Hello World']
-    })).then(() => fs.exists(path)).then(exist => {
-      exist.should.be.true;
-
-      return Promise.all([
-        fs.unlink(path),
-        fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
-      ]);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        n({
+          _: ['Hello World']
+        })
+      )
+      .then(() => fs.exists(path))
+      .then(exist => {
+        exist.should.be.true;
+
+        return Promise.all([
+          fs.unlink(path),
+          fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
+        ]);
+      });
   });
 
   it('replace existing files', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => n({
-      _: ['Hello World'],
-      replace: true
-    })).then(() => fs.exists(pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md'))).then(exist => {
-      exist.should.be.false;
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        n({
+          _: ['Hello World'],
+          replace: true
+        })
+      )
+      .then(() =>
+        fs.exists(pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md'))
+      )
+      .then(exist => {
+        exist.should.be.false;
+        return fs.unlink(path);
+      });
   });
 
   it('extra data', () => {
     const date = moment(now);
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
-    const body = [
-      'title: Hello World',
-      'foo: bar',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const body =
+      [
+        'title: Hello World',
+        'foo: bar',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return n({
       _: ['Hello World'],
       foo: 'bar'
-    }).then(() => fs.readFile(path)).then(content => {
-      content.should.eql(body);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(content => {
+        content.should.eql(body);
+        return fs.unlink(path);
+      });
   });
 });
diff --git a/test/scripts/console/publish.js b/test/scripts/console/publish.js
index 8252dbe74f..7e178913af 100644
--- a/test/scripts/console/publish.js
+++ b/test/scripts/console/publish.js
@@ -8,7 +8,9 @@ const sinon = require('sinon');
 
 describe('publish', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'publish_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'publish_test'), {
+    silent: true
+  });
   const publish = require('../../../lib/plugins/console/publish').bind(hexo);
   const post = hexo.post;
   const now = Date.now();
@@ -17,18 +19,27 @@ describe('publish', () => {
   before(() => {
     clock = sinon.useFakeTimers(now);
 
-    return fs.mkdirs(hexo.base_dir).then(() => hexo.init()).then(() => hexo.scaffold.set('post', [
-      '---',
-      'title: {{ title }}',
-      'date: {{ date }}',
-      'tags:',
-      '---'
-    ].join('\n'))).then(() => hexo.scaffold.set('draft', [
-      '---',
-      'title: {{ title }}',
-      'tags:',
-      '---'
-    ].join('\n')));
+    return fs
+      .mkdirs(hexo.base_dir)
+      .then(() => hexo.init())
+      .then(() =>
+        hexo.scaffold.set(
+          'post',
+          [
+            '---',
+            'title: {{ title }}',
+            'date: {{ date }}',
+            'tags:',
+            '---'
+          ].join('\n')
+        )
+      )
+      .then(() =>
+        hexo.scaffold.set(
+          'draft',
+          ['---', 'title: {{ title }}', 'tags:', '---'].join('\n')
+        )
+      );
   });
 
   after(() => {
@@ -36,87 +47,106 @@ describe('publish', () => {
     return fs.rmdir(hexo.base_dir);
   });
 
-  beforeEach(() => post.create({
-    title: 'Hello World',
-    layout: 'draft'
-  }));
+  beforeEach(() =>
+    post.create({
+      title: 'Hello World',
+      layout: 'draft'
+    })
+  );
 
   it('slug', () => {
     const draftPath = pathFn.join(hexo.source_dir, '_drafts', 'Hello-World.md');
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return publish({
       _: ['Hello-World']
-    }).then(() => Promise.all([
-      fs.exists(draftPath),
-      fs.readFile(path)
-    ])).spread((exist, data) => {
-      exist.should.be.false;
-      data.should.eql(content);
-
-      return fs.unlink(path);
-    });
+    })
+      .then(() => Promise.all([fs.exists(draftPath), fs.readFile(path)]))
+      .spread((exist, data) => {
+        exist.should.be.false;
+        data.should.eql(content);
+
+        return fs.unlink(path);
+      });
   });
 
   it('layout', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'layout: photo',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const content =
+      [
+        '---',
+        'layout: photo',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     return publish({
       _: ['photo', 'Hello-World']
-    }).then(() => fs.readFile(path)).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    })
+      .then(() => fs.readFile(path))
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('rename if target existed', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => publish({
-      _: ['Hello-World']
-    })).then(() => fs.exists(path)).then(exist => {
-      exist.should.be.true;
-
-      return Promise.all([
-        fs.unlink(path),
-        fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
-      ]);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        publish({
+          _: ['Hello-World']
+        })
+      )
+      .then(() => fs.exists(path))
+      .then(exist => {
+        exist.should.be.true;
+
+        return Promise.all([
+          fs.unlink(path),
+          fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
+        ]);
+      });
   });
 
   it('replace existing target', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => publish({
-      _: ['Hello-World'],
-      replace: true
-    })).then(() => fs.exists(pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md'))).then(exist => {
-      exist.should.be.false;
-
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        publish({
+          _: ['Hello-World'],
+          replace: true
+        })
+      )
+      .then(() =>
+        fs.exists(pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md'))
+      )
+      .then(exist => {
+        exist.should.be.false;
+
+        return fs.unlink(path);
+      });
   });
 });
diff --git a/test/scripts/console/render.js b/test/scripts/console/render.js
index 5243703740..8b8bd8bc81 100644
--- a/test/scripts/console/render.js
+++ b/test/scripts/console/render.js
@@ -6,74 +6,75 @@ const Promise = require('bluebird');
 
 describe('render', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'render_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'render_test'), {
+    silent: true
+  });
   const render = require('../../../lib/plugins/console/render').bind(hexo);
 
   before(() => fs.mkdirs(hexo.base_dir).then(() => hexo.init()));
 
   after(() => fs.rmdir(hexo.base_dir));
 
-  const body = [
-    'foo: 1',
-    'bar:',
-    '  boo: 2'
-  ].join('\n');
+  const body = ['foo: 1', 'bar:', '  boo: 2'].join('\n');
 
   it('relative path', () => {
     const src = pathFn.join(hexo.base_dir, 'test.yml');
     const dest = pathFn.join(hexo.base_dir, 'result.json');
 
-    return fs.writeFile(src, body).then(() => render({_: ['test.yml'], output: 'result.json'})).then(() => fs.readFile(dest)).then(result => {
-      JSON.parse(result).should.eql({
-        foo: 1,
-        bar: {
-          boo: 2
-        }
+    return fs
+      .writeFile(src, body)
+      .then(() => render({ _: ['test.yml'], output: 'result.json' }))
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        JSON.parse(result).should.eql({
+          foo: 1,
+          bar: {
+            boo: 2
+          }
+        });
+
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
       });
-
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
   });
 
   it('absolute path', () => {
     const src = pathFn.join(hexo.base_dir, 'test.yml');
     const dest = pathFn.join(hexo.base_dir, 'result.json');
 
-    return fs.writeFile(src, body).then(() => render({_: [src], output: 'result.json'})).then(() => fs.readFile(dest)).then(result => {
-      JSON.parse(result).should.eql({
-        foo: 1,
-        bar: {
-          boo: 2
-        }
+    return fs
+      .writeFile(src, body)
+      .then(() => render({ _: [src], output: 'result.json' }))
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        JSON.parse(result).should.eql({
+          foo: 1,
+          bar: {
+            boo: 2
+          }
+        });
+
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
       });
-
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
   });
 
   it('absolute output', () => {
     const src = pathFn.join(hexo.base_dir, 'test.yml');
     const dest = pathFn.join(hexo.base_dir, 'result.json');
 
-    return fs.writeFile(src, body).then(() => render({_: ['test.yml'], output: dest})).then(() => fs.readFile(dest)).then(result => {
-      JSON.parse(result).should.eql({
-        foo: 1,
-        bar: {
-          boo: 2
-        }
+    return fs
+      .writeFile(src, body)
+      .then(() => render({ _: ['test.yml'], output: dest }))
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        JSON.parse(result).should.eql({
+          foo: 1,
+          bar: {
+            boo: 2
+          }
+        });
+
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
       });
-
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
   });
 
   it('output');
@@ -82,37 +83,49 @@ describe('render', () => {
     const src = pathFn.join(hexo.base_dir, 'test');
     const dest = pathFn.join(hexo.base_dir, 'result.json');
 
-    return fs.writeFile(src, body).then(() => render({_: ['test'], output: 'result.json', engine: 'yaml'})).then(() => fs.readFile(dest)).then(result => {
-      JSON.parse(result).should.eql({
-        foo: 1,
-        bar: {
-          boo: 2
-        }
+    return fs
+      .writeFile(src, body)
+      .then(() =>
+        render({ _: ['test'], output: 'result.json', engine: 'yaml' })
+      )
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        JSON.parse(result).should.eql({
+          foo: 1,
+          bar: {
+            boo: 2
+          }
+        });
+
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
       });
-
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
   });
 
   it('pretty', () => {
     const src = pathFn.join(hexo.base_dir, 'test.yml');
     const dest = pathFn.join(hexo.base_dir, 'result.json');
 
-    return fs.writeFile(src, body).then(() => render({_: ['test.yml'], output: 'result.json', pretty: true})).then(() => fs.readFile(dest)).then(result => {
-      result.should.eql(JSON.stringify({
-        foo: 1,
-        bar: {
-          boo: 2
-        }
-      }, null, '  '));
-
-      return Promise.all([
-        fs.unlink(src),
-        fs.unlink(dest)
-      ]);
-    });
+    return fs
+      .writeFile(src, body)
+      .then(() =>
+        render({ _: ['test.yml'], output: 'result.json', pretty: true })
+      )
+      .then(() => fs.readFile(dest))
+      .then(result => {
+        result.should.eql(
+          JSON.stringify(
+            {
+              foo: 1,
+              bar: {
+                boo: 2
+              }
+            },
+            null,
+            '  '
+          )
+        );
+
+        return Promise.all([fs.unlink(src), fs.unlink(dest)]);
+      });
   });
 });
diff --git a/test/scripts/extend/console.js b/test/scripts/extend/console.js
index 5eaa2fcd59..2d68d60d6a 100644
--- a/test/scripts/extend/console.js
+++ b/test/scripts/extend/console.js
@@ -45,7 +45,7 @@ describe('Console', () => {
     }
 
     // name, desc, options, fn
-    c.register('test', 'this is a test', {init: true}, () => {});
+    c.register('test', 'this is a test', { init: true }, () => {});
 
     c.get('test').should.exist;
     c.get('test').desc.should.eql('this is a test');
@@ -53,7 +53,7 @@ describe('Console', () => {
 
     // name, desc, options, not fn
     try {
-      c.register('test', 'this is a test', {init: true});
+      c.register('test', 'this is a test', { init: true });
     } catch (err) {
       err.should.be
         .instanceOf(TypeError)
@@ -78,7 +78,7 @@ describe('Console', () => {
     const c = new Console();
 
     c.register('test', (args, callback) => {
-      args.should.eql({foo: 'bar'});
+      args.should.eql({ foo: 'bar' });
       callback(null, 'foo');
     });
 
diff --git a/test/scripts/extend/deployer.js b/test/scripts/extend/deployer.js
index e07d37c4e1..6ee657faf5 100644
--- a/test/scripts/extend/deployer.js
+++ b/test/scripts/extend/deployer.js
@@ -34,7 +34,7 @@ describe('Deployer', () => {
     const d = new Deployer();
 
     d.register('test', (args, callback) => {
-      args.should.eql({foo: 'bar'});
+      args.should.eql({ foo: 'bar' });
       callback(null, 'foo');
     });
 
@@ -49,7 +49,7 @@ describe('Deployer', () => {
     const d = new Deployer();
 
     d.register('test', args => {
-      args.should.eql({foo: 'bar'});
+      args.should.eql({ foo: 'bar' });
       return 'foo';
     });
 
diff --git a/test/scripts/extend/filter.js b/test/scripts/extend/filter.js
index 1c9d88bf32..e3c9f3aa00 100644
--- a/test/scripts/extend/filter.js
+++ b/test/scripts/extend/filter.js
@@ -63,7 +63,9 @@ describe('Filter', () => {
 
     f.register('test', () => {}, 15);
 
-    f.list('test').map(item => item.priority).should.eql([5, 10, 15]);
+    f.list('test')
+      .map(item => item.priority)
+      .should.eql([5, 10, 15]);
   });
 
   it('unregister()', () => {
@@ -151,7 +153,7 @@ describe('Filter', () => {
 
     const filter2 = sinon.spy(data => {
       filter1.calledOnce.should.be.true;
-      data.should.eql({foo: 1});
+      data.should.eql({ foo: 1 });
       data.bar = 2;
     });
 
@@ -161,7 +163,7 @@ describe('Filter', () => {
     return f.exec('test', {}).then(data => {
       filter1.calledOnce.should.be.true;
       filter2.calledOnce.should.be.true;
-      data.should.eql({foo: 1, bar: 2});
+      data.should.eql({ foo: 1, bar: 2 });
     });
   });
 
@@ -181,17 +183,23 @@ describe('Filter', () => {
     f.register('test', filter1);
     f.register('test', filter2);
 
-    return f.exec('test', {}, {
-      args: [1, 2]
-    }).then(() => {
-      filter1.calledOnce.should.be.true;
-      filter2.calledOnce.should.be.true;
-    });
+    return f
+      .exec(
+        'test',
+        {},
+        {
+          args: [1, 2]
+        }
+      )
+      .then(() => {
+        filter1.calledOnce.should.be.true;
+        filter2.calledOnce.should.be.true;
+      });
   });
 
   it('exec() - context', () => {
     const f = new Filter();
-    const ctx = {foo: 1, bar: 2};
+    const ctx = { foo: 1, bar: 2 };
 
     const filter1 = sinon.spy(function(data) {
       this.should.eql(ctx);
@@ -204,7 +212,7 @@ describe('Filter', () => {
     f.register('test', filter1);
     f.register('test', filter2);
 
-    return f.exec('test', {}, {context: ctx}).then(() => {
+    return f.exec('test', {}, { context: ctx }).then(() => {
       filter1.calledOnce.should.be.true;
       filter2.calledOnce.should.be.true;
     });
@@ -242,14 +250,14 @@ describe('Filter', () => {
 
     const filter2 = sinon.spy(data => {
       filter1.calledOnce.should.be.true;
-      data.should.eql({foo: 1});
+      data.should.eql({ foo: 1 });
       data.bar = 2;
     });
 
     f.register('test', filter1);
     f.register('test', filter2);
 
-    f.execSync('test', {}).should.eql({foo: 1, bar: 2});
+    f.execSync('test', {}).should.eql({ foo: 1, bar: 2 });
     filter1.calledOnce.should.be.true;
     filter2.calledOnce.should.be.true;
   });
@@ -270,9 +278,13 @@ describe('Filter', () => {
     f.register('test', filter1);
     f.register('test', filter2);
 
-    f.execSync('test', {}, {
-      args: [1, 2]
-    });
+    f.execSync(
+      'test',
+      {},
+      {
+        args: [1, 2]
+      }
+    );
 
     filter1.calledOnce.should.be.true;
     filter2.calledOnce.should.be.true;
@@ -280,7 +292,7 @@ describe('Filter', () => {
 
   it('execSync() - context', () => {
     const f = new Filter();
-    const ctx = {foo: 1, bar: 2};
+    const ctx = { foo: 1, bar: 2 };
 
     const filter1 = sinon.spy(function(data) {
       this.should.eql(ctx);
@@ -293,7 +305,7 @@ describe('Filter', () => {
     f.register('test', filter1);
     f.register('test', filter2);
 
-    f.execSync('test', {}, {context: ctx});
+    f.execSync('test', {}, { context: ctx });
     filter1.calledOnce.should.be.true;
     filter2.calledOnce.should.be.true;
   });
diff --git a/test/scripts/extend/migrator.js b/test/scripts/extend/migrator.js
index a00a341945..6462c95f66 100644
--- a/test/scripts/extend/migrator.js
+++ b/test/scripts/extend/migrator.js
@@ -34,7 +34,7 @@ describe('Migrator', () => {
     const d = new Migrator();
 
     d.register('test', (args, callback) => {
-      args.should.eql({foo: 'bar'});
+      args.should.eql({ foo: 'bar' });
       callback(null, 'foo');
     });
 
@@ -49,7 +49,7 @@ describe('Migrator', () => {
     const d = new Migrator();
 
     d.register('test', args => {
-      args.should.eql({foo: 'bar'});
+      args.should.eql({ foo: 'bar' });
       return 'foo';
     });
 
diff --git a/test/scripts/extend/tag.js b/test/scripts/extend/tag.js
index 2481ea96b8..99dbee3eed 100644
--- a/test/scripts/extend/tag.js
+++ b/test/scripts/extend/tag.js
@@ -12,15 +12,19 @@ describe('Tag', () => {
 
     tag.register('test', (args, content) => args.join(' '));
 
-    return tag.render('{% test foo.bar | abcdef > fn(a, b, c) < fn() %}').then(result => {
-      result.should.eql('foo.bar | abcdef > fn(a, b, c) < fn()');
-    });
+    return tag
+      .render('{% test foo.bar | abcdef > fn(a, b, c) < fn() %}')
+      .then(result => {
+        result.should.eql('foo.bar | abcdef > fn(a, b, c) < fn()');
+      });
   });
 
   it('register() - async', () => {
     const tag = new Tag();
 
-    tag.register('test', (args, content) => Promise.resolve(args.join(' ')), {async: true});
+    tag.register('test', (args, content) => Promise.resolve(args.join(' ')), {
+      async: true
+    });
 
     return tag.render('{% test foo bar %}').then(result => {
       result.should.eql('foo bar');
@@ -30,13 +34,15 @@ describe('Tag', () => {
   it('register() - block', () => {
     const tag = new Tag();
 
-    tag.register('test', (args, content) => args.join(' ') + ' ' + content, true);
+    tag.register(
+      'test',
+      (args, content) => args.join(' ') + ' ' + content,
+      true
+    );
 
-    const str = [
-      '{% test foo bar %}',
-      'test content',
-      '{% endtest %}'
-    ].join('\n');
+    const str = ['{% test foo bar %}', 'test content', '{% endtest %}'].join(
+      '\n'
+    );
 
     return tag.render(str).then(result => {
       result.should.eql('foo bar test content');
@@ -46,13 +52,15 @@ describe('Tag', () => {
   it('register() - async block', () => {
     const tag = new Tag();
 
-    tag.register('test', (args, content) => Promise.resolve(args.join(' ') + ' ' + content), {ends: true, async: true});
+    tag.register(
+      'test',
+      (args, content) => Promise.resolve(args.join(' ') + ' ' + content),
+      { ends: true, async: true }
+    );
 
-    const str = [
-      '{% test foo bar %}',
-      'test content',
-      '{% endtest %}'
-    ].join('\n');
+    const str = ['{% test foo bar %}', 'test content', '{% endtest %}'].join(
+      '\n'
+    );
 
     return tag.render(str).then(result => {
       result.should.eql('foo bar test content');
@@ -85,10 +93,17 @@ describe('Tag', () => {
   it('register() - nested async / async test', () => {
     const tag = new Tag();
 
-    tag.register('test', (args, content) => content, {ends: true, async: true});
-    tag.register('async', (args, content) => {
-      return Promise.resolve(args.join(' ') + ' ' + content);
-    }, {ends: true, async: true});
+    tag.register('test', (args, content) => content, {
+      ends: true,
+      async: true
+    });
+    tag.register(
+      'async',
+      (args, content) => {
+        return Promise.resolve(args.join(' ') + ' ' + content);
+      },
+      { ends: true, async: true }
+    );
 
     const str = [
       '{% test %}',
@@ -110,11 +125,7 @@ describe('Tag', () => {
 
     tag.register('test', (args, content) => content, true);
 
-    const str = [
-      '{% test %}',
-      '  test content',
-      '{% endtest %}'
-    ].join('\n');
+    const str = ['{% test %}', '  test content', '{% endtest %}'].join('\n');
 
     return tag.render(str).then(result => {
       result.should.eql('test content');
@@ -124,9 +135,13 @@ describe('Tag', () => {
   it('register() - async callback', () => {
     const tag = new Tag();
 
-    tag.register('test', (args, content, callback) => {
-      callback(null, args.join(' '));
-    }, {async: true});
+    tag.register(
+      'test',
+      (args, content, callback) => {
+        callback(null, args.join(' '));
+      },
+      { async: true }
+    );
 
     return tag.render('{% test foo bar %}').then(result => {
       result.should.eql('foo bar');
@@ -168,7 +183,7 @@ describe('Tag', () => {
       return this.foo;
     });
 
-    return tag.render('{% test %}', {foo: 'bar'}).then(result => {
+    return tag.render('{% test %}', { foo: 'bar' }).then(result => {
       result.should.eql('bar');
     });
   });
diff --git a/test/scripts/extend/tag_errors.js b/test/scripts/extend/tag_errors.js
index 3322332c2a..c3d2b67d7d 100644
--- a/test/scripts/extend/tag_errors.js
+++ b/test/scripts/extend/tag_errors.js
@@ -18,13 +18,10 @@ describe('Tag Errors', () => {
   it('unknown tag', () => {
     const tag = new Tag();
 
-    const body = [
-      '{% abc %}',
-      '  content',
-      '{% endabc %}'
-    ].join('\n');
+    const body = ['{% abc %}', '  content', '{% endabc %}'].join('\n');
 
-    return tag.render(body)
+    return tag
+      .render(body)
       .then(result => {
         console.log(result);
         throw new Error('should return error');
@@ -37,16 +34,12 @@ describe('Tag Errors', () => {
   it('no closing tag 1', () => {
     const tag = new Tag();
 
-    tag.register('test',
-      (args, content) => {},
-      { ends: true });
+    tag.register('test', (args, content) => {}, { ends: true });
 
-    const body = [
-      '{% test %}',
-      '  content'
-    ].join('\n');
+    const body = ['{% test %}', '  content'].join('\n');
 
-    return tag.render(body)
+    return tag
+      .render(body)
       .then(result => {
         console.log(result);
         throw new Error('should return error');
@@ -61,17 +54,12 @@ describe('Tag Errors', () => {
   it('no closing tag 2', () => {
     const tag = new Tag();
 
-    tag.register('test',
-      (args, content) => {},
-      { ends: true });
+    tag.register('test', (args, content) => {}, { ends: true });
 
-    const body = [
-      '{% test %}',
-      '  content',
-      '{% test %}'
-    ].join('\n');
+    const body = ['{% test %}', '  content', '{% test %}'].join('\n');
 
-    return tag.render(body)
+    return tag
+      .render(body)
       .then(result => {
         console.log(result);
         throw new Error('should return error');
@@ -90,7 +78,8 @@ describe('Tag Errors', () => {
       '<code>{{docker ps -aq | map docker inspect -f "{{.Name}} {{.Mounts}}"}}</code>'
     ].join('\n');
 
-    return tag.render(body)
+    return tag
+      .render(body)
       .then(result => {
         console.log(result);
         throw new Error('should return error');
@@ -103,9 +92,7 @@ describe('Tag Errors', () => {
   it('nested curly braces', () => {
     const tag = new Tag();
 
-    tag.register('test',
-      (args, content) => {},
-      { ends: true });
+    tag.register('test', (args, content) => {}, { ends: true });
 
     const body = [
       '{% test %}',
@@ -113,7 +100,8 @@ describe('Tag Errors', () => {
       '{% endtest %}'
     ].join('\n');
 
-    return tag.render(body)
+    return tag
+      .render(body)
       .then(result => {
         console.log(result);
         throw new Error('should return error');
@@ -122,5 +110,4 @@ describe('Tag Errors', () => {
         assertNunjucksError(err, 2, 'expected variable end');
       });
   });
-
 });
diff --git a/test/scripts/filters/backtick_code_block.js b/test/scripts/filters/backtick_code_block.js
index 76a70a078f..52bc8b7fb7 100644
--- a/test/scripts/filters/backtick_code_block.js
+++ b/test/scripts/filters/backtick_code_block.js
@@ -7,16 +7,15 @@ const defaultConfig = require('../../../lib/hexo/default_config');
 describe('Backtick code block', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const codeBlock = require('../../../lib/plugins/filter/before_post_render/backtick_code_block').bind(hexo);
+  const codeBlock = require('../../../lib/plugins/filter/before_post_render/backtick_code_block').bind(
+    hexo
+  );
 
-  const code = [
-    'if (tired && night){',
-    '  sleep();',
-    '}'
-  ].join('\n');
+  const code = ['if (tired && night){', '  sleep();', '}'].join('\n');
 
   function highlight(code, options) {
-    return util.highlight(code, options || {})
+    return util
+      .highlight(code, options || {})
       .replace(/{/g, '{')
       .replace(/}/g, '}');
   }
@@ -27,13 +26,9 @@ describe('Backtick code block', () => {
   });
 
   it('disabled', () => {
-    const content = [
-      '``` js',
-      code,
-      '```'
-    ].join('\n');
+    const content = ['``` js', code, '```'].join('\n');
 
-    const data = {content};
+    const data = { content };
 
     hexo.config.highlight.enable = false;
     codeBlock(data);
@@ -41,13 +36,9 @@ describe('Backtick code block', () => {
   });
 
   it('with no config (disabled)', () => {
-    const content = [
-      '``` js',
-      code,
-      '```'
-    ].join('\n');
+    const content = ['``` js', code, '```'].join('\n');
 
-    const data = {content};
+    const data = { content };
 
     const oldConfig = hexo.config.highlight;
     delete hexo.config.highlight;
@@ -60,24 +51,18 @@ describe('Backtick code block', () => {
 
   it('default', () => {
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     codeBlock(data);
-    data.content.should.eql('<escape>' + highlight(code, {lang: 'js'}) + '</escape>');
+    data.content.should.eql(
+      '<escape>' + highlight(code, { lang: 'js' }) + '</escape>'
+    );
   });
 
   it('without language name', () => {
     const data = {
-      content: [
-        '```',
-        code,
-        '```'
-      ].join('\n')
+      content: ['```', code, '```'].join('\n')
     };
 
     const expected = highlight(code);
@@ -88,11 +73,7 @@ describe('Backtick code block', () => {
 
   it('without language name - ignore tab character', () => {
     const data = {
-      content: [
-        '``` \t',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` \t', code, '```'].join('\n')
     };
 
     const expected = highlight(code);
@@ -103,11 +84,7 @@ describe('Backtick code block', () => {
 
   it('title', () => {
     const data = {
-      content: [
-        '``` js Hello world',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js Hello world', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -121,11 +98,7 @@ describe('Backtick code block', () => {
 
   it('url', () => {
     const data = {
-      content: [
-        '``` js Hello world https://hexo.io/',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js Hello world https://hexo.io/', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -139,11 +112,9 @@ describe('Backtick code block', () => {
 
   it('link text', () => {
     const data = {
-      content: [
-        '``` js Hello world https://hexo.io/ Hexo',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js Hello world https://hexo.io/ Hexo', code, '```'].join(
+        '\n'
+      )
     };
 
     const expected = highlight(code, {
@@ -156,14 +127,15 @@ describe('Backtick code block', () => {
   });
 
   it('indent', () => {
-    const indentCode = code.split('\n').map(line => '  ' + line).join('\n');
+    const indentCode = code
+      .split('\n')
+      .map(line => '  ' + line)
+      .join('\n');
 
     const data = {
-      content: [
-        '``` js Hello world https://hexo.io/',
-        indentCode,
-        '```'
-      ].join('\n')
+      content: ['``` js Hello world https://hexo.io/', indentCode, '```'].join(
+        '\n'
+      )
     };
 
     const expected = highlight(code, {
@@ -179,11 +151,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.line_number = false;
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -200,11 +168,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'always1';
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -221,11 +185,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'inilne';
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -241,11 +201,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.line_number = true;
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -262,11 +218,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'always1';
 
     const data = {
-      content: [
-        '``` js=',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js=', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -284,11 +236,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'inline';
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -306,11 +254,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'inline';
 
     const data = {
-      content: [
-        '``` js=1',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js=1', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -328,11 +272,7 @@ describe('Backtick code block', () => {
     hexo.config.highlight.first_line_number = 'inline';
 
     const data = {
-      content: [
-        '``` js=2',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js=2', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
@@ -348,18 +288,10 @@ describe('Backtick code block', () => {
   it('tab replace', () => {
     hexo.config.highlight.tab_replace = '  ';
 
-    const code = [
-      'if (tired && night){',
-      '\tsleep();',
-      '}'
-    ].join('\n');
+    const code = ['if (tired && night){', '\tsleep();', '}'].join('\n');
 
     const data = {
-      content: [
-        '``` js',
-        code,
-        '```'
-      ].join('\n')
+      content: ['``` js', code, '```'].join('\n')
     };
 
     const expected = highlight(code, {
diff --git a/test/scripts/filters/excerpt.js b/test/scripts/filters/excerpt.js
index e3e9efe39c..e2c3f8c07d 100644
--- a/test/scripts/filters/excerpt.js
+++ b/test/scripts/filters/excerpt.js
@@ -3,14 +3,12 @@
 describe('Excerpt', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const excerpt = require('../../../lib/plugins/filter/after_post_render/excerpt').bind(hexo);
+  const excerpt = require('../../../lib/plugins/filter/after_post_render/excerpt').bind(
+    hexo
+  );
 
   it('without <!-- more -->', () => {
-    const content = [
-      'foo',
-      'bar',
-      'baz'
-    ].join('\n');
+    const content = ['foo', 'bar', 'baz'].join('\n');
 
     const data = {
       content
@@ -23,13 +21,13 @@ describe('Excerpt', () => {
   });
 
   it('with <!-- more -->', () => {
-
     _moreCases().forEach(_test);
 
     function _moreCases() {
       const template = '<!--{{lead}}more{{tail}}-->';
       // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Special_characters_meaning_in_regular_expressions
-      const spaces = ' \f\n\r\t\v\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
+      const spaces =
+        ' \f\n\r\t\v\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
       const cases = [];
       let more, lead, tail, s, e;
 
@@ -55,12 +53,7 @@ describe('Excerpt', () => {
     }
 
     function _test(more) {
-      const content = [
-        'foo',
-        'bar',
-        more,
-        'baz'
-      ].join('\n');
+      const content = ['foo', 'bar', more, 'baz'].join('\n');
 
       const data = {
         content
@@ -68,21 +61,13 @@ describe('Excerpt', () => {
 
       excerpt(data);
 
-      data.content.should.eql([
-        'foo',
-        'bar',
-        '<a id="more"></a>',
-        'baz'
-      ].join('\n'));
-
-      data.excerpt.should.eql([
-        'foo',
-        'bar'
-      ].join('\n'));
-
-      data.more.should.eql([
-        'baz'
-      ].join('\n'));
+      data.content.should.eql(
+        ['foo', 'bar', '<a id="more"></a>', 'baz'].join('\n')
+      );
+
+      data.excerpt.should.eql(['foo', 'bar'].join('\n'));
+
+      data.more.should.eql(['baz'].join('\n'));
     }
   });
 
@@ -101,31 +86,17 @@ describe('Excerpt', () => {
 
     excerpt(data);
 
-    data.content.should.eql([
-      'foo',
-      '<a id="more"></a>',
-      'bar',
-      '<!-- more -->',
-      'baz'
-    ].join('\n'));
+    data.content.should.eql(
+      ['foo', '<a id="more"></a>', 'bar', '<!-- more -->', 'baz'].join('\n')
+    );
 
-    data.excerpt.should.eql([
-      'foo'
-    ].join('\n'));
+    data.excerpt.should.eql(['foo'].join('\n'));
 
-    data.more.should.eql([
-      'bar',
-      '<!-- more -->',
-      'baz'
-    ].join('\n'));
+    data.more.should.eql(['bar', '<!-- more -->', 'baz'].join('\n'));
   });
 
   it('skip processing if post/page.excerpt is present in the front-matter', () => {
-    const content = [
-      'foo',
-      '<!-- more -->',
-      'bar'
-    ].join('\n');
+    const content = ['foo', '<!-- more -->', 'bar'].join('\n');
 
     const data = {
       content,
@@ -134,20 +105,10 @@ describe('Excerpt', () => {
 
     excerpt(data);
 
-    data.content.should.eql([
-      'foo',
-      '<!-- more -->',
-      'bar'
-    ].join('\n'));
+    data.content.should.eql(['foo', '<!-- more -->', 'bar'].join('\n'));
 
-    data.excerpt.should.eql([
-      'baz'
-    ].join('\n'));
+    data.excerpt.should.eql(['baz'].join('\n'));
 
-    data.more.should.eql([
-      'foo',
-      '<!-- more -->',
-      'bar'
-    ].join('\n'));
+    data.more.should.eql(['foo', '<!-- more -->', 'bar'].join('\n'));
   });
 });
diff --git a/test/scripts/filters/external_link.js b/test/scripts/filters/external_link.js
index 1e095d6a82..fe433d5758 100644
--- a/test/scripts/filters/external_link.js
+++ b/test/scripts/filters/external_link.js
@@ -3,17 +3,17 @@
 describe('External link', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const externalLink = require('../../../lib/plugins/filter/after_post_render/external_link').bind(hexo);
+  const externalLink = require('../../../lib/plugins/filter/after_post_render/external_link').bind(
+    hexo
+  );
 
   hexo.config.external_link = true;
   hexo.config.url = 'https://example.com';
 
   it('disabled', () => {
-    const content = 'foo'
-      + '<a href="https://hexo.io/">Hexo</a>'
-      + 'bar';
+    const content = 'foo<a href="https://hexo.io/">Hexo</a>bar';
 
-    const data = {content};
+    const data = { content };
     hexo.config.external_link = false;
 
     externalLink(data);
@@ -46,32 +46,34 @@ describe('External link', () => {
       '<a href="https://example.com">Example Domain</a>'
     ].join('\n');
 
-    const data = {content};
+    const data = { content };
 
     externalLink(data);
 
-    data.content.should.eql([
-      '# External link test',
-      '1. External link',
-      '<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
-      '2. External link with "rel" Attribute',
-      '<a rel="external noopener" href="https://hexo.io/" target="_blank">Hexo</a>',
-      '<a href="https://hexo.io/" target="_blank" rel="external noopener">Hexo</a>',
-      '<a rel="noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
-      '<a href="https://hexo.io/" target="_blank" rel="noopenner">Hexo</a>',
-      '<a rel="external noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
-      '<a href="https://hexo.io/" target="_blank" rel="external noopenner">Hexo</a>',
-      '3. External link with Other Attributes',
-      '<a class="img" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
-      '<a href="https://hexo.io/" target="_blank" rel="noopener" class="img">Hexo</a>',
-      '4. Internal link',
-      '<a href="/archives/foo.html">Link</a>',
-      '5. Ignore links have "target" attribute',
-      '<a href="https://hexo.io/" target="_blank">Hexo</a>',
-      '6. Ignore links don\'t have "href" attribute',
-      '<a>Anchor</a>',
-      '7. Ignore links whose hostname is same as config',
-      '<a href="https://example.com">Example Domain</a>'
-    ].join('\n'));
+    data.content.should.eql(
+      [
+        '# External link test',
+        '1. External link',
+        '<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
+        '2. External link with "rel" Attribute',
+        '<a rel="external noopener" href="https://hexo.io/" target="_blank">Hexo</a>',
+        '<a href="https://hexo.io/" target="_blank" rel="external noopener">Hexo</a>',
+        '<a rel="noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
+        '<a href="https://hexo.io/" target="_blank" rel="noopenner">Hexo</a>',
+        '<a rel="external noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
+        '<a href="https://hexo.io/" target="_blank" rel="external noopenner">Hexo</a>',
+        '3. External link with Other Attributes',
+        '<a class="img" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
+        '<a href="https://hexo.io/" target="_blank" rel="noopener" class="img">Hexo</a>',
+        '4. Internal link',
+        '<a href="/archives/foo.html">Link</a>',
+        '5. Ignore links have "target" attribute',
+        '<a href="https://hexo.io/" target="_blank">Hexo</a>',
+        '6. Ignore links don\'t have "href" attribute',
+        '<a>Anchor</a>',
+        '7. Ignore links whose hostname is same as config',
+        '<a href="https://example.com">Example Domain</a>'
+      ].join('\n')
+    );
   });
 });
diff --git a/test/scripts/filters/i18n_locals.js b/test/scripts/filters/i18n_locals.js
index 75fe3ed9f0..fc92812b53 100644
--- a/test/scripts/filters/i18n_locals.js
+++ b/test/scripts/filters/i18n_locals.js
@@ -3,7 +3,9 @@
 describe('i18n locals', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const i18nFilter = require('../../../lib/plugins/filter/template_locals/i18n').bind(hexo);
+  const i18nFilter = require('../../../lib/plugins/filter/template_locals/i18n').bind(
+    hexo
+  );
   const theme = hexo.theme;
   const i18n = theme.i18n;
 
diff --git a/test/scripts/filters/meta_generator.js b/test/scripts/filters/meta_generator.js
index 03814a4e63..42443141be 100644
--- a/test/scripts/filters/meta_generator.js
+++ b/test/scripts/filters/meta_generator.js
@@ -3,7 +3,9 @@
 describe('Meta Generator', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const metaGenerator = require('../../../lib/plugins/filter/meta_generator').bind(hexo);
+  const metaGenerator = require('../../../lib/plugins/filter/meta_generator').bind(
+    hexo
+  );
   const cheerio = require('cheerio');
 
   it('default', () => {
@@ -12,7 +14,9 @@ describe('Meta Generator', () => {
 
     const $ = cheerio.load(result);
     $('meta[name="generator"]').length.should.eql(1);
-    $('meta[name="generator"]').attr('content').should.eql(`Hexo ${hexo.version}`);
+    $('meta[name="generator"]')
+      .attr('content')
+      .should.eql(`Hexo ${hexo.version}`);
   });
 
   it('disable meta_generator', () => {
@@ -25,8 +29,7 @@ describe('Meta Generator', () => {
   });
 
   it('no duplicate generator tag', () => {
-    const content = '<head><link>'
-      + '<meta name="generator" content="foo"></head>';
+    const content = '<head><link><meta name="generator" content="foo"></head>';
     hexo.config.meta_generator = true;
     const result = metaGenerator(content);
 
@@ -35,34 +38,32 @@ describe('Meta Generator', () => {
   });
 
   it('ignore empty head tag', () => {
-    const content = '<head></head>'
-      + '<head><link></head>'
-      + '<head></head>';
+    const content = '<head></head><head><link></head><head></head>';
     hexo.config.meta_generator = true;
     const result = metaGenerator(content);
 
     const $ = cheerio.load(result);
     $('meta[name="generator"]').length.should.eql(1);
 
-    const expected = '<head></head>'
-    + '<head><link><meta name="generator" content="Hexo ' + hexo.version + '"></head>'
-    + '<head></head>';
+    const expected =
+      '<head></head><head><link><meta name="generator" content="Hexo ' +
+      hexo.version +
+      '"></head><head></head>';
     result.should.eql(expected);
   });
 
   it('apply to first non-empty head tag only', () => {
-    const content = '<head></head>'
-      + '<head><link></head>'
-      + '<head><link></head>';
+    const content = '<head></head><head><link></head><head><link></head>';
     hexo.config.meta_generator = true;
     const result = metaGenerator(content);
 
     const $ = cheerio.load(result);
     $('meta[name="generator"]').length.should.eql(1);
 
-    const expected = '<head></head>'
-    + '<head><link><meta name="generator" content="Hexo ' + hexo.version + '"></head>'
-    + '<head><link></head>';
+    const expected =
+      '<head></head><head><link><meta name="generator" content="Hexo ' +
+      hexo.version +
+      '"></head><head><link></head>';
     result.should.eql(expected);
   });
 });
diff --git a/test/scripts/filters/new_post_path.js b/test/scripts/filters/new_post_path.js
index cfe99e265f..be240047dd 100644
--- a/test/scripts/filters/new_post_path.js
+++ b/test/scripts/filters/new_post_path.js
@@ -11,7 +11,9 @@ const NEW_POST_NAME = ':title.md';
 describe('new_post_path', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo(pathFn.join(__dirname, 'new_post_path_test'));
-  const newPostPath = require('../../../lib/plugins/filter/new_post_path').bind(hexo);
+  const newPostPath = require('../../../lib/plugins/filter/new_post_path').bind(
+    hexo
+  );
   const sourceDir = hexo.source_dir;
   const draftDir = pathFn.join(sourceDir, '_drafts');
   const postDir = pathFn.join(sourceDir, '_posts');
@@ -24,39 +26,44 @@ describe('new_post_path', () => {
 
   after(() => fs.rmdir(hexo.base_dir));
 
-  it('page layout + path', () => newPostPath({
-    path: 'foo',
-    layout: 'page'
-  }).then(target => {
-    target.should.eql(pathFn.join(sourceDir, 'foo.md'));
-  }));
-
-  it('draft layout + path', () => newPostPath({
-    path: 'foo',
-    layout: 'draft'
-  }).then(target => {
-    target.should.eql(pathFn.join(draftDir, 'foo.md'));
-  }));
-
-  it('default layout + path', () => newPostPath({
-    path: 'foo'
-  }).then(target => {
-    target.should.eql(pathFn.join(postDir, 'foo.md'));
-  }));
-
-  it('page layout + slug', () => newPostPath({
-    slug: 'foo',
-    layout: 'page'
-  }).then(target => {
-    target.should.eql(pathFn.join(sourceDir, 'foo', 'index.md'));
-  }));
-
-  it('draft layout + slug', () => newPostPath({
-    slug: 'foo',
-    layout: 'draft'
-  }).then(target => {
-    target.should.eql(pathFn.join(draftDir, 'foo.md'));
-  }));
+  it('page layout + path', () =>
+    newPostPath({
+      path: 'foo',
+      layout: 'page'
+    }).then(target => {
+      target.should.eql(pathFn.join(sourceDir, 'foo.md'));
+    }));
+
+  it('draft layout + path', () =>
+    newPostPath({
+      path: 'foo',
+      layout: 'draft'
+    }).then(target => {
+      target.should.eql(pathFn.join(draftDir, 'foo.md'));
+    }));
+
+  it('default layout + path', () =>
+    newPostPath({
+      path: 'foo'
+    }).then(target => {
+      target.should.eql(pathFn.join(postDir, 'foo.md'));
+    }));
+
+  it('page layout + slug', () =>
+    newPostPath({
+      slug: 'foo',
+      layout: 'page'
+    }).then(target => {
+      target.should.eql(pathFn.join(sourceDir, 'foo', 'index.md'));
+    }));
+
+  it('draft layout + slug', () =>
+    newPostPath({
+      slug: 'foo',
+      layout: 'draft'
+    }).then(target => {
+      target.should.eql(pathFn.join(draftDir, 'foo.md'));
+    }));
 
   it('default layout + slug', () => {
     const now = moment();
@@ -65,7 +72,9 @@ describe('new_post_path', () => {
     return newPostPath({
       slug: 'foo'
     }).then(target => {
-      target.should.eql(pathFn.join(postDir, now.format('YYYY-MM-DD') + '-foo.md'));
+      target.should.eql(
+        pathFn.join(postDir, now.format('YYYY-MM-DD') + '-foo.md')
+      );
       hexo.config.new_post_name = NEW_POST_NAME;
     });
   });
@@ -78,7 +87,9 @@ describe('new_post_path', () => {
       slug: 'foo',
       date: date.toDate()
     }).then(target => {
-      target.should.eql(pathFn.join(postDir, date.format('YYYY-M-D') + '-foo.md'));
+      target.should.eql(
+        pathFn.join(postDir, date.format('YYYY-M-D') + '-foo.md')
+      );
       hexo.config.new_post_name = NEW_POST_NAME;
     });
   });
@@ -107,49 +118,63 @@ describe('new_post_path', () => {
     });
   });
 
-  it('don\'t append extension name if existed', () => newPostPath({
-    path: 'foo.markdown'
-  }).then(target => {
-    target.should.eql(pathFn.join(postDir, 'foo.markdown'));
-  }));
+  it("don't append extension name if existed", () =>
+    newPostPath({
+      path: 'foo.markdown'
+    }).then(target => {
+      target.should.eql(pathFn.join(postDir, 'foo.markdown'));
+    }));
 
   it('replace existing files', () => {
     const filename = 'test.md';
     const path = pathFn.join(postDir, filename);
 
-    return fs.writeFile(path, '').then(() => newPostPath({
-      path: filename
-    }, true)).then(target => {
-      target.should.eql(path);
-      return fs.unlink(path);
-    });
+    return fs
+      .writeFile(path, '')
+      .then(() =>
+        newPostPath(
+          {
+            path: filename
+          },
+          true
+        )
+      )
+      .then(target => {
+        target.should.eql(path);
+        return fs.unlink(path);
+      });
   });
 
   it('rename if target existed', () => {
-    const filename = [
-      'test.md',
-      'test-1.md',
-      'test-2.md',
-      'test-foo.md'
-    ];
+    const filename = ['test.md', 'test-1.md', 'test-2.md', 'test-foo.md'];
 
     const path = filename.map(item => pathFn.join(postDir, item));
 
-    return Promise.map(path, item => fs.writeFile(item, '')).then(() => newPostPath({
-      path: filename[0]
-    })).then(target => {
-      target.should.eql(pathFn.join(postDir, 'test-3.md'));
-      return path;
-    }).map(item => fs.unlink(item));
+    return Promise.map(path, item => fs.writeFile(item, ''))
+      .then(() =>
+        newPostPath({
+          path: filename[0]
+        })
+      )
+      .then(target => {
+        target.should.eql(pathFn.join(postDir, 'test-3.md'));
+        return path;
+      })
+      .map(item => fs.unlink(item));
   });
 
   it('data is required', () => {
     const errorCallback = sinon.spy(err => {
-      err.should.have.property('message', 'Either data.path or data.slug is required!');
+      err.should.have.property(
+        'message',
+        'Either data.path or data.slug is required!'
+      );
     });
 
-    return newPostPath().catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return newPostPath()
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 });
diff --git a/test/scripts/filters/post_permalink.js b/test/scripts/filters/post_permalink.js
index 4b5ba16f7f..23c17623f6 100644
--- a/test/scripts/filters/post_permalink.js
+++ b/test/scripts/filters/post_permalink.js
@@ -7,7 +7,9 @@ const PERMALINK = ':year/:month/:day/:title/';
 describe('post_permalink', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const postPermalink = require('../../../lib/plugins/filter/post_permalink').bind(hexo);
+  const postPermalink = require('../../../lib/plugins/filter/post_permalink').bind(
+    hexo
+  );
   const Post = hexo.model('Post');
   let post;
 
@@ -16,16 +18,22 @@ describe('post_permalink', () => {
   before(() => {
     let id;
 
-    return hexo.init().then(() => Post.insert({
-      source: 'foo.md',
-      slug: 'foo',
-      date: moment('2014-01-02')
-    })).then(post => {
-      id = post._id;
-      return post.setCategories(['foo', 'bar']);
-    }).then(() => {
-      post = Post.findById(id);
-    });
+    return hexo
+      .init()
+      .then(() =>
+        Post.insert({
+          source: 'foo.md',
+          slug: 'foo',
+          date: moment('2014-01-02')
+        })
+      )
+      .then(post => {
+        id = post._id;
+        return post.setCategories(['foo', 'bar']);
+      })
+      .then(() => {
+        post = Post.findById(id);
+      });
   });
 
   it('default', () => {
diff --git a/test/scripts/filters/render_post.js b/test/scripts/filters/render_post.js
index 815bfa87a3..be6eb2d31e 100644
--- a/test/scripts/filters/render_post.js
+++ b/test/scripts/filters/render_post.js
@@ -7,9 +7,15 @@ describe('Render post', () => {
   const hexo = new Hexo();
   const Post = hexo.model('Post');
   const Page = hexo.model('Page');
-  const renderPost = require('../../../lib/plugins/filter/before_generate/render_post').bind(hexo);
+  const renderPost = require('../../../lib/plugins/filter/before_generate/render_post').bind(
+    hexo
+  );
 
-  before(() => hexo.init().then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked'))));
+  before(() =>
+    hexo
+      .init()
+      .then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked')))
+  );
 
   it('post', () => {
     let id;
@@ -18,15 +24,17 @@ describe('Render post', () => {
       source: 'foo.md',
       slug: 'foo',
       _content: fixture.content
-    }).then(post => {
-      id = post._id;
-      return renderPost();
-    }).then(() => {
-      const post = Post.findById(id);
-      post.content.trim().should.eql(fixture.expected);
+    })
+      .then(post => {
+        id = post._id;
+        return renderPost();
+      })
+      .then(() => {
+        const post = Post.findById(id);
+        post.content.trim().should.eql(fixture.expected);
 
-      return post.remove();
-    });
+        return post.remove();
+      });
   });
 
   it('page', () => {
@@ -36,15 +44,17 @@ describe('Render post', () => {
       source: 'foo.md',
       path: 'foo.html',
       _content: fixture.content
-    }).then(page => {
-      id = page._id;
-      return renderPost();
-    }).then(() => {
-      const page = Page.findById(id);
-      page.content.trim().should.eql(fixture.expected);
+    })
+      .then(page => {
+        id = page._id;
+        return renderPost();
+      })
+      .then(() => {
+        const page = Page.findById(id);
+        page.content.trim().should.eql(fixture.expected);
 
-      return page.remove();
-    });
+        return page.remove();
+      });
   });
 
   it('use data variables', () => {
@@ -54,15 +64,16 @@ describe('Render post', () => {
       source: 'foo.md',
       path: 'foo.html',
       _content: '<p>Hello {{site.data.foo.name}}</p>'
-    }).then(page => {
-      id = page._id;
-      return renderPost({foo: {name: 'Hexo'}});
-    }).then(() => {
-      const page = Page.findById(id);
-      page.content.trim().should.eql('<p>Hello Hexo</p>');
+    })
+      .then(page => {
+        id = page._id;
+        return renderPost({ foo: { name: 'Hexo' } });
+      })
+      .then(() => {
+        const page = Page.findById(id);
+        page.content.trim().should.eql('<p>Hello Hexo</p>');
 
-      return page.remove();
-    });
+        return page.remove();
+      });
   });
-
 });
diff --git a/test/scripts/filters/save_database.js b/test/scripts/filters/save_database.js
index 641cdfb8b5..20ecbab1e6 100644
--- a/test/scripts/filters/save_database.js
+++ b/test/scripts/filters/save_database.js
@@ -6,23 +6,29 @@ const Promise = require('bluebird');
 describe('Save database', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const saveDatabase = Promise.method(require('../../../lib/plugins/filter/before_exit/save_database')).bind(hexo);
+  const saveDatabase = Promise.method(
+    require('../../../lib/plugins/filter/before_exit/save_database')
+  ).bind(hexo);
   const dbPath = hexo.database.options.path;
 
   it('default', () => {
     hexo.env.init = true;
 
-    return saveDatabase().then(() => fs.exists(dbPath)).then(exist => {
-      exist.should.be.true;
-      return fs.unlink(dbPath);
-    });
+    return saveDatabase()
+      .then(() => fs.exists(dbPath))
+      .then(exist => {
+        exist.should.be.true;
+        return fs.unlink(dbPath);
+      });
   });
 
   it('do nothing if hexo is not initialized', () => {
     hexo.env.init = false;
 
-    return saveDatabase().then(() => fs.exists(dbPath)).then(exist => {
-      exist.should.be.false;
-    });
+    return saveDatabase()
+      .then(() => fs.exists(dbPath))
+      .then(exist => {
+        exist.should.be.false;
+      });
   });
 });
diff --git a/test/scripts/filters/titlecase.js b/test/scripts/filters/titlecase.js
index 38e3ae43f0..1cde9251f9 100644
--- a/test/scripts/filters/titlecase.js
+++ b/test/scripts/filters/titlecase.js
@@ -3,11 +3,13 @@
 describe('Titlecase', () => {
   const Hexo = require('../../../lib/hexo');
   const hexo = new Hexo();
-  const titlecase = require('../../../lib/plugins/filter/before_post_render/titlecase').bind(hexo);
+  const titlecase = require('../../../lib/plugins/filter/before_post_render/titlecase').bind(
+    hexo
+  );
 
   it('disabled', () => {
     const title = 'Today is a good day';
-    const data = {title};
+    const data = { title };
     hexo.config.titlecase = false;
 
     titlecase(data);
@@ -16,7 +18,7 @@ describe('Titlecase', () => {
 
   it('enabled', () => {
     const title = 'Today is a good day';
-    const data = {title};
+    const data = { title };
     hexo.config.titlecase = true;
 
     titlecase(data);
diff --git a/test/scripts/generators/asset.js b/test/scripts/generators/asset.js
index fa1f75cc8c..3e1de8a0c8 100644
--- a/test/scripts/generators/asset.js
+++ b/test/scripts/generators/asset.js
@@ -7,7 +7,7 @@ const testUtil = require('../../util');
 
 describe('asset', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'asset_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'asset_test'), { silent: true });
   const generator = require('../../../lib/plugins/generator/asset').bind(hexo);
   const Asset = hexo.model('Asset');
 
@@ -27,19 +27,19 @@ describe('asset', () => {
     const content = 'foo: bar';
 
     return Promise.all([
-      Asset.insert({_id: path, path}),
+      Asset.insert({ _id: path, path }),
       fs.writeFile(source, content)
-    ]).then(() => generator(hexo.locals)).then(data => {
-      data[0].path.should.eql('test.json');
-      data[0].data.modified.should.be.true;
-
-      return data[0].data.data().then(result => {
-        result.should.eql('{"foo":"bar"}');
-      });
-    }).then(() => Promise.all([
-      Asset.removeById(path),
-      fs.unlink(source)
-    ]));
+    ])
+      .then(() => generator(hexo.locals))
+      .then(data => {
+        data[0].path.should.eql('test.json');
+        data[0].data.modified.should.be.true;
+
+        return data[0].data.data().then(result => {
+          result.should.eql('{"foo":"bar"}');
+        });
+      })
+      .then(() => Promise.all([Asset.removeById(path), fs.unlink(source)]));
   });
 
   it('not renderable', () => {
@@ -48,17 +48,17 @@ describe('asset', () => {
     const content = 'test content';
 
     return Promise.all([
-      Asset.insert({_id: path, path}),
+      Asset.insert({ _id: path, path }),
       fs.writeFile(source, content)
-    ]).then(() => generator(hexo.locals)).then(data => {
-      data[0].path.should.eql(path);
-      data[0].data.modified.should.be.true;
-
-      return checkStream(data[0].data.data(), content);
-    }).then(() => Promise.all([
-      Asset.removeById(path),
-      fs.unlink(source)
-    ]));
+    ])
+      .then(() => generator(hexo.locals))
+      .then(data => {
+        data[0].path.should.eql(path);
+        data[0].data.modified.should.be.true;
+
+        return checkStream(data[0].data.data(), content);
+      })
+      .then(() => Promise.all([Asset.removeById(path), fs.unlink(source)]));
   });
 
   it('skip render', () => {
@@ -67,17 +67,17 @@ describe('asset', () => {
     const content = 'foo: bar';
 
     return Promise.all([
-      Asset.insert({_id: path, path, renderable: false}),
+      Asset.insert({ _id: path, path, renderable: false }),
       fs.writeFile(source, content)
-    ]).then(() => generator(hexo.locals)).then(data => {
-      data[0].path.should.eql('test.yml');
-      data[0].data.modified.should.be.true;
-
-      return checkStream(data[0].data.data(), content);
-    }).then(() => Promise.all([
-      Asset.removeById(path),
-      fs.unlink(source)
-    ]));
+    ])
+      .then(() => generator(hexo.locals))
+      .then(data => {
+        data[0].path.should.eql('test.yml');
+        data[0].data.modified.should.be.true;
+
+        return checkStream(data[0].data.data(), content);
+      })
+      .then(() => Promise.all([Asset.removeById(path), fs.unlink(source)]));
   });
 
   it('remove assets which does not exist', () => {
@@ -86,25 +86,26 @@ describe('asset', () => {
     return Asset.insert({
       _id: path,
       path
-    }).then(() => generator(hexo.locals)).then(() => {
-      should.not.exist(Asset.findById(path));
-    });
+    })
+      .then(() => generator(hexo.locals))
+      .then(() => {
+        should.not.exist(Asset.findById(path));
+      });
   });
 
-  it('don\'t remove extension name', () => {
+  it("don't remove extension name", () => {
     const path = 'test.min.js';
     const source = pathFn.join(hexo.base_dir, path);
 
     return Promise.all([
-      Asset.insert({_id: path, path}),
+      Asset.insert({ _id: path, path }),
       fs.writeFile(source, '')
-    ]).then(() => generator(hexo.locals)).then(data => {
-      data[0].path.should.eql('test.min.js');
+    ])
+      .then(() => generator(hexo.locals))
+      .then(data => {
+        data[0].path.should.eql('test.min.js');
 
-      return Promise.all([
-        Asset.removeById(path),
-        fs.unlink(source)
-      ]);
-    });
+        return Promise.all([Asset.removeById(path), fs.unlink(source)]);
+      });
   });
 });
diff --git a/test/scripts/generators/page.js b/test/scripts/generators/page.js
index 27105df15c..7447706733 100644
--- a/test/scripts/generators/page.js
+++ b/test/scripts/generators/page.js
@@ -4,49 +4,63 @@ const Promise = require('bluebird');
 
 describe('page', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(__dirname, {silent: true});
+  const hexo = new Hexo(__dirname, { silent: true });
   const Page = hexo.model('Page');
-  const generator = Promise.method(require('../../../lib/plugins/generator/page').bind(hexo));
+  const generator = Promise.method(
+    require('../../../lib/plugins/generator/page').bind(hexo)
+  );
 
   function locals() {
     hexo.locals.invalidate();
     return hexo.locals.toObject();
   }
 
-  it('default layout', () => Page.insert({
-    source: 'foo',
-    path: 'bar'
-  }).then(page => generator(locals()).then(data => {
-    page.__page = true;
-
-    data.should.eql([
-      {
-        path: page.path,
-        layout: ['page', 'post', 'index'],
-        data: page
-      }
-    ]);
-
-    return page.remove();
-  })));
-
-  it('custom layout', () => Page.insert({
-    source: 'foo',
-    path: 'bar',
-    layout: 'photo'
-  }).then(page => generator(locals()).then(data => {
-    data[0].layout.should.eql(['photo', 'page', 'post', 'index']);
-
-    return page.remove();
-  })));
+  it('default layout', () =>
+    Page.insert({
+      source: 'foo',
+      path: 'bar'
+    }).then(page =>
+      generator(locals()).then(data => {
+        page.__page = true;
 
-  [false, 'false', 'off'].forEach(layout => {
-    it('layout = ' + JSON.stringify(layout), () => Page.insert({
+        data.should.eql([
+          {
+            path: page.path,
+            layout: ['page', 'post', 'index'],
+            data: page
+          }
+        ]);
+
+        return page.remove();
+      })
+    ));
+
+  it('custom layout', () =>
+    Page.insert({
       source: 'foo',
       path: 'bar',
-      layout
-    }).then(page => generator(locals()).then(data => {
-      should.not.exist(data[0].layout);
-    }).finally(() => page.remove())));
+      layout: 'photo'
+    }).then(page =>
+      generator(locals()).then(data => {
+        data[0].layout.should.eql(['photo', 'page', 'post', 'index']);
+
+        return page.remove();
+      })
+    ));
+
+  [false, 'false', 'off'].forEach(layout => {
+    it('layout = ' + JSON.stringify(layout), () =>
+      Page.insert({
+        source: 'foo',
+        path: 'bar',
+        layout
+      }).then(page =>
+        generator(locals())
+          .then(data => {
+            should.not.exist(data[0].layout);
+          })
+          .finally(() => page.remove())
+      )
+    );
   });
 });
diff --git a/test/scripts/generators/post.js b/test/scripts/generators/post.js
index 6a0bf67fbc..b8d4ae6b43 100644
--- a/test/scripts/generators/post.js
+++ b/test/scripts/generators/post.js
@@ -4,9 +4,11 @@ const Promise = require('bluebird');
 
 describe('post', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(__dirname, {silent: true});
+  const hexo = new Hexo(__dirname, { silent: true });
   const Post = hexo.model('Post');
-  const generator = Promise.method(require('../../../lib/plugins/generator/post').bind(hexo));
+  const generator = Promise.method(
+    require('../../../lib/plugins/generator/post').bind(hexo)
+  );
 
   hexo.config.permalink = ':title/';
 
@@ -17,53 +19,69 @@ describe('post', () => {
 
   before(() => hexo.init());
 
-  it('default layout', () => Post.insert({
-    source: 'foo',
-    slug: 'bar'
-  }).then(post => generator(locals()).then(data => {
-    post.__post = true;
+  it('default layout', () =>
+    Post.insert({
+      source: 'foo',
+      slug: 'bar'
+    }).then(post =>
+      generator(locals()).then(data => {
+        post.__post = true;
 
-    data.should.eql([
-      {
-        path: 'bar/',
-        layout: ['post', 'page', 'index'],
-        data: post
-      }
-    ]);
+        data.should.eql([
+          {
+            path: 'bar/',
+            layout: ['post', 'page', 'index'],
+            data: post
+          }
+        ]);
 
-    return post.remove();
-  })));
+        return post.remove();
+      })
+    ));
 
-  it('custom layout', () => Post.insert({
-    source: 'foo',
-    slug: 'bar',
-    layout: 'photo'
-  }).then(post => generator(locals()).then(data => {
-    data[0].layout.should.eql(['photo', 'post', 'page', 'index']);
+  it('custom layout', () =>
+    Post.insert({
+      source: 'foo',
+      slug: 'bar',
+      layout: 'photo'
+    }).then(post =>
+      generator(locals()).then(data => {
+        data[0].layout.should.eql(['photo', 'post', 'page', 'index']);
 
-    return post.remove();
-  })));
+        return post.remove();
+      })
+    ));
 
-  it('layout disabled', () => Post.insert({
-    source: 'foo',
-    slug: 'bar',
-    layout: false
-  }).then(post => generator(locals()).then(data => {
-    should.not.exist(data[0].layout);
+  it('layout disabled', () =>
+    Post.insert({
+      source: 'foo',
+      slug: 'bar',
+      layout: false
+    }).then(post =>
+      generator(locals()).then(data => {
+        should.not.exist(data[0].layout);
 
-    return post.remove();
-  })));
+        return post.remove();
+      })
+    ));
 
-  it('prev/next post', () => Post.insert([
-    {source: 'foo', slug: 'foo', date: 1e8},
-    {source: 'bar', slug: 'bar', date: 1e8 + 1},
-    {source: 'baz', slug: 'baz', date: 1e8 - 1}
-  ]).then(posts => generator(locals()).then(data => {
-    should.not.exist(data[0].data.prev);
-    data[0].data.next._id.should.eq(posts[0]._id);
-    data[1].data.prev._id.should.eq(posts[1]._id);
-    data[1].data.next._id.should.eq(posts[2]._id);
-    data[2].data.prev._id.should.eq(posts[0]._id);
-    should.not.exist(data[2].data.next);
-  }).thenReturn(posts)).map(post => post.remove()));
+  it('prev/next post', () =>
+    Post.insert([
+      { source: 'foo', slug: 'foo', date: 1e8 },
+      { source: 'bar', slug: 'bar', date: 1e8 + 1 },
+      { source: 'baz', slug: 'baz', date: 1e8 - 1 }
+    ])
+      .then(posts =>
+        generator(locals())
+          .then(data => {
+            should.not.exist(data[0].data.prev);
+            data[0].data.next._id.should.eq(posts[0]._id);
+            data[1].data.prev._id.should.eq(posts[1]._id);
+            data[1].data.next._id.should.eq(posts[2]._id);
+            data[2].data.prev._id.should.eq(posts[0]._id);
+            should.not.exist(data[2].data.next);
+          })
+          .thenReturn(posts)
+      )
+      .map(post => post.remove()));
 });
diff --git a/test/scripts/helpers/css.js b/test/scripts/helpers/css.js
index f9c8ba4b5f..f808239c7e 100644
--- a/test/scripts/helpers/css.js
+++ b/test/scripts/helpers/css.js
@@ -30,7 +30,12 @@ describe('css', () => {
   });
 
   it('an array', () => {
-    assertResult(css(['foo', 'bar', 'baz']), '/foo.css', '/bar.css', '/baz.css');
+    assertResult(
+      css(['foo', 'bar', 'baz']),
+      '/foo.css',
+      '/bar.css',
+      '/baz.css'
+    );
   });
 
   it('multiple strings', () => {
@@ -38,10 +43,20 @@ describe('css', () => {
   });
 
   it('multiple arrays', () => {
-    assertResult(css(['foo', 'bar'], ['baz']), '/foo.css', '/bar.css', '/baz.css');
+    assertResult(
+      css(['foo', 'bar'], ['baz']),
+      '/foo.css',
+      '/bar.css',
+      '/baz.css'
+    );
   });
 
   it('mixed', () => {
-    assertResult(css(['foo', 'bar'], 'baz'), '/foo.css', '/bar.css', '/baz.css');
+    assertResult(
+      css(['foo', 'bar'], 'baz'),
+      '/foo.css',
+      '/bar.css',
+      '/baz.css'
+    );
   });
 });
diff --git a/test/scripts/helpers/date.js b/test/scripts/helpers/date.js
index d45bed0298..c741104ffb 100644
--- a/test/scripts/helpers/date.js
+++ b/test/scripts/helpers/date.js
@@ -42,17 +42,29 @@ describe('date', () => {
 
     // page.lang
     ctx.page.lang = 'zh-tw';
-    date(Date.now(), 'MMM D YYYY').should.eql(moment().locale('zh-tw').format('MMM D YYYY'));
+    date(Date.now(), 'MMM D YYYY').should.eql(
+      moment()
+        .locale('zh-tw')
+        .format('MMM D YYYY')
+    );
     ctx.page.lang = '';
 
     // config.language
     ctx.config.language = 'ja';
-    date(Date.now(), 'MMM D YYYY').should.eql(moment().locale('ja').format('MMM D YYYY'));
+    date(Date.now(), 'MMM D YYYY').should.eql(
+      moment()
+        .locale('ja')
+        .format('MMM D YYYY')
+    );
     ctx.config.language = '';
 
     // timezone
     ctx.config.timezone = 'UTC';
-    date(Date.now(), 'LLL').should.eql(moment().tz('UTC').format('LLL'));
+    date(Date.now(), 'LLL').should.eql(
+      moment()
+        .tz('UTC')
+        .format('LLL')
+    );
     ctx.config.timezone = '';
   });
 
@@ -118,17 +130,29 @@ describe('date', () => {
 
     // page.lang
     ctx.page.lang = 'zh-tw';
-    time(Date.now(), 'A H:mm').should.eql(moment().locale('zh-tw').format('A H:mm'));
+    time(Date.now(), 'A H:mm').should.eql(
+      moment()
+        .locale('zh-tw')
+        .format('A H:mm')
+    );
     ctx.page.lang = '';
 
     // config.language
     ctx.config.language = 'ja';
-    time(Date.now(), 'A H:mm').should.eql(moment().locale('ja').format('A H:mm'));
+    time(Date.now(), 'A H:mm').should.eql(
+      moment()
+        .locale('ja')
+        .format('A H:mm')
+    );
     ctx.config.language = '';
 
     // timezone
     ctx.config.timezone = 'UTC';
-    time().should.eql(moment().tz('UTC').format(hexo.config.time_format));
+    time().should.eql(
+      moment()
+        .tz('UTC')
+        .format(hexo.config.time_format)
+    );
     ctx.config.timezone = '';
   });
 
@@ -141,7 +165,8 @@ describe('date', () => {
     };
 
     const fullDate = dateHelper.full_date.bind(ctx);
-    const fullDateFormat = hexo.config.date_format + ' ' + hexo.config.time_format;
+    const fullDateFormat =
+      hexo.config.date_format + ' ' + hexo.config.time_format;
 
     // now
     fullDate().should.eql(moment().format(fullDateFormat));
@@ -152,25 +177,41 @@ describe('date', () => {
 
     // date
     fullDate(new Date()).should.eql(moment().format(fullDateFormat));
-    fullDate(new Date(), 'MMM-D-YYYY').should.eql(moment().format('MMM-D-YYYY'));
+    fullDate(new Date(), 'MMM-D-YYYY').should.eql(
+      moment().format('MMM-D-YYYY')
+    );
 
     // number
     fullDate(Date.now()).should.eql(moment().format(fullDateFormat));
-    fullDate(Date.now(), 'MMM-D-YYYY').should.eql(moment().format('MMM-D-YYYY'));
+    fullDate(Date.now(), 'MMM-D-YYYY').should.eql(
+      moment().format('MMM-D-YYYY')
+    );
 
     // page.lang
     ctx.page.lang = 'zh-tw';
-    fullDate(Date.now(), 'LLL').should.eql(moment().locale('zh-tw').format('LLL'));
+    fullDate(Date.now(), 'LLL').should.eql(
+      moment()
+        .locale('zh-tw')
+        .format('LLL')
+    );
     ctx.page.lang = '';
 
     // config.language
     ctx.config.language = 'ja';
-    fullDate(Date.now(), 'LLL').should.eql(moment().locale('ja').format('LLL'));
+    fullDate(Date.now(), 'LLL').should.eql(
+      moment()
+        .locale('ja')
+        .format('LLL')
+    );
     ctx.config.language = '';
 
     // timezone
     ctx.config.timezone = 'UTC';
-    fullDate().should.eql(moment().tz('UTC').format(fullDateFormat));
+    fullDate().should.eql(
+      moment()
+        .tz('UTC')
+        .format(fullDateFormat)
+    );
     ctx.config.timezone = '';
   });
 
@@ -186,7 +227,13 @@ describe('date', () => {
     function result(date, format) {
       date = date || new Date();
       format = format || hexo.config.date_format;
-      return '<time datetime="' + moment(date).toISOString() + '">' + moment(date).format(format) + '</time>';
+      return (
+        '<time datetime="' +
+        moment(date).toISOString() +
+        '">' +
+        moment(date).format(format) +
+        '</time>'
+      );
     }
 
     function check(date, format) {
@@ -211,17 +258,41 @@ describe('date', () => {
 
     // page.lang
     ctx.page.lang = 'zh-tw';
-    timeTag(Date.now(), 'LLL').should.eql('<time datetime="' + moment().toISOString() + '">' + moment().locale('zh-tw').format('LLL') + '</time>');
+    timeTag(Date.now(), 'LLL').should.eql(
+      '<time datetime="' +
+        moment().toISOString() +
+        '">' +
+        moment()
+          .locale('zh-tw')
+          .format('LLL') +
+        '</time>'
+    );
     ctx.page.lang = '';
 
     // config.language
     ctx.config.language = 'ja';
-    timeTag(Date.now(), 'LLL').should.eql('<time datetime="' + moment().toISOString() + '">' + moment().locale('ja').format('LLL') + '</time>');
+    timeTag(Date.now(), 'LLL').should.eql(
+      '<time datetime="' +
+        moment().toISOString() +
+        '">' +
+        moment()
+          .locale('ja')
+          .format('LLL') +
+        '</time>'
+    );
     ctx.config.language = '';
 
     // timezone
     ctx.config.timezone = 'UTC';
-    timeTag(Date.now(), 'LLL').should.eql('<time datetime="' + moment().toISOString() + '">' + moment().tz('UTC').format('LLL') + '</time>');
+    timeTag(Date.now(), 'LLL').should.eql(
+      '<time datetime="' +
+        moment().toISOString() +
+        '">' +
+        moment()
+          .tz('UTC')
+          .format('LLL') +
+        '</time>'
+    );
     ctx.config.timezone = '';
   });
 });
diff --git a/test/scripts/helpers/debug.js b/test/scripts/helpers/debug.js
index 5bc8b8e4fd..fb6041d974 100644
--- a/test/scripts/helpers/debug.js
+++ b/test/scripts/helpers/debug.js
@@ -20,9 +20,15 @@ describe('debug', () => {
   });
 
   it('inspect deep object', () => {
-    const obj = { baz: { thud: 'narf', dur: { foo: 'bar', baz: { bang: 'zoom' } } } };
-    debug.inspectObject(obj, {depth: 2}).should.not.eql(inspect(obj, {depth: 5}));
-    debug.inspectObject(obj, {depth: 5}).should.eql(inspect(obj, {depth: 5}));
+    const obj = {
+      baz: { thud: 'narf', dur: { foo: 'bar', baz: { bang: 'zoom' } } }
+    };
+    debug
+      .inspectObject(obj, { depth: 2 })
+      .should.not.eql(inspect(obj, { depth: 5 }));
+    debug
+      .inspectObject(obj, { depth: 5 })
+      .should.eql(inspect(obj, { depth: 5 }));
   });
 
   it('log should print to console', () => {
diff --git a/test/scripts/helpers/favicon_tag.js b/test/scripts/helpers/favicon_tag.js
index 17b5f6dc67..af5422af99 100644
--- a/test/scripts/helpers/favicon_tag.js
+++ b/test/scripts/helpers/favicon_tag.js
@@ -13,6 +13,8 @@ describe('favicon_tag', () => {
   const favicon = require('../../../lib/plugins/helper/favicon_tag').bind(ctx);
 
   it('path', () => {
-    favicon('favicon.ico').should.eql('<link rel="shortcut icon" href="/favicon.ico">');
+    favicon('favicon.ico').should.eql(
+      '<link rel="shortcut icon" href="/favicon.ico">'
+    );
   });
 });
diff --git a/test/scripts/helpers/feed_tag.js b/test/scripts/helpers/feed_tag.js
index 5d2b7b2f7c..06981b0310 100644
--- a/test/scripts/helpers/feed_tag.js
+++ b/test/scripts/helpers/feed_tag.js
@@ -13,14 +13,20 @@ describe('feed_tag', () => {
   const feed = require('../../../lib/plugins/helper/feed_tag').bind(ctx);
 
   it('path', () => {
-    feed('atom.xml').should.eql('<link rel="alternate" href="/atom.xml" title="Hexo">');
+    feed('atom.xml').should.eql(
+      '<link rel="alternate" href="/atom.xml" title="Hexo">'
+    );
   });
 
   it('title', () => {
-    feed('atom.xml', {title: 'RSS Feed'}).should.eql('<link rel="alternate" href="/atom.xml" title="RSS Feed">');
+    feed('atom.xml', { title: 'RSS Feed' }).should.eql(
+      '<link rel="alternate" href="/atom.xml" title="RSS Feed">'
+    );
   });
 
   it('type', () => {
-    feed('rss.xml', {type: 'rss'}).should.eql('<link rel="alternate" href="/rss.xml" title="Hexo">');
+    feed('rss.xml', { type: 'rss' }).should.eql(
+      '<link rel="alternate" href="/rss.xml" title="Hexo">'
+    );
   });
 });
diff --git a/test/scripts/helpers/fragment_cache.js b/test/scripts/helpers/fragment_cache.js
index 5a816cb0cf..bfc508b909 100644
--- a/test/scripts/helpers/fragment_cache.js
+++ b/test/scripts/helpers/fragment_cache.js
@@ -3,13 +3,13 @@
 describe('fragment_cache', () => {
   const fragment_cache = require('../../../lib/plugins/helper/fragment_cache')();
 
-  fragment_cache.call({cache: true}, 'foo', () => 123);
+  fragment_cache.call({ cache: true }, 'foo', () => 123);
 
   it('cache enabled', () => {
-    fragment_cache.call({cache: true}, 'foo').should.eql(123);
+    fragment_cache.call({ cache: true }, 'foo').should.eql(123);
   });
 
   it('cache disabled', () => {
-    fragment_cache.call({cache: false}, 'foo', () => 456).should.eql(456);
+    fragment_cache.call({ cache: false }, 'foo', () => 456).should.eql(456);
   });
 });
diff --git a/test/scripts/helpers/gravatar.js b/test/scripts/helpers/gravatar.js
index 8b577e97af..bf5541617f 100644
--- a/test/scripts/helpers/gravatar.js
+++ b/test/scripts/helpers/gravatar.js
@@ -6,7 +6,10 @@ describe('gravatar', () => {
   const gravatar = require('../../../lib/plugins/helper/gravatar');
 
   function md5(str) {
-    return crypto.createHash('md5').update(str).digest('hex');
+    return crypto
+      .createHash('md5')
+      .update(str)
+      .digest('hex');
   }
 
   const email = 'abc@abc.com';
@@ -17,7 +20,9 @@ describe('gravatar', () => {
   });
 
   it('size', () => {
-    gravatar(email, 100).should.eql('https://www.gravatar.com/avatar/' + hash + '?s=100');
+    gravatar(email, 100).should.eql(
+      'https://www.gravatar.com/avatar/' + hash + '?s=100'
+    );
   });
 
   it('options', () => {
@@ -25,6 +30,8 @@ describe('gravatar', () => {
       s: 200,
       r: 'pg',
       d: 'mm'
-    }).should.eql('https://www.gravatar.com/avatar/' + hash + '?s=200&r=pg&d=mm');
+    }).should.eql(
+      'https://www.gravatar.com/avatar/' + hash + '?s=200&r=pg&d=mm'
+    );
   });
 });
diff --git a/test/scripts/helpers/image_tag.js b/test/scripts/helpers/image_tag.js
index 293c8e020f..60bd6d218b 100644
--- a/test/scripts/helpers/image_tag.js
+++ b/test/scripts/helpers/image_tag.js
@@ -13,21 +13,26 @@ describe('image_tag', () => {
   const img = require('../../../lib/plugins/helper/image_tag').bind(ctx);
 
   it('path', () => {
-    img('https://hexo.io/image.jpg').should.eql('<img src="https://hexo.io/image.jpg">');
+    img('https://hexo.io/image.jpg').should.eql(
+      '<img src="https://hexo.io/image.jpg">'
+    );
   });
 
   it('class (string)', () => {
-    img('https://hexo.io/image.jpg', {class: 'foo'})
-      .should.eql('<img src="https://hexo.io/image.jpg" class="foo">');
+    img('https://hexo.io/image.jpg', { class: 'foo' }).should.eql(
+      '<img src="https://hexo.io/image.jpg" class="foo">'
+    );
   });
 
   it('class (array)', () => {
-    img('https://hexo.io/image.jpg', {class: ['foo', 'bar']})
-      .should.eql('<img src="https://hexo.io/image.jpg" class="foo bar">');
+    img('https://hexo.io/image.jpg', { class: ['foo', 'bar'] }).should.eql(
+      '<img src="https://hexo.io/image.jpg" class="foo bar">'
+    );
   });
 
   it('alt', () => {
-    img('https://hexo.io/image.jpg', {alt: 'Image caption'})
-      .should.eql('<img src="https://hexo.io/image.jpg" alt="Image caption">');
+    img('https://hexo.io/image.jpg', { alt: 'Image caption' }).should.eql(
+      '<img src="https://hexo.io/image.jpg" alt="Image caption">'
+    );
   });
 });
diff --git a/test/scripts/helpers/is.js b/test/scripts/helpers/is.js
index 404fa4dfee..4da7a713b8 100644
--- a/test/scripts/helpers/is.js
+++ b/test/scripts/helpers/is.js
@@ -6,73 +6,96 @@ describe('is', () => {
   const is = require('../../../lib/plugins/helper/is');
 
   it('is_current', () => {
-    is.current.call({path: 'index.html', config: hexo.config}).should.be.true;
-    is.current.call({path: 'tags/index.html', config: hexo.config}).should.be.false;
-    is.current.call({path: 'index.html', config: hexo.config}, '/').should.be.true;
-    is.current.call({path: 'index.html', config: hexo.config}, 'index.html').should.be.true;
-    is.current.call({path: 'tags/index.html', config: hexo.config}, '/').should.be.false;
-    is.current.call({path: 'tags/index.html', config: hexo.config}, '/index.html').should.be.false;
-    is.current.call({path: 'index.html', config: hexo.config}, '/', true).should.be.true;
-    is.current.call({path: 'index.html', config: hexo.config}, '/index.html', true).should.be.true;
-    is.current.call({path: 'foo/bar', config: hexo.config}, 'foo', true).should.be.false;
-    is.current.call({path: 'foo/bar', config: hexo.config}, 'foo').should.be.true;
-    is.current.call({path: 'foo/bar', config: hexo.config}, 'foo/bar').should.be.true;
-    is.current.call({path: 'foo/bar', config: hexo.config}, 'foo/baz').should.be.false;
+    is.current.call({ path: 'index.html', config: hexo.config }).should.be.true;
+    is.current.call({ path: 'tags/index.html', config: hexo.config }).should.be
+      .false;
+    is.current.call({ path: 'index.html', config: hexo.config }, '/').should.be
+      .true;
+    is.current.call({ path: 'index.html', config: hexo.config }, 'index.html')
+      .should.be.true;
+    is.current.call({ path: 'tags/index.html', config: hexo.config }, '/')
+      .should.be.false;
+    is.current.call(
+      { path: 'tags/index.html', config: hexo.config },
+      '/index.html'
+    ).should.be.false;
+    is.current.call({ path: 'index.html', config: hexo.config }, '/', true)
+      .should.be.true;
+    is.current.call(
+      { path: 'index.html', config: hexo.config },
+      '/index.html',
+      true
+    ).should.be.true;
+    is.current.call({ path: 'foo/bar', config: hexo.config }, 'foo', true)
+      .should.be.false;
+    is.current.call({ path: 'foo/bar', config: hexo.config }, 'foo').should.be
+      .true;
+    is.current.call({ path: 'foo/bar', config: hexo.config }, 'foo/bar').should
+      .be.true;
+    is.current.call({ path: 'foo/bar', config: hexo.config }, 'foo/baz').should
+      .be.false;
   });
 
   it('is_home', () => {
-    is.home.call({page: {__index: true}}).should.be.true;
-    is.home.call({page: {}}).should.be.false;
+    is.home.call({ page: { __index: true } }).should.be.true;
+    is.home.call({ page: {} }).should.be.false;
   });
 
   it('is_post', () => {
-    is.post.call({page: {__post: true}}).should.be.true;
-    is.post.call({page: {}}).should.be.false;
+    is.post.call({ page: { __post: true } }).should.be.true;
+    is.post.call({ page: {} }).should.be.false;
   });
 
   it('is_page', () => {
-    is.page.call({page: {__page: true}}).should.be.true;
-    is.page.call({page: {}}).should.be.false;
+    is.page.call({ page: { __page: true } }).should.be.true;
+    is.page.call({ page: {} }).should.be.false;
   });
 
   it('is_archive', () => {
-    is.archive.call({page: {}}).should.be.false;
-    is.archive.call({page: {archive: true}}).should.be.true;
-    is.archive.call({page: {archive: false}}).should.be.false;
+    is.archive.call({ page: {} }).should.be.false;
+    is.archive.call({ page: { archive: true } }).should.be.true;
+    is.archive.call({ page: { archive: false } }).should.be.false;
   });
 
   it('is_year', () => {
-    is.year.call({page: {}}).should.be.false;
-    is.year.call({page: {archive: true}}).should.be.false;
-    is.year.call({page: {archive: true, year: 2014}}).should.be.true;
-    is.year.call({page: {archive: true, year: 2014}}, 2014).should.be.true;
-    is.year.call({page: {archive: true, year: 2014}}, 2015).should.be.false;
-    is.year.call({page: {archive: true, year: 2014, month: 10}}).should.be.true;
+    is.year.call({ page: {} }).should.be.false;
+    is.year.call({ page: { archive: true } }).should.be.false;
+    is.year.call({ page: { archive: true, year: 2014 } }).should.be.true;
+    is.year.call({ page: { archive: true, year: 2014 } }, 2014).should.be.true;
+    is.year.call({ page: { archive: true, year: 2014 } }, 2015).should.be.false;
+    is.year.call({ page: { archive: true, year: 2014, month: 10 } }).should.be
+      .true;
   });
 
   it('is_month', () => {
-    is.month.call({page: {}}).should.be.false;
-    is.month.call({page: {archive: true}}).should.be.false;
-    is.month.call({page: {archive: true, year: 2014}}).should.be.false;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}).should.be.true;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}, 2014, 10).should.be.true;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}, 2015, 10).should.be.false;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}, 2014, 12).should.be.false;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}, 10).should.be.true;
-    is.month.call({page: {archive: true, year: 2014, month: 10}}, 12).should.be.false;
+    is.month.call({ page: {} }).should.be.false;
+    is.month.call({ page: { archive: true } }).should.be.false;
+    is.month.call({ page: { archive: true, year: 2014 } }).should.be.false;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }).should.be
+      .true;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }, 2014, 10)
+      .should.be.true;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }, 2015, 10)
+      .should.be.false;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }, 2014, 12)
+      .should.be.false;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }, 10).should
+      .be.true;
+    is.month.call({ page: { archive: true, year: 2014, month: 10 } }, 12).should
+      .be.false;
   });
 
   it('is_category', () => {
-    is.category.call({page: {category: 'foo'}}).should.be.true;
-    is.category.call({page: {category: 'foo'}}, 'foo').should.be.true;
-    is.category.call({page: {category: 'foo'}}, 'bar').should.be.false;
-    is.category.call({page: {}}).should.be.false;
+    is.category.call({ page: { category: 'foo' } }).should.be.true;
+    is.category.call({ page: { category: 'foo' } }, 'foo').should.be.true;
+    is.category.call({ page: { category: 'foo' } }, 'bar').should.be.false;
+    is.category.call({ page: {} }).should.be.false;
   });
 
   it('is_tag', () => {
-    is.tag.call({page: {tag: 'foo'}}).should.be.true;
-    is.tag.call({page: {tag: 'foo'}}, 'foo').should.be.true;
-    is.tag.call({page: {tag: 'foo'}}, 'bar').should.be.false;
-    is.tag.call({page: {}}).should.be.false;
+    is.tag.call({ page: { tag: 'foo' } }).should.be.true;
+    is.tag.call({ page: { tag: 'foo' } }, 'foo').should.be.true;
+    is.tag.call({ page: { tag: 'foo' } }, 'bar').should.be.false;
+    is.tag.call({ page: {} }).should.be.false;
   });
 });
diff --git a/test/scripts/helpers/link_to.js b/test/scripts/helpers/link_to.js
index 0f8f3c7c82..ba80b6c164 100644
--- a/test/scripts/helpers/link_to.js
+++ b/test/scripts/helpers/link_to.js
@@ -13,35 +13,44 @@ describe('link_to', () => {
   const linkTo = require('../../../lib/plugins/helper/link_to').bind(ctx);
 
   it('path', () => {
-    linkTo('https://hexo.io/').should.eql('<a href="https://hexo.io/" title="hexo.io">hexo.io</a>');
+    linkTo('https://hexo.io/').should.eql(
+      '<a href="https://hexo.io/" title="hexo.io">hexo.io</a>'
+    );
   });
 
   it('title', () => {
-    linkTo('https://hexo.io/', 'Hexo').should.eql('<a href="https://hexo.io/" title="Hexo">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo').should.eql(
+      '<a href="https://hexo.io/" title="Hexo">Hexo</a>'
+    );
   });
 
   it('external (boolean)', () => {
-    linkTo('https://hexo.io/', 'Hexo', true)
-      .should.eql('<a href="https://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo', true).should.eql(
+      '<a href="https://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>'
+    );
   });
 
   it('external (object)', () => {
-    linkTo('https://hexo.io/', 'Hexo', {external: true})
-      .should.eql('<a href="https://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo', { external: true }).should.eql(
+      '<a href="https://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a>'
+    );
   });
 
   it('class (string)', () => {
-    linkTo('https://hexo.io/', 'Hexo', {class: 'foo'})
-      .should.eql('<a href="https://hexo.io/" title="Hexo" class="foo">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo', { class: 'foo' }).should.eql(
+      '<a href="https://hexo.io/" title="Hexo" class="foo">Hexo</a>'
+    );
   });
 
   it('class (array)', () => {
-    linkTo('https://hexo.io/', 'Hexo', {class: ['foo', 'bar']})
-      .should.eql('<a href="https://hexo.io/" title="Hexo" class="foo bar">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo', { class: ['foo', 'bar'] }).should.eql(
+      '<a href="https://hexo.io/" title="Hexo" class="foo bar">Hexo</a>'
+    );
   });
 
   it('id', () => {
-    linkTo('https://hexo.io/', 'Hexo', {id: 'foo'})
-      .should.eql('<a href="https://hexo.io/" title="Hexo" id="foo">Hexo</a>');
+    linkTo('https://hexo.io/', 'Hexo', { id: 'foo' }).should.eql(
+      '<a href="https://hexo.io/" title="Hexo" id="foo">Hexo</a>'
+    );
   });
 });
diff --git a/test/scripts/helpers/list_archives.js b/test/scripts/helpers/list_archives.js
index d9c8990b9e..46bc9506c3 100644
--- a/test/scripts/helpers/list_archives.js
+++ b/test/scripts/helpers/list_archives.js
@@ -12,32 +12,43 @@ describe('list_archives', () => {
 
   ctx.url_for = require('../../../lib/plugins/helper/url_for').bind(ctx);
 
-  const listArchives = require('../../../lib/plugins/helper/list_archives').bind(ctx);
+  const listArchives = require('../../../lib/plugins/helper/list_archives').bind(
+    ctx
+  );
 
   function resetLocals() {
     hexo.locals.invalidate();
     ctx.site = hexo.locals.toObject();
   }
 
-  before(() => hexo.init().then(() => Post.insert([
-    {source: 'foo', slug: 'foo', date: new Date(2014, 1, 2)},
-    {source: 'bar', slug: 'bar', date: new Date(2013, 5, 6)},
-    {source: 'baz', slug: 'baz', date: new Date(2013, 9, 10)},
-    {source: 'boo', slug: 'boo', date: new Date(2013, 5, 8)}
-  ])).then(() => {
-    resetLocals();
-  }));
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert([
+          { source: 'foo', slug: 'foo', date: new Date(2014, 1, 2) },
+          { source: 'bar', slug: 'bar', date: new Date(2013, 5, 6) },
+          { source: 'baz', slug: 'baz', date: new Date(2013, 9, 10) },
+          { source: 'boo', slug: 'boo', date: new Date(2013, 5, 8) }
+        ])
+      )
+      .then(() => {
+        resetLocals();
+      })
+  );
 
   it('default', () => {
     const result = listArchives();
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('type: yearly', () => {
@@ -45,12 +56,14 @@ describe('list_archives', () => {
       type: 'yearly'
     });
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/">2014</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/">2013</a><span class="archive-list-count">3</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/">2014</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/">2013</a><span class="archive-list-count">3</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('format', () => {
@@ -58,13 +71,15 @@ describe('list_archives', () => {
       format: 'YYYY/M'
     });
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">2014/2</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">2013/10</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">2013/6</a><span class="archive-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">2014/2</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">2013/10</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">2013/6</a><span class="archive-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('style: false', () => {
@@ -72,11 +87,13 @@ describe('list_archives', () => {
       style: false
     });
 
-    result.should.eql([
-      '<a class="archive-link" href="/archives/2014/02/">February 2014<span class="archive-count">1</span></a>',
-      '<a class="archive-link" href="/archives/2013/10/">October 2013<span class="archive-count">1</span></a>',
-      '<a class="archive-link" href="/archives/2013/06/">June 2013<span class="archive-count">2</span></a>'
-    ].join(', '));
+    result.should.eql(
+      [
+        '<a class="archive-link" href="/archives/2014/02/">February 2014<span class="archive-count">1</span></a>',
+        '<a class="archive-link" href="/archives/2013/10/">October 2013<span class="archive-count">1</span></a>',
+        '<a class="archive-link" href="/archives/2013/06/">June 2013<span class="archive-count">2</span></a>'
+      ].join(', ')
+    );
   });
 
   it('show_count', () => {
@@ -84,13 +101,15 @@ describe('list_archives', () => {
       show_count: false
     });
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('order', () => {
@@ -98,13 +117,15 @@ describe('list_archives', () => {
       order: 1
     });
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">2</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">1</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">2</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">October 2013</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">1</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('transform', () => {
@@ -114,13 +135,15 @@ describe('list_archives', () => {
       }
     });
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">FEBRUARY 2014</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">OCTOBER 2013</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">JUNE 2013</a><span class="archive-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">FEBRUARY 2014</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">OCTOBER 2013</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">JUNE 2013</a><span class="archive-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('separator', () => {
@@ -129,11 +152,13 @@ describe('list_archives', () => {
       separator: ''
     });
 
-    result.should.eql([
-      '<a class="archive-link" href="/archives/2014/02/">February 2014<span class="archive-count">1</span></a>',
-      '<a class="archive-link" href="/archives/2013/10/">October 2013<span class="archive-count">1</span></a>',
-      '<a class="archive-link" href="/archives/2013/06/">June 2013<span class="archive-count">2</span></a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="archive-link" href="/archives/2014/02/">February 2014<span class="archive-count">1</span></a>',
+        '<a class="archive-link" href="/archives/2013/10/">October 2013<span class="archive-count">1</span></a>',
+        '<a class="archive-link" href="/archives/2013/06/">June 2013<span class="archive-count">2</span></a>'
+      ].join('')
+    );
   });
 
   it('class', () => {
@@ -141,13 +166,15 @@ describe('list_archives', () => {
       class: 'test'
     });
 
-    result.should.eql([
-      '<ul class="test-list">',
-      '<li class="test-list-item"><a class="test-list-link" href="/archives/2014/02/">February 2014</a><span class="test-list-count">1</span></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/archives/2013/10/">October 2013</a><span class="test-list-count">1</span></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/archives/2013/06/">June 2013</a><span class="test-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="test-list">',
+        '<li class="test-list-item"><a class="test-list-link" href="/archives/2014/02/">February 2014</a><span class="test-list-count">1</span></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/archives/2013/10/">October 2013</a><span class="test-list-count">1</span></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/archives/2013/06/">June 2013</a><span class="test-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('page.lang', () => {
@@ -155,13 +182,15 @@ describe('list_archives', () => {
     const result = listArchives();
     ctx.page.lang = '';
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">二月 2014</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">十月 2013</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">六月 2013</a><span class="archive-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">二月 2014</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">十月 2013</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">六月 2013</a><span class="archive-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('config.language', () => {
@@ -169,13 +198,15 @@ describe('list_archives', () => {
     const result = listArchives();
     ctx.config.language = '';
 
-    result.should.eql([
-      '<ul class="archive-list">',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">Februar 2014</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">Oktober 2013</a><span class="archive-list-count">1</span></li>',
-      '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">Juni 2013</a><span class="archive-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="archive-list">',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">Februar 2014</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/10/">Oktober 2013</a><span class="archive-list-count">1</span></li>',
+        '<li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">Juni 2013</a><span class="archive-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('timezone');
diff --git a/test/scripts/helpers/list_categories.js b/test/scripts/helpers/list_categories.js
index f145eac462..119924dda7 100644
--- a/test/scripts/helpers/list_categories.js
+++ b/test/scripts/helpers/list_categories.js
@@ -14,67 +14,82 @@ describe('list_categories', () => {
 
   ctx.url_for = require('../../../lib/plugins/helper/url_for').bind(ctx);
 
-  const listCategories = require('../../../lib/plugins/helper/list_categories').bind(ctx);
-
-  before(() => hexo.init().then(() => Post.insert([
-    {source: 'foo', slug: 'foo'},
-    {source: 'bar', slug: 'bar'},
-    {source: 'baz', slug: 'baz'},
-    {source: 'boo', slug: 'boo'},
-    {source: 'bat', slug: 'bat'}
-  ])).then(posts => Promise.each([
-    ['baz'],
-    ['baz', 'bar'],
-    ['foo'],
-    ['baz'],
-    ['bat', ['baz', 'bar']]
-  ], (cats, i) => posts[i].setCategories(cats))).then(() => {
-    hexo.locals.invalidate();
-    ctx.site = hexo.locals.toObject();
-    ctx.page = ctx.site.posts.data[1];
-  }));
+  const listCategories = require('../../../lib/plugins/helper/list_categories').bind(
+    ctx
+  );
+
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert([
+          { source: 'foo', slug: 'foo' },
+          { source: 'bar', slug: 'bar' },
+          { source: 'baz', slug: 'baz' },
+          { source: 'boo', slug: 'boo' },
+          { source: 'bat', slug: 'bat' }
+        ])
+      )
+      .then(posts =>
+        Promise.each(
+          [['baz'], ['baz', 'bar'], ['foo'], ['baz'], ['bat', ['baz', 'bar']]],
+          (cats, i) => posts[i].setCategories(cats)
+        )
+      )
+      .then(() => {
+        hexo.locals.invalidate();
+        ctx.site = hexo.locals.toObject();
+        ctx.page = ctx.site.posts.data[1];
+      })
+  );
 
   it('default', () => {
     const result = listCategories();
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('specified collection', () => {
-    const result = listCategories(Category.find({
-      parent: {$exists: false}
-    }));
-
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    const result = listCategories(
+      Category.find({
+        parent: { $exists: false }
+      })
+    );
+
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('style: false', () => {
@@ -82,12 +97,14 @@ describe('list_categories', () => {
       style: false
     });
 
-    result.should.eql([
-      '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>',
-      '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>',
-      '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>',
-      '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
-    ].join(', '));
+    result.should.eql(
+      [
+        '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>',
+        '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>',
+        '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>',
+        '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
+      ].join(', ')
+    );
   });
 
   it('show_count: false', () => {
@@ -95,24 +112,26 @@ describe('list_categories', () => {
       show_count: false
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">bar</a>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">bar</a>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('class', () => {
@@ -120,24 +139,26 @@ describe('list_categories', () => {
       class: 'test'
     });
 
-    result.should.eql([
-      '<ul class="test-list">',
-      '<li class="test-list-item">',
-      '<a class="test-list-link" href="/categories/bat/">bat</a><span class="test-list-count">1</span>',
-      '</li>',
-      '<li class="test-list-item">',
-      '<a class="test-list-link" href="/categories/baz/">baz</a><span class="test-list-count">4</span>',
-      '<ul class="test-list-child">',
-      '<li class="test-list-item">',
-      '<a class="test-list-link" href="/categories/baz/bar/">bar</a><span class="test-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="test-list-item">',
-      '<a class="test-list-link" href="/categories/foo/">foo</a><span class="test-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="test-list">',
+        '<li class="test-list-item">',
+        '<a class="test-list-link" href="/categories/bat/">bat</a><span class="test-list-count">1</span>',
+        '</li>',
+        '<li class="test-list-item">',
+        '<a class="test-list-link" href="/categories/baz/">baz</a><span class="test-list-count">4</span>',
+        '<ul class="test-list-child">',
+        '<li class="test-list-item">',
+        '<a class="test-list-link" href="/categories/baz/bar/">bar</a><span class="test-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="test-list-item">',
+        '<a class="test-list-link" href="/categories/foo/">foo</a><span class="test-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('depth', () => {
@@ -145,19 +166,21 @@ describe('list_categories', () => {
       depth: 1
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('orderby', () => {
@@ -165,24 +188,26 @@ describe('list_categories', () => {
       orderby: 'length'
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('order', () => {
@@ -190,24 +215,26 @@ describe('list_categories', () => {
       order: -1
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('transform', () => {
@@ -217,24 +244,26 @@ describe('list_categories', () => {
       }
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">BAT</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/">BAZ</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">BAR</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">FOO</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">BAT</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/">BAZ</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">BAR</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">FOO</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('separator (blank)', () => {
@@ -243,12 +272,14 @@ describe('list_categories', () => {
       separator: ''
     });
 
-    result.should.eql([
-      '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>',
-      '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>',
-      '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>',
-      '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>',
+        '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>',
+        '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>',
+        '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
+      ].join('')
+    );
   });
 
   it('separator (non-blank)', () => {
@@ -257,12 +288,14 @@ describe('list_categories', () => {
       separator: '|'
     });
 
-    result.should.eql([
-      '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>|',
-      '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>|',
-      '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>|',
-      '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="category-link" href="/categories/bat/">bat<span class="category-count">1</span></a>|',
+        '<a class="category-link" href="/categories/baz/">baz<span class="category-count">4</span></a>|',
+        '<a class="category-link" href="/categories/baz/bar/">bar<span class="category-count">2</span></a>|',
+        '<a class="category-link" href="/categories/foo/">foo<span class="category-count">1</span></a>'
+      ].join('')
+    );
   });
 
   it('children-indicator', () => {
@@ -270,24 +303,26 @@ describe('list_categories', () => {
       children_indicator: 'has-children'
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item has-children">',
-      '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item has-children">',
+        '<a class="category-list-link" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('show-current', () => {
@@ -295,23 +330,25 @@ describe('list_categories', () => {
       show_current: true
     });
 
-    result.should.eql([
-      '<ul class="category-list">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link current" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
-      '<ul class="category-list-child">',
-      '<li class="category-list-item">',
-      '<a class="category-list-link current" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
-      '</li>',
-      '</ul>',
-      '</li>',
-      '<li class="category-list-item">',
-      '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
-      '</li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="category-list">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/bat/">bat</a><span class="category-list-count">1</span>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link current" href="/categories/baz/">baz</a><span class="category-list-count">4</span>',
+        '<ul class="category-list-child">',
+        '<li class="category-list-item">',
+        '<a class="category-list-link current" href="/categories/baz/bar/">bar</a><span class="category-list-count">2</span>',
+        '</li>',
+        '</ul>',
+        '</li>',
+        '<li class="category-list-item">',
+        '<a class="category-list-link" href="/categories/foo/">foo</a><span class="category-list-count">1</span>',
+        '</li>',
+        '</ul>'
+      ].join('')
+    );
   });
 });
diff --git a/test/scripts/helpers/list_posts.js b/test/scripts/helpers/list_posts.js
index 032c1a7133..18882a69b1 100644
--- a/test/scripts/helpers/list_posts.js
+++ b/test/scripts/helpers/list_posts.js
@@ -15,37 +15,50 @@ describe('list_posts', () => {
 
   hexo.config.permalink = ':title/';
 
-  before(() => hexo.init().then(() => Post.insert([
-    {source: 'foo', slug: 'foo', title: 'Its', date: 1e8},
-    {source: 'bar', slug: 'bar', title: 'Chemistry', date: 1e8 + 1},
-    {source: 'baz', slug: 'baz', title: 'Bitch', date: 1e8 - 1}
-  ])).then(() => {
-    hexo.locals.invalidate();
-    ctx.site = hexo.locals.toObject();
-  }));
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert([
+          { source: 'foo', slug: 'foo', title: 'Its', date: 1e8 },
+          { source: 'bar', slug: 'bar', title: 'Chemistry', date: 1e8 + 1 },
+          { source: 'baz', slug: 'baz', title: 'Bitch', date: 1e8 - 1 }
+        ])
+      )
+      .then(() => {
+        hexo.locals.invalidate();
+        ctx.site = hexo.locals.toObject();
+      })
+  );
 
   it('default', () => {
     const result = listPosts();
 
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('specified collection', () => {
-    const result = listPosts(Post.find({
-      title: 'Its'
-    }));
-
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
-      '</ul>'
-    ].join(''));
+    const result = listPosts(
+      Post.find({
+        title: 'Its'
+      })
+    );
+
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('style: false', () => {
@@ -53,11 +66,13 @@ describe('list_posts', () => {
       style: false
     });
 
-    result.should.eql([
-      '<a class="post-link" href="/bar/">Chemistry</a>',
-      '<a class="post-link" href="/foo/">Its</a>',
-      '<a class="post-link" href="/baz/">Bitch</a>'
-    ].join(', '));
+    result.should.eql(
+      [
+        '<a class="post-link" href="/bar/">Chemistry</a>',
+        '<a class="post-link" href="/foo/">Its</a>',
+        '<a class="post-link" href="/baz/">Bitch</a>'
+      ].join(', ')
+    );
   });
 
   it('orderby', () => {
@@ -65,13 +80,15 @@ describe('list_posts', () => {
       orderby: 'title'
     });
 
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('order', () => {
@@ -79,13 +96,15 @@ describe('list_posts', () => {
       order: 1
     });
 
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/baz/">Bitch</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('class', () => {
@@ -93,13 +112,15 @@ describe('list_posts', () => {
       class: 'test'
     });
 
-    result.should.eql([
-      '<ul class="test-list">',
-      '<li class="test-list-item"><a class="test-list-link" href="/bar/">Chemistry</a></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/foo/">Its</a></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/baz/">Bitch</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="test-list">',
+        '<li class="test-list-item"><a class="test-list-link" href="/bar/">Chemistry</a></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/foo/">Its</a></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/baz/">Bitch</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('transform', () => {
@@ -109,13 +130,15 @@ describe('list_posts', () => {
       }
     });
 
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/bar/">CHEMISTRY</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">ITS</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/baz/">BITCH</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/bar/">CHEMISTRY</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">ITS</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/baz/">BITCH</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('separator', () => {
@@ -124,11 +147,13 @@ describe('list_posts', () => {
       separator: ''
     });
 
-    result.should.eql([
-      '<a class="post-link" href="/bar/">Chemistry</a>',
-      '<a class="post-link" href="/foo/">Its</a>',
-      '<a class="post-link" href="/baz/">Bitch</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="post-link" href="/bar/">Chemistry</a>',
+        '<a class="post-link" href="/foo/">Its</a>',
+        '<a class="post-link" href="/baz/">Bitch</a>'
+      ].join('')
+    );
   });
 
   it('amount', () => {
@@ -136,11 +161,13 @@ describe('list_posts', () => {
       amount: 2
     });
 
-    result.should.eql([
-      '<ul class="post-list">',
-      '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
-      '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="post-list">',
+        '<li class="post-list-item"><a class="post-list-link" href="/bar/">Chemistry</a></li>',
+        '<li class="post-list-item"><a class="post-list-link" href="/foo/">Its</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 });
diff --git a/test/scripts/helpers/list_tags.js b/test/scripts/helpers/list_tags.js
index ccfce8a39b..605e1eb6e8 100644
--- a/test/scripts/helpers/list_tags.js
+++ b/test/scripts/helpers/list_tags.js
@@ -16,45 +16,59 @@ describe('list_tags', () => {
 
   const listTags = require('../../../lib/plugins/helper/list_tags').bind(ctx);
 
-  before(() => hexo.init().then(() => Post.insert([
-    {source: 'foo', slug: 'foo'},
-    {source: 'bar', slug: 'bar'},
-    {source: 'baz', slug: 'baz'},
-    {source: 'boo', slug: 'boo'}
-  ])).then(posts => // TODO: Warehouse needs to add a mutex lock when writing data to avoid data sync problem
-    Promise.each([
-      ['foo'],
-      ['baz'],
-      ['baz'],
-      ['bar']
-    ], (tags, i) => posts[i].setTags(tags))).then(() => {
-    hexo.locals.invalidate();
-    ctx.site = hexo.locals.toObject();
-  }));
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert([
+          { source: 'foo', slug: 'foo' },
+          { source: 'bar', slug: 'bar' },
+          { source: 'baz', slug: 'baz' },
+          { source: 'boo', slug: 'boo' }
+        ])
+      )
+      .then((
+        posts // TODO: Warehouse needs to add a mutex lock when writing data to avoid data sync problem
+      ) =>
+        Promise.each([['foo'], ['baz'], ['baz'], ['bar']], (tags, i) =>
+          posts[i].setTags(tags)
+        )
+      )
+      .then(() => {
+        hexo.locals.invalidate();
+        ctx.site = hexo.locals.toObject();
+      })
+  );
 
   it('default', () => {
     const result = listTags();
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('specified collection', () => {
-    const result = listTags(Tag.find({
-      name: /^b/
-    }));
-
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    const result = listTags(
+      Tag.find({
+        name: /^b/
+      })
+    );
+
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('style: false', () => {
@@ -62,11 +76,13 @@ describe('list_tags', () => {
       style: false
     });
 
-    result.should.eql([
-      '<a class="tag-link" href="/tags/bar/" rel="tag">bar<span class="tag-count">1</span></a>',
-      '<a class="tag-link" href="/tags/baz/" rel="tag">baz<span class="tag-count">2</span></a>',
-      '<a class="tag-link" href="/tags/foo/" rel="tag">foo<span class="tag-count">1</span></a>'
-    ].join(', '));
+    result.should.eql(
+      [
+        '<a class="tag-link" href="/tags/bar/" rel="tag">bar<span class="tag-count">1</span></a>',
+        '<a class="tag-link" href="/tags/baz/" rel="tag">baz<span class="tag-count">2</span></a>',
+        '<a class="tag-link" href="/tags/foo/" rel="tag">foo<span class="tag-count">1</span></a>'
+      ].join(', ')
+    );
   });
 
   it('show_count: false', () => {
@@ -74,13 +90,15 @@ describe('list_tags', () => {
       show_count: false
     });
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('class', () => {
@@ -88,13 +106,15 @@ describe('list_tags', () => {
       class: 'test'
     });
 
-    result.should.eql([
-      '<ul class="test-list" itemprop="keywords">',
-      '<li class="test-list-item"><a class="test-list-link" href="/tags/bar/" rel="tag">bar</a><span class="test-list-count">1</span></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/tags/baz/" rel="tag">baz</a><span class="test-list-count">2</span></li>',
-      '<li class="test-list-item"><a class="test-list-link" href="/tags/foo/" rel="tag">foo</a><span class="test-list-count">1</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="test-list" itemprop="keywords">',
+        '<li class="test-list-item"><a class="test-list-link" href="/tags/bar/" rel="tag">bar</a><span class="test-list-count">1</span></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/tags/baz/" rel="tag">baz</a><span class="test-list-count">2</span></li>',
+        '<li class="test-list-item"><a class="test-list-link" href="/tags/foo/" rel="tag">foo</a><span class="test-list-count">1</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('orderby', () => {
@@ -102,13 +122,15 @@ describe('list_tags', () => {
       orderby: 'length'
     });
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('order', () => {
@@ -116,13 +138,15 @@ describe('list_tags', () => {
       order: -1
     });
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">foo</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('transform', () => {
@@ -132,13 +156,15 @@ describe('list_tags', () => {
       }
     });
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">BAR</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">BAZ</a><span class="tag-list-count">2</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">FOO</a><span class="tag-list-count">1</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">BAR</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">BAZ</a><span class="tag-list-count">2</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/foo/" rel="tag">FOO</a><span class="tag-list-count">1</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 
   it('separator', () => {
@@ -147,11 +173,13 @@ describe('list_tags', () => {
       separator: ''
     });
 
-    result.should.eql([
-      '<a class="tag-link" href="/tags/bar/" rel="tag">bar<span class="tag-count">1</span></a>',
-      '<a class="tag-link" href="/tags/baz/" rel="tag">baz<span class="tag-count">2</span></a>',
-      '<a class="tag-link" href="/tags/foo/" rel="tag">foo<span class="tag-count">1</span></a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="tag-link" href="/tags/bar/" rel="tag">bar<span class="tag-count">1</span></a>',
+        '<a class="tag-link" href="/tags/baz/" rel="tag">baz<span class="tag-count">2</span></a>',
+        '<a class="tag-link" href="/tags/foo/" rel="tag">foo<span class="tag-count">1</span></a>'
+      ].join('')
+    );
   });
 
   it('amount', () => {
@@ -159,11 +187,13 @@ describe('list_tags', () => {
       amount: 2
     });
 
-    result.should.eql([
-      '<ul class="tag-list" itemprop="keywords">',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
-      '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
-      '</ul>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<ul class="tag-list" itemprop="keywords">',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/bar/" rel="tag">bar</a><span class="tag-list-count">1</span></li>',
+        '<li class="tag-list-item"><a class="tag-list-link" href="/tags/baz/" rel="tag">baz</a><span class="tag-list-count">2</span></li>',
+        '</ul>'
+      ].join('')
+    );
   });
 });
diff --git a/test/scripts/helpers/mail_to.js b/test/scripts/helpers/mail_to.js
index 73bb24c4ee..3b29293a4d 100644
--- a/test/scripts/helpers/mail_to.js
+++ b/test/scripts/helpers/mail_to.js
@@ -15,67 +15,92 @@ describe('mail_to', () => {
   const mailto = require('../../../lib/plugins/helper/mail_to').bind(ctx);
 
   it('path', () => {
-    mailto('abc@example.com').should.eql('<a href="mailto:abc@example.com" title="abc@example.com">abc@example.com</a>');
+    mailto('abc@example.com').should.eql(
+      '<a href="mailto:abc@example.com" title="abc@example.com">abc@example.com</a>'
+    );
   });
 
   it('text', () => {
-    mailto('abc@example.com', 'Email').should.eql('<a href="mailto:abc@example.com" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email').should.eql(
+      '<a href="mailto:abc@example.com" title="Email">Email</a>'
+    );
   });
 
   it('subject', () => {
-    mailto('abc@example.com', 'Email', {subject: 'Hello'})
-      .should.eql('<a href="mailto:abc@example.com?subject=Hello" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', { subject: 'Hello' }).should.eql(
+      '<a href="mailto:abc@example.com?subject=Hello" title="Email">Email</a>'
+    );
   });
 
   it('cc (string)', () => {
-    const data = {cc: 'abc@abc.com'};
+    const data = { cc: 'abc@abc.com' };
     const querystring = qs.stringify(data);
 
-    mailto('abc@example.com', 'Email', {cc: 'abc@abc.com'})
-      .should.eql('<a href="mailto:abc@example.com?' + querystring + '" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', { cc: 'abc@abc.com' }).should.eql(
+      '<a href="mailto:abc@example.com?' +
+        querystring +
+        '" title="Email">Email</a>'
+    );
   });
 
   it('cc (array)', () => {
-    const data = {cc: 'abc@abc.com,bcd@bcd.com'};
+    const data = { cc: 'abc@abc.com,bcd@bcd.com' };
     const querystring = qs.stringify(data);
 
-    mailto('abc@example.com', 'Email', {cc: ['abc@abc.com', 'bcd@bcd.com']})
-      .should.eql('<a href="mailto:abc@example.com?' + querystring + '" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', {
+      cc: ['abc@abc.com', 'bcd@bcd.com']
+    }).should.eql(
+      '<a href="mailto:abc@example.com?' +
+        querystring +
+        '" title="Email">Email</a>'
+    );
   });
 
   it('bcc (string)', () => {
-    const data = {bcc: 'abc@abc.com'};
+    const data = { bcc: 'abc@abc.com' };
     const querystring = qs.stringify(data);
 
-    mailto('abc@example.com', 'Email', {bcc: 'abc@abc.com'})
-      .should.eql('<a href="mailto:abc@example.com?' + querystring + '" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', { bcc: 'abc@abc.com' }).should.eql(
+      '<a href="mailto:abc@example.com?' +
+        querystring +
+        '" title="Email">Email</a>'
+    );
   });
 
   it('bcc (array)', () => {
-    const data = {bcc: 'abc@abc.com,bcd@bcd.com'};
+    const data = { bcc: 'abc@abc.com,bcd@bcd.com' };
     const querystring = qs.stringify(data);
 
-    mailto('abc@example.com', 'Email', {bcc: ['abc@abc.com', 'bcd@bcd.com']})
-      .should.eql('<a href="mailto:abc@example.com?' + querystring + '" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', {
+      bcc: ['abc@abc.com', 'bcd@bcd.com']
+    }).should.eql(
+      '<a href="mailto:abc@example.com?' +
+        querystring +
+        '" title="Email">Email</a>'
+    );
   });
 
   it('body', () => {
-    mailto('abc@example.com', 'Email', {body: 'Hello'})
-      .should.eql('<a href="mailto:abc@example.com?body=Hello" title="Email">Email</a>');
+    mailto('abc@example.com', 'Email', { body: 'Hello' }).should.eql(
+      '<a href="mailto:abc@example.com?body=Hello" title="Email">Email</a>'
+    );
   });
 
   it('class (string)', () => {
-    mailto('abc@example.com', 'Email', {class: 'foo'})
-      .should.eql('<a href="mailto:abc@example.com" title="Email" class="foo">Email</a>');
+    mailto('abc@example.com', 'Email', { class: 'foo' }).should.eql(
+      '<a href="mailto:abc@example.com" title="Email" class="foo">Email</a>'
+    );
   });
 
   it('class (array)', () => {
-    mailto('abc@example.com', 'Email', {class: ['foo', 'bar']})
-      .should.eql('<a href="mailto:abc@example.com" title="Email" class="foo bar">Email</a>');
+    mailto('abc@example.com', 'Email', { class: ['foo', 'bar'] }).should.eql(
+      '<a href="mailto:abc@example.com" title="Email" class="foo bar">Email</a>'
+    );
   });
 
   it('id', () => {
-    mailto('abc@example.com', 'Email', {id: 'foo'})
-      .should.eql('<a href="mailto:abc@example.com" title="Email" id="foo">Email</a>');
+    mailto('abc@example.com', 'Email', { id: 'foo' }).should.eql(
+      '<a href="mailto:abc@example.com" title="Email" id="foo">Email</a>'
+    );
   });
 });
diff --git a/test/scripts/helpers/markdown.js b/test/scripts/helpers/markdown.js
index 524c64b7fe..e6dd0f88ed 100644
--- a/test/scripts/helpers/markdown.js
+++ b/test/scripts/helpers/markdown.js
@@ -10,9 +10,15 @@ describe('markdown', () => {
 
   const markdown = require('../../../lib/plugins/helper/markdown').bind(ctx);
 
-  before(() => hexo.init().then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked'))));
+  before(() =>
+    hexo
+      .init()
+      .then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked')))
+  );
 
   it('default', () => {
-    markdown('123456 **bold** and *italic*').should.eql('<p>123456 <strong>bold</strong> and <em>italic</em></p>\n');
+    markdown('123456 **bold** and *italic*').should.eql(
+      '<p>123456 <strong>bold</strong> and <em>italic</em></p>\n'
+    );
   });
 });
diff --git a/test/scripts/helpers/number_format.js b/test/scripts/helpers/number_format.js
index 1ae0f95f96..87da664cd7 100644
--- a/test/scripts/helpers/number_format.js
+++ b/test/scripts/helpers/number_format.js
@@ -8,19 +8,19 @@ describe('number_format', () => {
   });
 
   it('precision', () => {
-    numberFormat(1234.567, {precision: false}).should.eql('1,234.567');
-    numberFormat(1234.567, {precision: 0}).should.eql('1,234');
-    numberFormat(1234.567, {precision: 1}).should.eql('1,234.6');
-    numberFormat(1234.567, {precision: 2}).should.eql('1,234.57');
-    numberFormat(1234.567, {precision: 3}).should.eql('1,234.567');
-    numberFormat(1234.567, {precision: 4}).should.eql('1,234.5670');
+    numberFormat(1234.567, { precision: false }).should.eql('1,234.567');
+    numberFormat(1234.567, { precision: 0 }).should.eql('1,234');
+    numberFormat(1234.567, { precision: 1 }).should.eql('1,234.6');
+    numberFormat(1234.567, { precision: 2 }).should.eql('1,234.57');
+    numberFormat(1234.567, { precision: 3 }).should.eql('1,234.567');
+    numberFormat(1234.567, { precision: 4 }).should.eql('1,234.5670');
   });
 
   it('delimiter', () => {
-    numberFormat(1234.567, {delimiter: ' '}).should.eql('1 234.567');
+    numberFormat(1234.567, { delimiter: ' ' }).should.eql('1 234.567');
   });
 
   it('separator', () => {
-    numberFormat(1234.567, {separator: '*'}).should.eql('1,234*567');
+    numberFormat(1234.567, { separator: '*' }).should.eql('1,234*567');
   });
 });
diff --git a/test/scripts/helpers/open_graph.js b/test/scripts/helpers/open_graph.js
index 18faaab6e9..15651c00b0 100644
--- a/test/scripts/helpers/open_graph.js
+++ b/test/scripts/helpers/open_graph.js
@@ -23,57 +23,75 @@ describe('open_graph', () => {
     Post.insert({
       source: 'foo.md',
       slug: 'bar'
-    }).then(post => post.setTags(['optimize', 'web'])
-      .thenReturn(Post.findById(post._id))).then(post => {
-      openGraph.call({
-        page: post,
-        config: hexo.config,
-        is_post: isPost
-      }).should.eql([
-        meta({name: 'keywords', content: 'optimize,web'}),
-        meta({property: 'og:type', content: 'website'}),
-        meta({property: 'og:title', content: hexo.config.title}),
-        meta({property: 'og:url'}),
-        meta({property: 'og:site_name', content: hexo.config.title}),
-        meta({property: 'og:locale', content: 'en'}),
-        meta({property: 'og:updated_time', content: post.updated.toISOString()}),
-        meta({name: 'twitter:card', content: 'summary'})
-      ].join('\n'));
-
-      return Post.removeById(post._id);
-    });
+    })
+      .then(post =>
+        post.setTags(['optimize', 'web']).thenReturn(Post.findById(post._id))
+      )
+      .then(post => {
+        openGraph
+          .call({
+            page: post,
+            config: hexo.config,
+            is_post: isPost
+          })
+          .should.eql(
+            [
+              meta({ name: 'keywords', content: 'optimize,web' }),
+              meta({ property: 'og:type', content: 'website' }),
+              meta({ property: 'og:title', content: hexo.config.title }),
+              meta({ property: 'og:url' }),
+              meta({ property: 'og:site_name', content: hexo.config.title }),
+              meta({ property: 'og:locale', content: 'en' }),
+              meta({
+                property: 'og:updated_time',
+                content: post.updated.toISOString()
+              }),
+              meta({ name: 'twitter:card', content: 'summary' })
+            ].join('\n')
+          );
+
+        return Post.removeById(post._id);
+      });
   });
 
   it('title - page', () => {
     const ctx = {
-      page: {title: 'Hello world'},
+      page: { title: 'Hello world' },
       config: hexo.config,
       is_post: isPost
     };
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({property: 'og:title', content: ctx.page.title}));
+    result.should.contain(
+      meta({ property: 'og:title', content: ctx.page.title })
+    );
   });
 
   it('title - options', () => {
-    const result = openGraph.call({
-      page: {title: 'Hello world'},
-      config: hexo.config,
-      is_post: isPost
-    }, {title: 'test'});
+    const result = openGraph.call(
+      {
+        page: { title: 'Hello world' },
+        config: hexo.config,
+        is_post: isPost
+      },
+      { title: 'test' }
+    );
 
-    result.should.contain(meta({property: 'og:title', content: 'test'}));
+    result.should.contain(meta({ property: 'og:title', content: 'test' }));
   });
 
   it('type - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {type: 'photo'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { type: 'photo' }
+    );
 
-    result.should.contain(meta({property: 'og:type', content: 'photo'}));
+    result.should.contain(meta({ property: 'og:type', content: 'photo' }));
   });
 
   it('type - is_post', () => {
@@ -85,7 +103,7 @@ describe('open_graph', () => {
       }
     });
 
-    result.should.contain(meta({property: 'og:type', content: 'article'}));
+    result.should.contain(meta({ property: 'og:type', content: 'article' }));
   });
 
   it('url - context', () => {
@@ -98,18 +116,23 @@ describe('open_graph', () => {
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({property: 'og:url', content: ctx.url}));
+    result.should.contain(meta({ property: 'og:url', content: ctx.url }));
   });
 
   it('url - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost,
-      url: 'https://hexo.io/foo'
-    }, {url: 'https://hexo.io/bar'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost,
+        url: 'https://hexo.io/foo'
+      },
+      { url: 'https://hexo.io/bar' }
+    );
 
-    result.should.contain(meta({property: 'og:url', content: 'https://hexo.io/bar'}));
+    result.should.contain(
+      meta({ property: 'og:url', content: 'https://hexo.io/bar' })
+    );
   });
 
   it('images - content', () => {
@@ -126,7 +149,9 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.contain(meta({property: 'og:image', content: 'https://hexo.io/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: 'https://hexo.io/test.jpg' })
+    );
   });
 
   it('images - string', () => {
@@ -138,28 +163,29 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.contain(meta({property: 'og:image', content: 'https://hexo.io/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: 'https://hexo.io/test.jpg' })
+    );
   });
 
   it('images - array', () => {
     const result = openGraph.call({
       page: {
-        photos: [
-          'https://hexo.io/foo.jpg',
-          'https://hexo.io/bar.jpg'
-        ]
+        photos: ['https://hexo.io/foo.jpg', 'https://hexo.io/bar.jpg']
       },
       config: hexo.config,
       is_post: isPost
     });
 
-    result.should.contain([
-      meta({property: 'og:image', content: 'https://hexo.io/foo.jpg'}),
-      meta({property: 'og:image', content: 'https://hexo.io/bar.jpg'})
-    ].join('\n'));
+    result.should.contain(
+      [
+        meta({ property: 'og:image', content: 'https://hexo.io/foo.jpg' }),
+        meta({ property: 'og:image', content: 'https://hexo.io/bar.jpg' })
+      ].join('\n')
+    );
   });
 
-  it('images - don\'t pollute context', () => {
+  it("images - don't pollute context", () => {
     const ctx = {
       page: {
         content: [
@@ -179,43 +205,63 @@ describe('open_graph', () => {
   });
 
   it('images - options.image', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {image: 'https://hexo.io/test.jpg'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { image: 'https://hexo.io/test.jpg' }
+    );
 
-    result.should.contain(meta({property: 'og:image', content: 'https://hexo.io/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: 'https://hexo.io/test.jpg' })
+    );
   });
 
   it('images - options.images', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {images: 'https://hexo.io/test.jpg'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { images: 'https://hexo.io/test.jpg' }
+    );
 
-    result.should.contain(meta({property: 'og:image', content: 'https://hexo.io/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: 'https://hexo.io/test.jpg' })
+    );
   });
 
   it('images - prepend config.url to the path (without prefixing /)', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {images: 'test.jpg'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { images: 'test.jpg' }
+    );
 
-    result.should.contain(meta({property: 'og:image', content: hexo.config.url + '/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: hexo.config.url + '/test.jpg' })
+    );
   });
 
   it('images - prepend config.url to the path (with prefixing /)', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {images: '/test.jpg'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { images: '/test.jpg' }
+    );
 
-    result.should.contain(meta({property: 'og:image', content: hexo.config.url + '/test.jpg'}));
+    result.should.contain(
+      meta({ property: 'og:image', content: hexo.config.url + '/test.jpg' })
+    );
   });
 
   it('images - resolve relative path when site is hosted in subdirectory', () => {
@@ -225,76 +271,99 @@ describe('open_graph', () => {
     config.root = 'blog';
     const postUrl = urlFn.resolve(config.url, '/foo/bar/index.html');
 
-    const result = openGraph.call({
-      page: {},
-      config,
-      is_post: isPost,
-      url: postUrl
-    }, {images: 'test.jpg'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config,
+        is_post: isPost,
+        url: postUrl
+      },
+      { images: 'test.jpg' }
+    );
 
-    result.should.contain(meta({property: 'og:image', content: urlFn.resolve(config.url, '/foo/bar/test.jpg')}));
+    result.should.contain(
+      meta({
+        property: 'og:image',
+        content: urlFn.resolve(config.url, '/foo/bar/test.jpg')
+      })
+    );
   });
 
   it('site_name - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {site_name: 'foo'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { site_name: 'foo' }
+    );
 
-    result.should.contain(meta({property: 'og:site_name', content: 'foo'}));
+    result.should.contain(meta({ property: 'og:site_name', content: 'foo' }));
   });
 
   it('description - page', () => {
     const ctx = {
-      page: {description: 'test'},
+      page: { description: 'test' },
       config: hexo.config,
       is_post: isPost
     };
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({name: 'description', content: ctx.page.description}));
-    result.should.contain(meta({property: 'og:description', content: ctx.page.description}));
+    result.should.contain(
+      meta({ name: 'description', content: ctx.page.description })
+    );
+    result.should.contain(
+      meta({ property: 'og:description', content: ctx.page.description })
+    );
   });
 
   it('description - options', () => {
     const ctx = {
-      page: {description: 'test'},
+      page: { description: 'test' },
       config: hexo.config,
       is_post: isPost
     };
 
-    const result = openGraph.call(ctx, {description: 'foo'});
+    const result = openGraph.call(ctx, { description: 'foo' });
 
-    result.should.contain(meta({name: 'description', content: 'foo'}));
-    result.should.contain(meta({property: 'og:description', content: 'foo'}));
+    result.should.contain(meta({ name: 'description', content: 'foo' }));
+    result.should.contain(meta({ property: 'og:description', content: 'foo' }));
   });
 
   it('description - excerpt', () => {
     const ctx = {
-      page: {excerpt: 'test'},
+      page: { excerpt: 'test' },
       config: hexo.config,
       is_post: isPost
     };
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({name: 'description', content: ctx.page.excerpt}));
-    result.should.contain(meta({property: 'og:description', content: ctx.page.excerpt}));
+    result.should.contain(
+      meta({ name: 'description', content: ctx.page.excerpt })
+    );
+    result.should.contain(
+      meta({ property: 'og:description', content: ctx.page.excerpt })
+    );
   });
 
   it('description - content', () => {
     const ctx = {
-      page: {content: 'test'},
+      page: { content: 'test' },
       config: hexo.config,
       is_post: isPost
     };
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({name: 'description', content: ctx.page.content}));
-    result.should.contain(meta({property: 'og:description', content: ctx.page.content}));
+    result.should.contain(
+      meta({ name: 'description', content: ctx.page.content })
+    );
+    result.should.contain(
+      meta({ property: 'og:description', content: ctx.page.content })
+    );
   });
 
   it('description - config', () => {
@@ -308,15 +377,19 @@ describe('open_graph', () => {
 
     const result = openGraph.call(ctx);
 
-    result.should.contain(meta({name: 'description', content: hexo.config.description}));
-    result.should.contain(meta({property: 'og:description', content: hexo.config.description}));
+    result.should.contain(
+      meta({ name: 'description', content: hexo.config.description })
+    );
+    result.should.contain(
+      meta({ property: 'og:description', content: hexo.config.description })
+    );
 
     hexo.config.description = '';
   });
 
   it('description - escape', () => {
     const ctx = {
-      page: {description: '<b>Important!</b> Today is "not" \'Xmas\'!'},
+      page: { description: '<b>Important!</b> Today is "not" \'Xmas\'!' },
       config: hexo.config,
       is_post: isPost
     };
@@ -324,119 +397,170 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const escaped = 'Important! Today is "not" 'Xmas'!';
 
-    result.should.contain(meta({name: 'description', content: escaped}));
-    result.should.contain(meta({property: 'og:description', content: escaped}));
+    result.should.contain(meta({ name: 'description', content: escaped }));
+    result.should.contain(
+      meta({ property: 'og:description', content: escaped })
+    );
   });
 
   it('twitter_card - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {twitter_card: 'photo'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { twitter_card: 'photo' }
+    );
 
-    result.should.contain(meta({name: 'twitter:card', content: 'photo'}));
+    result.should.contain(meta({ name: 'twitter:card', content: 'photo' }));
   });
 
   it('twitter_id - options (without prefixing @)', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {twitter_id: 'hexojs'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { twitter_id: 'hexojs' }
+    );
 
-    result.should.contain(meta({name: 'twitter:creator', content: '@hexojs'}));
+    result.should.contain(
+      meta({ name: 'twitter:creator', content: '@hexojs' })
+    );
   });
 
   it('twitter_id - options (with prefixing @)', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {twitter_id: '@hexojs'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { twitter_id: '@hexojs' }
+    );
 
-    result.should.contain(meta({name: 'twitter:creator', content: '@hexojs'}));
+    result.should.contain(
+      meta({ name: 'twitter:creator', content: '@hexojs' })
+    );
   });
 
   it('twitter_site - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {twitter_site: 'Hello'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { twitter_site: 'Hello' }
+    );
 
-    result.should.contain(meta({name: 'twitter:site', content: 'Hello'}));
+    result.should.contain(meta({ name: 'twitter:site', content: 'Hello' }));
   });
 
   it('google_plus - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {google_plus: '+123456789'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { google_plus: '+123456789' }
+    );
 
-    result.should.contain(tag('link', {rel: 'publisher', href: '+123456789'}));
+    result.should.contain(
+      tag('link', { rel: 'publisher', href: '+123456789' })
+    );
   });
 
   it('fb_admins - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {fb_admins: '123456789'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { fb_admins: '123456789' }
+    );
 
-    result.should.contain(meta({property: 'fb:admins', content: '123456789'}));
+    result.should.contain(
+      meta({ property: 'fb:admins', content: '123456789' })
+    );
   });
 
   it('fb_app_id - options', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {fb_app_id: '123456789'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { fb_app_id: '123456789' }
+    );
 
-    result.should.contain(meta({property: 'fb:app_id', content: '123456789'}));
+    result.should.contain(
+      meta({ property: 'fb:app_id', content: '123456789' })
+    );
   });
 
   it('updated - options', () => {
-    const result = openGraph.call({
-      page: { updated: moment('2016-05-23T21:20:21.372Z') },
-      config: {},
-      is_post: isPost
-    }, { });
+    const result = openGraph.call(
+      {
+        page: { updated: moment('2016-05-23T21:20:21.372Z') },
+        config: {},
+        is_post: isPost
+      },
+      {}
+    );
 
-    result.should.contain(meta({property: 'og:updated_time', content: '2016-05-23T21:20:21.372Z'}));
+    result.should.contain(
+      meta({ property: 'og:updated_time', content: '2016-05-23T21:20:21.372Z' })
+    );
   });
 
   it('updated - options - allow overriding og:updated_time', () => {
-    const result = openGraph.call({
-      page: { updated: moment('2016-05-23T21:20:21.372Z') },
-      config: {},
-      is_post: isPost
-    }, { updated: moment('2015-04-22T20:19:20.371Z') });
+    const result = openGraph.call(
+      {
+        page: { updated: moment('2016-05-23T21:20:21.372Z') },
+        config: {},
+        is_post: isPost
+      },
+      { updated: moment('2015-04-22T20:19:20.371Z') }
+    );
 
-    result.should.contain(meta({property: 'og:updated_time', content: '2015-04-22T20:19:20.371Z'}));
+    result.should.contain(
+      meta({ property: 'og:updated_time', content: '2015-04-22T20:19:20.371Z' })
+    );
   });
 
   it('updated - options - allow disabling og:updated_time', () => {
-    const result = openGraph.call({
-      page: { updated: moment('2016-05-23T21:20:21.372Z') },
-      config: {},
-      is_post: isPost
-    }, { updated: false });
+    const result = openGraph.call(
+      {
+        page: { updated: moment('2016-05-23T21:20:21.372Z') },
+        config: {},
+        is_post: isPost
+      },
+      { updated: false }
+    );
 
-    result.should.not.contain(meta({property: 'og:updated_time', content: '2016-05-23T21:20:21.372Z'}));
+    result.should.not.contain(
+      meta({ property: 'og:updated_time', content: '2016-05-23T21:20:21.372Z' })
+    );
   });
 
   it('description - do not add /(?:og:)?description/ meta tags if there is no description', () => {
-    const result = openGraph.call({
-      page: { },
-      config: {},
-      is_post: isPost
-    }, { });
+    const result = openGraph.call(
+      {
+        page: {},
+        config: {},
+        is_post: isPost
+      },
+      {}
+    );
 
-    result.should.not.contain(meta({property: 'og:description'}));
-    result.should.not.contain(meta({property: 'description'}));
+    result.should.not.contain(meta({ property: 'og:description' }));
+    result.should.not.contain(meta({ property: 'description' }));
   });
 
   it('keywords - page keywords string', () => {
@@ -449,7 +573,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const escaped = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: escaped}));
+    result.should.contain(meta({ name: 'keywords', content: escaped }));
   });
 
   it('keywords - page keywords array', () => {
@@ -462,7 +586,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - page tags', () => {
@@ -475,7 +599,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - config keywords string', () => {
@@ -488,7 +612,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - config keywords array', () => {
@@ -501,7 +625,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - page keywords first', () => {
@@ -517,7 +641,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'web1,web2';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - page tags second', () => {
@@ -530,7 +654,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - page tags empty', () => {
@@ -543,7 +667,7 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'web5,web6';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('keywords - escape', () => {
@@ -556,17 +680,20 @@ describe('open_graph', () => {
     const result = openGraph.call(ctx);
     const keywords = 'optimize,web&<>"'/,site';
 
-    result.should.contain(meta({name: 'keywords', content: keywords}));
+    result.should.contain(meta({ name: 'keywords', content: keywords }));
   });
 
   it('og:locale - options.language', () => {
-    const result = openGraph.call({
-      page: {},
-      config: hexo.config,
-      is_post: isPost
-    }, {language: 'es-cr'});
+    const result = openGraph.call(
+      {
+        page: {},
+        config: hexo.config,
+        is_post: isPost
+      },
+      { language: 'es-cr' }
+    );
 
-    result.should.contain(meta({property: 'og:locale', content: 'es-cr'}));
+    result.should.contain(meta({ property: 'og:locale', content: 'es-cr' }));
   });
 
   it('og:locale - page.lang', () => {
@@ -576,7 +703,7 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.contain(meta({property: 'og:locale', content: 'es-mx'}));
+    result.should.contain(meta({ property: 'og:locale', content: 'es-mx' }));
   });
 
   it('og:locale - page.language', () => {
@@ -586,7 +713,7 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.contain(meta({property: 'og:locale', content: 'es-gt'}));
+    result.should.contain(meta({ property: 'og:locale', content: 'es-gt' }));
   });
 
   it('og:locale - config.language', () => {
@@ -598,7 +725,7 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.contain(meta({property: 'og:locale', content: 'es-pa'}));
+    result.should.contain(meta({ property: 'og:locale', content: 'es-pa' }));
   });
 
   it('og:locale - no language set', () => {
@@ -608,6 +735,6 @@ describe('open_graph', () => {
       is_post: isPost
     });
 
-    result.should.not.contain(meta({property: 'og:locale'}));
+    result.should.not.contain(meta({ property: 'og:locale' }));
   });
 });
diff --git a/test/scripts/helpers/paginator.js b/test/scripts/helpers/paginator.js
index d02ea0d75c..9f750d2638 100644
--- a/test/scripts/helpers/paginator.js
+++ b/test/scripts/helpers/paginator.js
@@ -27,11 +27,16 @@ describe('paginator', () => {
     const total = data.total;
     const pages = data.pages;
     const space = data.space || '…';
-    const prevNext = Object.prototype.hasOwnProperty.call(data, 'prev_next') ? data.prev_next : true;
+    const prevNext = Object.prototype.hasOwnProperty.call(data, 'prev_next')
+      ? data.prev_next
+      : true;
     let num;
 
     if (prevNext && current > 1) {
-      expected += '<a class="extend prev" rel="prev" href="' + link(current - 1) + '">Prev</a>';
+      expected +=
+        '<a class="extend prev" rel="prev" href="' +
+        link(current - 1) +
+        '">Prev</a>';
     }
 
     for (let i = 0, len = pages.length; i < len; i++) {
@@ -42,12 +47,16 @@ describe('paginator', () => {
       } else if (num === current) {
         expected += '<span class="page-number current">' + current + '</span>';
       } else {
-        expected += '<a class="page-number" href="' + link(num) + '">' + num + '</a>';
+        expected +=
+          '<a class="page-number" href="' + link(num) + '">' + num + '</a>';
       }
     }
 
     if (prevNext && current < total) {
-      expected += '<a class="extend next" rel="next" href="' + link(current + 1) + '">Next</a>';
+      expected +=
+        '<a class="extend next" rel="next" href="' +
+        link(current + 1) +
+        '">Next</a>';
     }
 
     result.should.eql(expected);
@@ -180,14 +189,16 @@ describe('paginator', () => {
       base: 'archives/'
     });
 
-    result.should.eql([
-      '<span class="page-number current">1</span>',
-      '<a class="page-number" href="/archives/page/2/">2</a>',
-      '<a class="page-number" href="/archives/page/3/">3</a>',
-      '<span class="space">…</span>',
-      '<a class="page-number" href="/archives/page/10/">10</a>',
-      '<a class="extend next" rel="next" href="/archives/page/2/">Next</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<span class="page-number current">1</span>',
+        '<a class="page-number" href="/archives/page/2/">2</a>',
+        '<a class="page-number" href="/archives/page/3/">3</a>',
+        '<span class="space">…</span>',
+        '<a class="page-number" href="/archives/page/10/">10</a>',
+        '<a class="extend next" rel="next" href="/archives/page/2/">Next</a>'
+      ].join('')
+    );
   });
 
   it('format', () => {
@@ -196,14 +207,16 @@ describe('paginator', () => {
       format: 'index-%d.html'
     });
 
-    result.should.eql([
-      '<span class="page-number current">1</span>',
-      '<a class="page-number" href="/index-2.html">2</a>',
-      '<a class="page-number" href="/index-3.html">3</a>',
-      '<span class="space">…</span>',
-      '<a class="page-number" href="/index-10.html">10</a>',
-      '<a class="extend next" rel="next" href="/index-2.html">Next</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<span class="page-number current">1</span>',
+        '<a class="page-number" href="/index-2.html">2</a>',
+        '<a class="page-number" href="/index-3.html">3</a>',
+        '<span class="space">…</span>',
+        '<a class="page-number" href="/index-10.html">10</a>',
+        '<a class="extend next" rel="next" href="/index-2.html">Next</a>'
+      ].join('')
+    );
   });
 
   it('prev_text / next_text', () => {
@@ -213,16 +226,18 @@ describe('paginator', () => {
       next_text: 'Older'
     });
 
-    result.should.eql([
-      '<a class="extend prev" rel="prev" href="/">Newer</a>',
-      '<a class="page-number" href="/">1</a>',
-      '<span class="page-number current">2</span>',
-      '<a class="page-number" href="/page/3/">3</a>',
-      '<a class="page-number" href="/page/4/">4</a>',
-      '<span class="space">…</span>',
-      '<a class="page-number" href="/page/10/">10</a>',
-      '<a class="extend next" rel="next" href="/page/3/">Older</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="extend prev" rel="prev" href="/">Newer</a>',
+        '<a class="page-number" href="/">1</a>',
+        '<span class="page-number current">2</span>',
+        '<a class="page-number" href="/page/3/">3</a>',
+        '<a class="page-number" href="/page/4/">4</a>',
+        '<span class="space">…</span>',
+        '<a class="page-number" href="/page/10/">10</a>',
+        '<a class="extend next" rel="next" href="/page/3/">Older</a>'
+      ].join('')
+    );
   });
 
   it('prev_next', () => {
@@ -231,14 +246,16 @@ describe('paginator', () => {
       prev_next: false
     });
 
-    result.should.eql([
-      '<a class="page-number" href="/">1</a>',
-      '<span class="page-number current">2</span>',
-      '<a class="page-number" href="/page/3/">3</a>',
-      '<a class="page-number" href="/page/4/">4</a>',
-      '<span class="space">…</span>',
-      '<a class="page-number" href="/page/10/">10</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="page-number" href="/">1</a>',
+        '<span class="page-number current">2</span>',
+        '<a class="page-number" href="/page/3/">3</a>',
+        '<a class="page-number" href="/page/4/">4</a>',
+        '<span class="space">…</span>',
+        '<a class="page-number" href="/page/10/">10</a>'
+      ].join('')
+    );
   });
 
   it('transform', () => {
@@ -249,16 +266,18 @@ describe('paginator', () => {
       }
     });
 
-    result.should.eql([
-      '<a class="extend prev" rel="prev" href="/">Prev</a>',
-      '<a class="page-number" href="/">Page 1</a>',
-      '<span class="page-number current">Page 2</span>',
-      '<a class="page-number" href="/page/3/">Page 3</a>',
-      '<a class="page-number" href="/page/4/">Page 4</a>',
-      '<span class="space">…</span>',
-      '<a class="page-number" href="/page/10/">Page 10</a>',
-      '<a class="extend next" rel="next" href="/page/3/">Next</a>'
-    ].join(''));
+    result.should.eql(
+      [
+        '<a class="extend prev" rel="prev" href="/">Prev</a>',
+        '<a class="page-number" href="/">Page 1</a>',
+        '<span class="page-number current">Page 2</span>',
+        '<a class="page-number" href="/page/3/">Page 3</a>',
+        '<a class="page-number" href="/page/4/">Page 4</a>',
+        '<span class="space">…</span>',
+        '<a class="page-number" href="/page/10/">Page 10</a>',
+        '<a class="extend next" rel="next" href="/page/3/">Next</a>'
+      ].join('')
+    );
   });
 
   it('context', () => {
diff --git a/test/scripts/helpers/partial.js b/test/scripts/helpers/partial.js
index 6606fd70f2..5456e6c5a5 100644
--- a/test/scripts/helpers/partial.js
+++ b/test/scripts/helpers/partial.js
@@ -7,7 +7,9 @@ const Promise = require('bluebird');
 
 describe('partial', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'partial_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'partial_test'), {
+    silent: true
+  });
   const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test');
   const viewDir = pathFn.join(themeDir, 'layout') + pathFn.sep;
   const viewName = 'article.swig';
@@ -21,18 +23,26 @@ describe('partial', () => {
     cache: true
   };
 
-  ctx.fragment_cache = require('../../../lib/plugins/helper/fragment_cache')(hexo);
+  ctx.fragment_cache = require('../../../lib/plugins/helper/fragment_cache')(
+    hexo
+  );
 
   hexo.env.init = true;
 
-  const partial = require('../../../lib/plugins/helper/partial')(hexo).bind(ctx);
-
-  before(() => Promise.all([
-    fs.mkdirs(themeDir),
-    fs.writeFile(hexo.config_path, 'theme: test')
-  ]).then(() => hexo.init()).then(() => {
-    hexo.theme.setView('widget/tag.swig', 'tag widget');
-  }));
+  const partial = require('../../../lib/plugins/helper/partial')(hexo).bind(
+    ctx
+  );
+
+  before(() =>
+    Promise.all([
+      fs.mkdirs(themeDir),
+      fs.writeFile(hexo.config_path, 'theme: test')
+    ])
+      .then(() => hexo.init())
+      .then(() => {
+        hexo.theme.setView('widget/tag.swig', 'tag widget');
+      })
+  );
 
   after(() => fs.rmdir(hexo.base_dir));
 
@@ -57,20 +67,20 @@ describe('partial', () => {
   it('locals', () => {
     hexo.theme.setView('test.swig', '{{ foo }}');
 
-    partial('test', {foo: 'bar'}).should.eql('bar');
+    partial('test', { foo: 'bar' }).should.eql('bar');
   });
 
   it('cache', () => {
     hexo.theme.setView('test.swig', '{{ foo }}');
 
-    partial('test', {foo: 'bar'}, {cache: true}).should.eql('bar');
-    partial('test', {}, {cache: true}).should.eql('bar');
+    partial('test', { foo: 'bar' }, { cache: true }).should.eql('bar');
+    partial('test', {}, { cache: true }).should.eql('bar');
   });
 
   it('only', () => {
     hexo.theme.setView('test.swig', '{{ foo }}{{ bar }}');
 
-    partial('test', {bar: 'bar'}, {only: true}).should.eql('bar');
+    partial('test', { bar: 'bar' }, { only: true }).should.eql('bar');
   });
 
   it('a partial in another partial', () => {
diff --git a/test/scripts/helpers/relative_url.js b/test/scripts/helpers/relative_url.js
index 8f511747b4..9753a563e4 100644
--- a/test/scripts/helpers/relative_url.js
+++ b/test/scripts/helpers/relative_url.js
@@ -12,14 +12,20 @@ describe('relative_url', () => {
     relativeURL('foo/', 'foo/style.css').should.eql('style.css');
     relativeURL('foo/index.html', 'foo/style.css').should.eql('style.css');
     relativeURL('foo/bar/', 'foo/bar/style.css').should.eql('style.css');
-    relativeURL('foo/bar/index.html', 'foo/bar/style.css').should.eql('style.css');
+    relativeURL('foo/bar/index.html', 'foo/bar/style.css').should.eql(
+      'style.css'
+    );
   });
 
   it('from different root', () => {
     relativeURL('foo/', 'css/style.css').should.eql('../css/style.css');
-    relativeURL('foo/index.html', 'css/style.css').should.eql('../css/style.css');
+    relativeURL('foo/index.html', 'css/style.css').should.eql(
+      '../css/style.css'
+    );
     relativeURL('foo/bar/', 'css/style.css').should.eql('../../css/style.css');
-    relativeURL('foo/bar/index.html', 'css/style.css').should.eql('../../css/style.css');
+    relativeURL('foo/bar/index.html', 'css/style.css').should.eql(
+      '../../css/style.css'
+    );
   });
 
   it('to root', () => {
diff --git a/test/scripts/helpers/render.js b/test/scripts/helpers/render.js
index 568af34c0f..f0016f238d 100644
--- a/test/scripts/helpers/render.js
+++ b/test/scripts/helpers/render.js
@@ -8,11 +8,7 @@ describe('render', () => {
   before(() => hexo.init());
 
   it('default', () => {
-    const body = [
-      'foo: 1',
-      'bar:',
-      '\tbaz: 3'
-    ].join('\n');
+    const body = ['foo: 1', 'bar:', '\tbaz: 3'].join('\n');
 
     const result = render(body, 'yaml');
 
diff --git a/test/scripts/helpers/search_form.js b/test/scripts/helpers/search_form.js
index b297c6cf93..7fc5c671a4 100644
--- a/test/scripts/helpers/search_form.js
+++ b/test/scripts/helpers/search_form.js
@@ -2,43 +2,53 @@
 
 describe('search_form', () => {
   const searchForm = require('../../../lib/plugins/helper/search_form').bind({
-    config: {url: 'https://hexo.io'}
+    config: { url: 'https://hexo.io' }
   });
 
   it('default', () => {
-    searchForm().should.eql('<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">'
-      + '<input type="search" name="q" class="search-form-input" placeholder="Search">'
-      + '<input type="hidden" name="sitesearch" value="https://hexo.io">'
-      + '</form>');
+    searchForm().should.eql(
+      '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">' +
+        '<input type="search" name="q" class="search-form-input" placeholder="Search">' +
+        '<input type="hidden" name="sitesearch" value="https://hexo.io">' +
+        '</form>'
+    );
   });
 
   it('class', () => {
-    searchForm({class: 'foo'}).should.eql('<form action="//google.com/search" method="get" accept-charset="UTF-8" class="foo">'
-      + '<input type="search" name="q" class="foo-input" placeholder="Search">'
-      + '<input type="hidden" name="sitesearch" value="https://hexo.io">'
-      + '</form>');
+    searchForm({ class: 'foo' }).should.eql(
+      '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="foo">' +
+        '<input type="search" name="q" class="foo-input" placeholder="Search">' +
+        '<input type="hidden" name="sitesearch" value="https://hexo.io">' +
+        '</form>'
+    );
   });
 
   it('text', () => {
-    searchForm({text: 'Find'}).should.eql('<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">'
-      + '<input type="search" name="q" class="search-form-input" placeholder="Find">'
-      + '<input type="hidden" name="sitesearch" value="https://hexo.io">'
-      + '</form>');
+    searchForm({ text: 'Find' }).should.eql(
+      '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">' +
+        '<input type="search" name="q" class="search-form-input" placeholder="Find">' +
+        '<input type="hidden" name="sitesearch" value="https://hexo.io">' +
+        '</form>'
+    );
   });
 
   it('button enabled', () => {
-    searchForm({button: true, text: 'Find'}).should.eql('<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">'
-      + '<input type="search" name="q" class="search-form-input" placeholder="Find">'
-      + '<button type="submit" class="search-form-submit">Find</button>'
-      + '<input type="hidden" name="sitesearch" value="https://hexo.io">'
-      + '</form>');
+    searchForm({ button: true, text: 'Find' }).should.eql(
+      '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">' +
+        '<input type="search" name="q" class="search-form-input" placeholder="Find">' +
+        '<button type="submit" class="search-form-submit">Find</button>' +
+        '<input type="hidden" name="sitesearch" value="https://hexo.io">' +
+        '</form>'
+    );
   });
 
   it('button text', () => {
-    searchForm({button: 'Go', text: 'Find'}).should.eql('<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">'
-      + '<input type="search" name="q" class="search-form-input" placeholder="Find">'
-      + '<button type="submit" class="search-form-submit">Go</button>'
-      + '<input type="hidden" name="sitesearch" value="https://hexo.io">'
-      + '</form>');
+    searchForm({ button: 'Go', text: 'Find' }).should.eql(
+      '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form">' +
+        '<input type="search" name="q" class="search-form-input" placeholder="Find">' +
+        '<button type="submit" class="search-form-submit">Go</button>' +
+        '<input type="hidden" name="sitesearch" value="https://hexo.io">' +
+        '</form>'
+    );
   });
 });
diff --git a/test/scripts/helpers/tagcloud.js b/test/scripts/helpers/tagcloud.js
index 605e75189b..6cda237828 100644
--- a/test/scripts/helpers/tagcloud.js
+++ b/test/scripts/helpers/tagcloud.js
@@ -16,42 +16,62 @@ describe('tagcloud', () => {
 
   const tagcloud = require('../../../lib/plugins/helper/tagcloud').bind(ctx);
 
-  before(() => hexo.init().then(() => Post.insert([
-    {source: 'foo', slug: 'foo'},
-    {source: 'bar', slug: 'bar'},
-    {source: 'baz', slug: 'baz'},
-    {source: 'boo', slug: 'boo'}
-  ])).then(posts => // TODO: Warehouse needs to add a mutex lock when writing data to avoid data sync problem
-    Promise.each([
-      ['bcd'],
-      ['bcd', 'cde'],
-      ['bcd', 'cde', 'abc'],
-      ['bcd', 'cde', 'abc', 'def']
-    ], (tags, i) => posts[i].setTags(tags))).then(() => {
-    hexo.locals.invalidate();
-    ctx.site = hexo.locals.toObject();
-  }));
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert([
+          { source: 'foo', slug: 'foo' },
+          { source: 'bar', slug: 'bar' },
+          { source: 'baz', slug: 'baz' },
+          { source: 'boo', slug: 'boo' }
+        ])
+      )
+      .then((
+        posts // TODO: Warehouse needs to add a mutex lock when writing data to avoid data sync problem
+      ) =>
+        Promise.each(
+          [
+            ['bcd'],
+            ['bcd', 'cde'],
+            ['bcd', 'cde', 'abc'],
+            ['bcd', 'cde', 'abc', 'def']
+          ],
+          (tags, i) => posts[i].setTags(tags)
+        )
+      )
+      .then(() => {
+        hexo.locals.invalidate();
+        ctx.site = hexo.locals.toObject();
+      })
+  );
 
   it('default', () => {
     const result = tagcloud();
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px;">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px;">def</a>'
+      ].join(' ')
+    );
   });
 
   it('specified collection', () => {
-    const result = tagcloud(Tag.find({
-      name: /bc/
-    }));
-
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 10px;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
-    ].join(' '));
+    const result = tagcloud(
+      Tag.find({
+        name: /bc/
+      })
+    );
+
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 10px;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
+      ].join(' ')
+    );
   });
 
   it('font size', () => {
@@ -60,25 +80,30 @@ describe('tagcloud', () => {
       max_font: 30
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 20px;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 30px;">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 25px;">cde</a>',
-      '<a href="/tags/def/" style="font-size: 15px;">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 20px;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 30px;">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 25px;">cde</a>',
+        '<a href="/tags/def/" style="font-size: 15px;">def</a>'
+      ].join(' ')
+    );
   });
 
   it('font size - when every tag has the same number of posts, font-size should be minimum.', () => {
-    const result = tagcloud(Tag.find({
-      name: /abc/
-    }), {
-      min_font: 15,
-      max_font: 30
-    });
+    const result = tagcloud(
+      Tag.find({
+        name: /abc/
+      }),
+      {
+        min_font: 15,
+        max_font: 30
+      }
+    );
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 15px;">abc</a>'
-    ].join(' '));
+    result.should.eql(
+      ['<a href="/tags/abc/" style="font-size: 15px;">abc</a>'].join(' ')
+    );
   });
 
   it('font unit', () => {
@@ -86,12 +111,14 @@ describe('tagcloud', () => {
       unit: 'em'
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33em;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20em;">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67em;">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10em;">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33em;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20em;">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67em;">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10em;">def</a>'
+      ].join(' ')
+    );
   });
 
   it('orderby', () => {
@@ -99,12 +126,14 @@ describe('tagcloud', () => {
       orderby: 'length'
     });
 
-    result.should.eql([
-      '<a href="/tags/def/" style="font-size: 10px;">def</a>',
-      '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/def/" style="font-size: 10px;">def</a>',
+        '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
+      ].join(' ')
+    );
   });
 
   it('order', () => {
@@ -112,12 +141,14 @@ describe('tagcloud', () => {
       order: -1
     });
 
-    result.should.eql([
-      '<a href="/tags/def/" style="font-size: 10px;">def</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
-      '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/def/" style="font-size: 10px;">def</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
+        '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>'
+      ].join(' ')
+    );
   });
 
   it('amount', () => {
@@ -125,10 +156,12 @@ describe('tagcloud', () => {
       amount: 2
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 10px;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 10px;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>'
+      ].join(' ')
+    );
   });
 
   it('transform', () => {
@@ -138,12 +171,14 @@ describe('tagcloud', () => {
       }
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px;">ABC</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">BCD</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px;">CDE</a>',
-      '<a href="/tags/def/" style="font-size: 10px;">DEF</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px;">ABC</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">BCD</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px;">CDE</a>',
+        '<a href="/tags/def/" style="font-size: 10px;">DEF</a>'
+      ].join(' ')
+    );
   });
 
   it('color: name', () => {
@@ -153,12 +188,14 @@ describe('tagcloud', () => {
       end_color: 'pink'
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px; color: #ff4044">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px; color: #ffc0cb">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px; color: #ff8087">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px; color: #f00">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px; color: #ff4044">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px; color: #ffc0cb">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px; color: #ff8087">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px; color: #f00">def</a>'
+      ].join(' ')
+    );
   });
 
   it('color: hex', () => {
@@ -168,12 +205,14 @@ describe('tagcloud', () => {
       end_color: '#ffc0cb' // pink
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px; color: #ff4044">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px; color: #ffc0cb">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px; color: #ff8087">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px; color: #f00">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px; color: #ff4044">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px; color: #ffc0cb">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px; color: #ff8087">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px; color: #f00">def</a>'
+      ].join(' ')
+    );
   });
 
   it('color: RGBA', () => {
@@ -183,12 +222,14 @@ describe('tagcloud', () => {
       end_color: 'rgb(70, 130, 180)'
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px; color: rgba(70, 130, 180, 0.53)">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px; color: #4682b4">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px; color: rgba(70, 130, 180, 0.77)">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px; color: rgba(70, 130, 180, 0.3)">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px; color: rgba(70, 130, 180, 0.53)">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px; color: #4682b4">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px; color: rgba(70, 130, 180, 0.77)">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px; color: rgba(70, 130, 180, 0.3)">def</a>'
+      ].join(' ')
+    );
   });
 
   it('color: HSLA', () => {
@@ -198,26 +239,33 @@ describe('tagcloud', () => {
       end_color: 'hsl(207, 44%, 49%)' // rgb(70, 130, 180)
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px; color: rgba(70, 130, 180, 0.53)">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px; color: #4682b4">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px; color: rgba(70, 130, 180, 0.77)">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px; color: rgba(70, 130, 180, 0.3)">def</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px; color: rgba(70, 130, 180, 0.53)">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px; color: #4682b4">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px; color: rgba(70, 130, 180, 0.77)">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px; color: rgba(70, 130, 180, 0.3)">def</a>'
+      ].join(' ')
+    );
   });
 
   it('color - when every tag has the same number of posts, start_color should be used.', () => {
-    const result = tagcloud(Tag.find({
-      name: /abc/
-    }), {
-      color: true,
-      start_color: 'red',
-      end_color: 'pink'
-    });
+    const result = tagcloud(
+      Tag.find({
+        name: /abc/
+      }),
+      {
+        color: true,
+        start_color: 'red',
+        end_color: 'pink'
+      }
+    );
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 10px; color: #f00">abc</a>'
-    ].join(' '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 10px; color: #f00">abc</a>'
+      ].join(' ')
+    );
   });
 
   it('separator', () => {
@@ -225,11 +273,13 @@ describe('tagcloud', () => {
       separator: ', '
     });
 
-    result.should.eql([
-      '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
-      '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
-      '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
-      '<a href="/tags/def/" style="font-size: 10px;">def</a>'
-    ].join(', '));
+    result.should.eql(
+      [
+        '<a href="/tags/abc/" style="font-size: 13.33px;">abc</a>',
+        '<a href="/tags/bcd/" style="font-size: 20px;">bcd</a>',
+        '<a href="/tags/cde/" style="font-size: 16.67px;">cde</a>',
+        '<a href="/tags/def/" style="font-size: 10px;">def</a>'
+      ].join(', ')
+    );
   });
 });
diff --git a/test/scripts/helpers/toc.js b/test/scripts/helpers/toc.js
index 02c2cd17f6..29e753eab9 100644
--- a/test/scripts/helpers/toc.js
+++ b/test/scripts/helpers/toc.js
@@ -21,11 +21,14 @@ describe('toc', () => {
   ].join('');
 
   const genResult = options => {
-    options = Object.assign({
-      class: 'toc',
-      list_number: true,
-      max_depth: 6
-    }, options);
+    options = Object.assign(
+      {
+        class: 'toc',
+        list_number: true,
+        max_depth: 6
+      },
+      options
+    );
 
     const className = options.class;
     const listNumber = options.list_number;
@@ -35,7 +38,11 @@ describe('toc', () => {
       '<ol class="' + className + '-child">',
       '<li class="' + className + '-item ' + className + '-level-3">',
       '<a class="' + className + '-link" href="#title_1_1_1">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.1.1.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.1.1.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1.1.1</span>',
       '</a>',
       '</li>',
@@ -46,7 +53,11 @@ describe('toc', () => {
       '<ol class="' + className + '-child">',
       '<li class="' + className + '-item ' + className + '-level-3">',
       '<a class="' + className + '-link" href="#title_1_3_1">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.3.1.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.3.1.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1.3.1</span>',
       '</a>',
       '</li>',
@@ -57,20 +68,32 @@ describe('toc', () => {
       '<ol class="' + className + '-child">',
       '<li class="' + className + '-item ' + className + '-level-2">',
       '<a class="' + className + '-link" href="#title_1_1">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.1.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.1.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1.1</span>',
       '</a>',
       ifTrue(maxDepth >= 3, resultTitle_1_1_1, ''),
       '</li>',
       '<li class="' + className + '-item ' + className + '-level-2">',
       '<a class="' + className + '-link" href="#title_1_2">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.2.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.2.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1.2</span>',
       '</a>',
       '</li>',
       '<li class="' + className + '-item ' + className + '-level-2">',
       '<a class="' + className + '-link" href="#title_1_3">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.3.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.3.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1.3</span>',
       '</a>',
       ifTrue(maxDepth >= 3, resultTitle_1_3_1, ''),
@@ -82,7 +105,11 @@ describe('toc', () => {
       '<ol class="' + className + '-child">',
       '<li class="' + className + '-item ' + className + '-level-2">',
       '<a class="' + className + '-link" href="#title_2_1">',
-      ifTrue(listNumber, '<span class="' + className + '-number">2.1.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">2.1.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 2.1</span>',
       '</a>',
       '</li>',
@@ -92,28 +119,48 @@ describe('toc', () => {
     const resultAllTitles_Level1 = [
       '<li class="' + className + '-item ' + className + '-level-1">',
       '<a class="' + className + '-link" href="#title_1">',
-      ifTrue(listNumber, '<span class="' + className + '-number">1.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">1.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 1</span>',
       '</a>',
       ifTrue(maxDepth >= 2, resultTitle_1_1, ''),
       '</li>',
       '<li class="' + className + '-item ' + className + '-level-1">',
       '<a class="' + className + '-link" href="#title_2">',
-      ifTrue(listNumber, '<span class="' + className + '-number">2.</span> ', ''),
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">2.</span> ',
+        ''
+      ),
       '<span class="' + className + '-text">Title 2</span>',
       '</a>',
       ifTrue(maxDepth >= 2, resultTitle_2_1, ''),
       '</li>',
       '<li class="' + className + '-item ' + className + '-level-1">',
       '<a class="' + className + '-link" href="#title_3">',
-      ifTrue(listNumber, '<span class="' + className + '-number">3.</span> ', ''),
-      '<span class="' + className + '-text">Title should escape &, <, ', and "</span>',
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">3.</span> ',
+        ''
+      ),
+      '<span class="' +
+        className +
+        '-text">Title should escape &, <, ', and "</span>',
       '</a>',
       '</li>',
       '<li class="' + className + '-item ' + className + '-level-1">',
       '<a class="' + className + '-link" href="#title_4">',
-      ifTrue(listNumber, '<span class="' + className + '-number">4.</span> ', ''),
-      '<span class="' + className + '-text">Chapter 1 should be printed to toc</span>',
+      ifTrue(
+        listNumber,
+        '<span class="' + className + '-number">4.</span> ',
+        ''
+      ),
+      '<span class="' +
+        className +
+        '-text">Chapter 1 should be printed to toc</span>',
       '</a>',
       '</li>'
     ].join('');
diff --git a/test/scripts/helpers/url_for.js b/test/scripts/helpers/url_for.js
index 0195805d9f..dc5a3903d8 100644
--- a/test/scripts/helpers/url_for.js
+++ b/test/scripts/helpers/url_for.js
@@ -35,18 +35,15 @@ describe('url_for', () => {
 
   it('internal url (options.relative)', () => {
     ctx.path = '';
-    urlFor('index.html', {relative: true}).should.eql('index.html');
+    urlFor('index.html', { relative: true }).should.eql('index.html');
 
     ctx.config.relative_link = true;
-    urlFor('index.html', {relative: false}).should.eql('/index.html');
+    urlFor('index.html', { relative: false }).should.eql('/index.html');
     ctx.config.relative_link = false;
   });
 
   it('external url', () => {
-    [
-      'https://hexo.io/',
-      '//google.com/'
-    ].forEach(url => {
+    ['https://hexo.io/', '//google.com/'].forEach(url => {
       urlFor(url).should.eql(url);
     });
   });
diff --git a/test/scripts/hexo/hexo.js b/test/scripts/hexo/hexo.js
index de3290fb98..5c89225b40 100644
--- a/test/scripts/hexo/hexo.js
+++ b/test/scripts/hexo/hexo.js
@@ -10,7 +10,7 @@ const testUtil = require('../../util');
 describe('Hexo', () => {
   const base_dir = pathFn.join(__dirname, 'hexo_test');
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(base_dir, {silent: true});
+  const hexo = new Hexo(base_dir, { silent: true });
   const coreDir = pathFn.join(__dirname, '../../..');
   const version = require('../../../package.json').version;
   const Post = hexo.model('Post');
@@ -25,7 +25,10 @@ describe('Hexo', () => {
   }
 
   function loadAssetGenerator() {
-    hexo.extend.generator.register('asset', require('../../../lib/plugins/generator/asset'));
+    hexo.extend.generator.register(
+      'asset',
+      require('../../../lib/plugins/generator/asset')
+    );
   }
 
   before(() => fs.mkdirs(hexo.base_dir).then(() => hexo.init()));
@@ -68,20 +71,24 @@ describe('Hexo', () => {
   });
 
   it('constructs mutli-config', () => {
-    const configs = ['../../../fixtures/_config.json', '../../../fixtures/_config.json'];
+    const configs = [
+      '../../../fixtures/_config.json',
+      '../../../fixtures/_config.json'
+    ];
     const args = { _: [], config: configs.join(',') };
     const hexo = new Hexo(base_dir, args);
     hexo.config_path.should.eql(pathFn.join(base_dir, '_multiconfig.yml'));
   });
 
-  it('call()', () => hexo.call('test', {foo: 'bar'}).then(data => {
-    data.should.eql({foo: 'bar'});
-  }));
+  it('call()', () =>
+    hexo.call('test', { foo: 'bar' }).then(data => {
+      data.should.eql({ foo: 'bar' });
+    }));
 
   it('call() - callback', callback => {
-    hexo.call('test', {foo: 'bar'}, (err, data) => {
+    hexo.call('test', { foo: 'bar' }, (err, data) => {
       should.not.exist(err);
-      data.should.eql({foo: 'bar'});
+      data.should.eql({ foo: 'bar' });
 
       callback();
     });
@@ -98,16 +105,24 @@ describe('Hexo', () => {
 
   it('call() - console not registered', () => {
     const errorCallback = sinon.spy(err => {
-      err.should.have.property('message', 'Console `nothing` has not been registered yet!');
+      err.should.have.property(
+        'message',
+        'Console `nothing` has not been registered yet!'
+      );
     });
 
-    return hexo.call('nothing').catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return hexo
+      .call('nothing')
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('init()', () => {
-    const hexo = new Hexo(pathFn.join(__dirname, 'hexo_test'), {silent: true});
+    const hexo = new Hexo(pathFn.join(__dirname, 'hexo_test'), {
+      silent: true
+    });
     const hook = sinon.spy();
 
     hexo.extend.filter.register('after_init', hook);
@@ -141,7 +156,11 @@ describe('Hexo', () => {
 
     loadAssetGenerator();
 
-    return fs.writeFile(target, body).then(() => hexo.load()).then(() => checkStream(route.get('test.txt'), body)).then(() => fs.unlink(target));
+    return fs
+      .writeFile(target, body)
+      .then(() => hexo.load())
+      .then(() => checkStream(route.get('test.txt'), body))
+      .then(() => fs.unlink(target));
   }
 
   it('load() - source', () => testLoad(hexo.source_dir));
@@ -155,12 +174,30 @@ describe('Hexo', () => {
 
     loadAssetGenerator();
 
-    return fs.writeFile(target, body).then(() => hexo.watch()).then(() => // Test for first generation
-      checkStream(route.get('test.txt'), body)).then(() => // Update the file
-      fs.writeFile(target, newBody)).delay(300).then(() => // Check the new route
-      checkStream(route.get('test.txt'), newBody)).then(() => // Stop watching
-      hexo.unwatch()).then(() => // Delete the file
-      fs.unlink(target));
+    return fs
+      .writeFile(target, body)
+      .then(() => hexo.watch())
+      .then(() =>
+        // Test for first generation
+        checkStream(route.get('test.txt'), body)
+      )
+      .then(() =>
+        // Update the file
+        fs.writeFile(target, newBody)
+      )
+      .delay(300)
+      .then(() =>
+        // Check the new route
+        checkStream(route.get('test.txt'), newBody)
+      )
+      .then(() =>
+        // Stop watching
+        hexo.unwatch()
+      )
+      .then(() =>
+        // Delete the file
+        fs.unlink(target)
+      );
   }
 
   it('watch() - source', () => testWatch(hexo.source_dir));
@@ -184,20 +221,20 @@ describe('Hexo', () => {
 
   it('exit() - error handling - callback', callback => {
     hexo.once('exit', err => {
-      err.should.eql({foo: 'bar'});
+      err.should.eql({ foo: 'bar' });
       callback();
     });
 
-    hexo.exit({foo: 'bar'});
+    hexo.exit({ foo: 'bar' });
   });
 
   it('exit() - error handling - promise', () => {
     return Promise.all([
-      hexo.exit({foo: 'bar'}),
+      hexo.exit({ foo: 'bar' }),
       new Promise((resolve, reject) => {
         hexo.once('exit', err => {
           try {
-            err.should.eql({foo: 'bar'});
+            err.should.eql({ foo: 'bar' });
             resolve();
           } catch (e) {
             reject(e);
@@ -207,76 +244,106 @@ describe('Hexo', () => {
     ]);
   });
 
-  it('draft visibility', () => Post.insert([
-    {source: 'foo', slug: 'foo', published: true},
-    {source: 'bar', slug: 'bar', published: false}
-  ]).then(posts => {
-    hexo.locals.invalidate();
-    hexo.locals.get('posts').toArray().should.eql(posts.slice(0, 1));
-
-    // draft visible
-    hexo.config.render_drafts = true;
-    hexo.locals.invalidate();
-    hexo.locals.get('posts').toArray().should.eql(posts);
-    hexo.config.render_drafts = false;
-
-    return posts;
-  }).map(post => Post.removeById(post._id)));
-
-  it('future posts', () => Post.insert([
-    {source: 'foo', slug: 'foo', date: Date.now() - 3600},
-    {source: 'bar', slug: 'bar', date: Date.now() + 3600}
-  ]).then(posts => {
-    function mapper(post) {
-      return post._id;
-    }
-
-    // future on
-    hexo.config.future = true;
-    hexo.locals.invalidate();
-    hexo.locals.get('posts').map(mapper).should.eql(posts.map(mapper));
-
-    // future off
-    hexo.config.future = false;
-    hexo.locals.invalidate();
-    hexo.locals.get('posts').map(mapper).should.eql([posts[0]._id]);
-
-    return posts;
-  }).map(post => Post.removeById(post._id)));
-
-  it('future pages', () => Page.insert([
-    {source: 'foo', path: 'foo', date: Date.now() - 3600},
-    {source: 'bar', path: 'bar', date: Date.now() + 3600}
-  ]).then(pages => {
-    function mapper(page) {
-      return page._id;
-    }
-
-    // future on
-    hexo.config.future = true;
-    hexo.locals.invalidate();
-    hexo.locals.get('pages').map(mapper).should.eql(pages.map(mapper));
-
-    // future off
-    hexo.config.future = false;
-    hexo.locals.invalidate();
-    hexo.locals.get('pages').map(mapper).should.eql([pages[0]._id]);
-
-    return pages;
-  }).map(page => Page.removeById(page._id)));
-
-  it('locals.data', () => Data.insert([
-    {_id: 'users', data: {foo: 1}},
-    {_id: 'comments', data: {bar: 2}}
-  ]).then(data => {
-    hexo.locals.invalidate();
-    hexo.locals.get('data').should.eql({
-      users: {foo: 1},
-      comments: {bar: 2}
-    });
+  it('draft visibility', () =>
+    Post.insert([
+      { source: 'foo', slug: 'foo', published: true },
+      { source: 'bar', slug: 'bar', published: false }
+    ])
+      .then(posts => {
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('posts')
+          .toArray()
+          .should.eql(posts.slice(0, 1));
+
+        // draft visible
+        hexo.config.render_drafts = true;
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('posts')
+          .toArray()
+          .should.eql(posts);
+        hexo.config.render_drafts = false;
+
+        return posts;
+      })
+      .map(post => Post.removeById(post._id)));
+
+  it('future posts', () =>
+    Post.insert([
+      { source: 'foo', slug: 'foo', date: Date.now() - 3600 },
+      { source: 'bar', slug: 'bar', date: Date.now() + 3600 }
+    ])
+      .then(posts => {
+        function mapper(post) {
+          return post._id;
+        }
+
+        // future on
+        hexo.config.future = true;
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('posts')
+          .map(mapper)
+          .should.eql(posts.map(mapper));
+
+        // future off
+        hexo.config.future = false;
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('posts')
+          .map(mapper)
+          .should.eql([posts[0]._id]);
+
+        return posts;
+      })
+      .map(post => Post.removeById(post._id)));
+
+  it('future pages', () =>
+    Page.insert([
+      { source: 'foo', path: 'foo', date: Date.now() - 3600 },
+      { source: 'bar', path: 'bar', date: Date.now() + 3600 }
+    ])
+      .then(pages => {
+        function mapper(page) {
+          return page._id;
+        }
+
+        // future on
+        hexo.config.future = true;
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('pages')
+          .map(mapper)
+          .should.eql(pages.map(mapper));
+
+        // future off
+        hexo.config.future = false;
+        hexo.locals.invalidate();
+        hexo.locals
+          .get('pages')
+          .map(mapper)
+          .should.eql([pages[0]._id]);
+
+        return pages;
+      })
+      .map(page => Page.removeById(page._id)));
+
+  it('locals.data', () =>
+    Data.insert([
+      { _id: 'users', data: { foo: 1 } },
+      { _id: 'comments', data: { bar: 2 } }
+    ])
+      .then(data => {
+        hexo.locals.invalidate();
+        hexo.locals.get('data').should.eql({
+          users: { foo: 1 },
+          comments: { bar: 2 }
+        });
 
-    return data;
-  }).map(data => data.remove()));
+        return data;
+      })
+      .map(data => data.remove()));
 
   it('_generate()', () => {
     // object
@@ -293,10 +360,7 @@ describe('Hexo', () => {
     hexo.extend.generator.register('test_arr', locals => {
       locals.test.should.eql('foo');
 
-      return [
-        {path: 'bar', data: 'bar'},
-        {path: 'baz', data: 'baz'}
-      ];
+      return [{ path: 'bar', data: 'bar' }, { path: 'baz', data: 'baz' }];
     });
 
     const beforeListener = sinon.spy();
@@ -329,12 +393,15 @@ describe('Hexo', () => {
   });
 
   it('_generate() - layout', () => {
-    hexo.theme.setView('test.swig', [
-      '{{ config.title }}',
-      '{{ page.foo }}',
-      '{{ layout }}',
-      '{{ view_dir }}'
-    ].join('\n'));
+    hexo.theme.setView(
+      'test.swig',
+      [
+        '{{ config.title }}',
+        '{{ page.foo }}',
+        '{{ layout }}',
+        '{{ view_dir }}'
+      ].join('\n')
+    );
 
     hexo.extend.generator.register('test', () => ({
       path: 'test',
@@ -352,7 +419,9 @@ describe('Hexo', () => {
       pathFn.join(hexo.theme_dir, 'layout') + pathFn.sep
     ].join('\n');
 
-    return hexo._generate().then(() => checkStream(route.get('test'), expected));
+    return hexo
+      ._generate()
+      .then(() => checkStream(route.get('test'), expected));
   });
 
   it('_generate() - layout array', () => {
@@ -407,25 +476,31 @@ describe('Hexo', () => {
   });
 
   it('_generate() - validate locals', () => {
-    hexo.theme.setView('test.swig', [
-      '{{ path }}',
-      '{{ url }}',
-      '{{ view_dir }}'
-    ].join('\n'));
+    hexo.theme.setView(
+      'test.swig',
+      ['{{ path }}', '{{ url }}', '{{ view_dir }}'].join('\n')
+    );
 
     hexo.extend.generator.register('test', () => ({
       path: 'test',
       layout: 'test'
     }));
 
-    return hexo._generate().then(() => checkStream(route.get('test'), [
-      'test',
-      hexo.config.url + '/test',
-      pathFn.join(hexo.theme_dir, 'layout') + pathFn.sep
-    ].join('\n')));
+    return hexo
+      ._generate()
+      .then(() =>
+        checkStream(
+          route.get('test'),
+          [
+            'test',
+            hexo.config.url + '/test',
+            pathFn.join(hexo.theme_dir, 'layout') + pathFn.sep
+          ].join('\n')
+        )
+      );
   });
 
-  it('_generate() - do nothing if it\'s generating', () => {
+  it("_generate() - do nothing if it's generating", () => {
     const spy = sinon.spy();
     hexo.extend.generator.register('test', spy);
 
@@ -443,12 +518,18 @@ describe('Hexo', () => {
     hexo.extend.generator.register('test', () => ({
       path: 'test',
       layout: 'test',
-      data: {count: count++}
+      data: { count: count++ }
     }));
 
     // First generation
-    return hexo._generate({cache: true}).then(() => checkStream(route.get('test'), '0')).then(() => // Second generation
-      hexo._generate({cache: true})).then(() => checkStream(route.get('test'), '1'));
+    return hexo
+      ._generate({ cache: true })
+      .then(() => checkStream(route.get('test'), '0'))
+      .then(() =>
+        // Second generation
+        hexo._generate({ cache: true })
+      )
+      .then(() => checkStream(route.get('test'), '1'));
   });
 
   it('_generate() - cache disabled & update template', () => {
@@ -459,10 +540,13 @@ describe('Hexo', () => {
       layout: 'test'
     }));
 
-    return hexo._generate({cache: false}).then(() => checkStream(route.get('test'), '0')).then(() => {
-      hexo.theme.setView('test.swig', '1');
-      return checkStream(route.get('test'), '1');
-    });
+    return hexo
+      ._generate({ cache: false })
+      .then(() => checkStream(route.get('test'), '0'))
+      .then(() => {
+        hexo.theme.setView('test.swig', '1');
+        return checkStream(route.get('test'), '1');
+      });
   });
 
   it('execFilter()', () => {
diff --git a/test/scripts/hexo/load_config.js b/test/scripts/hexo/load_config.js
index 5c68e9c1ae..0073f45220 100644
--- a/test/scripts/hexo/load_config.js
+++ b/test/scripts/hexo/load_config.js
@@ -6,7 +6,9 @@ const cloneDeep = require('lodash/cloneDeep');
 
 describe('Load config', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {
+    silent: true
+  });
   const loadConfig = require('../../../lib/hexo/load_config');
   const defaultConfig = require('../../../lib/hexo/default_config');
 
@@ -20,94 +22,143 @@ describe('Load config', () => {
     hexo.config = cloneDeep(defaultConfig);
   });
 
-  it('config file does not exist', () => loadConfig(hexo).then(() => {
-    hexo.config.should.eql(defaultConfig);
-  }));
+  it('config file does not exist', () =>
+    loadConfig(hexo).then(() => {
+      hexo.config.should.eql(defaultConfig);
+    }));
 
   it('_config.yml exists', () => {
     const configPath = pathFn.join(hexo.base_dir, '_config.yml');
 
-    return fs.writeFile(configPath, 'foo: 1').then(() => loadConfig(hexo)).then(() => {
-      hexo.config.foo.should.eql(1);
-    }).finally(() => fs.unlink(configPath));
+    return fs
+      .writeFile(configPath, 'foo: 1')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.foo.should.eql(1);
+      })
+      .finally(() => fs.unlink(configPath));
   });
 
   it('_config.json exists', () => {
     const configPath = pathFn.join(hexo.base_dir, '_config.json');
 
-    return fs.writeFile(configPath, '{"baz": 3}').then(() => loadConfig(hexo)).then(() => {
-      hexo.config.baz.should.eql(3);
-    }).finally(() => fs.unlink(configPath));
+    return fs
+      .writeFile(configPath, '{"baz": 3}')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.baz.should.eql(3);
+      })
+      .finally(() => fs.unlink(configPath));
   });
 
   it('_config.txt exists', () => {
     const configPath = pathFn.join(hexo.base_dir, '_config.txt');
 
-    return fs.writeFile(configPath, 'foo: 1').then(() => loadConfig(hexo)).then(() => {
-      hexo.config.should.eql(defaultConfig);
-    }).finally(() => fs.unlink(configPath));
+    return fs
+      .writeFile(configPath, 'foo: 1')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.should.eql(defaultConfig);
+      })
+      .finally(() => fs.unlink(configPath));
   });
 
   it('custom config path', () => {
-    const configPath = hexo.config_path = pathFn.join(__dirname, 'werwerwer.yml');
-
-    return fs.writeFile(configPath, 'foo: 1').then(() => loadConfig(hexo)).then(() => {
-      hexo.config.foo.should.eql(1);
-    }).finally(() => {
-      hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
-      return fs.unlink(configPath);
-    });
+    const configPath = (hexo.config_path = pathFn.join(
+      __dirname,
+      'werwerwer.yml'
+    ));
+
+    return fs
+      .writeFile(configPath, 'foo: 1')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.foo.should.eql(1);
+      })
+      .finally(() => {
+        hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
+        return fs.unlink(configPath);
+      });
   });
 
   it('custom config path with different extension name', () => {
     const realPath = pathFn.join(__dirname, 'werwerwer.json');
     hexo.config_path = pathFn.join(__dirname, 'werwerwer.yml');
 
-    return fs.writeFile(realPath, '{"foo": 2}').then(() => loadConfig(hexo)).then(() => {
-      hexo.config.foo.should.eql(2);
-      hexo.config_path.should.eql(realPath);
-    }).finally(() => {
-      hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
-      return fs.unlink(realPath);
-    });
+    return fs
+      .writeFile(realPath, '{"foo": 2}')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.foo.should.eql(2);
+        hexo.config_path.should.eql(realPath);
+      })
+      .finally(() => {
+        hexo.config_path = pathFn.join(hexo.base_dir, '_config.yml');
+        return fs.unlink(realPath);
+      });
   });
 
   it('handle trailing "/" of url', () => {
-    const content = [
-      'root: foo',
-      'url: https://hexo.io/'
-    ].join('\n');
-
-    return fs.writeFile(hexo.config_path, content).then(() => loadConfig(hexo)).then(() => {
-      hexo.config.root.should.eql('foo/');
-      hexo.config.url.should.eql('https://hexo.io');
-    }).finally(() => fs.unlink(hexo.config_path));
+    const content = ['root: foo', 'url: https://hexo.io/'].join('\n');
+
+    return fs
+      .writeFile(hexo.config_path, content)
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.root.should.eql('foo/');
+        hexo.config.url.should.eql('https://hexo.io');
+      })
+      .finally(() => fs.unlink(hexo.config_path));
   });
 
-  it('custom public_dir', () => fs.writeFile(hexo.config_path, 'public_dir: foo').then(() => loadConfig(hexo)).then(() => {
-    hexo.public_dir.should.eql(pathFn.resolve(hexo.base_dir, 'foo') + pathFn.sep);
-  }).finally(() => fs.unlink(hexo.config_path)));
-
-  it('custom source_dir', () => fs.writeFile(hexo.config_path, 'source_dir: bar').then(() => loadConfig(hexo)).then(() => {
-    hexo.source_dir.should.eql(pathFn.resolve(hexo.base_dir, 'bar') + pathFn.sep);
-  }).finally(() => fs.unlink(hexo.config_path)));
-
-  it('custom theme', () => fs.writeFile(hexo.config_path, 'theme: test').then(() => loadConfig(hexo)).then(() => {
-    hexo.config.theme.should.eql('test');
-    hexo.theme_dir.should.eql(pathFn.join(hexo.base_dir, 'themes', 'test') + pathFn.sep);
-    hexo.theme_script_dir.should.eql(pathFn.join(hexo.theme_dir, 'scripts') + pathFn.sep);
-    hexo.theme.base.should.eql(hexo.theme_dir);
-  }).finally(() => fs.unlink(hexo.config_path)));
+  it('custom public_dir', () =>
+    fs
+      .writeFile(hexo.config_path, 'public_dir: foo')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.public_dir.should.eql(
+          pathFn.resolve(hexo.base_dir, 'foo') + pathFn.sep
+        );
+      })
+      .finally(() => fs.unlink(hexo.config_path)));
+
+  it('custom source_dir', () =>
+    fs
+      .writeFile(hexo.config_path, 'source_dir: bar')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.source_dir.should.eql(
+          pathFn.resolve(hexo.base_dir, 'bar') + pathFn.sep
+        );
+      })
+      .finally(() => fs.unlink(hexo.config_path)));
+
+  it('custom theme', () =>
+    fs
+      .writeFile(hexo.config_path, 'theme: test')
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.theme.should.eql('test');
+        hexo.theme_dir.should.eql(
+          pathFn.join(hexo.base_dir, 'themes', 'test') + pathFn.sep
+        );
+        hexo.theme_script_dir.should.eql(
+          pathFn.join(hexo.theme_dir, 'scripts') + pathFn.sep
+        );
+        hexo.theme.base.should.eql(hexo.theme_dir);
+      })
+      .finally(() => fs.unlink(hexo.config_path)));
 
   it('merge config', () => {
-    const content = [
-      'highlight:',
-      '  tab_replace: yoooo'
-    ].join('\n');
-
-    return fs.writeFile(hexo.config_path, content).then(() => loadConfig(hexo)).then(() => {
-      hexo.config.highlight.enable.should.be.true;
-      hexo.config.highlight.tab_replace.should.eql('yoooo');
-    }).finally(() => fs.unlink(hexo.config_path));
+    const content = ['highlight:', '  tab_replace: yoooo'].join('\n');
+
+    return fs
+      .writeFile(hexo.config_path, content)
+      .then(() => loadConfig(hexo))
+      .then(() => {
+        hexo.config.highlight.enable.should.be.true;
+        hexo.config.highlight.tab_replace.should.eql('yoooo');
+      })
+      .finally(() => fs.unlink(hexo.config_path));
   });
 });
diff --git a/test/scripts/hexo/load_database.js b/test/scripts/hexo/load_database.js
index 770e30fe35..5550a70c54 100644
--- a/test/scripts/hexo/load_database.js
+++ b/test/scripts/hexo/load_database.js
@@ -5,7 +5,7 @@ const fs = require('hexo-fs');
 
 describe('Load database', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'db_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'db_test'), { silent: true });
   const loadDatabase = require('../../../lib/hexo/load_database');
   const dbPath = hexo.database.options.path;
 
@@ -15,11 +15,7 @@ describe('Load database', () => {
       warehouse: require('warehouse').version
     },
     models: {
-      Test: [
-        {_id: 'A'},
-        {_id: 'B'},
-        {_id: 'C'}
-      ]
+      Test: [{ _id: 'A' }, { _id: 'B' }, { _id: 'C' }]
     }
   };
 
@@ -33,29 +29,44 @@ describe('Load database', () => {
 
   it('database does not exist', () => loadDatabase(hexo));
 
-  it('database load success', () => fs.writeFile(dbPath, JSON.stringify(fixture)).then(() => loadDatabase(hexo)).then(() => {
-    hexo._dbLoaded.should.be.true;
-    hexo.model('Test').toArray({lean: true}).should.eql(fixture.models.Test);
-    hexo.model('Test').destroy();
+  it('database load success', () =>
+    fs
+      .writeFile(dbPath, JSON.stringify(fixture))
+      .then(() => loadDatabase(hexo))
+      .then(() => {
+        hexo._dbLoaded.should.be.true;
+        hexo
+          .model('Test')
+          .toArray({ lean: true })
+          .should.eql(fixture.models.Test);
+        hexo.model('Test').destroy();
 
-    return fs.unlink(dbPath);
-  }));
+        return fs.unlink(dbPath);
+      }));
 
-  it('don\'t load database if loaded', () => {
+  it("don't load database if loaded", () => {
     hexo._dbLoaded = true;
 
-    return fs.writeFile(dbPath, JSON.stringify(fixture)).then(() => loadDatabase(hexo)).then(() => {
-      hexo.model('Test').length.should.eql(0);
-      return fs.unlink(dbPath);
-    });
+    return fs
+      .writeFile(dbPath, JSON.stringify(fixture))
+      .then(() => loadDatabase(hexo))
+      .then(() => {
+        hexo.model('Test').length.should.eql(0);
+        return fs.unlink(dbPath);
+      });
   });
 
   // I don't know why this test case can't pass on Windows
   // It always throws EPERM error
-  it.skip('database load failed', () => fs.writeFile(dbPath, '{1423432: 324').then(() => loadDatabase(hexo)).then(() => {
-    hexo._dbLoaded.should.be.false;
-    return fs.exists(dbPath);
-  }).then(exist => {
-    exist.should.be.false;
-  }));
+  it.skip('database load failed', () =>
+    fs
+      .writeFile(dbPath, '{1423432: 324')
+      .then(() => loadDatabase(hexo))
+      .then(() => {
+        hexo._dbLoaded.should.be.false;
+        return fs.exists(dbPath);
+      })
+      .then(exist => {
+        exist.should.be.false;
+      }));
 });
diff --git a/test/scripts/hexo/load_plugins.js b/test/scripts/hexo/load_plugins.js
index cdf8aef921..10ad609d7f 100644
--- a/test/scripts/hexo/load_plugins.js
+++ b/test/scripts/hexo/load_plugins.js
@@ -6,7 +6,9 @@ const Promise = require('bluebird');
 
 describe('Load plugins', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(pathFn.join(__dirname, 'plugin_test'), {silent: true});
+  const hexo = new Hexo(pathFn.join(__dirname, 'plugin_test'), {
+    silent: true
+  });
   const loadPlugins = require('../../../lib/hexo/load_plugins');
 
   const script = [
@@ -41,7 +43,10 @@ describe('Load plugins', () => {
       pkg.dependencies[args[i]] = '*';
     }
 
-    return fs.writeFile(pathFn.join(hexo.base_dir, 'package.json'), JSON.stringify(pkg, null, '  '));
+    return fs.writeFile(
+      pathFn.join(hexo.base_dir, 'package.json'),
+      JSON.stringify(pkg, null, '  ')
+    );
   }
 
   function createPackageFileWithDevDeps(...args) {
@@ -57,11 +62,19 @@ describe('Load plugins', () => {
       pkg.devDependencies[args[i]] = '*';
     }
 
-    return fs.writeFile(pathFn.join(hexo.base_dir, 'package.json'), JSON.stringify(pkg, null, '  '));
+    return fs.writeFile(
+      pathFn.join(hexo.base_dir, 'package.json'),
+      JSON.stringify(pkg, null, '  ')
+    );
   }
 
   hexo.env.init = true;
-  hexo.theme_script_dir = pathFn.join(hexo.base_dir, 'themes', 'test', 'scripts');
+  hexo.theme_script_dir = pathFn.join(
+    hexo.base_dir,
+    'themes',
+    'test',
+    'scripts'
+  );
 
   before(() => fs.mkdir(hexo.base_dir));
 
@@ -71,26 +84,24 @@ describe('Load plugins', () => {
     const name = 'hexo-plugin-test';
     const path = pathFn.join(hexo.plugin_dir, name, 'index.js');
 
-    return Promise.all([
-      createPackageFile(name),
-      fs.writeFile(path, script)
-    ]).then(() => loadPlugins(hexo)).then(() => {
-      validate(path);
-      return fs.unlink(path);
-    });
+    return Promise.all([createPackageFile(name), fs.writeFile(path, script)])
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        validate(path);
+        return fs.unlink(path);
+      });
   });
 
   it('load scoped plugins', () => {
     const name = '@some-scope/hexo-plugin-test';
     const path = pathFn.join(hexo.plugin_dir, name, 'index.js');
 
-    return Promise.all([
-      createPackageFile(name),
-      fs.writeFile(path, script)
-    ]).then(() => loadPlugins(hexo)).then(() => {
-      validate(path);
-      return fs.unlink(path);
-    });
+    return Promise.all([createPackageFile(name), fs.writeFile(path, script)])
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        validate(path);
+        return fs.unlink(path);
+      });
   });
 
   it('load devDep plugins', () => {
@@ -100,32 +111,38 @@ describe('Load plugins', () => {
     return Promise.all([
       createPackageFileWithDevDeps(name),
       fs.writeFile(path, script)
-    ]).then(() => loadPlugins(hexo)).then(() => {
-      validate(path);
-      return fs.unlink(path);
-    });
+    ])
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        validate(path);
+        return fs.unlink(path);
+      });
   });
 
   it('specify plugin list in config', () => {
     const names = ['hexo-plugin-test', 'another-plugin'];
-    const paths = names.map(name => pathFn.join(hexo.plugin_dir, name, 'index.js'));
+    const paths = names.map(name =>
+      pathFn.join(hexo.plugin_dir, name, 'index.js')
+    );
 
     return Promise.all([
       createPackageFile(...names),
       fs.writeFile(paths[0], 'hexo._script_test0 = true'),
       fs.writeFile(paths[1], 'hexo._script_test1 = true')
-    ]).then(() => {
-      hexo.config.plugins = [names[1]];
-      return loadPlugins(hexo);
-    }).then(() => {
-      should.not.exist(hexo._script_test0);
-      hexo._script_test1.should.be.true;
-
-      delete hexo.config.plugins;
-      delete hexo._script_test1;
-
-      return Promise.map(paths, path => fs.unlink(path));
-    });
+    ])
+      .then(() => {
+        hexo.config.plugins = [names[1]];
+        return loadPlugins(hexo);
+      })
+      .then(() => {
+        should.not.exist(hexo._script_test0);
+        hexo._script_test1.should.be.true;
+
+        delete hexo.config.plugins;
+        delete hexo._script_test1;
+
+        return Promise.map(paths, path => fs.unlink(path));
+      });
   });
 
   it('ignore plugins whose name is not started with "hexo-"', () => {
@@ -133,46 +150,55 @@ describe('Load plugins', () => {
     const name = 'another-plugin';
     const path = pathFn.join(hexo.plugin_dir, name, 'index.js');
 
-    return Promise.all([
-      createPackageFile(name),
-      fs.writeFile(path, script)
-    ]).then(() => loadPlugins(hexo)).then(() => {
-      should.not.exist(hexo._script_test);
-      return fs.unlink(path);
-    });
+    return Promise.all([createPackageFile(name), fs.writeFile(path, script)])
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        should.not.exist(hexo._script_test);
+        return fs.unlink(path);
+      });
   });
 
-  it('ignore plugins which are in package.json but not exist actually', () => createPackageFile('hexo-plugin-test').then(() => loadPlugins(hexo)));
+  it('ignore plugins which are in package.json but not exist actually', () =>
+    createPackageFile('hexo-plugin-test').then(() => loadPlugins(hexo)));
 
   it('load scripts', () => {
     const path = pathFn.join(hexo.script_dir, 'test.js');
 
-    return fs.writeFile(path, script).then(() => loadPlugins(hexo)).then(() => {
-      validate(path);
-      return fs.unlink(path);
-    });
+    return fs
+      .writeFile(path, script)
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        validate(path);
+        return fs.unlink(path);
+      });
   });
 
   it('load theme scripts', () => {
     const path = pathFn.join(hexo.theme_script_dir, 'test.js');
 
-    return fs.writeFile(path, script).then(() => loadPlugins(hexo)).then(() => {
-      validate(path);
-      return fs.unlink(path);
-    });
+    return fs
+      .writeFile(path, script)
+      .then(() => loadPlugins(hexo))
+      .then(() => {
+        validate(path);
+        return fs.unlink(path);
+      });
   });
 
-  it('don\'t load plugins in safe mode', () => {
+  it("don't load plugins in safe mode", () => {
     const script = 'hexo._script_test = true';
     const path = pathFn.join(hexo.script_dir, 'test.js');
 
-    return fs.writeFile(path, script).then(() => {
-      hexo.env.safe = true;
-      return loadPlugins(hexo);
-    }).then(() => {
-      hexo.env.safe = false;
-      should.not.exist(hexo._script_test);
-      return fs.unlink(path);
-    });
+    return fs
+      .writeFile(path, script)
+      .then(() => {
+        hexo.env.safe = true;
+        return loadPlugins(hexo);
+      })
+      .then(() => {
+        hexo.env.safe = false;
+        should.not.exist(hexo._script_test);
+        return fs.unlink(path);
+      });
   });
 });
diff --git a/test/scripts/hexo/locals.js b/test/scripts/hexo/locals.js
index f1addb2469..097b45fd98 100644
--- a/test/scripts/hexo/locals.js
+++ b/test/scripts/hexo/locals.js
@@ -92,7 +92,7 @@ describe('Locals', () => {
     locals.set('foo', 'foo');
     locals.set('bar', 'bar');
     locals.remove('bar');
-    locals.toObject().should.eql({foo: 'foo'});
+    locals.toObject().should.eql({ foo: 'foo' });
   });
 
   it('invalidate()', () => {
diff --git a/test/scripts/hexo/multi_config_path.js b/test/scripts/hexo/multi_config_path.js
index 3247c5a3c9..4cbefad3fa 100644
--- a/test/scripts/hexo/multi_config_path.js
+++ b/test/scripts/hexo/multi_config_path.js
@@ -17,7 +17,7 @@ describe('config flag handling', () => {
     this.d = function(...args) {
       const type = 'debug';
       let message = '';
-      for (let i = 0; i < args.length;) {
+      for (let i = 0; i < args.length; ) {
         message += args[i];
         if (++i < args.length) {
           message += ' ';
@@ -33,7 +33,7 @@ describe('config flag handling', () => {
     this.i = function(...args) {
       const type = 'info';
       let message = '';
-      for (let i = 0; i < args.length;) {
+      for (let i = 0; i < args.length; ) {
         message += args[i];
         if (++i < args.length) {
           message += ' ';
@@ -49,7 +49,7 @@ describe('config flag handling', () => {
     this.w = function(...args) {
       const type = 'warning';
       let message = '';
-      for (let i = 0; i < args.length;) {
+      for (let i = 0; i < args.length; ) {
         message += args[i];
         if (++i < args.length) {
           message += ' ';
@@ -65,7 +65,7 @@ describe('config flag handling', () => {
     this.e = function(...args) {
       const type = 'error';
       let message = '';
-      for (let i = 0; i < args.length;) {
+      for (let i = 0; i < args.length; ) {
         message += args[i];
         if (++i < args.length) {
           message += ' ';
@@ -148,11 +148,9 @@ describe('config flag handling', () => {
   });
 
   it('1 file', () => {
-    mcp(base, 'test1.yml').should.eql(
-      pathFn.resolve(base + 'test1.yml'));
+    mcp(base, 'test1.yml').should.eql(pathFn.resolve(base + 'test1.yml'));
 
-    mcp(base, 'test1.json').should.eql(
-      pathFn.resolve(base + 'test1.json'));
+    mcp(base, 'test1.json').should.eql(pathFn.resolve(base + 'test1.json'));
 
     mcp(base, '/tmp/test3.json').should.eql('/tmp/test3.json');
   });
@@ -162,8 +160,9 @@ describe('config flag handling', () => {
 
     mcp(base, notFile).should.eql(pathFn.join(base, '_config.yml'));
     hexo.log.reader[0].type.should.eql('warning');
-    hexo.log.reader[0].msg.should.eql('Config file ' + notFile
-                          + ' not found, using default.');
+    hexo.log.reader[0].msg.should.eql(
+      'Config file ' + notFile + ' not found, using default.'
+    );
   });
 
   it('1 not found file warning absolute', () => {
@@ -171,8 +170,9 @@ describe('config flag handling', () => {
 
     mcp(base, notFile).should.eql(pathFn.join(base, '_config.yml'));
     hexo.log.reader[0].type.should.eql('warning');
-    hexo.log.reader[0].msg.should.eql('Config file ' + notFile
-                          + ' not found, using default.');
+    hexo.log.reader[0].msg.should.eql(
+      'Config file ' + notFile + ' not found, using default.'
+    );
   });
 
   it('combined config output', () => {
@@ -194,8 +194,9 @@ describe('config flag handling', () => {
 
     mcp(base, 'notafile.yml,alsonotafile.json').should.not.eql(combinedPath);
     hexo.log.reader[11].type.should.eql('error');
-    hexo.log.reader[11].msg.should.eql('No config files found.'
-                                     + ' Using _config.yml.');
+    hexo.log.reader[11].msg.should.eql(
+      'No config files found. Using _config.yml.'
+    );
   });
 
   it('combine config output with absolute paths', () => {
@@ -264,10 +265,14 @@ describe('config flag handling', () => {
     mcp(base, 'test1.yml,test1.json', outputPath).should.eql(combinedPath);
     mcp(base, 'test1.json,test2.json', outputPath).should.eql(combinedPath);
     mcp(base, 'notafile.yml,test1.json', outputPath).should.eql(combinedPath);
-    mcp(base, 'notafile.yml,alsonotafile.json', outputPath).should.not.eql(combinedPath);
+    mcp(base, 'notafile.yml,alsonotafile.json', outputPath).should.not.eql(
+      combinedPath
+    );
 
     hexo.log.reader[1].type.should.eql('debug');
-    hexo.log.reader[1].msg.should.eql(`Writing _multiconfig.yml to ${combinedPath}`);
+    hexo.log.reader[1].msg.should.eql(
+      `Writing _multiconfig.yml to ${combinedPath}`
+    );
     hexo.log.reader[2].type.should.eql('info');
     hexo.log.reader[2].msg.should.eql('Config based on 2 files');
     hexo.log.reader[6].type.should.eql('warning');
@@ -275,7 +280,8 @@ describe('config flag handling', () => {
     hexo.log.reader[7].type.should.eql('info');
     hexo.log.reader[7].msg.should.eql('Config based on 1 files');
     hexo.log.reader[11].type.should.eql('error');
-    hexo.log.reader[11].msg.should.eql('No config files found.'
-                                     + ' Using _config.yml.');
+    hexo.log.reader[11].msg.should.eql(
+      'No config files found. Using _config.yml.'
+    );
   });
 });
diff --git a/test/scripts/hexo/post.js b/test/scripts/hexo/post.js
index c65ec59d98..c3781ade12 100644
--- a/test/scripts/hexo/post.js
+++ b/test/scripts/hexo/post.js
@@ -19,19 +19,30 @@ describe('Post', () => {
   before(() => {
     clock = sinon.useFakeTimers(now);
 
-    return fs.mkdirs(hexo.base_dir, () => hexo.init()).then(() => // Load marked renderer for testing
-      hexo.loadPlugin(require.resolve('hexo-renderer-marked'))).then(() => hexo.scaffold.set('post', [
-      '---',
-      'title: {{ title }}',
-      'date: {{ date }}',
-      'tags:',
-      '---'
-    ].join('\n'))).then(() => hexo.scaffold.set('draft', [
-      '---',
-      'title: {{ title }}',
-      'tags:',
-      '---'
-    ].join('\n')));
+    return fs
+      .mkdirs(hexo.base_dir, () => hexo.init())
+      .then(() =>
+        // Load marked renderer for testing
+        hexo.loadPlugin(require.resolve('hexo-renderer-marked'))
+      )
+      .then(() =>
+        hexo.scaffold.set(
+          'post',
+          [
+            '---',
+            'title: {{ title }}',
+            'date: {{ date }}',
+            'tags:',
+            '---'
+          ].join('\n')
+        )
+      )
+      .then(() =>
+        hexo.scaffold.set(
+          'draft',
+          ['---', 'title: {{ title }}', 'tags:', '---'].join('\n')
+        )
+      );
   });
 
   after(() => {
@@ -44,54 +55,62 @@ describe('Post', () => {
     const date = moment(now);
     const listener = sinon.spy();
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     hexo.once('new', listener);
 
-    return post.create({
-      title: 'Hello World'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-      listener.calledOnce.should.be.true;
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+        listener.calledOnce.should.be.true;
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - slug', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'foo.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World',
-      slug: 'foo'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World',
+        slug: 'foo'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - filename_case', () => {
@@ -100,113 +119,139 @@ describe('Post', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'hello-world.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-      hexo.config.filename_case = 0;
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+        hexo.config.filename_case = 0;
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - layout', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'layout: photo',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World',
-      layout: 'photo'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    const content =
+      [
+        '---',
+        'layout: photo',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World',
+        layout: 'photo'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - extra data', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'foo: bar',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World',
-      foo: 'bar'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'foo: bar',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World',
+        foo: 'bar'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - rename if target existed', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => post.create({
-      title: 'Hello World'
-    })).then(post => {
-      post.path.should.eql(path);
-      return fs.exists(path);
-    }).then(exist => {
-      exist.should.be.true;
-
-      return Promise.all([
-        fs.unlink(path),
-        fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
-      ]);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        post.create({
+          title: 'Hello World'
+        })
+      )
+      .then(post => {
+        post.path.should.eql(path);
+        return fs.exists(path);
+      })
+      .then(exist => {
+        exist.should.be.true;
+
+        return Promise.all([
+          fs.unlink(path),
+          fs.unlink(pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md'))
+        ]);
+      });
   });
 
   it('create() - replace existing files', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
 
-    return post.create({
-      title: 'Hello World'
-    }).then(() => post.create({
-      title: 'Hello World'
-    }, true)).then(post => {
-      post.path.should.eql(path);
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(() =>
+        post.create(
+          {
+            title: 'Hello World'
+          },
+          true
+        )
+      )
+      .then(post => {
+        post.path.should.eql(path);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - asset folder', () => {
@@ -214,90 +259,99 @@ describe('Post', () => {
 
     hexo.config.post_asset_folder = true;
 
-    return post.create({
-      title: 'Hello World'
-    }).then(post => {
-      hexo.config.post_asset_folder = false;
-      return fs.stat(path);
-    }).then(stats => {
-      stats.isDirectory().should.be.true;
-      return fs.unlink(path + '.md');
-    });
+    return post
+      .create({
+        title: 'Hello World'
+      })
+      .then(post => {
+        hexo.config.post_asset_folder = false;
+        return fs.stat(path);
+      })
+      .then(stats => {
+        stats.isDirectory().should.be.true;
+        return fs.unlink(path + '.md');
+      });
   });
 
   it('create() - follow the separator style in the scaffold', () => {
-    const scaffold = [
-      '---',
-      'title: {{ title }}',
-      '---'
-    ].join('\n');
-
-    return hexo.scaffold.set('test', scaffold).then(() => post.create({
-      title: 'Hello World',
-      layout: 'test'
-    })).then(post => {
-      post.content.should.eql([
-        '---',
-        'title: Hello World',
-        '---'
-      ].join('\n') + '\n');
-
-      return Promise.all([
-        fs.unlink(post.path),
-        hexo.scaffold.remove('test')
-      ]);
-    });
+    const scaffold = ['---', 'title: {{ title }}', '---'].join('\n');
+
+    return hexo.scaffold
+      .set('test', scaffold)
+      .then(() =>
+        post.create({
+          title: 'Hello World',
+          layout: 'test'
+        })
+      )
+      .then(post => {
+        post.content.should.eql(
+          ['---', 'title: Hello World', '---'].join('\n') + '\n'
+        );
+
+        return Promise.all([
+          fs.unlink(post.path),
+          hexo.scaffold.remove('test')
+        ]);
+      });
   });
 
   it('create() - JSON front-matter', () => {
-    const scaffold = [
-      '"title": {{ title }}',
-      ';;;'
-    ].join('\n');
-
-    return hexo.scaffold.set('test', scaffold).then(() => post.create({
-      title: 'Hello World',
-      layout: 'test',
-      lang: 'en'
-    })).then(post => {
-      post.content.should.eql([
-        '"title": "Hello World",',
-        '"lang": "en"',
-        ';;;'
-      ].join('\n') + '\n');
-
-      return Promise.all([
-        fs.unlink(post.path),
-        hexo.scaffold.remove('test')
-      ]);
-    });
+    const scaffold = ['"title": {{ title }}', ';;;'].join('\n');
+
+    return hexo.scaffold
+      .set('test', scaffold)
+      .then(() =>
+        post.create({
+          title: 'Hello World',
+          layout: 'test',
+          lang: 'en'
+        })
+      )
+      .then(post => {
+        post.content.should.eql(
+          ['"title": "Hello World",', '"lang": "en"', ';;;'].join('\n') + '\n'
+        );
+
+        return Promise.all([
+          fs.unlink(post.path),
+          hexo.scaffold.remove('test')
+        ]);
+      });
   });
 
   // https://github.com/hexojs/hexo/issues/1100
   it('create() - non-string title', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', '12345.md');
 
-    return post.create({
-      title: 12345
-    }).then(data => {
-      data.path.should.eql(path);
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 12345
+      })
+      .then(data => {
+        data.path.should.eql(path);
+        return fs.unlink(path);
+      });
   });
 
-  it('create() - escape title', () => post.create({
-    title: 'Foo: Bar'
-  }).then(data => {
-    data.content.should.eql([
-      // js-yaml use single-quotation for dumping since 3.3
-      '---',
-      'title: \'Foo: Bar\'',
-      'date: ' + moment(now).format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n');
-    return fs.unlink(data.path);
-  }));
+  it('create() - escape title', () =>
+    post
+      .create({
+        title: 'Foo: Bar'
+      })
+      .then(data => {
+        data.content.should.eql(
+          [
+            // js-yaml use single-quotation for dumping since 3.3
+            '---',
+            "title: 'Foo: Bar'",
+            'date: ' + moment(now).format('YYYY-MM-DD HH:mm:ss'),
+            'tags:',
+            '---'
+          ].join('\n') + '\n'
+        );
+        return fs.unlink(data.path);
+      }));
 
   it('create() - with content', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
@@ -313,46 +367,56 @@ describe('Post', () => {
       'Hello hexo'
     ].join('\n');
 
-    return post.create({
-      title: 'Hello World',
-      content: 'Hello hexo'
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World',
+        content: 'Hello hexo'
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('create() - with callback', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     const callback = sinon.spy(post => {
       post.path.should.eql(path);
       post.content.should.eql(content);
     });
 
-    return post.create({
-      title: 'Hello World'
-    }, callback).then(post => {
-      callback.calledOnce.should.be.true;
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-      return fs.unlink(path);
-    });
+    return post
+      .create(
+        {
+          title: 'Hello World'
+        },
+        callback
+      )
+      .then(post => {
+        callback.calledOnce.should.be.true;
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+        return fs.unlink(path);
+      });
   });
 
   it('publish()', () => {
@@ -360,100 +424,119 @@ describe('Post', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World',
-      layout: 'draft'
-    }).then(data => {
-      draftPath = data.path;
-
-      return post.publish({
-        slug: 'Hello-World'
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World',
+        layout: 'draft'
+      })
+      .then(data => {
+        draftPath = data.path;
+
+        return post.publish({
+          slug: 'Hello-World'
+        });
+      })
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return Promise.all([fs.exists(draftPath), fs.readFile(path)]);
+      })
+      .spread((exist, data) => {
+        exist.should.be.false;
+        data.should.eql(content);
+
+        return fs.unlink(path);
       });
-    }).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return Promise.all([
-        fs.exists(draftPath),
-        fs.readFile(path)
-      ]);
-    }).spread((exist, data) => {
-      exist.should.be.false;
-      data.should.eql(content);
-
-      return fs.unlink(path);
-    });
   });
 
   it('publish() - layout', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'layout: photo',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
-
-    return post.create({
-      title: 'Hello World',
-      layout: 'draft'
-    }).then(data => post.publish({
-      slug: 'Hello-World',
-      layout: 'photo'
-    })).then(post => {
-      post.path.should.eql(path);
-      post.content.should.eql(content);
-
-      return fs.readFile(path);
-    }).then(data => {
-      data.should.eql(content);
-
-      return fs.unlink(path);
-    });
+    const content =
+      [
+        '---',
+        'layout: photo',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
+
+    return post
+      .create({
+        title: 'Hello World',
+        layout: 'draft'
+      })
+      .then(data =>
+        post.publish({
+          slug: 'Hello-World',
+          layout: 'photo'
+        })
+      )
+      .then(post => {
+        post.path.should.eql(path);
+        post.content.should.eql(content);
+
+        return fs.readFile(path);
+      })
+      .then(data => {
+        data.should.eql(content);
+
+        return fs.unlink(path);
+      });
   });
 
   it('publish() - rename if target existed', () => {
     const paths = [pathFn.join(hexo.source_dir, '_posts', 'Hello-World-1.md')];
 
     return Promise.all([
-      post.create({title: 'Hello World', layout: 'draft'}),
-      post.create({title: 'Hello World'})
-    ]).then(data => {
-      paths.push(data[1].path);
-
-      return post.publish({
-        slug: 'Hello-World'
-      });
-    }).then(data => {
-      data.path.should.eql(paths[0]);
-      return paths;
-    }).map(item => fs.unlink(item));
+      post.create({ title: 'Hello World', layout: 'draft' }),
+      post.create({ title: 'Hello World' })
+    ])
+      .then(data => {
+        paths.push(data[1].path);
+
+        return post.publish({
+          slug: 'Hello-World'
+        });
+      })
+      .then(data => {
+        data.path.should.eql(paths[0]);
+        return paths;
+      })
+      .map(item => fs.unlink(item));
   });
 
   it('publish() - replace existing files', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
 
     return Promise.all([
-      post.create({title: 'Hello World', layout: 'draft'}),
-      post.create({title: 'Hello World'})
-    ]).then(data => post.publish({
-      slug: 'Hello-World'
-    }, true)).then(data => {
-      data.path.should.eql(path);
-      return fs.unlink(path);
-    });
+      post.create({ title: 'Hello World', layout: 'draft' }),
+      post.create({ title: 'Hello World' })
+    ])
+      .then(data =>
+        post.publish(
+          {
+            slug: 'Hello-World'
+          },
+          true
+        )
+      )
+      .then(data => {
+        data.path.should.eql(path);
+        return fs.unlink(path);
+      });
   });
 
   it('publish() - asset folder', () => {
@@ -461,40 +544,57 @@ describe('Post', () => {
     const newAssetDir = pathFn.join(hexo.source_dir, '_posts', 'Hello-World');
     hexo.config.post_asset_folder = true;
 
-    return post.create({
-      title: 'Hello World',
-      layout: 'draft'
-    }).then(data => // Put some files into the asset folder
-      Promise.all([
-        fs.writeFile(pathFn.join(assetDir, 'a.txt'), 'a'),
-        fs.writeFile(pathFn.join(assetDir, 'b.txt'), 'b')
-      ])).then(() => post.publish({
-      slug: 'Hello-World'
-    })).then(post => Promise.all([
-      fs.exists(assetDir),
-      fs.listDir(newAssetDir),
-      fs.unlink(post.path)
-    ])).spread((exist, files) => {
-      hexo.config.post_asset_folder = false;
-      exist.should.be.false;
-      files.should.have.members(['a.txt', 'b.txt']);
-      return fs.rmdir(newAssetDir);
-    });
+    return post
+      .create({
+        title: 'Hello World',
+        layout: 'draft'
+      })
+      .then((
+        data // Put some files into the asset folder
+      ) =>
+        Promise.all([
+          fs.writeFile(pathFn.join(assetDir, 'a.txt'), 'a'),
+          fs.writeFile(pathFn.join(assetDir, 'b.txt'), 'b')
+        ])
+      )
+      .then(() =>
+        post.publish({
+          slug: 'Hello-World'
+        })
+      )
+      .then(post =>
+        Promise.all([
+          fs.exists(assetDir),
+          fs.listDir(newAssetDir),
+          fs.unlink(post.path)
+        ])
+      )
+      .spread((exist, files) => {
+        hexo.config.post_asset_folder = false;
+        exist.should.be.false;
+        files.should.have.members(['a.txt', 'b.txt']);
+        return fs.rmdir(newAssetDir);
+      });
   });
 
   // https://github.com/hexojs/hexo/issues/1100
   it('publish() - non-string title', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', '12345.md');
 
-    return post.create({
-      title: 12345,
-      layout: 'draft'
-    }).then(data => post.publish({
-      slug: 12345
-    })).then(data => {
-      data.path.should.eql(path);
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 12345,
+        layout: 'draft'
+      })
+      .then(data =>
+        post.publish({
+          slug: 12345
+        })
+      )
+      .then(data => {
+        data.path.should.eql(path);
+        return fs.unlink(path);
+      });
   });
 
   it('publish() - with callback', () => {
@@ -502,55 +602,66 @@ describe('Post', () => {
     const path = pathFn.join(hexo.source_dir, '_posts', 'Hello-World.md');
     const date = moment(now);
 
-    const content = [
-      '---',
-      'title: Hello World',
-      'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
-      'tags:',
-      '---'
-    ].join('\n') + '\n';
+    const content =
+      [
+        '---',
+        'title: Hello World',
+        'date: ' + date.format('YYYY-MM-DD HH:mm:ss'),
+        'tags:',
+        '---'
+      ].join('\n') + '\n';
 
     const callback = sinon.spy(post => {
       post.path.should.eql(path);
       post.content.should.eql(content);
     });
 
-    return post.create({
-      title: 'Hello World',
-      layout: 'draft'
-    }).then(data => {
-      draftPath = data.path;
-
-      return post.publish({
-        slug: 'Hello-World'
-      }, callback);
-    }).then(post => {
-      callback.calledOnce.should.be.true;
-
-      return Promise.all([
-        fs.exists(draftPath),
-        fs.readFile(path)
-      ]);
-    }).spread((exist, data) => {
-      exist.should.be.false;
-      data.should.eql(content);
-
-      return fs.unlink(path);
-    });
+    return post
+      .create({
+        title: 'Hello World',
+        layout: 'draft'
+      })
+      .then(data => {
+        draftPath = data.path;
+
+        return post.publish(
+          {
+            slug: 'Hello-World'
+          },
+          callback
+        );
+      })
+      .then(post => {
+        callback.calledOnce.should.be.true;
+
+        return Promise.all([fs.exists(draftPath), fs.readFile(path)]);
+      })
+      .spread((exist, data) => {
+        exist.should.be.false;
+        data.should.eql(content);
+
+        return fs.unlink(path);
+      });
   });
 
   // https://github.com/hexojs/hexo/issues/1139
-  it('publish() - preserve non-null data in drafts', () => post.create({
-    title: 'foo',
-    layout: 'draft',
-    tags: ['tag', 'test']
-  }).then(data => post.publish({
-    slug: 'foo'
-  })).then(data => {
-    const meta = frontMatter(data.content);
-    meta.tags.should.eql(['tag', 'test']);
-    return fs.unlink(data.path);
-  }));
+  it('publish() - preserve non-null data in drafts', () =>
+    post
+      .create({
+        title: 'foo',
+        layout: 'draft',
+        tags: ['tag', 'test']
+      })
+      .then(data =>
+        post.publish({
+          slug: 'foo'
+        })
+      )
+      .then(data => {
+        const meta = frontMatter(data.content);
+        meta.tags.should.eql(['tag', 'test']);
+        return fs.unlink(data.path);
+      }));
 
   it('render()', () => {
     // TODO: validate data
@@ -560,62 +671,79 @@ describe('Post', () => {
     hexo.extend.filter.register('before_post_render', beforeHook);
     hexo.extend.filter.register('after_post_render', afterHook);
 
-    return post.render(null, {
-      content: fixture.content,
-      engine: 'markdown'
-    }).then(data => {
-      data.content.trim().should.eql(fixture.expected);
-      beforeHook.calledOnce.should.be.true;
-      afterHook.calledOnce.should.be.true;
-    });
+    return post
+      .render(null, {
+        content: fixture.content,
+        engine: 'markdown'
+      })
+      .then(data => {
+        data.content.trim().should.eql(fixture.expected);
+        beforeHook.calledOnce.should.be.true;
+        afterHook.calledOnce.should.be.true;
+      });
   });
 
   it('render() - callback', done => {
-    post.render(null, {
-      content: fixture.content,
-      engine: 'markdown'
-    }, err => {
-      done(err);
-    });
+    post.render(
+      null,
+      {
+        content: fixture.content,
+        engine: 'markdown'
+      },
+      err => {
+        done(err);
+      }
+    );
   });
 
   it('render() - file', () => {
     const content = '**file test**';
     const path = pathFn.join(hexo.base_dir, 'render_test.md');
 
-    return fs.writeFile(path, content).then(() => post.render(path)).then(data => {
-      data.content.trim().should.eql('<p><strong>file test</strong></p>');
-      return fs.unlink(path);
-    });
+    return fs
+      .writeFile(path, content)
+      .then(() => post.render(path))
+      .then(data => {
+        data.content.trim().should.eql('<p><strong>file test</strong></p>');
+        return fs.unlink(path);
+      });
   });
 
   it('render() - toString', () => {
     const content = 'foo: 1';
 
-    return post.render(null, {
-      content,
-      engine: 'yaml'
-    }).then(data => {
-      data.content.should.eql('{"foo":1}');
-    });
+    return post
+      .render(null, {
+        content,
+        engine: 'yaml'
+      })
+      .then(data => {
+        data.content.should.eql('{"foo":1}');
+      });
   });
 
-  it('render() - skip render phase if it\'s swig file', () => {
+  it("render() - skip render phase if it's swig file", () => {
     const content = [
       '{% quote Hello World %}',
       'quote content',
       '{% endquote %}'
     ].join('\n');
 
-    return post.render(null, {
-      content,
-      engine: 'swig'
-    }).then(data => {
-      data.content.trim().should.eql([
-        '<blockquote><p>quote content</p>\n',
-        '<footer><strong>Hello World</strong></footer></blockquote>'
-      ].join(''));
-    });
+    return post
+      .render(null, {
+        content,
+        engine: 'swig'
+      })
+      .then(data => {
+        data.content
+          .trim()
+          .should.eql(
+            [
+              '<blockquote><p>quote content</p>\n',
+              '<footer><strong>Hello World</strong></footer></blockquote>'
+            ].join('')
+          );
+      });
   });
 
   it('render() - escaping swig blocks with similar names', () => {
@@ -632,26 +760,28 @@ describe('Post', () => {
       '{% endcode %}'
     ].join('\n');
 
-    return post.render(null, {
-      content
-    }).then(data => {
-      data.content.trim().should.eql([
-        highlighted,
-        '',
-        highlighted
-      ].join('\n'));
-    });
+    return post
+      .render(null, {
+        content
+      })
+      .then(data => {
+        data.content
+          .trim()
+          .should.eql([highlighted, '', highlighted].join('\n'));
+      });
   });
 
   it('render() - recover escaped swig blocks which is html escaped', () => {
     const content = '`{% raw %}{{ test }}{% endraw %}`';
 
-    return post.render(null, {
-      content,
-      engine: 'markdown'
-    }).then(data => {
-      data.content.trim().should.eql('<p><code>{{ test }}</code></p>');
-    });
+    return post
+      .render(null, {
+        content,
+        engine: 'markdown'
+      })
+      .then(data => {
+        data.content.trim().should.eql('<p><code>{{ test }}</code></p>');
+      });
   });
 
   it('render() - recover escaped swig blocks which is html escaped before post_render', () => {
@@ -663,13 +793,15 @@ describe('Post', () => {
 
     hexo.extend.filter.register('after_render:html', filter);
 
-    return post.render(null, {
-      content,
-      engine: 'markdown'
-    }).then(data => {
-      filter.calledOnce.should.be.true;
-      hexo.extend.filter.unregister('after_render:html', filter);
-    });
+    return post
+      .render(null, {
+        content,
+        engine: 'markdown'
+      })
+      .then(data => {
+        filter.calledOnce.should.be.true;
+        hexo.extend.filter.unregister('after_render:html', filter);
+      });
   });
 
   it('render() - callback - not path and file', callback => {
@@ -692,14 +824,17 @@ describe('Post', () => {
     const renderer = hexo.render.renderer.get('markdown');
     renderer.disableNunjucks = true;
 
-    return post.render(null, {
-      content: fixture.content,
-      engine: 'markdown'
-    }).then(data => {
-      data.content.trim().should.eql(fixture.expected_disable_nunjucks);
-    }).then(data => {
-      renderer.disableNunjucks = false;
-    });
+    return post
+      .render(null, {
+        content: fixture.content,
+        engine: 'markdown'
+      })
+      .then(data => {
+        data.content.trim().should.eql(fixture.expected_disable_nunjucks);
+      })
+      .then(data => {
+        renderer.disableNunjucks = false;
+      });
   });
 
   // test for PR [#3573](https://github.com/hexojs/hexo/pull/3573)
@@ -707,14 +842,16 @@ describe('Post', () => {
     const renderer = hexo.render.renderer.get('markdown');
     renderer.disableNunjucks = false;
 
-    return post.render(null, {
-      content: fixture.content,
-      engine: 'markdown'
-    }).then(data => {
-      data.content.trim().should.eql(fixture.expected);
-    }).then(data => {
-      renderer.disableNunjucks = false;
-    });
+    return post
+      .render(null, {
+        content: fixture.content,
+        engine: 'markdown'
+      })
+      .then(data => {
+        data.content.trim().should.eql(fixture.expected);
+      })
+      .then(data => {
+        renderer.disableNunjucks = false;
+      });
   });
-
 });
diff --git a/test/scripts/hexo/render.js b/test/scripts/hexo/render.js
index 0c29203314..13fa115b2c 100644
--- a/test/scripts/hexo/render.js
+++ b/test/scripts/hexo/render.js
@@ -75,61 +75,78 @@ describe('Render', () => {
     hexo.render.getOutput('test.yaml').should.eql('json');
   });
 
-  it('render() - path', () => hexo.render.render({path}).then(result => {
-    result.should.eql(obj);
-  }));
+  it('render() - path', () =>
+    hexo.render.render({ path }).then(result => {
+      result.should.eql(obj);
+    }));
 
-  it('render() - text (without engine)', () => hexo.render.render({text: body}).then(result => {
-    result.should.eql(body);
-  }));
+  it('render() - text (without engine)', () =>
+    hexo.render.render({ text: body }).then(result => {
+      result.should.eql(body);
+    }));
 
-  it('render() - text (with engine)', () => hexo.render.render({text: body, engine: 'yaml'}).then(result => {
-    result.should.eql(obj);
-  }));
+  it('render() - text (with engine)', () =>
+    hexo.render.render({ text: body, engine: 'yaml' }).then(result => {
+      result.should.eql(obj);
+    }));
 
   it('render() - no path and text', () => {
     const errorCallback = sinon.spy(err => {
       err.should.have.property('message', 'No input file or string!');
     });
 
-    return hexo.render.render().catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return hexo.render
+      .render()
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('render() - options', () => hexo.render.render({
-    text: [
-      '<title>{{ title }}',
-      '{{ content }}'
-    ].join('\n'),
-    engine: 'swig'
-  }, {
-    title: 'Hello world',
-    content: 'foobar'
-  }).then(result => {
-    result.should.eql([
-      'Hello world',
-      'foobar'
-    ].join('\n'));
-  }));
-
-  it('render() - toString', () => hexo.render.render({
-    text: body,
-    engine: 'yaml',
-    toString: true
-  }).then(content => {
-    content.should.eql(JSON.stringify(obj));
-  }));
-
-  it('render() - custom toString method', () => hexo.render.render({
-    text: body,
-    engine: 'yaml',
-    toString(data) {
-      return JSON.stringify(data, null, '  ');
-    }
-  }).then(content => {
-    content.should.eql(JSON.stringify(obj, null, '  '));
-  }));
+  it('render() - options', () =>
+    hexo.render
+      .render(
+        {
+          text: [
+            '{{ title }}',
+            '{{ content }}'
+          ].join('\n'),
+          engine: 'swig'
+        },
+        {
+          title: 'Hello world',
+          content: 'foobar'
+        }
+      )
+      .then(result => {
+        result.should.eql(
+          ['Hello world', 'foobar'].join('\n')
+        );
+      }));
+
+  it('render() - toString', () =>
+    hexo.render
+      .render({
+        text: body,
+        engine: 'yaml',
+        toString: true
+      })
+      .then(content => {
+        content.should.eql(JSON.stringify(obj));
+      }));
+
+  it('render() - custom toString method', () =>
+    hexo.render
+      .render({
+        text: body,
+        engine: 'yaml',
+        toString(data) {
+          return JSON.stringify(data, null, '  ');
+        }
+      })
+      .then(content => {
+        content.should.eql(JSON.stringify(obj, null, '  '));
+      }));
 
   it('render() - after_render filter', () => {
     const data = {
@@ -192,17 +209,17 @@ describe('Render', () => {
   });
 
   it('renderSync() - path', () => {
-    const result = hexo.render.renderSync({path});
+    const result = hexo.render.renderSync({ path });
     result.should.eql(obj);
   });
 
   it('renderSync() - text (without engine)', () => {
-    const result = hexo.render.renderSync({text: body});
+    const result = hexo.render.renderSync({ text: body });
     result.should.eql(body);
   });
 
   it('renderSync() - text (with engine)', () => {
-    const result = hexo.render.renderSync({text: body, engine: 'yaml'});
+    const result = hexo.render.renderSync({ text: body, engine: 'yaml' });
     result.should.eql(obj);
   });
 
@@ -221,21 +238,22 @@ describe('Render', () => {
   });
 
   it('renderSync() - options', () => {
-    const result = hexo.render.renderSync({
-      text: [
-        '{{ title }}',
-        '{{ content }}'
-      ].join('\n'),
-      engine: 'swig'
-    }, {
-      title: 'Hello world',
-      content: 'foobar'
-    });
+    const result = hexo.render.renderSync(
+      {
+        text: ['{{ title }}', '{{ content }}'].join(
+          '\n'
+        ),
+        engine: 'swig'
+      },
+      {
+        title: 'Hello world',
+        content: 'foobar'
+      }
+    );
 
-    result.should.eql([
-      'Hello world',
-      'foobar'
-    ].join('\n'));
+    result.should.eql(
+      ['Hello world', 'foobar'].join('\n')
+    );
   });
 
   it('renderSync() - toString', () => {
diff --git a/test/scripts/hexo/router.js b/test/scripts/hexo/router.js
index eb46e74fd4..a572d93153 100644
--- a/test/scripts/hexo/router.js
+++ b/test/scripts/hexo/router.js
@@ -22,15 +22,18 @@ describe('Router', () => {
     return new Promise((resolve, reject) => {
       const hash = crypto.createHash('sha1');
 
-      stream.on('readable', () => {
-        let chunk;
-
-        while ((chunk = stream.read()) !== null) {
-          hash.update(chunk);
-        }
-      }).on('end', () => {
-        resolve(hash.digest('hex'));
-      }).on('error', reject);
+      stream
+        .on('readable', () => {
+          let chunk;
+
+          while ((chunk = stream.read()) !== null) {
+            hash.update(chunk);
+          }
+        })
+        .on('end', () => {
+          resolve(hash.digest('hex'));
+        })
+        .on('error', reject);
     });
   }
 
@@ -156,15 +159,16 @@ describe('Router', () => {
       err.should.have.property('message', 'error test');
     });
 
-    return testUtil.stream.read(router.get('test')).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return testUtil.stream
+      .read(router.get('test'))
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('get() - no data', () => {
-    router.set('test', () => {
-
-    });
+    router.set('test', () => {});
 
     return checkStream(router.get('test'), '');
   });
@@ -206,7 +210,7 @@ describe('Router', () => {
   });
 
   it('get() - export stringified JSON object', () => {
-    const obj = {foo: 1, bar: 2};
+    const obj = { foo: 1, bar: 2 };
 
     router.set('test', () => obj);
 
diff --git a/test/scripts/hexo/scaffold.js b/test/scripts/hexo/scaffold.js
index 26b0fe93a3..c651985b48 100644
--- a/test/scripts/hexo/scaffold.js
+++ b/test/scripts/hexo/scaffold.js
@@ -23,44 +23,48 @@ describe('Scaffold', () => {
 
   after(() => fs.rmdir(scaffoldDir));
 
-  it('get() - file exists', () => scaffold.get('test').then(data => {
-    data.should.eql(testContent);
-  }));
+  it('get() - file exists', () =>
+    scaffold.get('test').then(data => {
+      data.should.eql(testContent);
+    }));
 
-  it('get() - normal scaffold', () => scaffold.get('normal').then(data => {
-    data.should.eql(scaffold.defaults.normal);
-  }));
+  it('get() - normal scaffold', () =>
+    scaffold.get('normal').then(data => {
+      data.should.eql(scaffold.defaults.normal);
+    }));
 
-  it('set() - file exists', () => scaffold.set('test', 'foo').then(() => Promise.all([
-    fs.readFile(testPath),
-    scaffold.get('test')
-  ])).spread((file, data) => {
-    file.should.eql('foo');
-    data.should.eql('foo');
-    return fs.writeFile(testPath, testContent);
-  }));
+  it('set() - file exists', () =>
+    scaffold
+      .set('test', 'foo')
+      .then(() => Promise.all([fs.readFile(testPath), scaffold.get('test')]))
+      .spread((file, data) => {
+        file.should.eql('foo');
+        data.should.eql('foo');
+        return fs.writeFile(testPath, testContent);
+      }));
 
   it('set() - file does not exist', () => {
     const testPath = pathFn.join(scaffoldDir, 'foo.md');
 
-    return scaffold.set('foo', 'bar').then(() => Promise.all([
-      fs.readFile(testPath),
-      scaffold.get('foo')
-    ])).spread((file, data) => {
-      file.should.eql('bar');
-      data.should.eql('bar');
-      return fs.unlink(testPath);
-    });
+    return scaffold
+      .set('foo', 'bar')
+      .then(() => Promise.all([fs.readFile(testPath), scaffold.get('foo')]))
+      .spread((file, data) => {
+        file.should.eql('bar');
+        data.should.eql('bar');
+        return fs.unlink(testPath);
+      });
   });
 
-  it('remove() - file exist', () => scaffold.remove('test').then(() => Promise.all([
-    fs.exists(testPath),
-    scaffold.get('test')
-  ])).spread((exist, data) => {
-    exist.should.be.false;
-    should.not.exist(data);
-    return fs.writeFile(testPath, testContent);
-  }));
+  it('remove() - file exist', () =>
+    scaffold
+      .remove('test')
+      .then(() => Promise.all([fs.exists(testPath), scaffold.get('test')]))
+      .spread((exist, data) => {
+        exist.should.be.false;
+        should.not.exist(data);
+        return fs.writeFile(testPath, testContent);
+      }));
 
   it('remove() - file does not exist', () => scaffold.remove('foo'));
 });
diff --git a/test/scripts/hexo/update_package.js b/test/scripts/hexo/update_package.js
index 66f027b478..52dc80904a 100644
--- a/test/scripts/hexo/update_package.js
+++ b/test/scripts/hexo/update_package.js
@@ -5,7 +5,7 @@ const fs = require('hexo-fs');
 
 describe('Update package.json', () => {
   const Hexo = require('../../../lib/hexo');
-  const hexo = new Hexo(__dirname, {silent: true});
+  const hexo = new Hexo(__dirname, { silent: true });
   const updatePkg = require('../../../lib/hexo/update_package');
   const packagePath = pathFn.join(hexo.base_dir, 'package.json');
 
@@ -13,38 +13,47 @@ describe('Update package.json', () => {
     hexo.env.init = false;
   });
 
-  it('package.json does not exist', () => updatePkg(hexo).then(() => {
-    hexo.env.init.should.be.false;
-  }));
+  it('package.json does not exist', () =>
+    updatePkg(hexo).then(() => {
+      hexo.env.init.should.be.false;
+    }));
 
-  it('package.json exists, but the version doesn\'t match', () => {
+  it("package.json exists, but the version doesn't match", () => {
     const pkg = {
       hexo: {
         version: '0.0.1'
       }
     };
 
-    return fs.writeFile(packagePath, JSON.stringify(pkg)).then(() => updatePkg(hexo)).then(() => fs.readFile(packagePath)).then(content => {
-      JSON.parse(content).hexo.version.should.eql(hexo.version);
-      hexo.env.init.should.be.true;
+    return fs
+      .writeFile(packagePath, JSON.stringify(pkg))
+      .then(() => updatePkg(hexo))
+      .then(() => fs.readFile(packagePath))
+      .then(content => {
+        JSON.parse(content).hexo.version.should.eql(hexo.version);
+        hexo.env.init.should.be.true;
 
-      return fs.unlink(packagePath);
-    });
+        return fs.unlink(packagePath);
+      });
   });
 
-  it('package.json exists, but don\'t have hexo data', () => {
+  it("package.json exists, but don't have hexo data", () => {
     const pkg = {
       name: 'hexo',
       version: '0.0.1'
     };
 
-    return fs.writeFile(packagePath, JSON.stringify(pkg)).then(() => updatePkg(hexo)).then(() => fs.readFile(packagePath)).then(content => {
-      // Don't change the original package.json
-      JSON.parse(content).should.eql(pkg);
-      hexo.env.init.should.be.false;
+    return fs
+      .writeFile(packagePath, JSON.stringify(pkg))
+      .then(() => updatePkg(hexo))
+      .then(() => fs.readFile(packagePath))
+      .then(content => {
+        // Don't change the original package.json
+        JSON.parse(content).should.eql(pkg);
+        hexo.env.init.should.be.false;
 
-      return fs.unlink(packagePath);
-    });
+        return fs.unlink(packagePath);
+      });
   });
 
   it('package.json exists and everything is ok', () => {
@@ -54,11 +63,15 @@ describe('Update package.json', () => {
       }
     };
 
-    return fs.writeFile(packagePath, JSON.stringify(pkg)).then(() => updatePkg(hexo)).then(() => fs.readFile(packagePath)).then(content => {
-      JSON.parse(content).should.eql(pkg);
-      hexo.env.init.should.be.true;
+    return fs
+      .writeFile(packagePath, JSON.stringify(pkg))
+      .then(() => updatePkg(hexo))
+      .then(() => fs.readFile(packagePath))
+      .then(content => {
+        JSON.parse(content).should.eql(pkg);
+        hexo.env.init.should.be.true;
 
-      return fs.unlink(packagePath);
-    });
+        return fs.unlink(packagePath);
+      });
   });
 });
diff --git a/test/scripts/models/asset.js b/test/scripts/models/asset.js
index 0182dbe464..d5a65607b5 100644
--- a/test/scripts/models/asset.js
+++ b/test/scripts/models/asset.js
@@ -8,22 +8,25 @@ describe('Asset', () => {
   const hexo = new Hexo();
   const Asset = hexo.model('Asset');
 
-  it('default values', () => Asset.insert({
-    _id: 'foo',
-    path: 'bar'
-  }).then(data => {
-    data.modified.should.be.true;
-    return Asset.removeById(data._id);
-  }));
+  it('default values', () =>
+    Asset.insert({
+      _id: 'foo',
+      path: 'bar'
+    }).then(data => {
+      data.modified.should.be.true;
+      return Asset.removeById(data._id);
+    }));
 
   it('_id - required', () => {
     const errorCallback = sinon.spy(err => {
       err.should.have.property('message', 'ID is not defined');
     });
 
-    return Asset.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Asset.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('path - required', () => {
@@ -33,16 +36,19 @@ describe('Asset', () => {
 
     return Asset.insert({
       _id: 'foo'
-    }).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('source - virtual', () => Asset.insert({
-    _id: 'foo',
-    path: 'bar'
-  }).then(data => {
-    data.source.should.eql(pathFn.join(hexo.base_dir, data._id));
-    return Asset.removeById(data._id);
-  }));
+  it('source - virtual', () =>
+    Asset.insert({
+      _id: 'foo',
+      path: 'bar'
+    }).then(data => {
+      data.source.should.eql(pathFn.join(hexo.base_dir, data._id));
+      return Asset.removeById(data._id);
+    }));
 });
diff --git a/test/scripts/models/cache.js b/test/scripts/models/cache.js
index 6a3c00d4c0..4e5718800c 100644
--- a/test/scripts/models/cache.js
+++ b/test/scripts/models/cache.js
@@ -12,8 +12,10 @@ describe('Cache', () => {
       err.should.have.property('message', 'ID is not defined');
     });
 
-    return Cache.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Cache.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 });
diff --git a/test/scripts/models/category.js b/test/scripts/models/category.js
index 80dbb7f634..aee2b1ef0d 100644
--- a/test/scripts/models/category.js
+++ b/test/scripts/models/category.js
@@ -17,19 +17,22 @@ describe('Category', () => {
       err.should.have.property('message', '`name` is required!');
     });
 
-    return Category.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Category.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it.skip('parent - reference');
 
-  it('slug - virtual', () => Category.insert({
-    name: 'foo'
-  }).then(data => {
-    data.slug.should.eql('foo');
-    return Category.removeById(data._id);
-  }));
+  it('slug - virtual', () =>
+    Category.insert({
+      name: 'foo'
+    }).then(data => {
+      data.slug.should.eql('foo');
+      return Category.removeById(data._id);
+    }));
 
   it('slug - category_map', () => {
     hexo.config.category_map = {
@@ -45,12 +48,13 @@ describe('Category', () => {
     });
   });
 
-  it('slug - filename_case: 0', () => Category.insert({
-    name: 'WahAHa'
-  }).then(data => {
-    data.slug.should.eql('WahAHa');
-    return Category.removeById(data._id);
-  }));
+  it('slug - filename_case: 0', () =>
+    Category.insert({
+      name: 'WahAHa'
+    }).then(data => {
+      data.slug.should.eql('WahAHa');
+      return Category.removeById(data._id);
+    }));
 
   it('slug - filename_case: 1', () => {
     hexo.config.filename_case = 1;
@@ -76,158 +80,195 @@ describe('Category', () => {
     });
   });
 
-  it('slug - parent', () => Category.insert({
-    name: 'parent'
-  }).then(cat => Category.insert({
-    name: 'child',
-    parent: cat._id
-  })).then(cat => {
-    cat.slug.should.eql('parent/child');
-
-    return Promise.all([
-      Category.removeById(cat._id),
-      Category.removeById(cat.parent)
-    ]);
-  }));
-
-  it('path - virtual', () => Category.insert({
-    name: 'foo'
-  }).then(data => {
-    data.path.should.eql(hexo.config.category_dir + '/' + data.slug + '/');
-    return Category.removeById(data._id);
-  }));
-
-  it('permalink - virtual', () => Category.insert({
-    name: 'foo'
-  }).then(data => {
-    data.permalink.should.eql(hexo.config.url + '/' + data.path);
-    return Category.removeById(data._id);
-  }));
-
-  it('posts - virtual', () => Post.insert([
-    {source: 'foo.md', slug: 'foo'},
-    {source: 'bar.md', slug: 'bar'},
-    {source: 'baz.md', slug: 'baz'}
-  ]).each(post => post.setCategories(['foo'])).then(posts => {
-    const cat = Category.findOne({name: 'foo'});
-
-    function mapper(post) {
-      return post._id;
-    }
-
-    hexo.locals.invalidate();
-    cat.posts.map(mapper).should.eql(posts.map(mapper));
-    cat.length.should.eql(posts.length);
-
-    return cat.remove().thenReturn(posts);
-  }).map(post => post.remove()));
-
-  it('posts - draft', () => Post.insert([
-    {source: 'foo.md', slug: 'foo', published: true},
-    {source: 'bar.md', slug: 'bar', published: false},
-    {source: 'baz.md', slug: 'baz', published: true}
-  ]).each(post => post.setCategories(['foo'])).then(posts => {
-    let cat = Category.findOne({name: 'foo'});
-
-    function mapper(post) {
-      return post._id;
-    }
-
-    // draft off
-    hexo.locals.invalidate();
-    cat.posts.eq(0)._id.should.eql(posts[0]._id);
-    cat.posts.eq(1)._id.should.eql(posts[2]._id);
-    cat.length.should.eql(2);
-
-    // draft on
-    hexo.config.render_drafts = true;
-    hexo.locals.invalidate();
-    cat = Category.findOne({name: 'foo'});
-    cat.posts.map(mapper).should.eql(posts.map(mapper));
-    cat.length.should.eql(posts.length);
-    hexo.config.render_drafts = false;
-
-    return cat.remove().thenReturn(posts);
-  }).map(post => post.remove()));
+  it('slug - parent', () =>
+    Category.insert({
+      name: 'parent'
+    })
+      .then(cat =>
+        Category.insert({
+          name: 'child',
+          parent: cat._id
+        })
+      )
+      .then(cat => {
+        cat.slug.should.eql('parent/child');
+
+        return Promise.all([
+          Category.removeById(cat._id),
+          Category.removeById(cat.parent)
+        ]);
+      }));
+
+  it('path - virtual', () =>
+    Category.insert({
+      name: 'foo'
+    }).then(data => {
+      data.path.should.eql(hexo.config.category_dir + '/' + data.slug + '/');
+      return Category.removeById(data._id);
+    }));
+
+  it('permalink - virtual', () =>
+    Category.insert({
+      name: 'foo'
+    }).then(data => {
+      data.permalink.should.eql(hexo.config.url + '/' + data.path);
+      return Category.removeById(data._id);
+    }));
+
+  it('posts - virtual', () =>
+    Post.insert([
+      { source: 'foo.md', slug: 'foo' },
+      { source: 'bar.md', slug: 'bar' },
+      { source: 'baz.md', slug: 'baz' }
+    ])
+      .each(post => post.setCategories(['foo']))
+      .then(posts => {
+        const cat = Category.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        hexo.locals.invalidate();
+        cat.posts.map(mapper).should.eql(posts.map(mapper));
+        cat.length.should.eql(posts.length);
+
+        return cat.remove().thenReturn(posts);
+      })
+      .map(post => post.remove()));
+
+  it('posts - draft', () =>
+    Post.insert([
+      { source: 'foo.md', slug: 'foo', published: true },
+      { source: 'bar.md', slug: 'bar', published: false },
+      { source: 'baz.md', slug: 'baz', published: true }
+    ])
+      .each(post => post.setCategories(['foo']))
+      .then(posts => {
+        let cat = Category.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        // draft off
+        hexo.locals.invalidate();
+        cat.posts.eq(0)._id.should.eql(posts[0]._id);
+        cat.posts.eq(1)._id.should.eql(posts[2]._id);
+        cat.length.should.eql(2);
+
+        // draft on
+        hexo.config.render_drafts = true;
+        hexo.locals.invalidate();
+        cat = Category.findOne({ name: 'foo' });
+        cat.posts.map(mapper).should.eql(posts.map(mapper));
+        cat.length.should.eql(posts.length);
+        hexo.config.render_drafts = false;
+
+        return cat.remove().thenReturn(posts);
+      })
+      .map(post => post.remove()));
 
   it('posts - future', () => {
     const now = Date.now();
 
     return Post.insert([
-      {source: 'foo.md', slug: 'foo', date: now - 3600},
-      {source: 'bar.md', slug: 'bar', date: now + 3600},
-      {source: 'baz.md', slug: 'baz', date: now}
-    ]).each(post => post.setCategories(['foo'])).then(posts => {
-      let cat = Category.findOne({name: 'foo'});
-
-      function mapper(post) {
-        return post._id;
-      }
-
-      // future on
-      hexo.config.future = true;
-      hexo.locals.invalidate();
-      cat.posts.map(mapper).should.eql(posts.map(mapper));
-      cat.length.should.eql(posts.length);
-
-      // future off
-      hexo.config.future = false;
-      hexo.locals.invalidate();
-      cat = Category.findOne({name: 'foo'});
-      cat.posts.eq(0)._id.should.eql(posts[0]._id);
-      cat.posts.eq(1)._id.should.eql(posts[2]._id);
-      cat.length.should.eql(2);
-
-      return cat.remove().thenReturn(posts);
-    }).map(post => post.remove());
+      { source: 'foo.md', slug: 'foo', date: now - 3600 },
+      { source: 'bar.md', slug: 'bar', date: now + 3600 },
+      { source: 'baz.md', slug: 'baz', date: now }
+    ])
+      .each(post => post.setCategories(['foo']))
+      .then(posts => {
+        let cat = Category.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        // future on
+        hexo.config.future = true;
+        hexo.locals.invalidate();
+        cat.posts.map(mapper).should.eql(posts.map(mapper));
+        cat.length.should.eql(posts.length);
+
+        // future off
+        hexo.config.future = false;
+        hexo.locals.invalidate();
+        cat = Category.findOne({ name: 'foo' });
+        cat.posts.eq(0)._id.should.eql(posts[0]._id);
+        cat.posts.eq(1)._id.should.eql(posts[2]._id);
+        cat.length.should.eql(2);
+
+        return cat.remove().thenReturn(posts);
+      })
+      .map(post => post.remove());
   });
 
   it('check whether a category exists', () => {
     const errorCallback = sinon.spy(err => {
-      err.should.have.property('message', 'Category `foo` has already existed!');
+      err.should.have.property(
+        'message',
+        'Category `foo` has already existed!'
+      );
     });
 
     return Category.insert({
       name: 'foo'
-    }).then(data => {
-      Category.insert({
-        name: 'foo'
-      }).catch(errorCallback);
-
-      return Category.removeById(data._id);
-    }).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .then(data => {
+        Category.insert({
+          name: 'foo'
+        }).catch(errorCallback);
+
+        return Category.removeById(data._id);
+      })
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('check whether a category exists (with parent)', () => Category.insert({
-    name: 'foo'
-  }).then(data => Category.insert({
-    name: 'foo',
-    parent: data._id
-  })).then(data => Promise.all([
-    Category.removeById(data._id),
-    Category.removeById(data.parent)
-  ])));
+  it('check whether a category exists (with parent)', () =>
+    Category.insert({
+      name: 'foo'
+    })
+      .then(data =>
+        Category.insert({
+          name: 'foo',
+          parent: data._id
+        })
+      )
+      .then(data =>
+        Promise.all([
+          Category.removeById(data._id),
+          Category.removeById(data.parent)
+        ])
+      ));
 
   it('remove PostCategory references when a category is removed', () => {
     let cat;
 
     return Post.insert([
-      {source: 'foo.md', slug: 'foo'},
-      {source: 'bar.md', slug: 'bar'},
-      {source: 'baz.md', slug: 'baz'}
-    ]).then(posts => // One item a time
-      Promise.map(
-        posts,
-        post => post.setCategories(['foo']).thenReturn(post),
-        {concurrency: 1}
-      )).then(posts => {
-      cat = Category.findOne({name: 'foo'});
-      return Category.removeById(cat._id).thenReturn(posts);
-    }).then(posts => {
-      PostCategory.find({category_id: cat._id}).length.should.eql(0);
-      return posts;
-    }).map(post => Post.removeById(post._id));
+      { source: 'foo.md', slug: 'foo' },
+      { source: 'bar.md', slug: 'bar' },
+      { source: 'baz.md', slug: 'baz' }
+    ])
+      .then((
+        posts // One item a time
+      ) =>
+        Promise.map(
+          posts,
+          post => post.setCategories(['foo']).thenReturn(post),
+          { concurrency: 1 }
+        )
+      )
+      .then(posts => {
+        cat = Category.findOne({ name: 'foo' });
+        return Category.removeById(cat._id).thenReturn(posts);
+      })
+      .then(posts => {
+        PostCategory.find({ category_id: cat._id }).length.should.eql(0);
+        return posts;
+      })
+      .map(post => Post.removeById(post._id));
   });
 });
diff --git a/test/scripts/models/moment.js b/test/scripts/models/moment.js
index 14781b9ca5..ef576730f2 100644
--- a/test/scripts/models/moment.js
+++ b/test/scripts/models/moment.js
@@ -9,48 +9,73 @@ describe('SchemaTypeMoment', () => {
   it('cast()', () => {
     type.cast(1e8).should.eql(moment(1e8));
     type.cast(new Date(2014, 1, 1)).should.eql(moment(new Date(2014, 1, 1)));
-    type.cast('2014-11-03T07:45:41.237Z').should.eql(moment('2014-11-03T07:45:41.237Z'));
-    type.cast(moment(1e8)).valueOf().should.eql(1e8);
+    type
+      .cast('2014-11-03T07:45:41.237Z')
+      .should.eql(moment('2014-11-03T07:45:41.237Z'));
+    type
+      .cast(moment(1e8))
+      .valueOf()
+      .should.eql(1e8);
   });
 
   it('cast() - default', () => {
-    const type = new SchemaTypeMoment('test', {default: moment});
+    const type = new SchemaTypeMoment('test', { default: moment });
     moment.isMoment(type.cast()).should.be.true;
   });
 
   it('cast() - language', () => {
     const lang = 'zh-tw';
     const format = 'LLLL';
-    const type = new SchemaTypeMoment('test', {language: lang});
+    const type = new SchemaTypeMoment('test', { language: lang });
     const now = Date.now();
 
-    type.cast(now).format(format).should.eql(moment(now).locale(lang).format(format));
+    type
+      .cast(now)
+      .format(format)
+      .should.eql(
+        moment(now)
+          .locale(lang)
+          .format(format)
+      );
   });
 
   it('cast() - timezone', () => {
     const timezone = 'Etc/UTC';
     const format = 'LLLL';
-    const type = new SchemaTypeMoment('test', {timezone});
+    const type = new SchemaTypeMoment('test', { timezone });
     const now = Date.now();
 
-    type.cast(now).format(format).should.eql(moment(now).tz(timezone).format(format));
+    type
+      .cast(now)
+      .format(format)
+      .should.eql(
+        moment(now)
+          .tz(timezone)
+          .format(format)
+      );
   });
 
   function shouldThrowError(value) {
     try {
       type.validate(value);
     } catch (err) {
-      err.should.have.property('message', '`' + value + '` is not a valid date!');
+      err.should.have.property(
+        'message',
+        '`' + value + '` is not a valid date!'
+      );
     }
   }
 
   it('validate()', () => {
-    type.validate(moment(1e8)).valueOf().should.eql(1e8);
+    type
+      .validate(moment(1e8))
+      .valueOf()
+      .should.eql(1e8);
     shouldThrowError(moment.invalid());
   });
 
   it('validate() - required', () => {
-    const type = new SchemaTypeMoment('test', {required: true});
+    const type = new SchemaTypeMoment('test', { required: true });
 
     try {
       type.validate();
@@ -75,12 +100,16 @@ describe('SchemaTypeMoment', () => {
   });
 
   it('parse()', () => {
-    type.parse('2014-11-03T07:45:41.237Z').should.eql(moment('2014-11-03T07:45:41.237Z'));
+    type
+      .parse('2014-11-03T07:45:41.237Z')
+      .should.eql(moment('2014-11-03T07:45:41.237Z'));
     should.not.exist(type.parse());
   });
 
   it('value()', () => {
-    type.value(moment('2014-11-03T07:45:41.237Z')).should.eql('2014-11-03T07:45:41.237Z');
+    type
+      .value(moment('2014-11-03T07:45:41.237Z'))
+      .should.eql('2014-11-03T07:45:41.237Z');
     should.not.exist(type.value());
   });
 
@@ -103,12 +132,18 @@ describe('SchemaTypeMoment', () => {
   });
 
   it('u$inc()', () => {
-    type.u$inc(moment(1e8), 1).valueOf().should.eql(1e8 + 1);
+    type
+      .u$inc(moment(1e8), 1)
+      .valueOf()
+      .should.eql(1e8 + 1);
     should.not.exist(undefined, 1);
   });
 
   it('u$dec()', () => {
-    type.u$dec(moment(1e8), 1).valueOf().should.eql(1e8 - 1);
+    type
+      .u$dec(moment(1e8), 1)
+      .valueOf()
+      .should.eql(1e8 - 1);
     should.not.exist(undefined, 1);
   });
 });
diff --git a/test/scripts/models/page.js b/test/scripts/models/page.js
index a4efe34781..d06a9da2e2 100644
--- a/test/scripts/models/page.js
+++ b/test/scripts/models/page.js
@@ -35,9 +35,11 @@ describe('Page', () => {
       err.should.have.property('message', '`source` is required!');
     });
 
-    return Page.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Page.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('path - required', () => {
@@ -47,24 +49,28 @@ describe('Page', () => {
 
     return Page.insert({
       source: 'foo'
-    }).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('permalink - virtual', () => Page.insert({
-    source: 'foo',
-    path: 'bar'
-  }).then(data => {
-    data.permalink.should.eql(hexo.config.url + '/' + data.path);
-    return Page.removeById(data._id);
-  }));
+  it('permalink - virtual', () =>
+    Page.insert({
+      source: 'foo',
+      path: 'bar'
+    }).then(data => {
+      data.permalink.should.eql(hexo.config.url + '/' + data.path);
+      return Page.removeById(data._id);
+    }));
 
-  it('full_source - virtual', () => Page.insert({
-    source: 'foo',
-    path: 'bar'
-  }).then(data => {
-    data.full_source.should.eql(pathFn.join(hexo.source_dir, data.source));
-    return Page.removeById(data._id);
-  }));
+  it('full_source - virtual', () =>
+    Page.insert({
+      source: 'foo',
+      path: 'bar'
+    }).then(data => {
+      data.full_source.should.eql(pathFn.join(hexo.source_dir, data.source));
+      return Page.removeById(data._id);
+    }));
 });
diff --git a/test/scripts/models/post.js b/test/scripts/models/post.js
index 0b05b83014..21d2bde49a 100644
--- a/test/scripts/models/post.js
+++ b/test/scripts/models/post.js
@@ -48,9 +48,11 @@ describe('Post', () => {
       err.should.have.property('message', '`source` is required!');
     });
 
-    return Post.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Post.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('slug - required', () => {
@@ -60,18 +62,21 @@ describe('Post', () => {
 
     return Post.insert({
       source: 'foo.md'
-    }).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('path - virtual', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(data => {
-    data.path.should.eql(data.slug);
-    return Post.removeById(data._id);
-  }));
+  it('path - virtual', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    }).then(data => {
+      data.path.should.eql(data.slug);
+      return Post.removeById(data._id);
+    }));
 
   it('permalink - virtual', () => {
     hexo.config.root = '/';
@@ -121,53 +126,71 @@ describe('Post', () => {
     });
   });
 
-  it('full_source - virtual', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(data => {
-    data.full_source.should.eql(pathFn.join(hexo.source_dir, data.source));
-    return Post.removeById(data._id);
-  }));
-
-  it('asset_dir - virtual', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(data => {
-    data.asset_dir.should.eql(pathFn.join(hexo.source_dir, 'foo') + pathFn.sep);
-    return Post.removeById(data._id);
-  }));
-
-  it('tags - virtual', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setTags(['foo', 'bar', 'baz'])
-    .thenReturn(Post.findById(post._id))).then(post => {
-    post.tags.map(tag => tag.name).should.have.members(['bar', 'baz', 'foo']);
-
-    return Post.removeById(post._id);
-  }));
-
-  it('categories - virtual', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setCategories(['foo', 'bar', 'baz'])
-    .thenReturn(Post.findById(post._id))).then(post => {
-    const cats = post.categories;
-
-    // Make sure the order of categories is correct
-    cats.map((cat, i) => {
-      // Make sure the parent reference is correct
-      if (i) {
-        cat.parent.should.eql(cats.eq(i - 1)._id);
-      } else {
-        should.not.exist(cat.parent);
-      }
-
-      return cat.name;
-    }).should.eql(['foo', 'bar', 'baz']);
-
-    return Post.removeById(post._id);
-  }));
+  it('full_source - virtual', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    }).then(data => {
+      data.full_source.should.eql(pathFn.join(hexo.source_dir, data.source));
+      return Post.removeById(data._id);
+    }));
+
+  it('asset_dir - virtual', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    }).then(data => {
+      data.asset_dir.should.eql(
+        pathFn.join(hexo.source_dir, 'foo') + pathFn.sep
+      );
+      return Post.removeById(data._id);
+    }));
+
+  it('tags - virtual', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post.setTags(['foo', 'bar', 'baz']).thenReturn(Post.findById(post._id))
+      )
+      .then(post => {
+        post.tags
+          .map(tag => tag.name)
+          .should.have.members(['bar', 'baz', 'foo']);
+
+        return Post.removeById(post._id);
+      }));
+
+  it('categories - virtual', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post
+          .setCategories(['foo', 'bar', 'baz'])
+          .thenReturn(Post.findById(post._id))
+      )
+      .then(post => {
+        const cats = post.categories;
+
+        // Make sure the order of categories is correct
+        cats
+          .map((cat, i) => {
+            // Make sure the parent reference is correct
+            if (i) {
+              cat.parent.should.eql(cats.eq(i - 1)._id);
+            } else {
+              should.not.exist(cat.parent);
+            }
+
+            return cat.name;
+          })
+          .should.eql(['foo', 'bar', 'baz']);
+
+        return Post.removeById(post._id);
+      }));
 
   it('setTags() - old tags should be removed', () => {
     let id;
@@ -175,32 +198,41 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      id = post._id;
-      return post.setTags(['foo', 'bar']);
-    }).then(() => {
-      const post = Post.findById(id);
-      return post.setTags(['bar', 'baz']);
-    }).then(() => {
-      const post = Post.findById(id);
-
-      post.tags.map(tag => tag.name).should.eql(['bar', 'baz']);
-
-      return Post.removeById(id);
-    });
+    })
+      .then(post => {
+        id = post._id;
+        return post.setTags(['foo', 'bar']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+        return post.setTags(['bar', 'baz']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+
+        post.tags.map(tag => tag.name).should.eql(['bar', 'baz']);
+
+        return Post.removeById(id);
+      });
   });
 
-  it('setTags() - sync problem', () => Post.insert([
-    {source: 'foo.md', slug: 'foo'},
-    {source: 'bar.md', slug: 'bar'}
-  ]).then(posts => Promise.all([
-    posts[0].setTags(['foo', 'bar']),
-    posts[1].setTags(['bar', 'baz'])
-  ]).thenReturn(posts)).then(posts => {
-    Tag.map(tag => tag.name).should.have.members(['foo', 'bar', 'baz']);
-
-    return posts;
-  }).map(post => Post.removeById(post._id)));
+  it('setTags() - sync problem', () =>
+    Post.insert([
+      { source: 'foo.md', slug: 'foo' },
+      { source: 'bar.md', slug: 'bar' }
+    ])
+      .then(posts =>
+        Promise.all([
+          posts[0].setTags(['foo', 'bar']),
+          posts[1].setTags(['bar', 'baz'])
+        ]).thenReturn(posts)
+      )
+      .then(posts => {
+        Tag.map(tag => tag.name).should.have.members(['foo', 'bar', 'baz']);
+
+        return posts;
+      })
+      .map(post => Post.removeById(post._id)));
 
   it('setTags() - empty tag', () => {
     let id;
@@ -208,14 +240,17 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      id = post._id;
-      return post.setTags(['', undefined, null, false, 0, 'normal']);
-    }).then(() => {
-      const post = Post.findById(id);
-
-      post.tags.map(tag => tag.name).should.eql(['false', '0', 'normal']);
-    }).finally(() => Post.removeById(id));
+    })
+      .then(post => {
+        id = post._id;
+        return post.setTags(['', undefined, null, false, 0, 'normal']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+
+        post.tags.map(tag => tag.name).should.eql(['false', '0', 'normal']);
+      })
+      .finally(() => Post.removeById(id));
   });
 
   it('setCategories() - old categories should be removed', () => {
@@ -224,19 +259,22 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      id = post._id;
-      return post.setCategories(['foo', 'bar']);
-    }).then(() => {
-      const post = Post.findById(id);
-      return post.setCategories(['foo', 'baz']);
-    }).then(() => {
-      const post = Post.findById(id);
-
-      post.categories.map(cat => cat.name).should.eql(['foo', 'baz']);
-
-      return Post.removeById(id);
-    });
+    })
+      .then(post => {
+        id = post._id;
+        return post.setCategories(['foo', 'bar']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+        return post.setCategories(['foo', 'baz']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+
+        post.categories.map(cat => cat.name).should.eql(['foo', 'baz']);
+
+        return Post.removeById(id);
+      });
   });
 
   it('setCategories() - shared category should be same', () => {
@@ -245,26 +283,33 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      postIdA = post._id;
-      return post.setCategories(['foo', 'bar']);
-    }).then(() => Post.insert({
-      source: 'bar.md',
-      slug: 'bar'
-    }).then(post => {
-      postIdB = post._id;
-      return post.setCategories(['foo', 'bar']);
-    })).then(() => {
-      const postA = Post.findById(postIdA);
-      const postB = Post.findById(postIdB);
-
-      postA.categories.map(cat => cat._id).should.eql(postB.categories.map(cat => cat._id));
-
-      return Promise.all([
-        Post.removeById(postIdA),
-        Post.removeById(postIdB)
-      ]);
-    });
+    })
+      .then(post => {
+        postIdA = post._id;
+        return post.setCategories(['foo', 'bar']);
+      })
+      .then(() =>
+        Post.insert({
+          source: 'bar.md',
+          slug: 'bar'
+        }).then(post => {
+          postIdB = post._id;
+          return post.setCategories(['foo', 'bar']);
+        })
+      )
+      .then(() => {
+        const postA = Post.findById(postIdA);
+        const postB = Post.findById(postIdB);
+
+        postA.categories
+          .map(cat => cat._id)
+          .should.eql(postB.categories.map(cat => cat._id));
+
+        return Promise.all([
+          Post.removeById(postIdA),
+          Post.removeById(postIdB)
+        ]);
+      });
   });
 
   it('setCategories() - category not shared should be different', () => {
@@ -273,36 +318,41 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      postIdA = post._id;
-      return post.setCategories(['foo', 'bar']);
-    }).then(() => Post.insert({
-      source: 'bar.md',
-      slug: 'bar'
-    }).then(post => {
-      postIdB = post._id;
-      return post.setCategories(['baz', 'bar']);
-    })).then(() => {
-      const postA = Post.findById(postIdA);
-      const postB = Post.findById(postIdB);
-
-      const postCategoriesA = postA.categories.map(cat => cat._id);
-
-      const postCategoriesB = postB.categories.map(cat => cat._id);
-
-      postCategoriesA.forEach(catId => {
-        postCategoriesB.should.not.include(catId);
-      });
-
-      postCategoriesB.forEach(catId => {
-        postCategoriesA.should.not.include(catId);
+    })
+      .then(post => {
+        postIdA = post._id;
+        return post.setCategories(['foo', 'bar']);
+      })
+      .then(() =>
+        Post.insert({
+          source: 'bar.md',
+          slug: 'bar'
+        }).then(post => {
+          postIdB = post._id;
+          return post.setCategories(['baz', 'bar']);
+        })
+      )
+      .then(() => {
+        const postA = Post.findById(postIdA);
+        const postB = Post.findById(postIdB);
+
+        const postCategoriesA = postA.categories.map(cat => cat._id);
+
+        const postCategoriesB = postB.categories.map(cat => cat._id);
+
+        postCategoriesA.forEach(catId => {
+          postCategoriesB.should.not.include(catId);
+        });
+
+        postCategoriesB.forEach(catId => {
+          postCategoriesA.should.not.include(catId);
+        });
+
+        return Promise.all([
+          Post.removeById(postIdA),
+          Post.removeById(postIdB)
+        ]);
       });
-
-      return Promise.all([
-        Post.removeById(postIdA),
-        Post.removeById(postIdB)
-      ]);
-    });
   });
 
   it('setCategories() - empty category', () => {
@@ -311,14 +361,17 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      id = post._id;
-      return post.setCategories(['test', null]);
-    }).then(() => {
-      const post = Post.findById(id);
-
-      post.categories.map(cat => cat.name).should.eql(['test']);
-    }).finally(() => Post.removeById(id));
+    })
+      .then(post => {
+        id = post._id;
+        return post.setCategories(['test', null]);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+
+        post.categories.map(cat => cat.name).should.eql(['test']);
+      })
+      .finally(() => Post.removeById(id));
   });
 
   it('setCategories() - empty category in middle', () => {
@@ -327,84 +380,117 @@ describe('Post', () => {
     return Post.insert({
       source: 'foo.md',
       slug: 'foo'
-    }).then(post => {
-      id = post._id;
-      return post.setCategories(['foo', null, 'bar']);
-    }).then(() => {
-      const post = Post.findById(id);
-
-      post.categories.map(cat => cat.name).should.eql(['foo', 'bar']);
-    }).finally(() => Post.removeById(id));
+    })
+      .then(post => {
+        id = post._id;
+        return post.setCategories(['foo', null, 'bar']);
+      })
+      .then(() => {
+        const post = Post.findById(id);
+
+        post.categories.map(cat => cat.name).should.eql(['foo', 'bar']);
+      })
+      .finally(() => Post.removeById(id));
   });
 
-  it('setCategories() - multiple hierarchies', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setCategories([['foo', '', 'bar'], '', 'baz'])
-    .thenReturn(Post.findById(post._id))).then(post => {
-    const cats = post.categories.toArray();
-
-    // There should have been 3 categories set; blanks eliminated
-    cats.should.have.lengthOf(3);
-
-    // Category 1 should be foo, no parent
-    cats[0].name.should.eql('foo');
-    should.not.exist(cats[0].parent);
-
-    // Category 2 should be bar, foo as parent
-    cats[1].name.should.eql('bar');
-    cats[1].parent.should.eql(cats[0]._id);
-
-    // Category 3 should be baz, no parent
-    cats[2].name.should.eql('baz');
-    should.not.exist(cats[2].parent);
-
-    return Post.removeById(post._id);
-  }));
-
-  it('setCategories() - multiple hierarchies (dedupes repeated parent)', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setCategories([['foo', 'bar'], ['foo', 'baz']])
-    .thenReturn(Post.findById(post._id))).then(post => {
-    const cats = post.categories.toArray();
-
-    // There should have been 3 categories set (foo is dupe)
-    cats.should.have.lengthOf(3);
-
-    return Post.removeById(post._id);
-  }));
-
-  it('remove PostTag references when a post is removed', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setTags(['foo', 'bar', 'baz'])
-    .thenReturn(Post.findById(post._id))).then(post => Post.removeById(post._id)).then(post => {
-    PostTag.find({post_id: post._id}).length.should.eql(0);
-    Tag.findOne({name: 'foo'}).posts.length.should.eql(0);
-    Tag.findOne({name: 'bar'}).posts.length.should.eql(0);
-    Tag.findOne({name: 'baz'}).posts.length.should.eql(0);
-  }));
-
-  it('remove PostCategory references when a post is removed', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => post.setCategories(['foo', 'bar', 'baz'])
-    .thenReturn(Post.findById(post._id))).then(post => Post.removeById(post._id)).then(post => {
-    PostCategory.find({post_id: post._id}).length.should.eql(0);
-    Category.findOne({name: 'foo'}).posts.length.should.eql(0);
-    Category.findOne({name: 'bar'}).posts.length.should.eql(0);
-    Category.findOne({name: 'baz'}).posts.length.should.eql(0);
-  }));
-
-  it('remove related assets when a post is removed', () => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  }).then(post => Promise.all([
-    Asset.insert({_id: 'foo', path: 'foo'}),
-    Asset.insert({_id: 'bar', path: 'bar'}),
-    Asset.insert({_id: 'baz', path: 'bar'})
-  ]).thenReturn(post)).then(post => Post.removeById(post._id)).then(post => {
-    Asset.find({post: post._id}).length.should.eql(0);
-  }));
+  it('setCategories() - multiple hierarchies', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post
+          .setCategories([['foo', '', 'bar'], '', 'baz'])
+          .thenReturn(Post.findById(post._id))
+      )
+      .then(post => {
+        const cats = post.categories.toArray();
+
+        // There should have been 3 categories set; blanks eliminated
+        cats.should.have.lengthOf(3);
+
+        // Category 1 should be foo, no parent
+        cats[0].name.should.eql('foo');
+        should.not.exist(cats[0].parent);
+
+        // Category 2 should be bar, foo as parent
+        cats[1].name.should.eql('bar');
+        cats[1].parent.should.eql(cats[0]._id);
+
+        // Category 3 should be baz, no parent
+        cats[2].name.should.eql('baz');
+        should.not.exist(cats[2].parent);
+
+        return Post.removeById(post._id);
+      }));
+
+  it('setCategories() - multiple hierarchies (dedupes repeated parent)', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post
+          .setCategories([['foo', 'bar'], ['foo', 'baz']])
+          .thenReturn(Post.findById(post._id))
+      )
+      .then(post => {
+        const cats = post.categories.toArray();
+
+        // There should have been 3 categories set (foo is dupe)
+        cats.should.have.lengthOf(3);
+
+        return Post.removeById(post._id);
+      }));
+
+  it('remove PostTag references when a post is removed', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post.setTags(['foo', 'bar', 'baz']).thenReturn(Post.findById(post._id))
+      )
+      .then(post => Post.removeById(post._id))
+      .then(post => {
+        PostTag.find({ post_id: post._id }).length.should.eql(0);
+        Tag.findOne({ name: 'foo' }).posts.length.should.eql(0);
+        Tag.findOne({ name: 'bar' }).posts.length.should.eql(0);
+        Tag.findOne({ name: 'baz' }).posts.length.should.eql(0);
+      }));
+
+  it('remove PostCategory references when a post is removed', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        post
+          .setCategories(['foo', 'bar', 'baz'])
+          .thenReturn(Post.findById(post._id))
+      )
+      .then(post => Post.removeById(post._id))
+      .then(post => {
+        PostCategory.find({ post_id: post._id }).length.should.eql(0);
+        Category.findOne({ name: 'foo' }).posts.length.should.eql(0);
+        Category.findOne({ name: 'bar' }).posts.length.should.eql(0);
+        Category.findOne({ name: 'baz' }).posts.length.should.eql(0);
+      }));
+
+  it('remove related assets when a post is removed', () =>
+    Post.insert({
+      source: 'foo.md',
+      slug: 'bar'
+    })
+      .then(post =>
+        Promise.all([
+          Asset.insert({ _id: 'foo', path: 'foo' }),
+          Asset.insert({ _id: 'bar', path: 'bar' }),
+          Asset.insert({ _id: 'baz', path: 'bar' })
+        ]).thenReturn(post)
+      )
+      .then(post => Post.removeById(post._id))
+      .then(post => {
+        Asset.find({ post: post._id }).length.should.eql(0);
+      }));
 });
diff --git a/test/scripts/models/post_asset.js b/test/scripts/models/post_asset.js
index bea7ccaf83..0aafcb5b8a 100644
--- a/test/scripts/models/post_asset.js
+++ b/test/scripts/models/post_asset.js
@@ -10,30 +10,40 @@ describe('PostAsset', () => {
   const Post = hexo.model('Post');
   let post;
 
-  before(() => hexo.init().then(() => Post.insert({
-    source: 'foo.md',
-    slug: 'bar'
-  })).then(post_ => {
-    post = post_;
-  }));
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert({
+          source: 'foo.md',
+          slug: 'bar'
+        })
+      )
+      .then(post_ => {
+        post = post_;
+      })
+  );
 
-  it('default values', () => PostAsset.insert({
-    _id: 'foo',
-    slug: 'foo',
-    post: post._id
-  }).then(data => {
-    data.modified.should.be.true;
-    return PostAsset.removeById(data._id);
-  }));
+  it('default values', () =>
+    PostAsset.insert({
+      _id: 'foo',
+      slug: 'foo',
+      post: post._id
+    }).then(data => {
+      data.modified.should.be.true;
+      return PostAsset.removeById(data._id);
+    }));
 
   it('_id - required', () => {
     const errorCallback = sinon.spy(err => {
       err.should.have.property('message', 'ID is not defined');
     });
 
-    return PostAsset.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return PostAsset.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('slug - required', () => {
@@ -43,19 +53,22 @@ describe('PostAsset', () => {
 
     return PostAsset.insert({
       _id: 'foo'
-    }).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('path - virtual', () => PostAsset.insert({
-    _id: 'source/_posts/test/foo.jpg',
-    slug: 'foo.jpg',
-    post: post._id
-  }).then(data => {
-    data.path.should.eql(pathFn.join(post.path, data.slug));
-    return PostAsset.removeById(data._id);
-  }));
+  it('path - virtual', () =>
+    PostAsset.insert({
+      _id: 'source/_posts/test/foo.jpg',
+      slug: 'foo.jpg',
+      post: post._id
+    }).then(data => {
+      data.path.should.eql(pathFn.join(post.path, data.slug));
+      return PostAsset.removeById(data._id);
+    }));
 
   it('path - virtual - when permalink is .html', () => {
     hexo.config.permalink = ':year/:month/:day/:title.html';
@@ -63,12 +76,14 @@ describe('PostAsset', () => {
       _id: 'source/_posts/test/foo.html',
       slug: 'foo.htm',
       post: post._id
-    }).then(data => {
-      data.path.should.eql(pathFn.join(post.path, data.slug));
-      return PostAsset.removeById(data._id);
-    }).finally(() => {
-      hexo.config.permalink = ':year/:month/:day/:title';
-    });
+    })
+      .then(data => {
+        data.path.should.eql(pathFn.join(post.path, data.slug));
+        return PostAsset.removeById(data._id);
+      })
+      .finally(() => {
+        hexo.config.permalink = ':year/:month/:day/:title';
+      });
   });
 
   it('path - virtual - when permalink is .htm', () => {
@@ -77,12 +92,14 @@ describe('PostAsset', () => {
       _id: 'source/_posts/test/foo.htm',
       slug: 'foo.htm',
       post: post._id
-    }).then(data => {
-      data.path.should.eql(pathFn.join(post.path, data.slug));
-      return PostAsset.removeById(data._id);
-    }).finally(() => {
-      hexo.config.permalink = ':year/:month/:day/:title';
-    });
+    })
+      .then(data => {
+        data.path.should.eql(pathFn.join(post.path, data.slug));
+        return PostAsset.removeById(data._id);
+      })
+      .finally(() => {
+        hexo.config.permalink = ':year/:month/:day/:title';
+      });
   });
 
   it('path - virtual - when permalink contains .htm not in the end', () => {
@@ -91,20 +108,23 @@ describe('PostAsset', () => {
       _id: 'source/_posts/test/foo.html',
       slug: 'foo.html',
       post: post._id
-    }).then(data => {
-      data.path.should.eql(pathFn.join(post.path + '.htm-foo/', data.slug));
-      return PostAsset.removeById(data._id);
-    }).finally(() => {
-      hexo.config.permalink = ':year/:month/:day/:title';
-    });
+    })
+      .then(data => {
+        data.path.should.eql(pathFn.join(post.path + '.htm-foo/', data.slug));
+        return PostAsset.removeById(data._id);
+      })
+      .finally(() => {
+        hexo.config.permalink = ':year/:month/:day/:title';
+      });
   });
 
-  it('source - virtual', () => PostAsset.insert({
-    _id: 'source/_posts/test/foo.jpg',
-    slug: 'foo.jpg',
-    post: post._id
-  }).then(data => {
-    data.source.should.eql(pathFn.join(hexo.base_dir, data._id));
-    return PostAsset.removeById(data._id);
-  }));
+  it('source - virtual', () =>
+    PostAsset.insert({
+      _id: 'source/_posts/test/foo.jpg',
+      slug: 'foo.jpg',
+      post: post._id
+    }).then(data => {
+      data.source.should.eql(pathFn.join(hexo.base_dir, data._id));
+      return PostAsset.removeById(data._id);
+    }));
 });
diff --git a/test/scripts/models/tag.js b/test/scripts/models/tag.js
index 691a4085fb..924b83eb63 100644
--- a/test/scripts/models/tag.js
+++ b/test/scripts/models/tag.js
@@ -17,17 +17,20 @@ describe('Tag', () => {
       err.should.have.property('message', '`name` is required!');
     });
 
-    return Tag.insert({}).catch(errorCallback).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    return Tag.insert({})
+      .catch(errorCallback)
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
-  it('slug - virtual', () => Tag.insert({
-    name: 'foo'
-  }).then(data => {
-    data.slug.should.eql('foo');
-    return Tag.removeById(data._id);
-  }));
+  it('slug - virtual', () =>
+    Tag.insert({
+      name: 'foo'
+    }).then(data => {
+      data.slug.should.eql('foo');
+      return Tag.removeById(data._id);
+    }));
 
   it('slug - tag_map', () => {
     hexo.config.tag_map = {
@@ -44,12 +47,13 @@ describe('Tag', () => {
     });
   });
 
-  it('slug - filename_case: 0', () => Tag.insert({
-    name: 'WahAHa'
-  }).then(data => {
-    data.slug.should.eql('WahAHa');
-    return Tag.removeById(data._id);
-  }));
+  it('slug - filename_case: 0', () =>
+    Tag.insert({
+      name: 'WahAHa'
+    }).then(data => {
+      data.slug.should.eql('WahAHa');
+      return Tag.removeById(data._id);
+    }));
 
   it('slug - filename_case: 1', () => {
     hexo.config.filename_case = 1;
@@ -75,96 +79,109 @@ describe('Tag', () => {
     });
   });
 
-  it('path - virtual', () => Tag.insert({
-    name: 'foo'
-  }).then(data => {
-    data.path.should.eql(hexo.config.tag_dir + '/' + data.slug + '/');
-    return Tag.removeById(data._id);
-  }));
-
-  it('permalink - virtual', () => Tag.insert({
-    name: 'foo'
-  }).then(data => {
-    data.permalink.should.eql(hexo.config.url + '/' + data.path);
-    return Tag.removeById(data._id);
-  }));
-
-  it('posts - virtual', () => Post.insert([
-    {source: 'foo.md', slug: 'foo'},
-    {source: 'bar.md', slug: 'bar'},
-    {source: 'baz.md', slug: 'baz'}
-  ]).each(post => post.setTags(['foo'])).then(posts => {
-    const tag = Tag.findOne({name: 'foo'});
-
-    function mapper(post) {
-      return post._id;
-    }
-
-    hexo.locals.invalidate();
-    tag.posts.map(mapper).should.eql(posts.map(mapper));
-    tag.length.should.eql(posts.length);
-
-    return tag.remove().thenReturn(posts);
-  }).map(post => post.remove()));
-
-  it('posts - draft', () => Post.insert([
-    {source: 'foo.md', slug: 'foo', published: true},
-    {source: 'bar.md', slug: 'bar', published: false},
-    {source: 'baz.md', slug: 'baz', published: true}
-  ]).each(post => post.setTags(['foo'])).then(posts => {
-    let tag = Tag.findOne({name: 'foo'});
-
-    function mapper(post) {
-      return post._id;
-    }
-
-    // draft off
-    hexo.locals.invalidate();
-    tag.posts.eq(0)._id.should.eql(posts[0]._id);
-    tag.posts.eq(1)._id.should.eql(posts[2]._id);
-    tag.length.should.eql(2);
-
-    // draft on
-    hexo.config.render_drafts = true;
-    tag = Tag.findOne({name: 'foo'});
-    hexo.locals.invalidate();
-    tag.posts.map(mapper).should.eql(posts.map(mapper));
-    tag.length.should.eql(posts.length);
-    hexo.config.render_drafts = false;
-
-    return tag.remove().thenReturn(posts);
-  }).map(post => post.remove()));
+  it('path - virtual', () =>
+    Tag.insert({
+      name: 'foo'
+    }).then(data => {
+      data.path.should.eql(hexo.config.tag_dir + '/' + data.slug + '/');
+      return Tag.removeById(data._id);
+    }));
+
+  it('permalink - virtual', () =>
+    Tag.insert({
+      name: 'foo'
+    }).then(data => {
+      data.permalink.should.eql(hexo.config.url + '/' + data.path);
+      return Tag.removeById(data._id);
+    }));
+
+  it('posts - virtual', () =>
+    Post.insert([
+      { source: 'foo.md', slug: 'foo' },
+      { source: 'bar.md', slug: 'bar' },
+      { source: 'baz.md', slug: 'baz' }
+    ])
+      .each(post => post.setTags(['foo']))
+      .then(posts => {
+        const tag = Tag.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        hexo.locals.invalidate();
+        tag.posts.map(mapper).should.eql(posts.map(mapper));
+        tag.length.should.eql(posts.length);
+
+        return tag.remove().thenReturn(posts);
+      })
+      .map(post => post.remove()));
+
+  it('posts - draft', () =>
+    Post.insert([
+      { source: 'foo.md', slug: 'foo', published: true },
+      { source: 'bar.md', slug: 'bar', published: false },
+      { source: 'baz.md', slug: 'baz', published: true }
+    ])
+      .each(post => post.setTags(['foo']))
+      .then(posts => {
+        let tag = Tag.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        // draft off
+        hexo.locals.invalidate();
+        tag.posts.eq(0)._id.should.eql(posts[0]._id);
+        tag.posts.eq(1)._id.should.eql(posts[2]._id);
+        tag.length.should.eql(2);
+
+        // draft on
+        hexo.config.render_drafts = true;
+        tag = Tag.findOne({ name: 'foo' });
+        hexo.locals.invalidate();
+        tag.posts.map(mapper).should.eql(posts.map(mapper));
+        tag.length.should.eql(posts.length);
+        hexo.config.render_drafts = false;
+
+        return tag.remove().thenReturn(posts);
+      })
+      .map(post => post.remove()));
 
   it('posts - future', () => {
     const now = Date.now();
 
     return Post.insert([
-      {source: 'foo.md', slug: 'foo', date: now - 3600},
-      {source: 'bar.md', slug: 'bar', date: now + 3600},
-      {source: 'baz.md', slug: 'baz', date: now}
-    ]).each(post => post.setTags(['foo'])).then(posts => {
-      let tag = Tag.findOne({name: 'foo'});
-
-      function mapper(post) {
-        return post._id;
-      }
-
-      // future on
-      hexo.config.future = true;
-      hexo.locals.invalidate();
-      tag.posts.map(mapper).should.eql(posts.map(mapper));
-      tag.length.should.eql(posts.length);
-
-      // future off
-      hexo.config.future = false;
-      hexo.locals.invalidate();
-      tag = Tag.findOne({name: 'foo'});
-      tag.posts.eq(0)._id.should.eql(posts[0]._id);
-      tag.posts.eq(1)._id.should.eql(posts[2]._id);
-      tag.length.should.eql(2);
-
-      return tag.remove().thenReturn(posts);
-    }).map(post => post.remove());
+      { source: 'foo.md', slug: 'foo', date: now - 3600 },
+      { source: 'bar.md', slug: 'bar', date: now + 3600 },
+      { source: 'baz.md', slug: 'baz', date: now }
+    ])
+      .each(post => post.setTags(['foo']))
+      .then(posts => {
+        let tag = Tag.findOne({ name: 'foo' });
+
+        function mapper(post) {
+          return post._id;
+        }
+
+        // future on
+        hexo.config.future = true;
+        hexo.locals.invalidate();
+        tag.posts.map(mapper).should.eql(posts.map(mapper));
+        tag.length.should.eql(posts.length);
+
+        // future off
+        hexo.config.future = false;
+        hexo.locals.invalidate();
+        tag = Tag.findOne({ name: 'foo' });
+        tag.posts.eq(0)._id.should.eql(posts[0]._id);
+        tag.posts.eq(1)._id.should.eql(posts[2]._id);
+        tag.length.should.eql(2);
+
+        return tag.remove().thenReturn(posts);
+      })
+      .map(post => post.remove());
   });
 
   it('check whether a tag exists', () => {
@@ -174,31 +191,42 @@ describe('Tag', () => {
 
     return Tag.insert({
       name: 'foo'
-    }).then(data => {
-      Tag.insert({
-        name: 'foo'
-      }).catch(errorCallback);
-
-      return Tag.removeById(data._id);
-    }).finally(() => {
-      errorCallback.calledOnce.should.be.true;
-    });
+    })
+      .then(data => {
+        Tag.insert({
+          name: 'foo'
+        }).catch(errorCallback);
+
+        return Tag.removeById(data._id);
+      })
+      .finally(() => {
+        errorCallback.calledOnce.should.be.true;
+      });
   });
 
   it('remove PostTag references when a tag is removed', () => {
     let tag;
 
     return Post.insert([
-      {source: 'foo.md', slug: 'foo'},
-      {source: 'bar.md', slug: 'bar'},
-      {source: 'baz.md', slug: 'baz'}
-    ]).then(posts => // One item a time
-      Promise.map(posts, post => post.setTags(['foo']).thenReturn(post), {concurrency: 1})).then(posts => {
-      tag = Tag.findOne({name: 'foo'});
-      return Tag.removeById(tag._id).thenReturn(posts);
-    }).then(posts => {
-      PostTag.find({tag_id: tag._id}).length.should.eql(0);
-      return posts;
-    }).map(post => Post.removeById(post._id));
+      { source: 'foo.md', slug: 'foo' },
+      { source: 'bar.md', slug: 'bar' },
+      { source: 'baz.md', slug: 'baz' }
+    ])
+      .then((
+        posts // One item a time
+      ) =>
+        Promise.map(posts, post => post.setTags(['foo']).thenReturn(post), {
+          concurrency: 1
+        })
+      )
+      .then(posts => {
+        tag = Tag.findOne({ name: 'foo' });
+        return Tag.removeById(tag._id).thenReturn(posts);
+      })
+      .then(posts => {
+        PostTag.find({ tag_id: tag._id }).length.should.eql(0);
+        return posts;
+      })
+      .map(post => Post.removeById(post._id));
   });
 });
diff --git a/test/scripts/processors/asset.js b/test/scripts/processors/asset.js
index 3f00bec51c..5ae3ff2e5b 100644
--- a/test/scripts/processors/asset.js
+++ b/test/scripts/processors/asset.js
@@ -71,17 +71,21 @@ describe('asset', () => {
       renderable: false
     });
 
-    return fs.writeFile(file.source, 'foo').then(() => process(file)).then(() => {
-      const id = 'source/' + file.path;
-      const asset = Asset.findById(id);
-
-      asset._id.should.eql(id);
-      asset.path.should.eql(file.path);
-      asset.modified.should.be.true;
-      asset.renderable.should.be.false;
-
-      return asset.remove();
-    }).finally(() => fs.unlink(file.source));
+    return fs
+      .writeFile(file.source, 'foo')
+      .then(() => process(file))
+      .then(() => {
+        const id = 'source/' + file.path;
+        const asset = Asset.findById(id);
+
+        asset._id.should.eql(id);
+        asset.path.should.eql(file.path);
+        asset.modified.should.be.true;
+        asset.renderable.should.be.false;
+
+        return asset.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
   it('asset - type: create (when source path is configed to parent directory)', () => {
     const file = newFile({
@@ -90,20 +94,24 @@ describe('asset', () => {
       renderable: false
     });
 
-    return fs.writeFile(file.source, 'foo').then(() => process(file)).then(() => {
-      const id = '../source/foo.jpg'; // The id should a relative path,because the 'lib/models/assets.js' use asset path by joining base path with "_id" directly.
-      const asset = Asset.findById(id);
+    return fs
+      .writeFile(file.source, 'foo')
+      .then(() => process(file))
+      .then(() => {
+        const id = '../source/foo.jpg'; // The id should a relative path,because the 'lib/models/assets.js' use asset path by joining base path with "_id" directly.
+        const asset = Asset.findById(id);
 
-      asset._id.should.eql(id);
-      asset.path.should.eql(file.path);
-      asset.modified.should.be.true;
-      asset.renderable.should.be.false;
+        asset._id.should.eql(id);
+        asset.path.should.eql(file.path);
+        asset.modified.should.be.true;
+        asset.renderable.should.be.false;
 
-      return asset.remove();
-    }).finally(() => {
-      fs.unlink(file.source);
-      fs.rmdir(pathFn.dirname(file.source));
-    });
+        return asset.remove();
+      })
+      .finally(() => {
+        fs.unlink(file.source);
+        fs.rmdir(pathFn.dirname(file.source));
+      });
   });
   it('asset - type: update', () => {
     const file = newFile({
@@ -121,16 +129,19 @@ describe('asset', () => {
         path: file.path,
         modified: false
       })
-    ]).then(() => process(file)).then(() => {
-      const asset = Asset.findById(id);
+    ])
+      .then(() => process(file))
+      .then(() => {
+        const asset = Asset.findById(id);
 
-      asset._id.should.eql(id);
-      asset.path.should.eql(file.path);
-      asset.modified.should.be.true;
-      asset.renderable.should.be.false;
+        asset._id.should.eql(id);
+        asset.path.should.eql(file.path);
+        asset.modified.should.be.true;
+        asset.renderable.should.be.false;
 
-      return asset.remove();
-    }).finally(() => fs.unlink(file.source));
+        return asset.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('asset - type: skip', () => {
@@ -149,13 +160,15 @@ describe('asset', () => {
         path: file.path,
         modified: false
       })
-    ]).then(() => process(file)).then(() => {
-      const asset = Asset.findById(id);
-      asset.modified.should.be.false;
-    }).finally(() => Promise.all([
-      Asset.removeById(id),
-      fs.unlink(file.source)
-    ]));
+    ])
+      .then(() => process(file))
+      .then(() => {
+        const asset = Asset.findById(id);
+        asset.modified.should.be.false;
+      })
+      .finally(() =>
+        Promise.all([Asset.removeById(id), fs.unlink(file.source)])
+      );
   });
 
   it('asset - type: delete', () => {
@@ -170,9 +183,11 @@ describe('asset', () => {
     return Asset.insert({
       _id: id,
       path: file.path
-    }).then(() => process(file)).then(() => {
-      should.not.exist(Asset.findById(id));
-    });
+    })
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(Asset.findById(id));
+      });
   });
 
   it('page - type: create', () => {
@@ -190,30 +205,27 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
-
-      page.title.should.eql('Hello world');
-      page.date.format(dateFormat).should.eql('2006-01-02 15:04:05');
-      page.updated.format(dateFormat).should.eql('2014-12-13 01:02:03');
-      page._content.should.eql('The quick brown fox jumps over the lazy dog');
-      page.source.should.eql(file.path);
-      page.raw.should.eql(body);
-      page.path.should.eql('hello.html');
-      page.layout.should.eql('page');
-
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
+
+        page.title.should.eql('Hello world');
+        page.date.format(dateFormat).should.eql('2006-01-02 15:04:05');
+        page.updated.format(dateFormat).should.eql('2014-12-13 01:02:03');
+        page._content.should.eql('The quick brown fox jumps over the lazy dog');
+        page.source.should.eql(file.path);
+        page.raw.should.eql(body);
+        page.path.should.eql('hello.html');
+        page.layout.should.eql('page');
+
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - type: update', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: 'hello.swig',
@@ -224,22 +236,21 @@ describe('asset', () => {
     let id;
 
     return Promise.all([
-      Page.insert({source: file.path, path: 'hello.html'}),
+      Page.insert({ source: file.path, path: 'hello.html' }),
       fs.writeFile(file.source, body)
-    ]).spread(doc => {
-      id = doc._id;
-      return process(file);
-    }).then(() => {
-      const page = Page.findOne({source: file.path});
-
-      page._id.should.eql(id);
-      page.title.should.eql('Hello world');
-
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+    ])
+      .spread(doc => {
+        id = doc._id;
+        return process(file);
+      })
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
+
+        page._id.should.eql(id);
+        page.title.should.eql('Hello world');
+
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - type: delete', () => {
@@ -252,9 +263,11 @@ describe('asset', () => {
     return Page.insert({
       source: file.path,
       path: 'hello.html'
-    }).then(() => process(file)).then(() => {
-      should.not.exist(Page.findOne({source: file.path}));
-    });
+    })
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(Page.findOne({ source: file.path }));
+      });
   });
 
   it('page - use the status of the source file if date not set', () => {
@@ -264,28 +277,23 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, '').then(() => Promise.all([
-      fs.stat(file.source),
-      process(file)
-    ])).spread(stats => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, '')
+      .then(() => Promise.all([fs.stat(file.source), process(file)]))
+      .spread(stats => {
+        const page = Page.findOne({ source: file.path });
 
-      page.date.toDate().should.eql(stats.ctime);
-      page.updated.toDate().should.eql(stats.mtime);
+        page.date.toDate().should.eql(stats.ctime);
+        page.updated.toDate().should.eql(stats.mtime);
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - permalink', () => {
-    const body = [
-      'title: "Hello world"',
-      'permalink: foo.html',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'permalink: foo.html', '---'].join(
+      '\n'
+    );
 
     const file = newFile({
       path: 'hello.swig',
@@ -293,24 +301,20 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.path.should.eql('foo.html');
+        page.path.should.eql('foo.html');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - permalink (without extension name)', () => {
-    const body = [
-      'title: "Hello world"',
-      'permalink: foo',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'permalink: foo', '---'].join('\n');
 
     const file = newFile({
       path: 'hello.swig',
@@ -318,24 +322,20 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.path.should.eql('foo.html');
+        page.path.should.eql('foo.html');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - permalink (with trailing slash)', () => {
-    const body = [
-      'title: "Hello world"',
-      'permalink: foo/',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'permalink: foo/', '---'].join('\n');
 
     const file = newFile({
       path: 'hello.swig',
@@ -343,16 +343,16 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.path.should.eql('foo/index.html');
+        page.path.should.eql('foo/index.html');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - set layout to false if output is not html', () => {
@@ -364,24 +364,20 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.layout.should.eql('false');
+        page.layout.should.eql('false');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
-  it('page - don\'t set layout to false if layout is set but output is not html', () => {
-    const body = [
-      'layout: something',
-      '---',
-      'foo: 1'
-    ].join('\n');
+  it("page - don't set layout to false if layout is set but output is not html", () => {
+    const body = ['layout: something', '---', 'foo: 1'].join('\n');
 
     const file = newFile({
       path: 'test.yml',
@@ -389,16 +385,16 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.layout.should.eql('something');
+        page.layout.should.eql('something');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - parse date', () => {
@@ -415,17 +411,17 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.date.format(dateFormat).should.eql('2014-04-24 00:00:00');
-      page.updated.format(dateFormat).should.eql('2015-05-05 00:00:00');
+        page.date.format(dateFormat).should.eql('2014-04-24 00:00:00');
+        page.updated.format(dateFormat).should.eql('2015-05-05 00:00:00');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - use file stats instead if date is invalid', () => {
@@ -442,23 +438,20 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => Promise.all([
-      file.stat(),
-      process(file)
-    ])).spread(stats => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => Promise.all([file.stat(), process(file)]))
+      .spread(stats => {
+        const page = Page.findOne({ source: file.path });
 
-      page.date.toDate().should.eql(stats.ctime);
-      page.updated.toDate().should.eql(stats.mtime);
+        page.date.toDate().should.eql(stats.ctime);
+        page.updated.toDate().should.eql(stats.mtime);
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
-  it('page - don\'t remove extension name', () => {
+  it("page - don't remove extension name", () => {
     const body = '';
 
     const file = newFile({
@@ -467,16 +460,16 @@ describe('asset', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
 
-      page.path.should.eql('test.min.js');
+        page.path.should.eql('test.min.js');
 
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      });
   });
 
   it('page - timezone', () => {
@@ -495,18 +488,25 @@ describe('asset', () => {
 
     hexo.config.timezone = 'UTC';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const page = Page.findOne({source: file.path});
-
-      page.date.utc().format(dateFormat).should.eql('2014-04-24 00:00:00');
-      page.updated.utc().format(dateFormat).should.eql('2015-05-05 00:00:00');
-
-      return Promise.all([
-        page.remove(),
-        fs.unlink(file.source)
-      ]);
-    }).finally(() => {
-      hexo.config.timezone = '';
-    });
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const page = Page.findOne({ source: file.path });
+
+        page.date
+          .utc()
+          .format(dateFormat)
+          .should.eql('2014-04-24 00:00:00');
+        page.updated
+          .utc()
+          .format(dateFormat)
+          .should.eql('2015-05-05 00:00:00');
+
+        return Promise.all([page.remove(), fs.unlink(file.source)]);
+      })
+      .finally(() => {
+        hexo.config.timezone = '';
+      });
   });
 });
diff --git a/test/scripts/processors/common.js b/test/scripts/processors/common.js
index c0930038ca..04e0ebee0a 100644
--- a/test/scripts/processors/common.js
+++ b/test/scripts/processors/common.js
@@ -39,7 +39,9 @@ describe('common', () => {
     common.toDate(m).should.eql(m);
     common.toDate(d).should.eql(d);
     common.toDate(1e8).should.eql(new Date(1e8));
-    common.toDate('2014-04-25T01:32:21.196Z').should.eql(new Date('2014-04-25T01:32:21.196Z'));
+    common
+      .toDate('2014-04-25T01:32:21.196Z')
+      .should.eql(new Date('2014-04-25T01:32:21.196Z'));
     common.toDate('Apr 24 2014').should.eql(new Date(2014, 3, 24));
     should.not.exist(common.toDate('foo'));
   });
@@ -47,15 +49,23 @@ describe('common', () => {
   it('timezone() - date', () => {
     const d = new Date(Date.UTC(1972, 2, 29, 0, 0, 0));
     const d_timezone_UTC = common.timezone(d, 'UTC');
-    (common.timezone(d, 'Asia/Shanghai') - d_timezone_UTC).should.eql(-8 * 3600 * 1000);
-    (common.timezone(d, 'Asia/Bangkok') - d_timezone_UTC).should.eql(-7 * 3600 * 1000);
-    (common.timezone(d, 'America/Los_Angeles') - d_timezone_UTC).should.eql(8 * 3600 * 1000);
+    (common.timezone(d, 'Asia/Shanghai') - d_timezone_UTC).should.eql(
+      -8 * 3600 * 1000
+    );
+    (common.timezone(d, 'Asia/Bangkok') - d_timezone_UTC).should.eql(
+      -7 * 3600 * 1000
+    );
+    (common.timezone(d, 'America/Los_Angeles') - d_timezone_UTC).should.eql(
+      8 * 3600 * 1000
+    );
   });
 
   it('timezone() - moment', () => {
     const d = moment(new Date(Date.UTC(1972, 2, 29, 0, 0, 0)));
     const d_timezone_UTC = common.timezone(d, 'UTC');
-    (common.timezone(d, 'Europe/Moscow') - d_timezone_UTC).should.eql(-3 * 3600 * 1000);
+    (common.timezone(d, 'Europe/Moscow') - d_timezone_UTC).should.eql(
+      -3 * 3600 * 1000
+    );
   });
 
   it('isMatch() - string', () => {
@@ -66,8 +76,10 @@ describe('common', () => {
     // Array
     common.isMatch('foo/test.html', []).should.be.false;
     common.isMatch('foo/test.html', ['foo/*.html']).should.be.true;
-    common.isMatch('foo/test.html', ['bar/*.html', 'foo/*.html']).should.be.true;
-    common.isMatch('foo/test.html', ['bar/*.html', 'baz/*.html']).should.be.false;
+    common.isMatch('foo/test.html', ['bar/*.html', 'foo/*.html']).should.be
+      .true;
+    common.isMatch('foo/test.html', ['bar/*.html', 'baz/*.html']).should.be
+      .false;
 
     // Undefined
     common.isMatch('foo/test.html').should.be.false;
diff --git a/test/scripts/processors/data.js b/test/scripts/processors/data.js
index c980c5ac15..cf504bbe11 100644
--- a/test/scripts/processors/data.js
+++ b/test/scripts/processors/data.js
@@ -47,13 +47,17 @@ describe('data', () => {
       type: 'create'
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const data = Data.findById('users');
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const data = Data.findById('users');
 
-      data.data.should.eql({foo: 'bar'});
+        data.data.should.eql({ foo: 'bar' });
 
-      return data.remove();
-    }).finally(() => fs.unlink(file.source));
+        return data.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('type: create - json', () => {
@@ -64,13 +68,17 @@ describe('data', () => {
       type: 'create'
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const data = Data.findById('users');
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const data = Data.findById('users');
 
-      data.data.should.eql({foo: 1});
+        data.data.should.eql({ foo: 1 });
 
-      return data.remove();
-    }).finally(() => fs.unlink(file.source));
+        return data.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('type: create - others', () => {
@@ -79,13 +87,17 @@ describe('data', () => {
       type: 'create'
     });
 
-    return fs.writeFile(file.source, 'text').then(() => process(file)).then(() => {
-      const data = Data.findById('users');
+    return fs
+      .writeFile(file.source, 'text')
+      .then(() => process(file))
+      .then(() => {
+        const data = Data.findById('users');
 
-      data.data.should.eql('text');
+        data.data.should.eql('text');
 
-      return data.remove();
-    }).finally(() => fs.unlink(file.source));
+        return data.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('type: update', () => {
@@ -102,13 +114,16 @@ describe('data', () => {
         _id: 'users',
         data: {}
       })
-    ]).then(() => process(file)).then(() => {
-      const data = Data.findById('users');
+    ])
+      .then(() => process(file))
+      .then(() => {
+        const data = Data.findById('users');
 
-      data.data.should.eql({foo: 'bar'});
+        data.data.should.eql({ foo: 'bar' });
 
-      return data.remove();
-    }).finally(() => fs.unlink(file.source));
+        return data.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('type: delete', () => {
@@ -119,9 +134,11 @@ describe('data', () => {
 
     return Data.insert({
       _id: 'users',
-      data: {foo: 'bar'}
-    }).then(() => process(file)).then(() => {
-      should.not.exist(Data.findById('users'));
-    });
+      data: { foo: 'bar' }
+    })
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(Data.findById('users'));
+      });
   });
 });
diff --git a/test/scripts/processors/post.js b/test/scripts/processors/post.js
index 3fa2eb09ff..d7d1fabc5c 100644
--- a/test/scripts/processors/post.js
+++ b/test/scripts/processors/post.js
@@ -82,7 +82,9 @@ describe('post', () => {
 
     // Skip render files
     hexo.config.skip_render = ['_posts/foo/**'];
-    pattern.match('_posts/foo/bar.html').should.have.property('renderable', false);
+    pattern
+      .match('_posts/foo/bar.html')
+      .should.have.property('renderable', false);
     hexo.config.skip_render = [];
   });
 
@@ -120,25 +122,25 @@ describe('post', () => {
         slug: 'foo'
       }),
       fs.writeFile(file.source, 'test')
-    ]).spread(doc => {
-      postId = doc._id;
-      return process(file);
-    }).then(() => {
-      const id = 'source/' + file.path;
-      const asset = PostAsset.findById(id);
-
-      asset._id.should.eql(id);
-      asset.post.should.eql(postId);
-      asset.modified.should.be.true;
-      asset.renderable.should.be.false;
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
+    ])
+      .spread(doc => {
+        postId = doc._id;
+        return process(file);
+      })
+      .then(() => {
+        const id = 'source/' + file.path;
+        const asset = PostAsset.findById(id);
+
+        asset._id.should.eql(id);
+        asset.post.should.eql(postId);
+        asset.modified.should.be.true;
+        asset.renderable.should.be.false;
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return Promise.all([
-        Post.removeById(postId),
-        fs.unlink(file.source)
-      ]);
-    });
+        return Promise.all([Post.removeById(postId), fs.unlink(file.source)]);
+      });
   });
 
   it('asset - type: update', () => {
@@ -160,26 +162,27 @@ describe('post', () => {
         slug: 'foo'
       }),
       fs.writeFile(file.source, 'test')
-    ]).spread(post => {
-      postId = post._id;
+    ])
+      .spread(post => {
+        postId = post._id;
+
+        return PostAsset.insert({
+          _id: id,
+          slug: file.path,
+          modified: false,
+          post: postId
+        });
+      })
+      .then(() => process(file))
+      .then(() => {
+        const asset = PostAsset.findById(id);
+        asset.modified.should.be.true;
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return PostAsset.insert({
-        _id: id,
-        slug: file.path,
-        modified: false,
-        post: postId
+        return Promise.all([Post.removeById(postId), fs.unlink(file.source)]);
       });
-    }).then(() => process(file)).then(() => {
-      const asset = PostAsset.findById(id);
-      asset.modified.should.be.true;
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
-
-      return Promise.all([
-        Post.removeById(postId),
-        fs.unlink(file.source)
-      ]);
-    });
   });
 
   it('asset - type: skip', () => {
@@ -201,26 +204,27 @@ describe('post', () => {
         slug: 'foo'
       }),
       fs.writeFile(file.source, 'test')
-    ]).spread(post => {
-      postId = post._id;
+    ])
+      .spread(post => {
+        postId = post._id;
+
+        return PostAsset.insert({
+          _id: id,
+          slug: file.path,
+          modified: false,
+          post: postId
+        });
+      })
+      .then(() => process(file))
+      .then(() => {
+        const asset = PostAsset.findById(id);
+        asset.modified.should.be.false;
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return PostAsset.insert({
-        _id: id,
-        slug: file.path,
-        modified: false,
-        post: postId
+        return Promise.all([Post.removeById(postId), fs.unlink(file.source)]);
       });
-    }).then(() => process(file)).then(() => {
-      const asset = PostAsset.findById(id);
-      asset.modified.should.be.false;
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
-
-      return Promise.all([
-        Post.removeById(postId),
-        fs.unlink(file.source)
-      ]);
-    });
   });
 
   it('asset - type: delete', () => {
@@ -239,24 +243,28 @@ describe('post', () => {
     return Post.insert({
       source: '_posts/foo.html',
       slug: 'foo'
-    }).then(post => {
-      postId = post._id;
-
-      return PostAsset.insert({
-        _id: id,
-        slug: file.path,
-        modified: false,
-        post: postId
+    })
+      .then(post => {
+        postId = post._id;
+
+        return PostAsset.insert({
+          _id: id,
+          slug: file.path,
+          modified: false,
+          post: postId
+        });
+      })
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(PostAsset.findById(id));
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
+        return Post.removeById(postId);
       });
-    }).then(() => process(file)).then(() => {
-      should.not.exist(PostAsset.findById(id));
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
-      return Post.removeById(postId);
-    });
   });
 
-  it('asset - skip if can\'t find a matching post', () => {
+  it("asset - skip if can't find a matching post", () => {
     hexo.config.post_asset_folder = true;
 
     const file = newFile({
@@ -268,13 +276,17 @@ describe('post', () => {
 
     const id = 'source/' + file.path;
 
-    return fs.writeFile(file.source, 'test').then(() => process(file)).then(() => {
-      should.not.exist(PostAsset.findById(id));
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
+    return fs
+      .writeFile(file.source, 'test')
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(PostAsset.findById(id));
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return fs.unlink(file.source);
-    });
+        return fs.unlink(file.source);
+      });
   });
 
   it('asset - the related post has been deleted', () => {
@@ -295,13 +307,16 @@ describe('post', () => {
         _id: id,
         slug: file.path
       })
-    ]).then(() => process(file)).then(() => {
-      should.not.exist(PostAsset.findById(id));
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
+    ])
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(PostAsset.findById(id));
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return fs.unlink(file.source);
-    });
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - type: create', () => {
@@ -320,27 +335,28 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
-
-      post.title.should.eql('Hello world');
-      post.date.format(dateFormat).should.eql('2006-01-02 15:04:05');
-      post.updated.format(dateFormat).should.eql('2014-12-13 01:02:03');
-      post._content.should.eql('The quick brown fox jumps over the lazy dog');
-      post.source.should.eql(file.path);
-      post.raw.should.eql(body);
-      post.slug.should.eql('foo');
-      post.published.should.be.true;
-
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
+
+        post.title.should.eql('Hello world');
+        post.date.format(dateFormat).should.eql('2006-01-02 15:04:05');
+        post.updated.format(dateFormat).should.eql('2014-12-13 01:02:03');
+        post._content.should.eql('The quick brown fox jumps over the lazy dog');
+        post.source.should.eql(file.path);
+        post.raw.should.eql(body);
+        post.slug.should.eql('foo');
+        post.published.should.be.true;
+
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - type: update', () => {
-    const body = [
-      'title: "New world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "New world"', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -352,19 +368,22 @@ describe('post', () => {
     let id;
 
     return Promise.all([
-      Post.insert({source: file.path, slug: 'foo'}),
+      Post.insert({ source: file.path, slug: 'foo' }),
       fs.writeFile(file.source, body)
-    ]).spread(doc => {
-      id = doc._id;
-      return process(file);
-    }).then(() => {
-      const post = Post.findOne({source: file.path});
+    ])
+      .spread(doc => {
+        id = doc._id;
+        return process(file);
+      })
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post._id.should.eql(id);
-      post.title.should.eql('New world');
+        post._id.should.eql(id);
+        post.title.should.eql('New world');
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - type: delete', () => {
@@ -378,16 +397,15 @@ describe('post', () => {
     return Post.insert({
       source: file.path,
       slug: 'foo'
-    }).then(() => process(file)).then(() => {
-      should.not.exist(Post.findOne({source: file.path}));
-    });
+    })
+      .then(() => process(file))
+      .then(() => {
+        should.not.exist(Post.findOne({ source: file.path }));
+      });
   });
 
   it('post - parse file name', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: '2006/01/02/foo.html',
@@ -398,24 +416,25 @@ describe('post', () => {
 
     hexo.config.new_post_name = ':year/:month/:day/:title';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.slug.should.eql('foo');
-      post.date.format('YYYY-MM-DD').should.eql('2006-01-02');
+        post.slug.should.eql('foo');
+        post.date.format('YYYY-MM-DD').should.eql('2006-01-02');
 
-      return post.remove();
-    }).finally(() => {
-      hexo.config.new_post_name = newPostName;
-      return fs.unlink(file.source);
-    });
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.new_post_name = newPostName;
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - extra data in file name', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: 'zh/foo.html',
@@ -426,23 +445,24 @@ describe('post', () => {
 
     hexo.config.new_post_name = ':lang/:title';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.lang.should.eql('zh');
+        post.lang.should.eql('zh');
 
-      return post.remove();
-    }).finally(() => {
-      hexo.config.new_post_name = newPostName;
-      return fs.unlink(file.source);
-    });
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.new_post_name = newPostName;
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - file name does not match to the config', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -453,24 +473,24 @@ describe('post', () => {
 
     hexo.config.new_post_name = ':year/:month/:day/:title';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.slug.should.eql('foo');
+        post.slug.should.eql('foo');
 
-      return post.remove();
-    }).finally(() => {
-      hexo.config.new_post_name = newPostName;
-      return fs.unlink(file.source);
-    });
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.new_post_name = newPostName;
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - published', () => {
-    const body = [
-      'title: "Hello world"',
-      'published: false',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'published: false', '---'].join('\n');
 
     const file = newFile({
       path: 'zh/foo.html',
@@ -479,21 +499,21 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.published.should.be.false;
+        post.published.should.be.false;
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - always set published: false for drafts', () => {
-    const body = [
-      'title: "Hello world"',
-      'published: true',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'published: true', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -502,20 +522,21 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.published.should.be.false;
+        post.published.should.be.false;
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - use the status of the source file if date not set', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -524,17 +545,24 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => Promise.all([
-      file.stat(),
-      process(file)
-    ])).spread(stats => {
-      const post = Post.findOne({source: file.path});
-
-      post.date.toDate().setMilliseconds(0).should.eql(stats.birthtime.setMilliseconds(0));
-      post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0));
-
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+    return fs
+      .writeFile(file.source, body)
+      .then(() => Promise.all([file.stat(), process(file)]))
+      .spread(stats => {
+        const post = Post.findOne({ source: file.path });
+
+        post.date
+          .toDate()
+          .setMilliseconds(0)
+          .should.eql(stats.birthtime.setMilliseconds(0));
+        post.updated
+          .toDate()
+          .setMilliseconds(0)
+          .should.eql(stats.mtime.setMilliseconds(0));
+
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - photo is an alias for photos', () => {
@@ -553,18 +581,22 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.photos.should.eql([
-        'https://hexo.io/foo.jpg',
-        'https://hexo.io/bar.png'
-      ]);
+        post.photos.should.eql([
+          'https://hexo.io/foo.jpg',
+          'https://hexo.io/bar.png'
+        ]);
 
-      should.not.exist(post.photo);
+        should.not.exist(post.photo);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - photos (not array)', () => {
@@ -581,22 +613,21 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.photos.should.eql([
-        'https://hexo.io/foo.jpg'
-      ]);
+        post.photos.should.eql(['https://hexo.io/foo.jpg']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - link without title', () => {
-    const body = [
-      'link: https://hexo.io/',
-      '---'
-    ].join('\n');
+    const body = ['link: https://hexo.io/', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -605,17 +636,20 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.link.should.eql('https://hexo.io/');
-      post.title.should.eql('hexo.io');
+        post.link.should.eql('https://hexo.io/');
+        post.title.should.eql('hexo.io');
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
-
   it('post - link without title and link', () => {
     const body = '';
 
@@ -626,13 +660,17 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.title.should.eql('foo');
+        post.title.should.eql('foo');
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - category is an alias for categories', () => {
@@ -651,22 +689,22 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      should.not.exist(post.category);
-      post.categories.map(item => item.name).should.eql(['foo', 'bar']);
+        should.not.exist(post.category);
+        post.categories.map(item => item.name).should.eql(['foo', 'bar']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - categories (not array)', () => {
-    const body = [
-      'title: "Hello world"',
-      'categories: foo',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'categories: foo', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -675,13 +713,17 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.categories.map(item => item.name).should.eql(['foo']);
+        post.categories.map(item => item.name).should.eql(['foo']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - categories (multiple hierarchies)', () => {
@@ -700,13 +742,19 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.categories.map(item => item.name).should.eql(['foo', 'bar', 'baz']);
+        post.categories
+          .map(item => item.name)
+          .should.eql(['foo', 'bar', 'baz']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - tag is an alias for tags', () => {
@@ -725,22 +773,22 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      should.not.exist(post.tag);
-      post.tags.map(item => item.name).should.have.members(['foo', 'bar']);
+        should.not.exist(post.tag);
+        post.tags.map(item => item.name).should.have.members(['foo', 'bar']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - tags (not array)', () => {
-    const body = [
-      'title: "Hello world"',
-      'tags: foo',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'tags: foo', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -749,22 +797,23 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.tags.map(item => item.name).should.eql(['foo']);
+        post.tags.map(item => item.name).should.eql(['foo']);
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - post_asset_folder enabled', () => {
     hexo.config.post_asset_folder = true;
 
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: 'foo.html',
@@ -779,23 +828,23 @@ describe('post', () => {
     return Promise.all([
       fs.writeFile(file.source, body),
       fs.writeFile(assetPath, '')
-    ]).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
-      const asset = PostAsset.findById(assetId);
+    ])
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
+        const asset = PostAsset.findById(assetId);
 
-      asset._id.should.eql(assetId);
-      asset.post.should.eql(post._id);
-      asset.modified.should.be.true;
+        asset._id.should.eql(assetId);
+        asset.post.should.eql(post._id);
+        asset.modified.should.be.true;
 
-      return post.remove();
-    }).finally(() => {
-      hexo.config.post_asset_folder = false;
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.post_asset_folder = false;
 
-      return Promise.all([
-        fs.unlink(file.source),
-        fs.unlink(assetPath)
-      ]);
-    });
+        return Promise.all([fs.unlink(file.source), fs.unlink(assetPath)]);
+      });
   });
 
   it('post - post_asset_folder disabled', () => {
@@ -814,15 +863,17 @@ describe('post', () => {
     return Promise.all([
       fs.writeFile(file.source, ''),
       fs.writeFile(assetPath, '')
-    ]).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
-      should.not.exist(PostAsset.findById(assetId));
+    ])
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
+        should.not.exist(PostAsset.findById(assetId));
 
-      return post.remove();
-    }).finally(() => Promise.all([
-      fs.unlink(file.source),
-      fs.unlink(assetPath)
-    ]));
+        return post.remove();
+      })
+      .finally(() =>
+        Promise.all([fs.unlink(file.source), fs.unlink(assetPath)])
+      );
   });
 
   it('post - parse date', () => {
@@ -840,14 +891,18 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.date.format(dateFormat).should.eql('2014-04-24 00:00:00');
-      post.updated.format(dateFormat).should.eql('2015-05-05 00:00:00');
+        post.date.format(dateFormat).should.eql('2014-04-24 00:00:00');
+        post.updated.format(dateFormat).should.eql('2015-05-05 00:00:00');
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - use file stats instead if date is invalid', () => {
@@ -865,17 +920,24 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => Promise.all([
-      file.stat(),
-      process(file)
-    ])).spread(stats => {
-      const post = Post.findOne({source: file.path});
-
-      post.date.toDate().setMilliseconds(0).should.eql(stats.birthtime.setMilliseconds(0));
-      post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0));
-
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+    return fs
+      .writeFile(file.source, body)
+      .then(() => Promise.all([file.stat(), process(file)]))
+      .spread(stats => {
+        const post = Post.findOne({ source: file.path });
+
+        post.date
+          .toDate()
+          .setMilliseconds(0)
+          .should.eql(stats.birthtime.setMilliseconds(0));
+        post.updated
+          .toDate()
+          .setMilliseconds(0)
+          .should.eql(stats.mtime.setMilliseconds(0));
+
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 
   it('post - timezone', () => {
@@ -895,24 +957,31 @@ describe('post', () => {
 
     hexo.config.timezone = 'UTC';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
-
-      post.date.utc().format(dateFormat).should.eql('2014-04-24 00:00:00');
-      post.updated.utc().format(dateFormat).should.eql('2015-05-05 00:00:00');
-
-      return post.remove();
-    }).finally(() => {
-      hexo.config.timezone = '';
-      return fs.unlink(file.source);
-    });
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
+
+        post.date
+          .utc()
+          .format(dateFormat)
+          .should.eql('2014-04-24 00:00:00');
+        post.updated
+          .utc()
+          .format(dateFormat)
+          .should.eql('2015-05-05 00:00:00');
+
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.timezone = '';
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - new_post_name timezone', () => {
-    const body = [
-      'title: "Hello world"',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', '---'].join('\n');
 
     const file = newFile({
       path: '2006/01/02/foo.html',
@@ -924,26 +993,29 @@ describe('post', () => {
     hexo.config.new_post_name = ':year/:month/:day/:title';
     hexo.config.timezone = 'UTC';
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
 
-      post.date.utc().format(dateFormat).should.eql('2006-01-02 00:00:00');
+        post.date
+          .utc()
+          .format(dateFormat)
+          .should.eql('2006-01-02 00:00:00');
 
-      return post.remove();
-    }).finally(() => {
-      hexo.config.new_post_name = newPostName;
-      hexo.config.timezone = '';
+        return post.remove();
+      })
+      .finally(() => {
+        hexo.config.new_post_name = newPostName;
+        hexo.config.timezone = '';
 
-      return fs.unlink(file.source);
-    });
+        return fs.unlink(file.source);
+      });
   });
 
   it('post - permalink', () => {
-    const body = [
-      'title: "Hello world"',
-      'permalink: foooo',
-      '---'
-    ].join('\n');
+    const body = ['title: "Hello world"', 'permalink: foooo', '---'].join('\n');
 
     const file = newFile({
       path: 'test.html',
@@ -952,11 +1024,15 @@ describe('post', () => {
       renderable: true
     });
 
-    return fs.writeFile(file.source, body).then(() => process(file)).then(() => {
-      const post = Post.findOne({source: file.path});
-      post.slug.should.eql('foooo');
+    return fs
+      .writeFile(file.source, body)
+      .then(() => process(file))
+      .then(() => {
+        const post = Post.findOne({ source: file.path });
+        post.slug.should.eql('foooo');
 
-      return post.remove();
-    }).finally(() => fs.unlink(file.source));
+        return post.remove();
+      })
+      .finally(() => fs.unlink(file.source));
   });
 });
diff --git a/test/scripts/renderers/json.js b/test/scripts/renderers/json.js
index aa7896229b..ece9c068d8 100644
--- a/test/scripts/renderers/json.js
+++ b/test/scripts/renderers/json.js
@@ -11,6 +11,6 @@ describe('json', () => {
       }
     };
 
-    r({text: JSON.stringify(data)}).should.eql(data);
+    r({ text: JSON.stringify(data) }).should.eql(data);
   });
 });
diff --git a/test/scripts/renderers/plain.js b/test/scripts/renderers/plain.js
index 18d1ec0382..22681383a6 100644
--- a/test/scripts/renderers/plain.js
+++ b/test/scripts/renderers/plain.js
@@ -4,6 +4,6 @@ describe('plain', () => {
   const r = require('../../../lib/plugins/renderer/plain');
 
   it('normal', () => {
-    r({text: '123'}).should.eql('123');
+    r({ text: '123' }).should.eql('123');
   });
 });
diff --git a/test/scripts/renderers/swig.js b/test/scripts/renderers/swig.js
index 53727bb163..97d9f3c614 100644
--- a/test/scripts/renderers/swig.js
+++ b/test/scripts/renderers/swig.js
@@ -4,21 +4,18 @@ describe('swig', () => {
   const r = require('../../../lib/plugins/renderer/swig');
 
   it('normal', () => {
-    const body = [
-      'Hello {{ name }}!'
-    ].join('\n');
+    const body = ['Hello {{ name }}!'].join('\n');
 
-    r({text: body}, {
-      name: 'world'
-    }).should.eql('Hello world!');
+    r(
+      { text: body },
+      {
+        name: 'world'
+      }
+    ).should.eql('Hello world!');
   });
 
   it('override "for" tag', () => {
-    const body = [
-      '{% for x in arr %}',
-      '{{ x }}',
-      '{% endfor %}'
-    ].join('');
+    const body = ['{% for x in arr %}', '{{ x }}', '{% endfor %}'].join('');
 
     const data = {
       arr: {
@@ -28,13 +25,11 @@ describe('swig', () => {
       }
     };
 
-    r({text: body}, data).should.eql('123');
+    r({ text: body }, data).should.eql('123');
   });
 
   it('compile', () => {
-    const body = [
-      'Hello {{ name }}!'
-    ].join('\n');
+    const body = ['Hello {{ name }}!'].join('\n');
 
     const render = r.compile({
       text: body
diff --git a/test/scripts/renderers/yaml.js b/test/scripts/renderers/yaml.js
index 3f734d1766..c4b8843226 100644
--- a/test/scripts/renderers/yaml.js
+++ b/test/scripts/renderers/yaml.js
@@ -4,17 +4,13 @@ describe('yaml', () => {
   const r = require('../../../lib/plugins/renderer/yaml');
 
   it('normal', () => {
-    r({text: 'foo: 1'}).should.eql({foo: 1});
+    r({ text: 'foo: 1' }).should.eql({ foo: 1 });
   });
 
   it('escape', () => {
-    const body = [
-      'foo: 1',
-      'bar:',
-      '\tbaz: 3'
-    ].join('\n');
+    const body = ['foo: 1', 'bar:', '\tbaz: 3'].join('\n');
 
-    r({text: body}).should.eql({
+    r({ text: body }).should.eql({
       foo: 1,
       bar: {
         baz: 3
diff --git a/test/scripts/tags/asset_img.js b/test/scripts/tags/asset_img.js
index 1399654176..8827d8dcbb 100644
--- a/test/scripts/tags/asset_img.js
+++ b/test/scripts/tags/asset_img.js
@@ -16,48 +16,64 @@ describe('asset_img', () => {
     return assetImgTag.call(post, args.split(' '));
   }
 
-  before(() => hexo.init().then(() => Post.insert({
-    source: 'foo.md',
-    slug: 'foo'
-  })).then(post_ => {
-    post = post_;
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert({
+          source: 'foo.md',
+          slug: 'foo'
+        })
+      )
+      .then(post_ => {
+        post = post_;
 
-    return Promise.all([
-      PostAsset.insert({
-        _id: 'bar',
-        slug: 'bar',
-        post: post._id
-      }),
-      PostAsset.insert({
-        _id: 'spaced asset',
-        slug: 'spaced asset',
-        post: post._id
+        return Promise.all([
+          PostAsset.insert({
+            _id: 'bar',
+            slug: 'bar',
+            post: post._id
+          }),
+          PostAsset.insert({
+            _id: 'spaced asset',
+            slug: 'spaced asset',
+            post: post._id
+          })
+        ]);
       })
-    ]);
-  }));
+  );
 
   it('default', () => {
     assetImg('bar').should.eql('');
   });
 
   it('default', () => {
-    assetImg('bar title').should.eql('');
+    assetImg('bar title').should.eql(
+      ''
+    );
   });
 
   it('with space', () => {
     // {% asset_img "spaced asset" "spaced title" %}
-    assetImgTag.call(post, ['spaced asset', 'spaced title'])
-      .should.eql('');
+    assetImgTag
+      .call(post, ['spaced asset', 'spaced title'])
+      .should.eql(
+        ''
+      );
   });
 
   it('with alt and title', () => {
-    assetImgTag.call(post, ['bar', '"title"', '"alt"'])
+    assetImgTag
+      .call(post, ['bar', '"title"', '"alt"'])
       .should.eql('alt');
   });
 
   it('with width height alt and title', () => {
-    assetImgTag.call(post, ['bar', '100', '200', '"title"', '"alt"'])
-      .should.eql('alt');
+    assetImgTag
+      .call(post, ['bar', '100', '200', '"title"', '"alt"'])
+      .should.eql(
+        'alt'
+      );
   });
 
   it('no slug', () => {
diff --git a/test/scripts/tags/asset_link.js b/test/scripts/tags/asset_link.js
index d95697b724..a500ef5590 100644
--- a/test/scripts/tags/asset_link.js
+++ b/test/scripts/tags/asset_link.js
@@ -16,38 +16,50 @@ describe('asset_link', () => {
     return assetLinkTag.call(post, args.split(' '));
   }
 
-  before(() => hexo.init().then(() => Post.insert({
-    source: 'foo.md',
-    slug: 'foo'
-  })).then(post_ => {
-    post = post_;
-
-    return Promise.all([
-      PostAsset.insert({
-        _id: 'bar',
-        slug: 'bar',
-        post: post._id
-      }),
-      PostAsset.insert({
-        _id: 'spaced asset',
-        slug: 'spaced asset',
-        post: post._id
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert({
+          source: 'foo.md',
+          slug: 'foo'
+        })
+      )
+      .then(post_ => {
+        post = post_;
+
+        return Promise.all([
+          PostAsset.insert({
+            _id: 'bar',
+            slug: 'bar',
+            post: post._id
+          }),
+          PostAsset.insert({
+            _id: 'spaced asset',
+            slug: 'spaced asset',
+            post: post._id
+          })
+        ]);
       })
-    ]);
-  }));
+  );
 
   it('default', () => {
     assetLink('bar').should.eql('bar');
   });
 
   it('title', () => {
-    assetLink('bar Hello world').should.eql('Hello world');
+    assetLink('bar Hello world').should.eql(
+      'Hello world'
+    );
   });
 
   it('with space', () => {
     // {% asset_link "spaced asset" "spaced title" %}
-    assetLinkTag.call(post, ['spaced asset', 'spaced title'])
-      .should.eql('spaced title');
+    assetLinkTag
+      .call(post, ['spaced asset', 'spaced title'])
+      .should.eql(
+        'spaced title'
+      );
   });
 
   it('no slug', () => {
diff --git a/test/scripts/tags/asset_path.js b/test/scripts/tags/asset_path.js
index 60c50086fe..74861d1165 100644
--- a/test/scripts/tags/asset_path.js
+++ b/test/scripts/tags/asset_path.js
@@ -16,25 +16,32 @@ describe('asset_path', () => {
     return assetPathTag.call(post, args.split(' '));
   }
 
-  before(() => hexo.init().then(() => Post.insert({
-    source: 'foo.md',
-    slug: 'foo'
-  })).then(post_ => {
-    post = post_;
-
-    return Promise.all([
-      PostAsset.insert({
-        _id: 'bar',
-        slug: 'bar',
-        post: post._id
-      }),
-      PostAsset.insert({
-        _id: 'spaced asset',
-        slug: 'spaced asset',
-        post: post._id
+  before(() =>
+    hexo
+      .init()
+      .then(() =>
+        Post.insert({
+          source: 'foo.md',
+          slug: 'foo'
+        })
+      )
+      .then(post_ => {
+        post = post_;
+
+        return Promise.all([
+          PostAsset.insert({
+            _id: 'bar',
+            slug: 'bar',
+            post: post._id
+          }),
+          PostAsset.insert({
+            _id: 'spaced asset',
+            slug: 'spaced asset',
+            post: post._id
+          })
+        ]);
       })
-    ]);
-  }));
+  );
 
   it('default', () => {
     assetPath('bar').should.eql('/foo/bar');
@@ -42,8 +49,7 @@ describe('asset_path', () => {
 
   it('with space', () => {
     // {% asset_path "spaced asset" %}
-    assetPathTag.call(post, ['spaced asset'])
-      .should.eql('/foo/spaced%20asset');
+    assetPathTag.call(post, ['spaced asset']).should.eql('/foo/spaced%20asset');
   });
 
   it('no slug', () => {
diff --git a/test/scripts/tags/blockquote.js b/test/scripts/tags/blockquote.js
index 09be0d9010..866eb46e83 100644
--- a/test/scripts/tags/blockquote.js
+++ b/test/scripts/tags/blockquote.js
@@ -5,40 +5,56 @@ describe('blockquote', () => {
   const hexo = new Hexo(__dirname);
   const blockquote = require('../../../lib/plugins/tag/blockquote')(hexo);
 
-  before(() => hexo.init().then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked'))));
+  before(() =>
+    hexo
+      .init()
+      .then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked')))
+  );
 
   const bq = (args, content) => blockquote(args.split(' '), content || '');
 
   it('default', () => {
     const result = bq('', '123456 **bold** and *italic*');
-    result.should.eql('

123456 bold and italic

\n
'); + result.should.eql( + '

123456 bold and italic

\n
' + ); }); it('author', () => { const result = bq('John Doe', ''); - result.should.eql('
John Doe
'); + result.should.eql( + '
John Doe
' + ); }); it('source', () => { const result = bq('Jane Austen, Pride and Prejudice'); - result.should.eql('
Jane AustenPride and Prejudice
'); + result.should.eql( + '
Jane AustenPride and Prejudice
' + ); }); it('link', () => { const result = bq('John Doe https://hexo.io/'); - result.should.eql('
'); + result.should.eql( + '
' + ); }); it('link title', () => { const result = bq('John Doe https://hexo.io/ Hexo'); - result.should.eql('
'); + result.should.eql( + '
' + ); }); it('titlecase', () => { hexo.config.titlecase = true; const result = bq('Jane Austen, pride and prejudice'); - result.should.eql('
Jane AustenPride and Prejudice
'); + result.should.eql( + '
Jane AustenPride and Prejudice
' + ); hexo.config.titlecase = false; }); diff --git a/test/scripts/tags/code.js b/test/scripts/tags/code.js index 2c30d4caae..23e8a3b32d 100644 --- a/test/scripts/tags/code.js +++ b/test/scripts/tags/code.js @@ -9,18 +9,15 @@ describe('code', () => { const codeTag = require('../../../lib/plugins/tag/code')(hexo); const escapeHTML = util.escapeHTML; - const fixture = [ - 'if (tired && night){', - ' sleep();', - '}' - ].join('\n'); + const fixture = ['if (tired && night){', ' sleep();', '}'].join('\n'); function code(args, content) { return codeTag(args.split(' '), content); } function highlight(code, options) { - return util.highlight(code, options || {}) + return util + .highlight(code, options || {}) .replace(/{/g, '{') .replace(/}/g, '}'); } @@ -45,20 +42,26 @@ describe('code', () => { it('lang', () => { const result = code('lang:js', fixture); - result.should.eql(highlight(fixture, { - lang: 'js' - })); + result.should.eql( + highlight(fixture, { + lang: 'js' + }) + ); }); it('line_number', () => { let result = code('line_number:false', fixture); - result.should.eql(highlight(fixture, { - gutter: false - })); + result.should.eql( + highlight(fixture, { + gutter: false + }) + ); result = code('line_number:true', fixture); - result.should.eql(highlight(fixture, { - gutter: true - })); + result.should.eql( + highlight(fixture, { + gutter: true + }) + ); }); it('highlight disable', () => { @@ -68,9 +71,11 @@ describe('code', () => { it('title', () => { const result = code('Hello world', fixture); - result.should.eql(highlight(fixture, { - caption: 'Hello world' - })); + result.should.eql( + highlight(fixture, { + caption: 'Hello world' + }) + ); }); it('link', () => { @@ -102,33 +107,39 @@ describe('code', () => { it('first_line', () => { let result = code('first_line:1234', fixture); - result.should.eql(highlight(fixture, { - firstLine: 1234 - })); + result.should.eql( + highlight(fixture, { + firstLine: 1234 + }) + ); result = code('', fixture); - result.should.eql(highlight(fixture, { - firstLine: 1 - })); + result.should.eql( + highlight(fixture, { + firstLine: 1 + }) + ); }); it('mark', () => { const source = [ - 'const http = require(\'http\');', + "const http = require('http');", '', - 'const hostname = \'127.0.0.1\';', + "const hostname = '127.0.0.1';", 'const port = 1337;', '', 'http.createServer((req, res) => {', - ' res.writeHead(200, { \'Content-Type\': \'text/plain\' });', - ' res.end(\'Hello World\n\');', + " res.writeHead(200, { 'Content-Type': 'text/plain' });", + " res.end('Hello World\n');", '}).listen(port, hostname, () => {', ' console.log(`Server running at http://${hostname}:${port}/`);', '});' ].join('\n'); const result = code('mark:1,7-8,10', source); - result.should.eql(highlight(source, { - mark: [1, 7, 8, 10] - })); + result.should.eql( + highlight(source, { + mark: [1, 7, 8, 10] + }) + ); }); it('# lines', () => { diff --git a/test/scripts/tags/gist.js b/test/scripts/tags/gist.js index 5520e82aeb..a39340078c 100644 --- a/test/scripts/tags/gist.js +++ b/test/scripts/tags/gist.js @@ -7,11 +7,15 @@ describe('gist', () => { it('id', () => { const $ = cheerio.load(gist(['foo'])); - $('script').attr('src').should.eql('//gist.github.com/foo.js'); + $('script') + .attr('src') + .should.eql('//gist.github.com/foo.js'); }); it('file', () => { const $ = cheerio.load(gist(['foo', 'bar'])); - $('script').attr('src').should.eql('//gist.github.com/foo.js?file=bar'); + $('script') + .attr('src') + .should.eql('//gist.github.com/foo.js?file=bar'); }); }); diff --git a/test/scripts/tags/iframe.js b/test/scripts/tags/iframe.js index 41d9a7ded8..328cff64c8 100644 --- a/test/scripts/tags/iframe.js +++ b/test/scripts/tags/iframe.js @@ -8,30 +8,60 @@ describe('iframe', () => { it('url', () => { const $ = cheerio.load(iframe(['https://zespia.tw'])); - $('iframe').attr('src').should.eql('https://zespia.tw'); - $('iframe').attr('width').should.eql('100%'); - $('iframe').attr('height').should.eql('300'); - $('iframe').attr('frameborder').should.eql('0'); - $('iframe').attr('allowfullscreen').should.eql(''); + $('iframe') + .attr('src') + .should.eql('https://zespia.tw'); + $('iframe') + .attr('width') + .should.eql('100%'); + $('iframe') + .attr('height') + .should.eql('300'); + $('iframe') + .attr('frameborder') + .should.eql('0'); + $('iframe') + .attr('allowfullscreen') + .should.eql(''); }); it('width', () => { const $ = cheerio.load(iframe(['https://zespia.tw', '500'])); - $('iframe').attr('src').should.eql('https://zespia.tw'); - $('iframe').attr('width').should.eql('500'); - $('iframe').attr('height').should.eql('300'); - $('iframe').attr('frameborder').should.eql('0'); - $('iframe').attr('allowfullscreen').should.eql(''); + $('iframe') + .attr('src') + .should.eql('https://zespia.tw'); + $('iframe') + .attr('width') + .should.eql('500'); + $('iframe') + .attr('height') + .should.eql('300'); + $('iframe') + .attr('frameborder') + .should.eql('0'); + $('iframe') + .attr('allowfullscreen') + .should.eql(''); }); it('height', () => { const $ = cheerio.load(iframe(['https://zespia.tw', '500', '600'])); - $('iframe').attr('src').should.eql('https://zespia.tw'); - $('iframe').attr('width').should.eql('500'); - $('iframe').attr('height').should.eql('600'); - $('iframe').attr('frameborder').should.eql('0'); - $('iframe').attr('allowfullscreen').should.eql(''); + $('iframe') + .attr('src') + .should.eql('https://zespia.tw'); + $('iframe') + .attr('width') + .should.eql('500'); + $('iframe') + .attr('height') + .should.eql('600'); + $('iframe') + .attr('frameborder') + .should.eql('0'); + $('iframe') + .attr('allowfullscreen') + .should.eql(''); }); }); diff --git a/test/scripts/tags/img.js b/test/scripts/tags/img.js index fd9b54db68..4fe307dd4a 100644 --- a/test/scripts/tags/img.js +++ b/test/scripts/tags/img.js @@ -13,118 +13,222 @@ describe('img', () => { it('src', () => { const $ = cheerio.load(img(['https://placekitten.com/200/300'])); - $('img').attr('src').should.eql('https://placekitten.com/200/300'); + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); }); it('src //', () => { const $ = cheerio.load(img(['//placekitten.com/200/300'])); - $('img').attr('src').should.eql('//placekitten.com/200/300'); + $('img') + .attr('src') + .should.eql('//placekitten.com/200/300'); }); it('internal src', () => { hexo.config.root = '/'; let $ = cheerio.load(img(['/images/test.jpg'])); - $('img').attr('src').should.eql('/images/test.jpg'); + $('img') + .attr('src') + .should.eql('/images/test.jpg'); hexo.config.url = 'http://yoursite.com/root'; hexo.config.root = '/root/'; $ = cheerio.load(img(['/images/test.jpg'])); - $('img').attr('src').should.eql('/root/images/test.jpg'); + $('img') + .attr('src') + .should.eql('/root/images/test.jpg'); }); it('class + src', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); + const $ = cheerio.load( + img('left https://placekitten.com/200/300'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); }); it('class + internal src', () => { hexo.config.root = '/'; let $ = cheerio.load(img('left /images/test.jpg'.split(' '))); - $('img').attr('src').should.eql('/images/test.jpg'); - $('img').attr('class').should.eql('left'); + $('img') + .attr('src') + .should.eql('/images/test.jpg'); + $('img') + .attr('class') + .should.eql('left'); hexo.config.url = 'http://yoursite.com/root'; hexo.config.root = '/root/'; $ = cheerio.load(img('left /images/test.jpg'.split(' '))); - $('img').attr('src').should.eql('/root/images/test.jpg'); - $('img').attr('class').should.eql('left'); + $('img') + .attr('src') + .should.eql('/root/images/test.jpg'); + $('img') + .attr('class') + .should.eql('left'); }); it('multiple classes + src', () => { - const $ = cheerio.load(img('left top https://placekitten.com/200/300'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left top'); + const $ = cheerio.load( + img('left top https://placekitten.com/200/300'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left top'); }); it('multiple classes + internal src', () => { hexo.config.root = '/'; let $ = cheerio.load(img('left top /images/test.jpg'.split(' '))); - $('img').attr('src').should.eql('/images/test.jpg'); - $('img').attr('class').should.eql('left top'); + $('img') + .attr('src') + .should.eql('/images/test.jpg'); + $('img') + .attr('class') + .should.eql('left top'); hexo.config.url = 'http://yoursite.com/root'; hexo.config.root = '/root/'; $ = cheerio.load(img('left top /images/test.jpg'.split(' '))); - $('img').attr('src').should.eql('/root/images/test.jpg'); - $('img').attr('class').should.eql('left top'); + $('img') + .attr('src') + .should.eql('/root/images/test.jpg'); + $('img') + .attr('class') + .should.eql('left top'); }); it('class + src + width', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 200'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('width').should.eql('200'); + const $ = cheerio.load( + img('left https://placekitten.com/200/300 200'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('width') + .should.eql('200'); }); it('class + src + width + height', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 200 300'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('width').should.eql('200'); - $('img').attr('height').should.eql('300'); + const $ = cheerio.load( + img('left https://placekitten.com/200/300 200 300'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('width') + .should.eql('200'); + $('img') + .attr('height') + .should.eql('300'); }); it('class + src + title', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 Place Kitten'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('title').should.eql('Place Kitten'); + const $ = cheerio.load( + img('left https://placekitten.com/200/300 Place Kitten'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('title') + .should.eql('Place Kitten'); }); it('class + src + width + title', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 200 Place Kitten'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('width').should.eql('200'); - $('img').attr('title').should.eql('Place Kitten'); + const $ = cheerio.load( + img('left https://placekitten.com/200/300 200 Place Kitten'.split(' ')) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('width') + .should.eql('200'); + $('img') + .attr('title') + .should.eql('Place Kitten'); }); it('class + src + width + height + title', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 200 300 Place Kitten'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('width').should.eql('200'); - $('img').attr('height').should.eql('300'); - $('img').attr('title').should.eql('Place Kitten'); + const $ = cheerio.load( + img( + 'left https://placekitten.com/200/300 200 300 Place Kitten'.split(' ') + ) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('width') + .should.eql('200'); + $('img') + .attr('height') + .should.eql('300'); + $('img') + .attr('title') + .should.eql('Place Kitten'); }); it('class + src + width + height + title + alt', () => { - const $ = cheerio.load(img('left https://placekitten.com/200/300 200 300 "Place Kitten" "A cute kitten"'.split(' '))); - - $('img').attr('src').should.eql('https://placekitten.com/200/300'); - $('img').attr('class').should.eql('left'); - $('img').attr('width').should.eql('200'); - $('img').attr('height').should.eql('300'); - $('img').attr('title').should.eql('Place Kitten'); - $('img').attr('alt').should.eql('A cute kitten'); + const $ = cheerio.load( + img( + 'left https://placekitten.com/200/300 200 300 "Place Kitten" "A cute kitten"'.split( + ' ' + ) + ) + ); + + $('img') + .attr('src') + .should.eql('https://placekitten.com/200/300'); + $('img') + .attr('class') + .should.eql('left'); + $('img') + .attr('width') + .should.eql('200'); + $('img') + .attr('height') + .should.eql('300'); + $('img') + .attr('title') + .should.eql('Place Kitten'); + $('img') + .attr('alt') + .should.eql('A cute kitten'); }); }); diff --git a/test/scripts/tags/include_code.js b/test/scripts/tags/include_code.js index 610a8ee774..ee49382b16 100644 --- a/test/scripts/tags/include_code.js +++ b/test/scripts/tags/include_code.js @@ -8,14 +8,12 @@ const Promise = require('bluebird'); describe('include_code', () => { const Hexo = require('../../../lib/hexo'); const hexo = new Hexo(pathFn.join(__dirname, 'include_code_test')); - const includeCode = Promise.method(require('../../../lib/plugins/tag/include_code')(hexo)); + const includeCode = Promise.method( + require('../../../lib/plugins/tag/include_code')(hexo) + ); const path = pathFn.join(hexo.source_dir, hexo.config.code_dir, 'test.js'); - const fixture = [ - 'if (tired && night){', - ' sleep();', - '}' - ].join('\n'); + const fixture = ['if (tired && night){', ' sleep();', '}'].join('\n'); function code(args) { return includeCode(args.split(' ')); @@ -28,7 +26,8 @@ describe('include_code', () => { it('default', () => { const expected = highlight(fixture, { lang: 'js', - caption: 'test.jsview raw' + caption: + 'test.jsview raw' }); return code('test.js').then(result => { @@ -39,7 +38,8 @@ describe('include_code', () => { it('title', () => { const expected = highlight(fixture, { lang: 'js', - caption: 'Hello worldview raw' + caption: + 'Hello worldview raw' }); return code('Hello world test.js').then(result => { @@ -50,7 +50,8 @@ describe('include_code', () => { it('lang', () => { const expected = highlight(fixture, { lang: 'js', - caption: 'Hello worldview raw' + caption: + 'Hello worldview raw' }); return code('Hello world lang:js test.js').then(result => { @@ -59,12 +60,11 @@ describe('include_code', () => { }); it('from', () => { - const fixture = [ - '}' - ].join('\n'); + const fixture = ['}'].join('\n'); const expected = highlight(fixture, { lang: 'js', - caption: 'Hello worldview raw' + caption: + 'Hello worldview raw' }); return code('Hello world lang:js from:3 test.js').then(result => { @@ -73,13 +73,11 @@ describe('include_code', () => { }); it('to', () => { - const fixture = [ - 'if (tired && night){', - ' sleep();' - ].join('\n'); + const fixture = ['if (tired && night){', ' sleep();'].join('\n'); const expected = highlight(fixture, { lang: 'js', - caption: 'Hello worldview raw' + caption: + 'Hello worldview raw' }); return code('Hello world lang:js to:2 test.js').then(result => { @@ -88,12 +86,11 @@ describe('include_code', () => { }); it('from and to', () => { - const fixture = [ - 'sleep();' - ].join('\n'); + const fixture = ['sleep();'].join('\n'); const expected = highlight(fixture, { lang: 'js', - caption: 'Hello worldview raw' + caption: + 'Hello worldview raw' }); return code('Hello world lang:js from:2 to:2 test.js').then(result => { @@ -101,9 +98,10 @@ describe('include_code', () => { }); }); - it('file not found', () => code('nothing').then(result => { - should.not.exist(result); - })); + it('file not found', () => + code('nothing').then(result => { + should.not.exist(result); + })); it('disabled', () => { hexo.config.highlight.enable = false; diff --git a/test/scripts/tags/jsfiddle.js b/test/scripts/tags/jsfiddle.js index 55a85a5a4f..b964970d5d 100644 --- a/test/scripts/tags/jsfiddle.js +++ b/test/scripts/tags/jsfiddle.js @@ -8,46 +8,74 @@ describe('jsfiddle', () => { it('id', () => { const $ = cheerio.load(jsfiddle(['foo'])); - $('iframe').attr('src').should.eql('//jsfiddle.net/foo/embedded/js,resources,html,css,result/light'); + $('iframe') + .attr('src') + .should.eql( + '//jsfiddle.net/foo/embedded/js,resources,html,css,result/light' + ); }); it('tabs', () => { let $ = cheerio.load(jsfiddle(['foo', 'default'])); - $('iframe').attr('src').should.eql('//jsfiddle.net/foo/embedded/js,resources,html,css,result/light'); + $('iframe') + .attr('src') + .should.eql( + '//jsfiddle.net/foo/embedded/js,resources,html,css,result/light' + ); $ = cheerio.load(jsfiddle(['foo', 'html,css'])); - $('iframe').attr('src').should.eql('//jsfiddle.net/foo/embedded/html,css/light'); + $('iframe') + .attr('src') + .should.eql('//jsfiddle.net/foo/embedded/html,css/light'); }); it('skin', () => { let $ = cheerio.load(jsfiddle(['foo', 'default', 'default'])); - $('iframe').attr('src').should.eql('//jsfiddle.net/foo/embedded/js,resources,html,css,result/light'); + $('iframe') + .attr('src') + .should.eql( + '//jsfiddle.net/foo/embedded/js,resources,html,css,result/light' + ); $ = cheerio.load(jsfiddle(['foo', 'default', 'dark'])); - $('iframe').attr('src').should.eql('//jsfiddle.net/foo/embedded/js,resources,html,css,result/dark'); + $('iframe') + .attr('src') + .should.eql( + '//jsfiddle.net/foo/embedded/js,resources,html,css,result/dark' + ); }); it('width', () => { let $ = cheerio.load(jsfiddle(['foo', 'default', 'default', 'default'])); - $('iframe').attr('width').should.eql('100%'); + $('iframe') + .attr('width') + .should.eql('100%'); $ = cheerio.load(jsfiddle(['foo', 'default', 'default', '500'])); - $('iframe').attr('width').should.eql('500'); + $('iframe') + .attr('width') + .should.eql('500'); }); it('height', () => { - let $ = cheerio.load(jsfiddle(['foo', 'default', 'default', 'default', 'default'])); + let $ = cheerio.load( + jsfiddle(['foo', 'default', 'default', 'default', 'default']) + ); - $('iframe').attr('height').should.eql('300'); + $('iframe') + .attr('height') + .should.eql('300'); $ = cheerio.load(jsfiddle(['foo', 'default', 'default', 'default', '500'])); - $('iframe').attr('height').should.eql('500'); + $('iframe') + .attr('height') + .should.eql('500'); }); }); diff --git a/test/scripts/tags/link.js b/test/scripts/tags/link.js index 07740cceed..b5b163e0d0 100644 --- a/test/scripts/tags/link.js +++ b/test/scripts/tags/link.js @@ -6,48 +6,104 @@ describe('link', () => { const link = require('../../../lib/plugins/tag/link'); it('text + url', () => { - const $ = cheerio.load(link('Click here to Google https://google.com'.split(' '))); + const $ = cheerio.load( + link('Click here to Google https://google.com'.split(' ')) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); }); it('text + url + external', () => { - let $ = cheerio.load(link('Click here to Google https://google.com true'.split(' '))); + let $ = cheerio.load( + link('Click here to Google https://google.com true'.split(' ')) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); - $('a').attr('target').should.eql('_blank'); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); + $('a') + .attr('target') + .should.eql('_blank'); - $ = cheerio.load(link('Click here to Google https://google.com false'.split(' '))); + $ = cheerio.load( + link('Click here to Google https://google.com false'.split(' ')) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); - $('a').attr('title').should.eql(''); - $('a').attr('target').should.eql(''); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); + $('a') + .attr('title') + .should.eql(''); + $('a') + .attr('target') + .should.eql(''); }); it('text + url + title', () => { - const $ = cheerio.load(link('Click here to Google https://google.com Google link'.split(' '))); + const $ = cheerio.load( + link('Click here to Google https://google.com Google link'.split(' ')) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); - $('a').attr('title').should.eql('Google link'); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); + $('a') + .attr('title') + .should.eql('Google link'); }); it('text + url + external + title', () => { - let $ = cheerio.load(link('Click here to Google https://google.com true Google link'.split(' '))); + let $ = cheerio.load( + link( + 'Click here to Google https://google.com true Google link'.split(' ') + ) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); - $('a').attr('target').should.eql('_blank'); - $('a').attr('title').should.eql('Google link'); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); + $('a') + .attr('target') + .should.eql('_blank'); + $('a') + .attr('title') + .should.eql('Google link'); - $ = cheerio.load(link('Click here to Google https://google.com false Google link'.split(' '))); + $ = cheerio.load( + link( + 'Click here to Google https://google.com false Google link'.split(' ') + ) + ); - $('a').attr('href').should.eql('https://google.com'); - $('a').html().should.eql('Click here to Google'); - $('a').attr('target').should.eql(''); - $('a').attr('title').should.eql('Google link'); + $('a') + .attr('href') + .should.eql('https://google.com'); + $('a') + .html() + .should.eql('Click here to Google'); + $('a') + .attr('target') + .should.eql(''); + $('a') + .attr('title') + .should.eql('Google link'); }); }); diff --git a/test/scripts/tags/post_link.js b/test/scripts/tags/post_link.js index af7db1f435..233cdbd28f 100644 --- a/test/scripts/tags/post_link.js +++ b/test/scripts/tags/post_link.js @@ -8,18 +8,28 @@ describe('post_link', () => { hexo.config.permalink = ':title/'; - before(() => hexo.init().then(() => Post.insert({ - source: 'foo', - slug: 'foo', - title: 'Hello world' - }))); + before(() => + hexo.init().then(() => + Post.insert([ + { + source: 'foo', + slug: 'foo', + title: 'Hello world' + } + ]) + ) + ); it('default', () => { - postLink(['foo']).should.eql('Hello world'); + postLink(['foo']).should.eql( + 'Hello world' + ); }); it('title', () => { - postLink(['foo', 'test']).should.eql('test'); + postLink(['foo', 'test']).should.eql( + 'test' + ); }); it('no slug', () => { diff --git a/test/scripts/tags/post_path.js b/test/scripts/tags/post_path.js index 260a2ec818..9ca72bd150 100644 --- a/test/scripts/tags/post_path.js +++ b/test/scripts/tags/post_path.js @@ -8,10 +8,16 @@ describe('post_path', () => { hexo.config.permalink = ':title/'; - before(() => hexo.init().then(() => Post.insert({ - source: 'foo', - slug: 'foo' - }))); + before(() => + hexo.init().then(() => + Post.insert([ + { + source: 'foo', + slug: 'foo' + } + ]) + ) + ); it('default', () => { postPath(['foo']).should.eql('/foo/'); diff --git a/test/scripts/tags/pullquote.js b/test/scripts/tags/pullquote.js index acc0dc9f62..7476c3db3b 100644 --- a/test/scripts/tags/pullquote.js +++ b/test/scripts/tags/pullquote.js @@ -5,11 +5,17 @@ describe('pullquote', () => { const hexo = new Hexo(__dirname); const pullquote = require('../../../lib/plugins/tag/pullquote')(hexo); - before(() => hexo.init().then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked')))); + before(() => + hexo + .init() + .then(() => hexo.loadPlugin(require.resolve('hexo-renderer-marked'))) + ); it('default', () => { const result = pullquote([], '123456 **bold** and *italic*'); - result.should.eql('

123456 bold and italic

\n
'); + result.should.eql( + '

123456 bold and italic

\n
' + ); }); it('class', () => { diff --git a/test/scripts/tags/vimeo.js b/test/scripts/tags/vimeo.js index 25a0f1fd12..e41ce395aa 100644 --- a/test/scripts/tags/vimeo.js +++ b/test/scripts/tags/vimeo.js @@ -9,8 +9,14 @@ describe('vimeo', () => { const $ = cheerio.load(vimeo(['foo'])); $('.video-container').html().should.be.ok; - $('iframe').attr('src').should.eql('//player.vimeo.com/video/foo'); - $('iframe').attr('frameborder').should.eql('0'); - $('iframe').attr('allowfullscreen').should.eql(''); + $('iframe') + .attr('src') + .should.eql('//player.vimeo.com/video/foo'); + $('iframe') + .attr('frameborder') + .should.eql('0'); + $('iframe') + .attr('allowfullscreen') + .should.eql(''); }); }); diff --git a/test/scripts/tags/youtube.js b/test/scripts/tags/youtube.js index 8e14196359..7b4d605712 100644 --- a/test/scripts/tags/youtube.js +++ b/test/scripts/tags/youtube.js @@ -9,8 +9,14 @@ describe('youtube', () => { const $ = cheerio.load(youtube(['foo'])); $('.video-container').html().should.be.ok; - $('iframe').attr('src').should.eql('//www.youtube.com/embed/foo'); - $('iframe').attr('frameborder').should.eql('0'); - $('iframe').attr('allowfullscreen').should.eql(''); + $('iframe') + .attr('src') + .should.eql('//www.youtube.com/embed/foo'); + $('iframe') + .attr('frameborder') + .should.eql('0'); + $('iframe') + .attr('allowfullscreen') + .should.eql(''); }); }); diff --git a/test/scripts/theme/theme.js b/test/scripts/theme/theme.js index 67bdebae5b..ffd0e7d9c9 100644 --- a/test/scripts/theme/theme.js +++ b/test/scripts/theme/theme.js @@ -6,13 +6,15 @@ const Promise = require('bluebird'); describe('Theme', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(pathFn.join(__dirname, 'theme_test'), {silent: true}); + const hexo = new Hexo(pathFn.join(__dirname, 'theme_test'), { silent: true }); const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test'); - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init())); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]).then(() => hexo.init()) + ); after(() => fs.rmdir(hexo.base_dir)); @@ -34,7 +36,9 @@ describe('Theme', () => { it('getView() - escape backslashes', () => { hexo.theme.setView('foo/bar.swig', ''); - hexo.theme.getView('foo\\bar.swig').should.have.property('path', 'foo/bar.swig'); + hexo.theme + .getView('foo\\bar.swig') + .should.have.property('path', 'foo/bar.swig'); hexo.theme.removeView('foo/bar.swig'); }); diff --git a/test/scripts/theme/view.js b/test/scripts/theme/view.js index a48560ffff..e79158b90e 100644 --- a/test/scripts/theme/view.js +++ b/test/scripts/theme/view.js @@ -17,17 +17,20 @@ describe('View', () => { return new hexo.theme.View(path, data); } - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init()).then(() => { - // Setup layout - hexo.theme.setView('layout.swig', [ - 'pre', - '{{ body }}', - 'post' - ].join('\n')); - })); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]) + .then(() => hexo.init()) + .then(() => { + // Setup layout + hexo.theme.setView( + 'layout.swig', + ['pre', '{{ body }}', 'post'].join('\n') + ); + }) + ); after(() => fs.rmdir(hexo.base_dir)); @@ -43,11 +46,7 @@ describe('View', () => { }); it('parse front-matter', () => { - const body = [ - 'layout: false', - '---', - 'content' - ].join('\n'); + const body = ['layout: false', '---', 'content'].join('\n'); const view = newView('index.swig', body); @@ -61,15 +60,19 @@ describe('View', () => { const body = 'Hello {{ name }}'; const view = newView('index.swig', body); - view._compiledSync({ - name: 'Hexo' - }).should.eql('Hello Hexo'); - - return view._compiled({ - name: 'Hexo' - }).then(result => { - result.should.eql('Hello Hexo'); - }); + view + ._compiledSync({ + name: 'Hexo' + }) + .should.eql('Hello Hexo'); + + return view + ._compiled({ + name: 'Hexo' + }) + .then(result => { + result.should.eql('Hello Hexo'); + }); }); it('generate precompiled function even if renderer does not provide compile function', () => { @@ -80,111 +83,114 @@ describe('View', () => { const body = 'Hello {{ name }}'; const view = newView('index.swig', body); - view._compiledSync({ - name: 'Hexo' - }).should.eql('Hello Hexo'); - - return view._compiled({ - name: 'Hexo' - }).then(result => { - result.should.eql('Hello Hexo'); - }).finally(() => { - hexo.extend.renderer.store.swig.compile = compile; - }); + view + ._compiledSync({ + name: 'Hexo' + }) + .should.eql('Hello Hexo'); + + return view + ._compiled({ + name: 'Hexo' + }) + .then(result => { + result.should.eql('Hello Hexo'); + }) + .finally(() => { + hexo.extend.renderer.store.swig.compile = compile; + }); }); it('render()', () => { - const body = [ - '{{ test }}' - ].join('\n'); + const body = ['{{ test }}'].join('\n'); const view = newView('index.swig', body); - return view.render({ - test: 'foo' - }).then(content => { - content.should.eql('foo'); - }); + return view + .render({ + test: 'foo' + }) + .then(content => { + content.should.eql('foo'); + }); }); it('render() - front-matter', () => { // The priority of front-matter is higher - const body = [ - 'foo: bar', - '---', - '{{ foo }}', - '{{ test }}' - ].join('\n'); + const body = ['foo: bar', '---', '{{ foo }}', '{{ test }}'].join('\n'); const view = newView('index.swig', body); - return view.render({ - foo: 'foo', - test: 'test' - }).then(content => { - content.should.eql('bar\ntest'); - }); + return view + .render({ + foo: 'foo', + test: 'test' + }) + .then(content => { + content.should.eql('bar\ntest'); + }); }); it('render() - helper', () => { - const body = [ - '{{ date() }}' - ].join('\n'); + const body = ['{{ date() }}'].join('\n'); const view = newView('index.swig', body); - return view.render({ - config: hexo.config, - page: {} - }).then(content => { - content.should.eql(moment().format(hexo.config.date_format)); - }); + return view + .render({ + config: hexo.config, + page: {} + }) + .then(content => { + content.should.eql(moment().format(hexo.config.date_format)); + }); }); it('render() - layout', () => { const body = 'content'; const view = newView('index.swig', body); - return view.render({ - layout: 'layout' - }).then(content => { - content.should.eql('pre\n' + body + '\npost'); - }); + return view + .render({ + layout: 'layout' + }) + .then(content => { + content.should.eql('pre\n' + body + '\npost'); + }); }); it('render() - layout not found', () => { const body = 'content'; const view = newView('index.swig', body); - return view.render({ - layout: 'wtf' - }).then(content => { - content.should.eql(body); - }); + return view + .render({ + layout: 'wtf' + }) + .then(content => { + content.should.eql(body); + }); }); it('render() - callback', callback => { - const body = [ - '{{ test }}' - ].join('\n'); + const body = ['{{ test }}'].join('\n'); const view = newView('index.swig', body); - view.render({ - test: 'foo' - }, (err, content) => { - should.not.exist(err); - content.should.eql('foo'); - callback(); - }); + view.render( + { + test: 'foo' + }, + (err, content) => { + should.not.exist(err); + content.should.eql('foo'); + callback(); + } + ); }); it('render() - callback (without options)', callback => { - const body = [ - 'test: foo', - '---', - '{{ test }}' - ].join('\n'); + const body = ['test: foo', '---', '{{ test }}'].join('\n'); const view = newView('index.swig', body); @@ -196,9 +202,7 @@ describe('View', () => { }); it('render() - execute after_render:html', () => { - const body = [ - '{{ test }}' - ].join('\n'); + const body = ['{{ test }}'].join('\n'); const view = newView('index.swig', body); @@ -209,76 +213,76 @@ describe('View', () => { hexo.extend.filter.register('after_render:html', filter); - return view.render({ - test: 'foo' - }).then(content => { - content.should.eql('bar'); - }).finally(() => { - hexo.extend.filter.unregister('after_render:html', filter); - }); + return view + .render({ + test: 'foo' + }) + .then(content => { + content.should.eql('bar'); + }) + .finally(() => { + hexo.extend.filter.unregister('after_render:html', filter); + }); }); it('renderSync()', () => { - const body = [ - '{{ test }}' - ].join('\n'); + const body = ['{{ test }}'].join('\n'); const view = newView('index.swig', body); - view.renderSync({test: 'foo'}).should.eql('foo'); + view.renderSync({ test: 'foo' }).should.eql('foo'); }); it('renderSync() - front-matter', () => { // The priority of front-matter is higher - const body = [ - 'foo: bar', - '---', - '{{ foo }}', - '{{ test }}' - ].join('\n'); + const body = ['foo: bar', '---', '{{ foo }}', '{{ test }}'].join('\n'); const view = newView('index.swig', body); - view.renderSync({ - foo: 'foo', - test: 'test' - }).should.eql('bar\ntest'); + view + .renderSync({ + foo: 'foo', + test: 'test' + }) + .should.eql('bar\ntest'); }); it('renderSync() - helper', () => { - const body = [ - '{{ date() }}' - ].join('\n'); + const body = ['{{ date() }}'].join('\n'); const view = newView('index.swig', body); - view.renderSync({ - config: hexo.config, - page: {} - }).should.eql(moment().format(hexo.config.date_format)); + view + .renderSync({ + config: hexo.config, + page: {} + }) + .should.eql(moment().format(hexo.config.date_format)); }); it('renderSync() - layout', () => { const body = 'content'; const view = newView('index.swig', body); - view.renderSync({ - layout: 'layout' - }).should.eql('pre\n' + body + '\npost'); + view + .renderSync({ + layout: 'layout' + }) + .should.eql('pre\n' + body + '\npost'); }); it('renderSync() - layout not found', () => { const body = 'content'; const view = newView('index.swig', body); - view.renderSync({ - layout: 'wtf' - }).should.eql(body); + view + .renderSync({ + layout: 'wtf' + }) + .should.eql(body); }); it('renderSync() - execute after_render:html', () => { - const body = [ - '{{ test }}' - ].join('\n'); + const body = ['{{ test }}'].join('\n'); const view = newView('index.swig', body); @@ -288,7 +292,7 @@ describe('View', () => { }); hexo.extend.filter.register('after_render:html', filter); - view.renderSync({test: 'foo'}).should.eql('bar'); + view.renderSync({ test: 'foo' }).should.eql('bar'); hexo.extend.filter.unregister('after_render:html', filter); }); @@ -296,7 +300,9 @@ describe('View', () => { const view = newView('partials/header.swig', 'header'); // Relative path - view._resolveLayout('../layout').should.have.property('path', 'layout.swig'); + view + ._resolveLayout('../layout') + .should.have.property('path', 'layout.swig'); // Absolute path view._resolveLayout('layout').should.have.property('path', 'layout.swig'); diff --git a/test/scripts/theme_processors/config.js b/test/scripts/theme_processors/config.js index 5e8dd68d62..45fe0a1078 100644 --- a/test/scripts/theme_processors/config.js +++ b/test/scripts/theme_processors/config.js @@ -7,7 +7,9 @@ const Promise = require('bluebird'); describe('config', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {silent: true}); + const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), { + silent: true + }); const processor = require('../../../lib/theme/processors/config'); const process = Promise.method(processor.process.bind(hexo)); const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test'); @@ -17,10 +19,12 @@ describe('config', () => { return new hexo.theme.File(options); } - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init())); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]).then(() => hexo.init()) + ); after(() => fs.rmdir(hexo.base_dir)); @@ -34,11 +38,7 @@ describe('config', () => { }); it('type: create', () => { - const body = [ - 'name:', - ' first: John', - ' last: Doe' - ].join('\n'); + const body = ['name:', ' first: John', ' last: Doe'].join('\n'); const file = newFile({ path: '_config.yml', @@ -46,14 +46,18 @@ describe('config', () => { content: body }); - return fs.writeFile(file.source, body).then(() => process(file)).then(() => { - hexo.theme.config.should.eql({ - name: {first: 'John', last: 'Doe'} + return fs + .writeFile(file.source, body) + .then(() => process(file)) + .then(() => { + hexo.theme.config.should.eql({ + name: { first: 'John', last: 'Doe' } + }); + }) + .finally(() => { + hexo.theme.config = {}; + return fs.unlink(file.source); }); - }).finally(() => { - hexo.theme.config = {}; - return fs.unlink(file.source); - }); }); it('type: delete', () => { @@ -62,7 +66,7 @@ describe('config', () => { type: 'delete' }); - hexo.theme.config = {foo: 'bar'}; + hexo.theme.config = { foo: 'bar' }; return process(file).then(() => { hexo.theme.config.should.eql({}); @@ -79,8 +83,11 @@ describe('config', () => { err.should.have.property('message', 'Theme config load failed.'); }); - return process(file).catch(errorCallback).finally(() => { - errorCallback.calledOnce.should.be.true; - }).catch(() => {}); // Catch again because it throws error + return process(file) + .catch(errorCallback) + .finally(() => { + errorCallback.calledOnce.should.be.true; + }) + .catch(() => {}); // Catch again because it throws error }); }); diff --git a/test/scripts/theme_processors/i18n.js b/test/scripts/theme_processors/i18n.js index 24859babd6..10b9699ec8 100644 --- a/test/scripts/theme_processors/i18n.js +++ b/test/scripts/theme_processors/i18n.js @@ -6,7 +6,9 @@ const Promise = require('bluebird'); describe('i18n', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), {silent: true}); + const hexo = new Hexo(pathFn.join(__dirname, 'config_test'), { + silent: true + }); const processor = require('../../../lib/theme/processors/i18n'); const process = Promise.method(processor.process.bind(hexo)); const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test'); @@ -24,10 +26,12 @@ describe('i18n', () => { return new hexo.theme.File(options); } - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init())); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]).then(() => hexo.init()) + ); after(() => fs.rmdir(hexo.base_dir)); @@ -40,23 +44,23 @@ describe('i18n', () => { }); it('type: create', () => { - const body = [ - 'ok: OK', - 'index:', - ' title: Home' - ].join('\n'); + const body = ['ok: OK', 'index:', ' title: Home'].join('\n'); const file = newFile({ path: 'en.yml', type: 'create' }); - return fs.writeFile(file.source, body).then(() => process(file)).then(() => { - const __ = hexo.theme.i18n.__('en'); + return fs + .writeFile(file.source, body) + .then(() => process(file)) + .then(() => { + const __ = hexo.theme.i18n.__('en'); - __('ok').should.eql('OK'); - __('index.title').should.eql('Home'); - }).finally(() => fs.unlink(file.source)); + __('ok').should.eql('OK'); + __('index.title').should.eql('Home'); + }) + .finally(() => fs.unlink(file.source)); }); it('type: delete', () => { diff --git a/test/scripts/theme_processors/source.js b/test/scripts/theme_processors/source.js index b351d3d83a..2893f64b90 100644 --- a/test/scripts/theme_processors/source.js +++ b/test/scripts/theme_processors/source.js @@ -6,7 +6,9 @@ const Promise = require('bluebird'); describe('source', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(pathFn.join(__dirname, 'source_test'), {silent: true}); + const hexo = new Hexo(pathFn.join(__dirname, 'source_test'), { + silent: true + }); const processor = require('../../../lib/theme/processors/source'); const process = Promise.method(processor.process.bind(hexo)); const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test'); @@ -15,24 +17,26 @@ describe('source', () => { function newFile(options) { const path = options.path; - options.params = {path}; + options.params = { path }; options.path = 'source/' + path; options.source = pathFn.join(themeDir, options.path); return new hexo.theme.File(options); } - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init())); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]).then(() => hexo.init()) + ); after(() => fs.rmdir(hexo.base_dir)); it('pattern', () => { const pattern = processor.pattern; - pattern.match('source/foo.jpg').should.eql({path: 'foo.jpg'}); + pattern.match('source/foo.jpg').should.eql({ path: 'foo.jpg' }); pattern.match('source/_foo.jpg').should.be.false; pattern.match('source/foo/_bar.jpg').should.be.false; pattern.match('source/foo.jpg~').should.be.false; @@ -51,15 +55,19 @@ describe('source', () => { const id = 'themes/test/' + file.path; - return fs.writeFile(file.source, 'test').then(() => process(file)).then(() => { - const asset = Asset.findById(id); + return fs + .writeFile(file.source, 'test') + .then(() => process(file)) + .then(() => { + const asset = Asset.findById(id); - asset._id.should.eql(id); - asset.path.should.eql(file.params.path); - asset.modified.should.be.true; + asset._id.should.eql(id); + asset.path.should.eql(file.params.path); + asset.modified.should.be.true; - return asset.remove(); - }).finally(() => fs.unlink(file.source)); + return asset.remove(); + }) + .finally(() => fs.unlink(file.source)); }); it('type: update', () => { @@ -77,14 +85,16 @@ describe('source', () => { path: file.params.path, modified: false }) - ]).then(() => process(file)).then(() => { - const asset = Asset.findById(id); - - asset.modified.should.be.true; - }).finally(() => Promise.all([ - fs.unlink(file.source), - Asset.removeById(id) - ])); + ]) + .then(() => process(file)) + .then(() => { + const asset = Asset.findById(id); + + asset.modified.should.be.true; + }) + .finally(() => + Promise.all([fs.unlink(file.source), Asset.removeById(id)]) + ); }); it('type: skip', () => { @@ -102,14 +112,16 @@ describe('source', () => { path: file.params.path, modified: false }) - ]).then(() => process(file)).then(() => { - const asset = Asset.findById(id); - - asset.modified.should.be.false; - }).finally(() => Promise.all([ - fs.unlink(file.source), - Asset.removeById(id) - ])); + ]) + .then(() => process(file)) + .then(() => { + const asset = Asset.findById(id); + + asset.modified.should.be.false; + }) + .finally(() => + Promise.all([fs.unlink(file.source), Asset.removeById(id)]) + ); }); it('type: delete', () => { @@ -123,8 +135,10 @@ describe('source', () => { return Asset.insert({ _id: id, path: file.params.path - }).then(() => process(file)).then(() => { - should.not.exist(Asset.findById(id)); - }); + }) + .then(() => process(file)) + .then(() => { + should.not.exist(Asset.findById(id)); + }); }); }); diff --git a/test/scripts/theme_processors/view.js b/test/scripts/theme_processors/view.js index 64224fc537..2099d06482 100644 --- a/test/scripts/theme_processors/view.js +++ b/test/scripts/theme_processors/view.js @@ -6,7 +6,7 @@ const Promise = require('bluebird'); describe('view', () => { const Hexo = require('../../../lib/hexo'); - const hexo = new Hexo(pathFn.join(__dirname, 'view_test'), {silent: true}); + const hexo = new Hexo(pathFn.join(__dirname, 'view_test'), { silent: true }); const processor = require('../../../lib/theme/processors/view'); const process = Promise.method(processor.process.bind(hexo)); const themeDir = pathFn.join(hexo.base_dir, 'themes', 'test'); @@ -16,17 +16,19 @@ describe('view', () => { function newFile(options) { const path = options.path; - options.params = {path}; + options.params = { path }; options.path = 'layout/' + path; options.source = pathFn.join(themeDir, options.path); return new hexo.theme.File(options); } - before(() => Promise.all([ - fs.mkdirs(themeDir), - fs.writeFile(hexo.config_path, 'theme: test') - ]).then(() => hexo.init())); + before(() => + Promise.all([ + fs.mkdirs(themeDir), + fs.writeFile(hexo.config_path, 'theme: test') + ]).then(() => hexo.init()) + ); after(() => fs.rmdir(hexo.base_dir)); @@ -39,30 +41,30 @@ describe('view', () => { }); it('type: create', () => { - const body = [ - 'foo: bar', - '---', - 'test' - ].join('\n'); + const body = ['foo: bar', '---', 'test'].join('\n'); const file = newFile({ path: 'index.swig', type: 'create' }); - return fs.writeFile(file.source, body).then(() => process(file)).then(() => { - const view = hexo.theme.getView('index.swig'); - - view.path.should.eql('index.swig'); - view.source.should.eql(pathFn.join(themeDir, 'layout', 'index.swig')); - view.data.should.eql({ - foo: 'bar', - _content: 'test' + return fs + .writeFile(file.source, body) + .then(() => process(file)) + .then(() => { + const view = hexo.theme.getView('index.swig'); + + view.path.should.eql('index.swig'); + view.source.should.eql(pathFn.join(themeDir, 'layout', 'index.swig')); + view.data.should.eql({ + foo: 'bar', + _content: 'test' + }); + }) + .finally(() => { + hexo.theme.removeView('index.swig'); + return fs.unlink(file.source); }); - }).finally(() => { - hexo.theme.removeView('index.swig'); - return fs.unlink(file.source); - }); }); it('type: delete', () => { diff --git a/test/util/stream.js b/test/util/stream.js index 930e4ccdc4..ca0624b6fd 100644 --- a/test/util/stream.js +++ b/test/util/stream.js @@ -6,11 +6,14 @@ function readStream(stream) { return new Promise((resolve, reject) => { let data = ''; - stream.on('data', chunk => { - data += chunk.toString(); - }).on('end', () => { - resolve(data); - }).on('error', reject); + stream + .on('data', chunk => { + data += chunk.toString(); + }) + .on('end', () => { + resolve(data); + }) + .on('error', reject); }); }