Vue项目初始未集成E2E测试,如何后续添加?
Got it, let's break down how to properly add E2E testing to your existing Vue webpack project without hitting that frustrating webpack.optimize.ModuleConcatenationPlugin error you ran into.
为什么会出现这个错误?
The E2E test config you copied from a new project is almost certainly built for Webpack 3+, but your current project uses webpack@2.6.1. The ModuleConcatenationPlugin was experimental in Webpack 2 and had a different API than later stable versions—so dropping that config into your older setup causes the constructor error. Let's walk through two reliable fixes, plus a low-config alternative.
路径一:适配现有Webpack版本,添加Nightwatch E2E测试(Vue官方模板默认方案)
This is the most consistent approach for your existing setup, since it aligns with the Vue webpack template's original E2E tooling:
1. Install required dependencies
Run this to add Nightwatch and its supporting tools:
npm install --save-dev nightwatch chromedriver selenium-server
2. Set up the E2E directory structure
Create a test/e2e folder in your project root, then add these files:
nightwatch.conf.js(core test configuration)runner.js(script to launch tests)- A
specsfolder (to store your test cases, e.g.,test/e2e/specs/homepage.test.js)
Example nightwatch.conf.js (compatible with Webpack 2):
require('babel-register') var config = require('../../config') module.exports = { src_folders: ['test/e2e/specs'], output_folder: 'test/e2e/reports', custom_assertions_path: ['test/e2e/custom-assertions'], selenium: { start_process: true, server_path: require('selenium-server').path, host: '127.0.0.1', port: 4444, cli_args: { 'webdriver.chrome.driver': require('chromedriver').path } }, test_settings: { default: { selenium_port: 4444, selenium_host: 'localhost', silent: true, globals: { devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) } }, chrome: { desiredCapabilities: { browserName: 'chrome', javascriptEnabled: true, acceptSslCerts: true } } } }
Example runner.js:
var Nightwatch = require('nightwatch') var argv = process.argv.slice(2) try { Nightwatch.cli(argv) Nightwatch.runner(argv, function(err) { if (err) process.exit(1) process.exit(0) }) } catch (e) { console.error('An error occurred:', e.message) process.exit(2) }
3. Add npm scripts to package.json
Update your scripts section to include:
"e2e": "node test/e2e/runner.js", "e2e:chrome": "npm run e2e -- --env chrome"
4. Test it out
First start your dev server:
npm run dev
Then in a new terminal, run the E2E tests:
npm run e2e
路径二:Use Tarun Lalwani's Adaptation
If you don't want to rebuild the config from scratch, Tarun Lalwani's solution focuses on tweaking the copied E2E config to work with Webpack 2:
- Locate any references to
webpack.optimize.ModuleConcatenationPluginin the E2E webpack config files and comment/remove them - Ensure all other plugins in the config are compatible with Webpack 2's API
路径三:Use TestCafe (No Config Headache)
If you want to skip Webpack compatibility entirely, TestCafe is a fantastic low-config alternative for Vue E2E testing:
1. Install TestCafe
npm install --save-dev testcafe testcafe-vue-selectors
2. Write a test case
Create a tests/e2e folder and add a test file like homepage.test.js:
import { VueSelector } from 'testcafe-vue-selectors'; import { Selector } from 'testcafe'; fixture `Homepage Test` .page `http://localhost:8080`; test('Verify app loads correctly', async t => { await t.expect(VueSelector('app').exists).ok(); await t.expect(Selector('title').innerText).eql('premium-poker-tools'); });
3. Add an npm script
Update your package.json scripts:
"testcafe": "testcafe chrome tests/e2e/"
4. Run the tests
Start your dev server, then run:
npm run testcafe
Your Current package.json Reference
{ "name": "premium-poker-tools", "version": "1.0.0", "description": "A Vue.js project", "author": "Adam Zerner <azerner3@gmail.com>", "private": true, "scripts": { "dev": "node build/dev-server.js", "start": "node build/dev-server.js", "build": "node build/build.js", "test": "BABEL_ENV=test karma start test/unit/karma.conf.js", "deploy": "git subtree push --prefix dist heroku master" }, "dependencies": { "bootstrap": "^3.3.7", "bootstrap-sass": "^3.3.7", "chart.js": "^2.5.0", "express-sslify": "^1.2.0", "jquery": "^3.2.1", "lodash": "^4.17.4", "vue": "^2.4.2", "vue-analytics": "^5.1.1", "vue-chartjs": "^2.8.7", "vue-router": "^2.7.0", "vue-slider-component": "^2.5.8", "vuex": "^3.0.0" }, "devDependencies": { "autoprefixer": "^7.1.2", "babel-core": "^6.22.1", "babel-loader": "^7.1.1", "babel-plugin-istanbul": "^4.1.1", "babel-plugin-transform-runtime": "^6.22.0", "babel-polyfill": "^6.26.0", "babel-preset-env": "^1.3.2", "babel-preset-stage-2": "^6.22.0", "babel-register": "^6.22.0", "chai": "^3.5.0", "chalk": "^2.0.1", "connect-history-api-fallback": "^1.3.0", "copy-webpack-plugin": "^4.0.1", "cross-env": "^5.0.1", "css-loader": "^0.28.0", "cssnano": "^3.10.0", "eventsource-polyfill": "^0.9.6", "express": "^4.14.1", "extract-text-webpack-plugin": "^2.0.0", "file-loader": "^0.11.1", "friendly-errors-webpack-plugin": "^1.1.3", "html-webpack-plugin": "^2.28.0", "http-proxy-middleware": "^0.17.3", "inject-loader": "^3.0.0", "karma": "^1.4.1", "karma-coverage": "^1.1.1", "karma-mocha": "^1.3.0", "karma-phantomjs-launcher": "^1.0.2", "karma-phantomjs-shim": "^1.4.0", "karma-sinon-chai": "^1.3.1", "karma-sourcemap-loader": "^0.3.7", "karma-spec-reporter": "0.0.31", "karma-webpack": "^2.0.2", "mocha": "^3.2.0", "node-sass": "^4.5.3", "opn": "^5.1.0", "optimize-css-assets-webpack-plugin": "^2.0.0", "ora": "^1.2.0", "phantomjs-prebuilt": "^2.1.14", "rimraf": "^2.6.0", "sass-loader": "^6.0.6", "semver": "^5.3.0", "shelljs": "^0.7.6", "sinon": "^2.1.0", "sinon-chai": "^2.8.0", "url-loader": "^0.5.8", "vue-loader": "^13.0.4", "vue-style-loader": "^3.0.1", "vue-template-compiler": "^2.4.2", "webpack": "^2.6.1", "webpack-bundle-analyzer": "^2.2.1", "webpack-dev-middleware": "^1.10.0", "webpack-hot-middleware": "^2.18.0", "webpack-merge": "^4.1.0", "worker-loader": "^1.1.1" }, "engines": { "node": ">= 4.0.0", "npm": ">= 3.0.0" }, "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ] }
内容的提问来源于stack exchange,提问作者Adam Zerner

