在开发react应用或者其他web应用时,我们经常要进行单元测试。jest是facebook开发的单元测试框架,但是他的测试结果通常是在终端或者cmd里面显示,其形式不够美观,而且无法一目了然的看到测试结果。
jest如何存储测试结果
经过一番调查,jest.config中有这么一项,根据官网的说法:
testResultsProcessor [string]
默认值:undefined
This option allows the use of a custom results processor. This processor must be a node module that
exports a function expecting an object with the following structure as the first argument and return it:
复制代码
意思就是,这个属性可以允许结果处理程序使用。这个处理器必须是一个输出函数的node模块,这个函数的第一个参数会接收测试结果,且必须在最终返回测试结果。
jest配置:
//jest.config.js
module.exports={
testResultsProcessor:'./testResult'
}
复制代码
//testResult/index.js
function test(result) {
console.log(result)
return result
}
module.exports = test
复制代码
你会在命令行上看到打印出一个庞大的对象,这个对象就是处理结果。
注:要想看到,你首先要安装jest,并且需要运行test测试,该函数才会调用
如何把该对象发送到浏览器
现在,该对象所在的位置实际上是在node环境中,也就是说,在后台。那么浏览器如何得到呢?答案当然是:发请求!
我们对test()
结果处理器进行扩充,让它在本地启动一个node服务器(练习node的好机会!):
//testResult/index.js
var http = require("http");
var url = require("url");
var path = require("path");
var fs = require('fs')
var {exec}=require('child_process')
var server = new http.Server();
function test(result) {
console.log(result.testResults[0].testResults);
server.on('request', function (req, res) {
console.log(req.method);
var urlObj = url.parse(req.url);
var urlPathname = urlObj.pathname;
if (urlPathname === "/") {
console.log(urlPathname);
var urlPathname = urlObj.pathname;
var filePathname = path.join(__dirname, './result.html', urlPathname)
fs.readFile(filePathname, (err, data) => { //读取文件响应
if (err) {
res.writeHead(404, {
"Context-type": "text/plain"
});
res.write('404');
res.end();
} else {
res.writeHead(200, {
"Context-type": "text/plain"
});
res.write(data); //返回数据
res.end();
}
})
} else {
res.writeHead(200, { 'Content-Type': 'aplication/json' })
res.end(JSON.stringify(result))//发送数据给浏览器
}
})
server.listen(4000, function () {
console.log("运行在:http://localhost:4000");
})
return result
}
module.exports = test
复制代码
你只需要一点node知识就可以搭建一个简易的服务器!
- 第一步:实例化server
var server = new http.Server();
- 第二步:给server添加request请求事件
server.on('request',(req,res)=>{})
- 第三步:绑定端口,
server.listen(4000, ()=>{})
此时一个简易的服务器就建好啦!只需要对req的url稍加判断就可以完成我们的想要的功能:
- 请求路径为
'/'
,就是打http://localhost:4000
时,我们返回一个html文件; - 请求路径为其他时,比如
fetch(http://localhost:4000/index.js)
,我们就要返回jset测试结果。
返回的html文件可以随便写:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
</head>
<body>
<script>
fetch("http://localhost:4000/index.js", {
headers: {
'content-type': 'application/json'
},
}).then(res => {
console.log(res);
return res.json()
}).then((data) => {
console.log(data);
})
</script>
</body>
</html>
复制代码
初次尝试
大胆的尝试一次npm test
,打开http://localhost:4000
,打开控制台,哇偶,我们已经拿到了!
{
failureMessage:
'\u001b[1m\u001b[31m \u001b[1m● \u001b[1madds 1 + 2 \u001b[39m\u001b[22m\n\n......'
}
复制代码
字符串的魔法艺术
两个结果中有一个字段一定吸引了你的注意,没错就是failureMessage
,前后端的打印,都呈现出令人困惑的形式,熟悉的人,一眼就能看出来这是ansi
码(作者查了好久,泪奔)。这样的信息,在命令行里打印出的字符串会有特效奥!不仅会呈现出多种色彩,还能出现各种人性化的特效,比如,npm install
时的进度条效果。 回到主题上来,前端的html是无法识别的(至少在作者眼中),况且在传递数据的是,完整的ansi字符还出现了缺失,这就很难受了啊!
谷歌搜索,github搜索快进中······
控制台字符样式:chalk,可以给控制台添加多彩的样式。它的依赖中有这一模块:strip-ansi,用以将字符串中ansi字符去掉。 我们在发送数据之前,对该字段的数据处理一下即可:
//testResult/result.js
const stripAnsi = require('strip-ansi');
const typeOf = (obj) => {
return Object.prototype.toString.call(obj)
}
const deal = (obj) => {
let copy;
if (typeOf(obj) === '[object Object]') {
copy = {}
for (let key in obj) {
copy[key] = deal(obj[key]);
}
} else if (typeOf(obj) === '[object Function]') {
copy = obj.bind();
} else if (typeOf(obj) === '[object Array]') {
copy = obj.map((item) => {
return deal(item);
})
} else if (typeof obj === "string") {
copy = stripAnsi(obj);
} else {
copy = obj
}
return copy
}
module.exports = deal
复制代码
//testResult/index.js
var deal=require('./result')
···
res.end(JSON.stringify(deal(result)))
···
复制代码
最终展示
我们最后再处理一下html,让结果呈现出来,简单使用了vue:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Page Title</title>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
</head>
<body>
<style>
.code {display: block;padding: 0.5em;font-size: 12px; margin-top: 0.5em;margin-bottom: 0.5em; overflow-x: auto; white-space: pre-wrap; border-radius: 0.25rem; background-color: rgba(206, 17, 38, 0.05);}
</style>
<div id="app">
<div v-for="(item,index) in testResults">
<h3>{{item.testFilePath}}</h3>
<pre class="code">
<code style=" font-family: Consolas, Menlo, monospace;" v-for="(minitem,minindex) in item.testResults">
{{item.failureMessage?item.failureMessage:minitem.status}}
</code>
</pre>
</div>
</div>
<script>
fetch("http://localhost:4000/index.js", {
headers: {
'content-type': 'application/json'
},
}).then(res => {
console.log(res);
return res.json()
}).then((data) => {
console.log(data);
render(data)
})
function render(data) {
var vm = new Vue({
el: "#app",
data: data,
mounted() {
this.testResults.forEach(item => {
item.testResults.forEach((item)=>{
item.failureMessages.forEach((err)=>{
throw err
})
})
});
},
})
}
</script>
</body>
</html>
复制代码
页面展示:
优缺点
本例只是简单的探索与实现,相信社区肯定有相关的架子,但是实现的过程,是最有趣的。
优点:可以在页面看到更直观的测试结果,
缺点:
- 每次重新测试要手动刷新页面,
- 错误显示还不够美观,
希望能给大家一些启发和新想法。仓库地址:github