├── .babelrc ├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── CNAME ├── README.md ├── build ├── build.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── deploy.sh ├── index.html ├── package.json ├── src ├── App.vue ├── assets │ ├── logo.png │ └── scss │ │ ├── app.scss │ │ ├── bootstrap │ │ ├── _bootstrap.scss │ │ ├── _mixins.scss │ │ └── _variables.scss │ │ └── font-awesome │ │ └── _font-awesome.scss ├── components │ ├── About.vue │ ├── Home.vue │ ├── Navbar.vue │ └── errors │ │ └── 404.vue ├── http │ ├── interceptors.js │ ├── middlewares.js │ └── routes.js ├── main.js └── vuex │ ├── actions.js │ ├── getters.js │ ├── modules │ └── navbar.js │ ├── mutation-types.js │ └── store.js ├── static └── .gitkeep └── test ├── e2e ├── custom-assertions │ └── elementCount.js ├── nightwatch.conf.js ├── runner.js └── specs │ └── test.js └── unit ├── .eslintrc ├── index.js ├── karma.conf.js └── specs └── Hello.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | GIT_DEPLOY_DIR=dist 2 | GIT_DEPLOY_BRANCH=gh-pages 3 | GIT_DEPLOY_USERNAME=ghprod 4 | GIT_DEPLOY_EMAIL=greenhouseprod@gmail.com -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | selenium-debug.log 6 | test/unit/coverage 7 | test/e2e/reports 8 | *.sublime-* -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | vue-bootstrap.ferrisutanto.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Bootstrap 2 | 3 | > A Vue Webpack Template With jQuery, Bootstrap Sass, and Font Awesome. 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # run unit tests 18 | npm run unit 19 | 20 | # run e2e tests 21 | npm run e2e 22 | 23 | # run all tests 24 | npm test 25 | ``` 26 | 27 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 28 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('shelljs/global') 3 | env.NODE_ENV = 'production' 4 | 5 | var path = require('path') 6 | var config = require('../config') 7 | var ora = require('ora') 8 | var webpack = require('webpack') 9 | var webpackConfig = require('./webpack.prod.conf') 10 | 11 | console.log( 12 | ' Tip:\n' + 13 | ' Built files are meant to be served over an HTTP server.\n' + 14 | ' Opening index.html over file:// won\'t work.\n' 15 | ) 16 | 17 | var spinner = ora('building for production...') 18 | spinner.start() 19 | 20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 21 | rm('-rf', assetsPath) 22 | mkdir('-p', assetsPath) 23 | cp('-R', 'static/', assetsPath) 24 | cp('CNAME', config.build.assetsRoot) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var express = require('express') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var proxyMiddleware = require('http-proxy-middleware') 6 | var webpackConfig = process.env.NODE_ENV === 'testing' 7 | ? require('./webpack.prod.conf') 8 | : require('./webpack.dev.conf') 9 | 10 | // default port where dev server listens for incoming traffic 11 | var port = process.env.PORT || config.dev.port 12 | // Define HTTP proxies to your custom API backend 13 | // https://github.com/chimurai/http-proxy-middleware 14 | var proxyTable = config.dev.proxyTable 15 | 16 | var app = express() 17 | var compiler = webpack(webpackConfig) 18 | 19 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 20 | publicPath: webpackConfig.output.publicPath, 21 | stats: { 22 | colors: true, 23 | chunks: false 24 | } 25 | }) 26 | 27 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 28 | // force page reload when html-webpack-plugin template changes 29 | compiler.plugin('compilation', function (compilation) { 30 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 31 | hotMiddleware.publish({ action: 'reload' }) 32 | cb() 33 | }) 34 | }) 35 | 36 | // proxy api requests 37 | Object.keys(proxyTable).forEach(function (context) { 38 | var options = proxyTable[context] 39 | if (typeof options === 'string') { 40 | options = { target: options } 41 | } 42 | app.use(proxyMiddleware(context, options)) 43 | }) 44 | 45 | // handle fallback for HTML5 history API 46 | app.use(require('connect-history-api-fallback')()) 47 | 48 | // serve webpack bundle output 49 | app.use(devMiddleware) 50 | 51 | // enable hot-reload and state-preserving 52 | // compilation error display 53 | app.use(hotMiddleware) 54 | 55 | // serve pure static assets 56 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 57 | app.use(staticPath, express.static('./static')) 58 | 59 | module.exports = app.listen(port, function (err) { 60 | if (err) { 61 | console.log(err) 62 | return 63 | } 64 | console.log('Listening at http://localhost:' + port + '\n') 65 | }) 66 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | return path.posix.join(config.build.assetsSubDirectory, _path) 7 | } 8 | 9 | exports.cssLoaders = function (options) { 10 | options = options || {} 11 | // generate loader string to be used with extract text plugin 12 | function generateLoaders (loaders) { 13 | var sourceLoader = loaders.map(function (loader) { 14 | var extraParamChar 15 | if (/\?/.test(loader)) { 16 | loader = loader.replace(/\?/, '-loader?') 17 | extraParamChar = '&' 18 | } else { 19 | loader = loader + '-loader' 20 | extraParamChar = '?' 21 | } 22 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 23 | }).join('!') 24 | 25 | if (options.extract) { 26 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 27 | } else { 28 | return ['vue-style-loader', sourceLoader].join('!') 29 | } 30 | } 31 | 32 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 33 | return { 34 | css: generateLoaders(['css']), 35 | postcss: generateLoaders(['css']), 36 | less: generateLoaders(['css', 'less']), 37 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 38 | scss: generateLoaders(['css', 'sass']), 39 | stylus: generateLoaders(['css', 'stylus']), 40 | styl: generateLoaders(['css', 'stylus']) 41 | } 42 | } 43 | 44 | // Generate loaders for standalone style files (outside of .vue) 45 | exports.styleLoaders = function (options) { 46 | var output = [] 47 | var loaders = exports.cssLoaders(options) 48 | for (var extension in loaders) { 49 | var loader = loaders[extension] 50 | output.push({ 51 | test: new RegExp('\\.' + extension + '$'), 52 | loader: loader 53 | }) 54 | } 55 | return output 56 | } 57 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var projectRoot = path.resolve(__dirname, '../') 6 | 7 | module.exports = { 8 | entry: { 9 | app: './src/main.js', 10 | vendor: [ 11 | 'jquery', 12 | 'bootstrap-sass', 13 | 'vue', 14 | 'vue-router', 15 | 'vue-resource', 16 | 'vuex', 17 | 'vuex-router-sync' 18 | ] 19 | }, 20 | output: { 21 | path: config.build.assetsRoot, 22 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 23 | filename: '[name].js' 24 | }, 25 | resolve: { 26 | extensions: ['', '.js', '.vue'], 27 | fallback: [path.join(__dirname, '../node_modules')], 28 | alias: { 29 | 'src': path.resolve(__dirname, '../src'), 30 | 'assets': path.resolve(__dirname, '../src/assets'), 31 | 'components': path.resolve(__dirname, '../src/components') 32 | } 33 | }, 34 | resolveLoader: { 35 | fallback: [path.join(__dirname, '../node_modules')] 36 | }, 37 | module: { 38 | preLoaders: [ 39 | { 40 | test: /\.vue$/, 41 | loader: 'eslint', 42 | include: projectRoot, 43 | exclude: /node_modules/ 44 | }, 45 | { 46 | test: /\.js$/, 47 | loader: 'eslint', 48 | include: projectRoot, 49 | exclude: /node_modules/ 50 | } 51 | ], 52 | loaders: [ 53 | { 54 | test: /\.vue$/, 55 | loader: 'vue' 56 | }, 57 | { 58 | test: /\.js$/, 59 | loader: 'babel', 60 | include: projectRoot, 61 | exclude: /node_modules/ 62 | }, 63 | { 64 | test: /\.json$/, 65 | loader: 'json' 66 | }, 67 | { 68 | test: /\.html$/, 69 | loader: 'vue-html' 70 | }, 71 | { 72 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 73 | loader: 'url', 74 | query: { 75 | limit: 10000, 76 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 77 | } 78 | }, 79 | { 80 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 81 | loader: 'url', 82 | query: { 83 | limit: 10000, 84 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 85 | } 86 | }, 87 | { 88 | test: require.resolve('jquery'), 89 | loader: 'expose?jQuery!expose?$' 90 | }, 91 | { 92 | test: /bootstrap-sass\/assets\/javascripts\//, 93 | loader: 'imports?jQuery=jquery' 94 | } 95 | ] 96 | }, 97 | eslint: { 98 | formatter: require('eslint-friendly-formatter') 99 | }, 100 | vue: { 101 | loaders: utils.cssLoaders() 102 | }, 103 | plugins: [ 104 | new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js') 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = process.env.NODE_ENV === 'testing' 10 | ? require('../config/test.env') 11 | : config.build.env 12 | 13 | var webpackConfig = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.build.productionSourceMap ? '#source-map' : false, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.build.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | } 38 | }), 39 | new webpack.optimize.OccurenceOrderPlugin(), 40 | // extract css into its own file 41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 42 | // generate dist index.html with correct asset hash for caching. 43 | // you can customize output by editing /index.html 44 | // see https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: process.env.NODE_ENV === 'testing' 47 | ? 'index.html' 48 | : config.build.index, 49 | template: 'index.html', 50 | inject: true, 51 | minify: { 52 | removeComments: true, 53 | collapseWhitespace: true, 54 | removeAttributeQuotes: true 55 | // more options: 56 | // https://github.com/kangax/html-minifier#options-quick-reference 57 | }, 58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 59 | chunksSortMode: 'dependency' 60 | }), 61 | // split vendor js into its own file 62 | new webpack.optimize.CommonsChunkPlugin({ 63 | name: 'vendor', 64 | minChunks: function (module, count) { 65 | // any required modules inside node_modules are extracted to vendor 66 | return ( 67 | module.resource && 68 | /\.js$/.test(module.resource) && 69 | module.resource.indexOf( 70 | path.join(__dirname, '../node_modules') 71 | ) === 0 72 | ) 73 | } 74 | }), 75 | // extract webpack runtime and module manifest to its own file in order to 76 | // prevent vendor hash from being updated whenever app bundle is updated 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'manifest', 79 | chunks: ['vendor'] 80 | }) 81 | ] 82 | }) 83 | 84 | if (config.build.productionGzip) { 85 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 86 | 87 | webpackConfig.plugins.push( 88 | new CompressionWebpackPlugin({ 89 | asset: '[path].gz[query]', 90 | algorithm: 'gzip', 91 | test: new RegExp( 92 | '\\.(' + 93 | config.build.productionGzipExtensions.join('|') + 94 | ')$' 95 | ), 96 | threshold: 10240, 97 | minRatio: 0.8 98 | }) 99 | ) 100 | } 101 | 102 | module.exports = webpackConfig 103 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8080, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -o errexit #abort if any command fails 3 | me=$(basename "$0") 4 | 5 | help_message="\ 6 | Usage: $me [-c FILE] [] 7 | Deploy generated files to a git branch. 8 | 9 | Options: 10 | 11 | -h, --help Show this help information. 12 | -v, --verbose Increase verbosity. Useful for debugging. 13 | -e, --allow-empty Allow deployment of an empty directory. 14 | -m, --message MESSAGE Specify the message used when committing on the 15 | deploy branch. 16 | -n, --no-hash Don't append the source commit's hash to the deploy 17 | commit's message. 18 | -c, --config-file PATH Override default & environment variables' values 19 | with those in set in the file at 'PATH'. Must be the 20 | first option specified. 21 | 22 | Variables: 23 | 24 | GIT_DEPLOY_DIR Folder path containing the files to deploy. 25 | GIT_DEPLOY_BRANCH Commit deployable files to this branch. 26 | GIT_DEPLOY_REPO Push the deploy branch to this repository. 27 | 28 | These variables have default values defined in the script. The defaults can be 29 | overridden by environment variables. Any environment variables are overridden 30 | by values set in a '.env' file (if it exists), and in turn by those set in a 31 | file specified by the '--config-file' option." 32 | 33 | parse_args() { 34 | # Set args from a local environment file. 35 | if [ -e ".env" ]; then 36 | source .env 37 | fi 38 | 39 | # Set args from file specified on the command-line. 40 | if [[ $1 = "-c" || $1 = "--config-file" ]]; then 41 | source "$2" 42 | shift 2 43 | fi 44 | 45 | # Parse arg flags 46 | # If something is exposed as an environment variable, set/overwrite it 47 | # here. Otherwise, set/overwrite the internal variable instead. 48 | while : ; do 49 | if [[ $1 = "-h" || $1 = "--help" ]]; then 50 | echo "$help_message" 51 | return 0 52 | elif [[ $1 = "-v" || $1 = "--verbose" ]]; then 53 | verbose=true 54 | shift 55 | elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then 56 | allow_empty=true 57 | shift 58 | elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then 59 | commit_message=$2 60 | shift 2 61 | elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then 62 | GIT_DEPLOY_APPEND_HASH=false 63 | shift 64 | else 65 | break 66 | fi 67 | done 68 | 69 | # Set internal option vars from the environment and arg flags. All internal 70 | # vars should be declared here, with sane defaults if applicable. 71 | 72 | # Source directory & target branch. 73 | deploy_directory=${GIT_DEPLOY_DIR:-dist} 74 | deploy_branch=${GIT_DEPLOY_BRANCH:-gh-pages} 75 | 76 | #if no user identity is already set in the current git environment, use this: 77 | default_username=${GIT_DEPLOY_USERNAME:-deploy.sh} 78 | default_email=${GIT_DEPLOY_EMAIL:-} 79 | 80 | #repository to deploy to. must be readable and writable. 81 | repo=${GIT_DEPLOY_REPO:-origin} 82 | 83 | #append commit hash to the end of message by default 84 | append_hash=${GIT_DEPLOY_APPEND_HASH:-true} 85 | } 86 | 87 | main() { 88 | parse_args "$@" 89 | 90 | enable_expanded_output 91 | 92 | if ! git diff --exit-code --quiet --cached; then 93 | echo Aborting due to uncommitted changes in the index >&2 94 | return 1 95 | fi 96 | 97 | commit_title=`git log -n 1 --format="%s" HEAD` 98 | commit_hash=` git log -n 1 --format="%H" HEAD` 99 | 100 | #default commit message uses last title if a custom one is not supplied 101 | if [[ -z $commit_message ]]; then 102 | commit_message="publish: $commit_title" 103 | fi 104 | 105 | #append hash to commit message unless no hash flag was found 106 | if [ $append_hash = true ]; then 107 | commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash" 108 | fi 109 | 110 | previous_branch=`git rev-parse --abbrev-ref HEAD` 111 | 112 | if [ ! -d "$deploy_directory" ]; then 113 | echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2 114 | return 1 115 | fi 116 | 117 | # must use short form of flag in ls for compatibility with OS X and BSD 118 | if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then 119 | echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2 120 | return 1 121 | fi 122 | 123 | if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then 124 | # deploy_branch exists in $repo; make sure we have the latest version 125 | 126 | disable_expanded_output 127 | git fetch --force $repo $deploy_branch:$deploy_branch 128 | enable_expanded_output 129 | fi 130 | 131 | # check if deploy_branch exists locally 132 | if git show-ref --verify --quiet "refs/heads/$deploy_branch" 133 | then incremental_deploy 134 | else initial_deploy 135 | fi 136 | 137 | restore_head 138 | } 139 | 140 | initial_deploy() { 141 | git --work-tree "$deploy_directory" checkout --orphan $deploy_branch 142 | git --work-tree "$deploy_directory" add --all 143 | commit+push 144 | } 145 | 146 | incremental_deploy() { 147 | #make deploy_branch the current branch 148 | git symbolic-ref HEAD refs/heads/$deploy_branch 149 | #put the previously committed contents of deploy_branch into the index 150 | git --work-tree "$deploy_directory" reset --mixed --quiet 151 | git --work-tree "$deploy_directory" add --all 152 | 153 | set +o errexit 154 | diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$? 155 | set -o errexit 156 | case $diff in 157 | 0) echo No changes to files in $deploy_directory. Skipping commit.;; 158 | 1) commit+push;; 159 | *) 160 | echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2 161 | return $diff 162 | ;; 163 | esac 164 | } 165 | 166 | commit+push() { 167 | set_user_id 168 | git --work-tree "$deploy_directory" commit -m "$commit_message" 169 | 170 | disable_expanded_output 171 | #--quiet is important here to avoid outputting the repo URL, which may contain a secret token 172 | git push --quiet $repo $deploy_branch 173 | enable_expanded_output 174 | } 175 | 176 | #echo expanded commands as they are executed (for debugging) 177 | enable_expanded_output() { 178 | if [ $verbose ]; then 179 | set -o xtrace 180 | set +o verbose 181 | fi 182 | } 183 | 184 | #this is used to avoid outputting the repo URL, which may contain a secret token 185 | disable_expanded_output() { 186 | if [ $verbose ]; then 187 | set +o xtrace 188 | set -o verbose 189 | fi 190 | } 191 | 192 | set_user_id() { 193 | if [[ -z `git config user.name` ]]; then 194 | git config user.name "$default_username" 195 | fi 196 | if [[ -z `git config user.email` ]]; then 197 | git config user.email "$default_email" 198 | fi 199 | } 200 | 201 | restore_head() { 202 | if [[ $previous_branch = "HEAD" ]]; then 203 | #we weren't on any branch before, so just set HEAD back to the commit it was on 204 | git update-ref --no-deref HEAD $commit_hash $deploy_branch 205 | else 206 | git symbolic-ref HEAD refs/heads/$previous_branch 207 | fi 208 | 209 | git reset --mixed 210 | } 211 | 212 | filter() { 213 | sed -e "s|$repo|\$repo|g" 214 | } 215 | 216 | sanitize() { 217 | "$@" 2> >(filter 1>&2) | filter 218 | } 219 | 220 | [[ $1 = --source-only ]] || main "$@" 221 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Vue jQuery Bootstrap Sass Font Awesome 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-bootstrap", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "Ferri Sutanto ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "unit": "karma start test/unit/karma.conf.js --single-run", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 14 | }, 15 | "dependencies": { 16 | "babel-runtime": "^6.0.0", 17 | "bootstrap-sass": "^3.3.7", 18 | "expose-loader": "^0.7.1", 19 | "font-awesome": "^4.6.3", 20 | "jquery": "^3.1.0", 21 | "vue": "^1.0.21", 22 | "vue-head": "^1.0.7", 23 | "vue-resource": "^0.9.3", 24 | "vue-router": "^0.7.13", 25 | "vuex": "^1.0.0-rc.2", 26 | "vuex-router-sync": "^2.1.0" 27 | }, 28 | "devDependencies": { 29 | "babel-core": "^6.0.0", 30 | "babel-eslint": "^6.1.2", 31 | "babel-loader": "^6.0.0", 32 | "babel-plugin-transform-runtime": "^6.0.0", 33 | "babel-preset-es2015": "^6.0.0", 34 | "babel-preset-stage-2": "^6.0.0", 35 | "babel-register": "^6.0.0", 36 | "chai": "^3.5.0", 37 | "chromedriver": "^2.21.2", 38 | "connect-history-api-fallback": "^1.1.0", 39 | "cross-spawn": "^2.1.5", 40 | "css-loader": "^0.23.0", 41 | "eslint": "^2.10.2", 42 | "eslint-config-standard": "^5.1.0", 43 | "eslint-friendly-formatter": "^2.0.5", 44 | "eslint-loader": "^1.3.0", 45 | "eslint-plugin-html": "^1.3.0", 46 | "eslint-plugin-promise": "^1.0.8", 47 | "eslint-plugin-standard": "^1.3.2", 48 | "eventsource-polyfill": "^0.9.6", 49 | "express": "^4.13.3", 50 | "extract-text-webpack-plugin": "^1.0.1", 51 | "file-loader": "^0.8.4", 52 | "function-bind": "^1.0.2", 53 | "html-webpack-plugin": "^2.8.1", 54 | "http-proxy-middleware": "^0.12.0", 55 | "imports-loader": "^0.6.5", 56 | "inject-loader": "^2.0.1", 57 | "isparta-loader": "^2.0.0", 58 | "json-loader": "^0.5.4", 59 | "karma": "^0.13.15", 60 | "karma-coverage": "^0.5.5", 61 | "karma-mocha": "^0.2.2", 62 | "karma-phantomjs-launcher": "^1.0.0", 63 | "karma-sinon-chai": "^1.2.0", 64 | "karma-sourcemap-loader": "^0.3.7", 65 | "karma-spec-reporter": "0.0.24", 66 | "karma-webpack": "^1.7.0", 67 | "lolex": "^1.4.0", 68 | "mocha": "^2.4.5", 69 | "nightwatch": "^0.8.18", 70 | "ora": "^0.2.0", 71 | "phantomjs-prebuilt": "^2.1.3", 72 | "sass-loader": "^4.0.0", 73 | "selenium-server": "2.53.0", 74 | "shelljs": "^0.6.0", 75 | "sinon": "^1.17.3", 76 | "sinon-chai": "^2.8.0", 77 | "url-loader": "^0.5.7", 78 | "vue-hot-reload-api": "^1.2.0", 79 | "vue-html-loader": "^1.0.0", 80 | "vue-loader": "^8.3.0", 81 | "vue-style-loader": "^1.0.0", 82 | "webpack": "^1.12.2", 83 | "webpack-dev-middleware": "^1.4.0", 84 | "webpack-hot-middleware": "^2.6.0", 85 | "webpack-merge": "^0.8.3" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fer-ri/vue-bootstrap/42a316d072e33f83c876c3ba9699586d1c8927a6/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/scss/app.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:400,300,700); 2 | @import 'bootstrap/bootstrap'; 3 | @import 'font-awesome/font-awesome'; 4 | 5 | body { 6 | padding-top: 85px; 7 | } -------------------------------------------------------------------------------- /src/assets/scss/bootstrap/_bootstrap.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | 4 | // Core variables and mixins 5 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/variables"; 6 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/mixins"; 7 | 8 | // Reset and dependencies 9 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/normalize"; 10 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/print"; 11 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/glyphicons"; 12 | 13 | // Core CSS 14 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/scaffolding"; 15 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/type"; 16 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/code"; 17 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/grid"; 18 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/tables"; 19 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/forms"; 20 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/buttons"; 21 | 22 | // Components 23 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/component-animations"; 24 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/dropdowns"; 25 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/button-groups"; 26 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/input-groups"; 27 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/navs"; 28 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/navbar"; 29 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs"; 30 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/pagination"; 31 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/pager"; 32 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/labels"; 33 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/badges"; 34 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/jumbotron"; 35 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/thumbnails"; 36 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/alerts"; 37 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/progress-bars"; 38 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/media"; 39 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/list-group"; 40 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/panels"; 41 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed"; 42 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/wells"; 43 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/close"; 44 | 45 | // Components w/ JavaScript 46 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/modals"; 47 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/tooltip"; 48 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/popovers"; 49 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/carousel"; 50 | 51 | // Utility classes 52 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/utilities"; 53 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities"; 54 | -------------------------------------------------------------------------------- /src/assets/scss/bootstrap/_mixins.scss: -------------------------------------------------------------------------------- 1 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/mixins"; -------------------------------------------------------------------------------- /src/assets/scss/bootstrap/_variables.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/"; 2 | 3 | $font-family-sans-serif: "Lato", Helvetica, Arial, sans-serif !default; 4 | $font-size-base: 14px; 5 | 6 | $navbar-height: 65px; 7 | $navbar-default-bg: #fff; 8 | 9 | $border-radius-base: 0; 10 | $border-radius-large: 0; 11 | $border-radius-small: 0; 12 | 13 | $brand-primary: #2B5A84; 14 | 15 | // Default bootstrap 16 | @import "~bootstrap-sass/assets/stylesheets/bootstrap/variables"; -------------------------------------------------------------------------------- /src/assets/scss/font-awesome/_font-awesome.scss: -------------------------------------------------------------------------------- 1 | @import "~font-awesome/scss/variables"; 2 | 3 | $fa-font-path: "~font-awesome/fonts"; 4 | 5 | @import "~font-awesome/scss/mixins"; 6 | @import "~font-awesome/scss/path"; 7 | @import "~font-awesome/scss/core"; 8 | @import "~font-awesome/scss/larger"; 9 | @import "~font-awesome/scss/fixed-width"; 10 | @import "~font-awesome/scss/list"; 11 | @import "~font-awesome/scss/bordered-pulled"; 12 | @import "~font-awesome/scss/animated"; 13 | @import "~font-awesome/scss/rotated-flipped"; 14 | @import "~font-awesome/scss/stacked"; 15 | @import "~font-awesome/scss/icons"; 16 | @import "~font-awesome/scss/screen-reader"; 17 | -------------------------------------------------------------------------------- /src/components/About.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 55 | 56 | 66 | -------------------------------------------------------------------------------- /src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/errors/404.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 29 | 30 | -------------------------------------------------------------------------------- /src/http/interceptors.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | request: function (request) { 4 | return request 5 | }, 6 | 7 | response: function (response) { 8 | if ([400, 401].find(x => response.status === x)) { 9 | // 10 | } 11 | 12 | if (response.status === 500) { 13 | // 14 | } 15 | 16 | return response 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /src/http/middlewares.js: -------------------------------------------------------------------------------- 1 | module.exports = function (router) { 2 | router.beforeEach(function (transition) { 3 | if (transition.to.auth) { 4 | // 5 | } 6 | 7 | transition.next() 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /src/http/routes.js: -------------------------------------------------------------------------------- 1 | import NotFound from '../components/errors/404.vue' 2 | import Home from '../components/Home.vue' 3 | import About from '../components/About.vue' 4 | 5 | module.exports = { 6 | '/': { 7 | component: Home 8 | }, 9 | '/about': { 10 | component: About 11 | }, 12 | '*': { 13 | component: NotFound 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // Core dependencies 2 | import Vue from 'vue' 3 | import VueHead from 'vue-head' 4 | import VueRouter from 'vue-router' 5 | import VueResource from 'vue-resource' 6 | import { sync } from 'vuex-router-sync' 7 | 8 | // App components 9 | import App from './App' 10 | import store from './vuex/store' 11 | import routes from './http/routes' 12 | import middlewares from './http/middlewares' 13 | import interceptors from './http/interceptors' 14 | 15 | Vue.use(VueHead) 16 | Vue.use(VueRouter) 17 | Vue.use(VueResource) 18 | 19 | Vue.http.interceptors.concat(interceptors) 20 | 21 | var router = new VueRouter({ 22 | linkActiveClass: 'active' 23 | }) 24 | 25 | router.map(routes) 26 | 27 | middlewares(router) 28 | 29 | sync(store, router) 30 | 31 | router.start(App, 'app') 32 | -------------------------------------------------------------------------------- /src/vuex/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | 3 | export const navbarDefault = ({ dispatch, state }) => { 4 | dispatch(types.NAVBAR_DEFAULT) 5 | } 6 | 7 | export const navbarInverse = ({ dispatch, state }) => { 8 | dispatch(types.NAVBAR_INVERSE) 9 | } 10 | -------------------------------------------------------------------------------- /src/vuex/getters.js: -------------------------------------------------------------------------------- 1 | export const isNavbarInverse = state => state.navbar.inverse 2 | -------------------------------------------------------------------------------- /src/vuex/modules/navbar.js: -------------------------------------------------------------------------------- 1 | import { 2 | NAVBAR_DEFAULT, 3 | NAVBAR_INVERSE 4 | } from '../mutation-types' 5 | 6 | const localStorage = window.localStorage 7 | 8 | const state = { 9 | inverse: false 10 | } 11 | 12 | const mutations = { 13 | [NAVBAR_DEFAULT] (state) { 14 | state.inverse = false 15 | 16 | localStorage.setItem('navbar_inverse', state.inverse) 17 | }, 18 | 19 | [NAVBAR_INVERSE] (state) { 20 | state.inverse = true 21 | 22 | localStorage.setItem('navbar_inverse', state.inverse) 23 | } 24 | } 25 | 26 | export default { 27 | state, 28 | mutations 29 | } 30 | -------------------------------------------------------------------------------- /src/vuex/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const NAVBAR_DEFAULT = 'NAVBAR_DEFAULT' 2 | export const NAVBAR_INVERSE = 'NAVBAR_INVERSE' 3 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import navbar from './modules/navbar' 4 | 5 | Vue.use(Vuex) 6 | 7 | const debug = process.env.NODE_ENV !== 'production' 8 | 9 | export default new Vuex.Store({ 10 | modules: { 11 | navbar 12 | }, 13 | strict: debug 14 | }) 15 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fer-ri/vue-bootstrap/42a316d072e33f83c876c3ba9699586d1c8927a6/static/.gitkeep -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | 3 | // http://nightwatchjs.org/guide#settings-file 4 | module.exports = { 5 | "src_folders": ["test/e2e/specs"], 6 | "output_folder": "test/e2e/reports", 7 | "custom_assertions_path": ["test/e2e/custom-assertions"], 8 | 9 | "selenium": { 10 | "start_process": true, 11 | "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar", 12 | "host": "127.0.0.1", 13 | "port": 4444, 14 | "cli_args": { 15 | "webdriver.chrome.driver": require('chromedriver').path 16 | } 17 | }, 18 | 19 | "test_settings": { 20 | "default": { 21 | "selenium_port": 4444, 22 | "selenium_host": "localhost", 23 | "silent": true 24 | }, 25 | 26 | "chrome": { 27 | "desiredCapabilities": { 28 | "browserName": "chrome", 29 | "javascriptEnabled": true, 30 | "acceptSslCerts": true 31 | } 32 | }, 33 | 34 | "firefox": { 35 | "desiredCapabilities": { 36 | "browserName": "firefox", 37 | "javascriptEnabled": true, 38 | "acceptSslCerts": true 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2) 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']) 18 | } 19 | 20 | var spawn = require('cross-spawn') 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | browser 7 | .url('http://localhost:8080') 8 | .waitForElementVisible('#app', 5000) 9 | .assert.elementPresent('.logo') 10 | .assert.containsText('h1', 'Hello World!') 11 | .assert.elementCount('p', 3) 12 | .end() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | var testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src') 40 | }) 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit') 46 | return true 47 | } 48 | }) 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' } 72 | ] 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | template: '
', 8 | components: { Hello } 9 | }).$mount() 10 | expect(vm.$el.querySelector('.hello h1').textContent).to.contain('Hello World!') 11 | }) 12 | }) 13 | --------------------------------------------------------------------------------