2019.08.19 修正文章中的错误
除了单元测试之外,前端还有一个额外的测试:e2e测试,也就是端到端测试,用来模拟用户操作。对于Vue来说,推荐的e2e测试框架有nightwatch和cypress,因为cypress只支持Chrome,而且尤大之前用的是nightwatch,所以我也选择了nightwatch。
vue-cli对nightwatch的整合可以说很完善了,基本上只需要一条命令就能完成安装和配置,然后就可以开始写测试了:
vue add @vue/e2e-nightwatch
之所以说基本上只需要一条命令,因为nightwatch基于java,需要先安装和配置Java。
本来一切都很美好,但是前段时间Chrome自动更新到了76版本,然后就出了问题。用vue-cli新建一个项目,新建的项目居然过不了测试!报错如下:
Error retrieving a new session from the selenium server
Connection refused! Is selenium server started?
{ value:
{ message:
'Unable to create new service: ChromeDriverService\nBuild info: version: \'3.141.59\', revision: \'e82be7d358\', time: \'2018-11-14T08:25:53\'\nSystem info: host: \'wensun\', ip:
\'192.168.199.1\', os.name: \'Windows 10\', os.arch: \'amd64\', os.version: \'10.0\', java.version: \'1.8.0_211\'\nDriver info: driver.version: unknown',
error: 'session not created' },
status: 33 }
这就很神秘了。网上转一圈,看到说是chromedriver版本过低,也就是测试需要的驱动掉链子了。因为从报错信息里可以看到,selenium无法识别驱动的版本,显示为unknown。那就装一个新版本的驱动:
npm install --save-dev chromedriver
但是连这个都报错了:
npm ERR! The operation was rejected by your operating system.
npm ERR! It's possible that the file was already in use (by a text editor or antivirus),
npm ERR! or that you lack permissions to access it.
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.
我:???
打开Windows的命令行,看看是不是chromedriver没有完全退出:
> tasklist|findstr chromedriver
chromedriver.exe 9980 Console 1 14,752 K
chromedriver.exe 15464 Console 1 14,672 K
> taskkill -pid 9980 -pid 15464 -f
成功: 已终止 PID 为 9980 的进程。
成功: 已终止 PID 为 15464 的进程。
首先吐槽Windows的命令行是真的难用。其次,chromedriver在后台居然有多个进程。我一开始以为是主从进程,或者是主进程和守护进程,后来才发现,运行几次测试,后台就会有几个进程……这个是真的不能理解。
解决完这个问题,再运行一次npm install --save-dev chromedriver
,这次安装上了。重新运行测试,这次还是一样的报错:
Error retrieving a new session from the selenium server
Connection refused! Is selenium server started?
{ value:
{ message:
'Unable to create new service: ChromeDriverService\nBuild info: version: \'3.141.59\', revision: \'e82be7d358\', time: \'2018-11-14T08:25:53\'\nSystem info: host: \'wensun\', ip:
\'192.168.199.1\', os.name: \'Windows 10\', os.arch: \'amd64\', os.version: \'10.0\', java.version: \'1.8.0_211\'\nDriver info: driver.version: unknown',
error: 'session not created' },
status: 33 }
仔细观察之后发现,selenium的版本是3.141.59。查看文档后发现,这个版本只支持Chrome 71-75。事实上,在这里还有可能遇到``session not created: Chrome version must be between 71 and 75`的报错。
首先想到的解决方案肯定是回退Chrome版本,退到75版本,但回退很麻烦,而且总不能因为这个一直用旧版本浏览器,也不符合正常用户的使用习惯。肯定有什么解决方案。
去vue-cli的issue里查询,发现了这么一条:
oh you may have to use
@vue/cli-plugin-e2e-nightwatch
v4.0.0-beta.0…
It was a breaking change to update thechromedriver
dependency so it’s only landed in v4… I totally forgot that.
……vue-cli默认安装的是3.10.0的稳定版本,但如果想支持新版本的chromedriver,必须要升级到4.x的测试版。在写这篇文章的时候,我安装的版本是4.0.0-beta.3:
"devDependencies": {
"@vue/cli-plugin-e2e-nightwatch": "^4.0.0-beta.3"
}
到了这里终于能跑了。如果还不能跑,报错Cannot find module 'chromedriver'
,首先试试删掉node_modules之后重新npm install
。
然而,好景不长,跑虽然能跑了,但是开始疯狂报错:
Error while running .isElementDisplayed() protocol action: TypeError [ERR_UNESCAPED_CHARACTERS]: Error while trying to create HTTP request for "/wd/hub/session/ff75c2c3ab2a905187aa80
193cfde80d/element/[object Object]/displayed": Request path contains unescaped characters
............
_________________________________________________
TEST FAILURE: 1 error during execution 0 tests failed, 1 passed. 10.254s
× test
– default e2e tests (5.632s)
中间的报错信息因为太长就省略了。也就是说,现在的问题是,测试能跑但跑不对。这里的不对不是说代码写错了,而是指测试本身出现了问题。后来查阅nightwatch的release note,发现了端倪:
- Fixed #2118 - Set default POST body to be empty JSON in order to use chromedriver 75
If using Chromedriver 75 you need to set the following capabilities in your config:desiredCapabilities : { browserName : 'chrome', chromeOptions: { w3c: false } }
Chromedriver 75 has W3C Webdriver protocol enabled by default, however we recommend sticking to the JSONWire for now as some endpoints aren’t implemented yet (e.g.
/displayed
). If using the default w3c webdriver mode, make sure to adjust the config like so:{ capabilities: { browserName : 'chrome' }, webdriver: { use_legacy_jsonwire: false } }
原来,从Chrome75版本开始,就默认使用了W3C的webdriver协议,但nightwatch用的是JSONWP,和W3C不兼容,所以如果想要正常使用,必须关闭W3C的协议。也就是说,可以在测试文件里加上这么一段:
module.exports = {
desiredCapabilities: {
browserName: "chrome",
chromeOptions: {
w3c: false
}
}
}
虽然release note里提到了另一种写法,但亲测不可用……可能是vue-cli内部有别的配置导致的不可用。最后的测试文件应该长这样:
// tests/e2e/specs/test.js
module.exports = {
desiredCapabilities: {
browserName: "chrome",
chromeOptions: {
w3c: false
}
},
'default e2e tests': browser => {
browser
.url(process.env.VUE_DEV_SERVER_URL)
.waitForElementVisible('#app', 5000)
.assert.elementPresent('.hello')
.assert.containsText('h1', 'Welcome to Your Vue.js App')
.assert.elementCount('img', 1)
.end();
}
};
如果还是不清楚……可以看看示例项目:chrome76-e2e-test-conf-example的stage1分支。
一切正常。兴冲冲地加进travis(具体怎么配置travis就不谈了,不然就跑题了;而且网上也有很多相关的资料),然后就报错了:
Error: Timeout while trying to connect to Selenium Server on port 4444.
at Socket.socketErrorListener (_http_client.js:392:9)
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
为什么会这样?在Windows下明明是好好的。
此外还有一个问题,这些配置是针对单个测试文件的,我们总不能每次新建一个测试文件就重复一次上面的操作,或者直接把所有的测试写在一个文件里,这个问题也是需要解决的。
这些问题让我陷入了沉思。
Vue + nightwatch + Chrome76进行e2e测试的正确配置(二)