├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── build ├── build.js ├── css-loaders.js ├── dev-client.js ├── dev-server.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── index.html ├── package.json ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ └── Hello.vue └── main.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 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 4 | extends: 'standard', 5 | // required to lint *.vue files 6 | plugins: [ 7 | 'html' 8 | ], 9 | // add your custom rules here 10 | 'rules': { 11 | // allow paren-less arrow functions 12 | 'arrow-parens': 0, 13 | // allow debugger during development 14 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # prerender-spa-plugin-vue-demo 2 | 3 | > A Vue.js project 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](https://github.com/vuejs-templates/webpack#vue-webpack-boilerplate) 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 ora = require('ora') 6 | var webpack = require('webpack') 7 | var conf = require('./webpack.prod.conf') 8 | 9 | var spinner = ora('building for production...') 10 | spinner.start() 11 | 12 | rm('-rf', 'dist') 13 | mkdir('dist') 14 | cp('-R', 'static', conf.output.path) 15 | 16 | webpack(conf, function (err, stats) { 17 | spinner.stop() 18 | if (err) throw err 19 | process.stdout.write(stats.toString({ 20 | colors: true, 21 | modules: false, 22 | children: false, 23 | chunks: false, 24 | chunkModules: false 25 | }) + '\n') 26 | }) 27 | -------------------------------------------------------------------------------- /build/css-loaders.js: -------------------------------------------------------------------------------- 1 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 2 | 3 | module.exports = function (options) { 4 | options = options || {} 5 | // generate loader string to be used with extract text plugin 6 | function generateLoaders (loaders) { 7 | var sourceLoader = loaders.map(function (loader) { 8 | var extraParamChar 9 | if (/\?/.test(loader)) { 10 | loader = loader.replace(/\?/, '-loader?') 11 | extraParamChar = '&' 12 | } else { 13 | loader = loader + '-loader' 14 | extraParamChar = '?' 15 | } 16 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 17 | }).join('!') 18 | 19 | if (options.extract) { 20 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 21 | } else { 22 | return ['vue-style-loader', sourceLoader].join('!') 23 | } 24 | } 25 | 26 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 27 | return { 28 | css: generateLoaders(['css']), 29 | less: generateLoaders(['css', 'less']), 30 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 31 | scss: generateLoaders(['css', 'sass']), 32 | stylus: generateLoaders(['css', 'stylus']), 33 | styl: generateLoaders(['css', 'stylus']) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | require('eventsource-polyfill') 2 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 3 | 4 | hotClient.subscribe(function (event) { 5 | if (event.action === 'reload') { 6 | window.location.reload() 7 | } 8 | }) 9 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var webpack = require('webpack') 3 | var config = require('./webpack.dev.conf') 4 | var proxyMiddleware = require('http-proxy-middleware') 5 | 6 | var app = express() 7 | var compiler = webpack(config) 8 | 9 | // Define HTTP proxies to your custom API backend 10 | // https://github.com/chimurai/http-proxy-middleware 11 | var proxyTable = { 12 | // '/api': { 13 | // target: 'http://jsonplaceholder.typicode.com', 14 | // changeOrigin: true, 15 | // pathRewrite: { 16 | // '^/api': '' 17 | // } 18 | // } 19 | } 20 | 21 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 22 | publicPath: config.output.publicPath, 23 | stats: { 24 | colors: true, 25 | chunks: false 26 | } 27 | }) 28 | 29 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 30 | // force page reload when html-webpack-plugin template changes 31 | compiler.plugin('compilation', function (compilation) { 32 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 33 | hotMiddleware.publish({ action: 'reload' }) 34 | cb() 35 | }) 36 | }) 37 | 38 | // proxy api requests 39 | Object.keys(proxyTable).forEach(function (context) { 40 | var options = proxyTable[context] 41 | if (typeof options === 'string') { 42 | options = { target: options } 43 | } 44 | app.use(proxyMiddleware(context, options)) 45 | }) 46 | 47 | // handle fallback for HTML5 history API 48 | app.use(require('connect-history-api-fallback')()) 49 | 50 | // serve webpack bundle output 51 | app.use(devMiddleware) 52 | 53 | // enable hot-reload and state-preserving 54 | // compilation error display 55 | app.use(hotMiddleware) 56 | 57 | // serve pure static assets 58 | app.use('/static', express.static('./static')) 59 | 60 | module.exports = app.listen(8080, function (err) { 61 | if (err) { 62 | console.log(err) 63 | return 64 | } 65 | console.log('Listening at http://localhost:8080\n') 66 | }) 67 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var cssLoaders = require('./css-loaders') 3 | var projectRoot = path.resolve(__dirname, '../') 4 | 5 | module.exports = { 6 | entry: { 7 | app: './src/main.js' 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, '../dist/static'), 11 | publicPath: './static/', 12 | filename: '[name].js' 13 | }, 14 | resolve: { 15 | extensions: ['', '.js', '.vue'], 16 | fallback: [path.join(__dirname, '../node_modules')], 17 | alias: { 18 | 'src': path.resolve(__dirname, '../src') 19 | } 20 | }, 21 | resolveLoader: { 22 | fallback: [path.join(__dirname, '../node_modules')] 23 | }, 24 | module: { 25 | preLoaders: [ 26 | { 27 | test: /\.vue$/, 28 | loader: 'eslint', 29 | include: projectRoot, 30 | exclude: /node_modules/ 31 | }, 32 | { 33 | test: /\.js$/, 34 | loader: 'eslint', 35 | include: projectRoot, 36 | exclude: /node_modules/ 37 | } 38 | ], 39 | loaders: [ 40 | { 41 | test: /\.vue$/, 42 | loader: 'vue' 43 | }, 44 | { 45 | test: /\.js$/, 46 | loader: 'babel', 47 | include: projectRoot, 48 | exclude: /node_modules/ 49 | }, 50 | { 51 | test: /\.json$/, 52 | loader: 'json' 53 | }, 54 | { 55 | test: /\.html$/, 56 | loader: 'vue-html' 57 | }, 58 | { 59 | test: /\.(png|jpg|gif|svg|woff2?|eot|ttf)(\?.*)?$/, 60 | loader: 'url', 61 | query: { 62 | limit: 10000, 63 | name: '[name].[ext]?[hash:7]' 64 | } 65 | } 66 | ] 67 | }, 68 | vue: { 69 | loaders: cssLoaders() 70 | }, 71 | eslint: { 72 | formatter: require('eslint-friendly-formatter') 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var merge = require('webpack-merge') 3 | var baseConfig = require('./webpack.base.conf') 4 | var HtmlWebpackPlugin = require('html-webpack-plugin') 5 | 6 | // add hot-reload related code to entry chunks 7 | Object.keys(baseConfig.entry).forEach(function (name) { 8 | baseConfig.entry[name] = ['./build/dev-client'].concat(baseConfig.entry[name]) 9 | }) 10 | 11 | module.exports = merge(baseConfig, { 12 | // eval-source-map is faster for development 13 | devtool: '#eval-source-map', 14 | output: { 15 | // necessary for the html plugin to work properly 16 | // when serving the html from in-memory 17 | publicPath: '/' 18 | }, 19 | plugins: [ 20 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 21 | new webpack.optimize.OccurenceOrderPlugin(), 22 | new webpack.HotModuleReplacementPlugin(), 23 | new webpack.NoErrorsPlugin(), 24 | // https://github.com/ampedandwired/html-webpack-plugin 25 | new HtmlWebpackPlugin({ 26 | filename: 'index.html', 27 | template: 'index.html', 28 | inject: true 29 | }) 30 | ] 31 | }) 32 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var merge = require('webpack-merge') 3 | var baseConfig = require('./webpack.base.conf') 4 | var cssLoaders = require('./css-loaders') 5 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var Path = require('path') 8 | var PrerenderSpaPlugin = require('prerender-spa-plugin') 9 | 10 | // whether to generate source map for production files. 11 | // disabling this can speed up the build. 12 | var SOURCE_MAP = true 13 | 14 | module.exports = merge(baseConfig, { 15 | devtool: SOURCE_MAP ? '#source-map' : false, 16 | output: { 17 | // naming output files with hashes for better caching. 18 | // dist/index.html will be auto-generated with correct URLs. 19 | filename: '[name].[chunkhash].js', 20 | chunkFilename: '[id].[chunkhash].js' 21 | }, 22 | vue: { 23 | loaders: cssLoaders({ 24 | sourceMap: SOURCE_MAP, 25 | extract: true 26 | }) 27 | }, 28 | plugins: [ 29 | // http://vuejs.github.io/vue-loader/workflow/production.html 30 | new webpack.DefinePlugin({ 31 | 'process.env': { 32 | NODE_ENV: '"production"' 33 | } 34 | }), 35 | new webpack.optimize.UglifyJsPlugin({ 36 | compress: { 37 | warnings: false 38 | } 39 | }), 40 | new webpack.optimize.OccurenceOrderPlugin(), 41 | // extract css into its own file 42 | new ExtractTextPlugin('[name].[contenthash].css'), 43 | // generate dist index.html with correct asset hash for caching. 44 | // you can customize output by editing /index.html 45 | // see https://github.com/ampedandwired/html-webpack-plugin 46 | new HtmlWebpackPlugin({ 47 | filename: '../index.html', 48 | template: 'index.html', 49 | inject: true, 50 | minify: { 51 | removeComments: true, 52 | collapseWhitespace: true, 53 | removeAttributeQuotes: true 54 | // more options: 55 | // https://github.com/kangax/html-minifier#options-quick-reference 56 | } 57 | }), 58 | 59 | new PrerenderSpaPlugin( 60 | Path.join(__dirname, '../dist'), 61 | [ '/' ] 62 | ) 63 | ] 64 | }) 65 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | prerender-spa-plugin-vue-demo 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prerender-spa-plugin-vue-demo", 3 | "version": "0.1.0", 4 | "description": "A Vue.js project", 5 | "author": "Chris Fritz ", 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 | }, 14 | "dependencies": { 15 | "vue": "^1.0.18", 16 | "babel-runtime": "^5.8.0" 17 | }, 18 | "devDependencies": { 19 | "babel-core": "^6.0.0", 20 | "babel-loader": "^6.0.0", 21 | "babel-plugin-transform-runtime": "^6.0.0", 22 | "babel-preset-es2015": "^6.0.0", 23 | "babel-preset-stage-2": "^6.0.0", 24 | "chromedriver": "^2.21.2", 25 | "connect-history-api-fallback": "^1.1.0", 26 | "cross-spawn": "^2.1.5", 27 | "css-loader": "^0.23.0", 28 | "eslint": "^2.0.0", 29 | "eslint-config-standard": "^5.1.0", 30 | "eslint-friendly-formatter": "^1.2.2", 31 | "eslint-loader": "^1.3.0", 32 | "eslint-plugin-html": "^1.3.0", 33 | "eslint-plugin-promise": "^1.0.8", 34 | "eslint-plugin-standard": "^1.3.2", 35 | "eventsource-polyfill": "^0.9.6", 36 | "express": "^4.13.3", 37 | "extract-text-webpack-plugin": "^1.0.1", 38 | "file-loader": "^0.8.4", 39 | "function-bind": "^1.0.2", 40 | "html-webpack-plugin": "^2.8.1", 41 | "http-proxy-middleware": "^0.12.0", 42 | "inject-loader": "^2.0.1", 43 | "isparta-loader": "^2.0.0", 44 | "jasmine-core": "^2.4.1", 45 | "json-loader": "^0.5.4", 46 | "karma": "^0.13.15", 47 | "karma-coverage": "^0.5.5", 48 | "karma-jasmine": "^0.3.6", 49 | "karma-phantomjs-launcher": "^1.0.0", 50 | "karma-sourcemap-loader": "^0.3.7", 51 | "karma-spec-reporter": "0.0.24", 52 | "karma-webpack": "^1.7.0", 53 | "nightwatch": "^0.8.18", 54 | "ora": "^0.2.0", 55 | "phantomjs-prebuilt": "^2.1.3", 56 | "prerender-spa-plugin": "git://github.com/chrisvfritz/prerender-spa-plugin.git", 57 | "selenium-server": "2.53.0", 58 | "shelljs": "^0.6.0", 59 | "url-loader": "^0.5.7", 60 | "vue-hot-reload-api": "^1.2.0", 61 | "vue-html-loader": "^1.0.0", 62 | "vue-loader": "^8.2.1", 63 | "vue-style-loader": "^1.0.0", 64 | "webpack": "^1.12.2", 65 | "webpack-dev-middleware": "^1.4.0", 66 | "webpack-hot-middleware": "^2.6.0", 67 | "webpack-merge": "^0.8.3" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 43 | 44 | 68 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisvfritz/prerender-spa-plugin-vue-demo/077a49a97ca6a622933ca50d7b7dcdccd89044e4/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | /* eslint-disable no-new */ 5 | new Vue({ 6 | el: '#app', 7 | replace: false, 8 | ...App 9 | }) 10 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisvfritz/prerender-spa-plugin-vue-demo/077a49a97ca6a622933ca50d7b7dcdccd89044e4/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 | // http://nightwatchjs.org/guide#settings-file 2 | module.exports = { 3 | "src_folders": ["test/e2e/specs"], 4 | "output_folder": "test/e2e/reports", 5 | "custom_assertions_path": ["test/e2e/custom-assertions"], 6 | 7 | "selenium": { 8 | "start_process": true, 9 | "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar", 10 | "host": "127.0.0.1", 11 | "port": 4444, 12 | "cli_args": { 13 | "webdriver.chrome.driver": require('chromedriver').path 14 | } 15 | }, 16 | 17 | "test_settings": { 18 | "default": { 19 | "selenium_port": 4444, 20 | "selenium_host": "localhost", 21 | "silent": true 22 | }, 23 | 24 | "chrome": { 25 | "desiredCapabilities": { 26 | "browserName": "chrome", 27 | "javascriptEnabled": true, 28 | "acceptSslCerts": true 29 | } 30 | }, 31 | 32 | "firefox": { 33 | "desiredCapabilities": { 34 | "browserName": "firefox", 35 | "javascriptEnabled": true, 36 | "acceptSslCerts": true 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server 2 | var server = require('../../build/dev-server.js') 3 | 4 | // 2. run the nightwatch test suite against it 5 | // to run in additional browsers: 6 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 7 | // 2. add it to the --env flag below 8 | // For more information on Nightwatch's config file, see 9 | // http://nightwatchjs.org/guide#settings-file 10 | var spawn = require('cross-spawn') 11 | var runner = spawn( 12 | './node_modules/.bin/nightwatch', 13 | [ 14 | '--config', 'test/e2e/nightwatch.conf.js', 15 | '--env', 'chrome,firefox' 16 | ], 17 | { 18 | stdio: 'inherit' 19 | } 20 | ) 21 | 22 | runner.on('exit', function (code) { 23 | server.close() 24 | process.exit(code) 25 | }) 26 | 27 | runner.on('error', function (err) { 28 | server.close() 29 | throw err 30 | }) 31 | -------------------------------------------------------------------------------- /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 | "jasmine": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /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 projectRoot = path.resolve(__dirname, '../../') 10 | 11 | var webpackConfig = merge(baseConfig, { 12 | // use inline sourcemap for karma-sourcemap-loader 13 | devtool: '#inline-source-map', 14 | vue: { 15 | loaders: { 16 | js: 'isparta' 17 | } 18 | } 19 | }) 20 | 21 | // no need for app entry during tests 22 | delete webpackConfig.entry 23 | 24 | // make sure isparta loader is applied before eslint 25 | webpackConfig.module.preLoaders.unshift({ 26 | test: /\.js$/, 27 | loader: 'isparta', 28 | include: projectRoot, 29 | exclude: /test\/unit|node_modules/ 30 | }) 31 | 32 | // only apply babel for test files when using isparta 33 | webpackConfig.module.loaders.some(function (loader, i) { 34 | if (loader.loader === 'babel') { 35 | loader.include = /test\/unit/ 36 | return true 37 | } 38 | }) 39 | 40 | module.exports = function (config) { 41 | config.set({ 42 | // to run in additional browsers: 43 | // 1. install corresponding karma launcher 44 | // http://karma-runner.github.io/0.13/config/browsers.html 45 | // 2. add it to the `browsers` array below. 46 | browsers: ['PhantomJS'], 47 | frameworks: ['jasmine'], 48 | reporters: ['spec', 'coverage'], 49 | files: ['./index.js'], 50 | preprocessors: { 51 | './index.js': ['webpack', 'sourcemap'] 52 | }, 53 | webpack: webpackConfig, 54 | webpackMiddleware: { 55 | noInfo: true 56 | }, 57 | coverageReporter: { 58 | dir: './coverage', 59 | reporters: [ 60 | { type: 'lcov', subdir: '.' }, 61 | { type: 'text-summary' } 62 | ] 63 | } 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /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).toBe('Hello World!') 11 | }) 12 | }) 13 | 14 | // also see example testing a component with mocks at 15 | // https://github.com/vuejs/vue-loader-example/blob/master/test/unit/a.spec.js#L24-L49 16 | --------------------------------------------------------------------------------