Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
x649585723
incubator-echarts
提交
ea440f6b
I
incubator-echarts
项目概览
x649585723
/
incubator-echarts
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
I
incubator-echarts
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ea440f6b
编写于
8月 29, 2019
作者:
P
pissang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
test: Improve visual regression test UI
上级
b6c67196
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
287 addition
and
47 deletion
+287
-47
test/runTest/blacklist.js
test/runTest/blacklist.js
+2
-2
test/runTest/cli.js
test/runTest/cli.js
+41
-18
test/runTest/client/client.css
test/runTest/client/client.css
+101
-6
test/runTest/client/client.js
test/runTest/client/client.js
+92
-10
test/runTest/client/index.html
test/runTest/client/index.html
+51
-11
未找到文件。
test/runTest/blacklist.js
浏览文件 @
ea440f6b
module
.
exports
=
[
'
-cases.html
'
,
'
geo-random-stream.html
'
'
-cases.html
'
,
'
geo-random-stream.html
'
];
\ No newline at end of file
test/runTest/cli.js
浏览文件 @
ea440f6b
...
...
@@ -140,7 +140,6 @@ async function takeScreenshot(page, elementQuery, fileUrl, desc, version) {
}
async
function
runTestPage
(
browser
,
fileUrl
,
version
)
{
const
{
keepWait
,
waitTimeout
}
=
createWaitTimeout
(
3200
);
const
testResults
=
[];
let
screenshotPromises
=
[];
...
...
@@ -176,10 +175,16 @@ async function runTestPage(browser, fileUrl, version) {
let
pageFinishPromise
=
waitPageForFinish
(
page
);
await
page
.
goto
(
`
${
origin
}
/test/
${
fileUrl
}
`
,
{
waitUntil
:
'
networkidle2
'
,
timeout
:
10000
});
try
{
await
page
.
goto
(
`
${
origin
}
/test/
${
fileUrl
}
`
,
{
waitUntil
:
'
networkidle2
'
,
timeout
:
10000
});
}
catch
(
e
)
{
// TODO Timeout Error
console
.
error
(
e
);
}
// Do auto screenshot for every 1 second.
let
count
=
1
;
...
...
@@ -213,6 +218,7 @@ async function runTestPage(browser, fileUrl, version) {
}
async
function
runTest
(
browser
,
testOpt
)
{
testOpt
.
status
===
'
running
'
;
const
fileUrl
=
testOpt
.
fileUrl
;
const
expectedShots
=
await
runTestPage
(
browser
,
fileUrl
,
'
4.2.1
'
);
const
actualShots
=
await
runTestPage
(
browser
,
fileUrl
);
...
...
@@ -238,6 +244,7 @@ async function runTest(browser, testOpt) {
expected
:
getClientRelativePath
(
expected
.
screenshotPath
),
diff
:
getClientRelativePath
(
diffPath
),
name
:
actual
.
testName
,
desc
:
actual
.
desc
,
diffRatio
});
});
...
...
@@ -292,21 +299,37 @@ async function start() {
io
.
on
(
'
connect
'
,
socket
=>
{
broadcast
({
tests
});
// TODO Stop previous?
socket
.
on
(
'
run
'
,
async
testsNameList
=>
{
console
.
log
(
testsNameList
);
const
pendingTests
=
tests
.
filter
(
testOpt
=>
{
return
testsNameList
.
includes
(
testOpt
.
name
);
});
for
(
let
testOpt
of
pendingTests
)
{
// Reset all tests results
testOpt
.
status
=
'
pending
'
;
testOpt
.
results
=
[];
}
broadcast
({
tests
});
try
{
for
(
let
testOpt
of
pendingTests
)
{
await
runTest
(
browser
,
testOpt
);
broadcast
({
tests
});
writeTestsToCache
(
tests
);
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
});
});
for
(
let
testOpt
of
tests
)
{
if
(
testOpt
.
status
===
'
finished
'
)
{
continue
;
}
console
.
log
(
`Running test
${
testOpt
.
fileUrl
}
`
)
await
runTest
(
browser
,
testOpt
);
broadcast
({
tests
});
writeTestsToCache
(
tests
);
}
// runTests(browser, tests, tests);
}
start
().
catch
(
e
=>
{
console
.
log
(
'
Error during test
'
);
console
.
log
(
e
);
})
\ No newline at end of file
start
()
\ No newline at end of file
test/runTest/client/client.css
浏览文件 @
ea440f6b
...
...
@@ -10,17 +10,112 @@
font-family
:
"Helvetica Neue"
,
Helvetica
,
"PingFang SC"
,
"Hiragino Sans GB"
,
"Microsoft YaHei"
,
"微软雅黑"
,
Arial
,
sans-serif
;
}
.menu-link
{
display
:
block
;
.header
{
background-color
:
#293c55
;
box-shadow
:
0
0
20px
rgba
(
0
,
0
,
0
,
0.2
);
position
:
relative
;
z-index
:
10
;
}
.header
h1
{
color
:
#fff
;
line-height
:
50px
;
margin
:
0
;
font-weight
:
200
;
font-size
:
20px
;
}
#logo
>*
{
display
:
inline-block
;
vertical-align
:
middle
;
}
#logo
img
{
height
:
30px
;
margin-right
:
20px
;
}
.nav-toolbar
{
padding
:
10px
10px
;
background
:
#162436
;
box-shadow
:
inset
0
0
5px
black
;
}
.nav-toolbar
.controls
{
margin-top
:
10px
;
}
.test-list
{
overflow-x
:
hidden
;
background
:
#293c55
;
margin
:
0
;
padding
:
0
;
}
.test-list
li
{
list-style
:
none
;
padding-left
:
10px
;
cursor
:
pointer
;
color
:
#f3f3f3
;
}
.test-list
li
a
.menu-link
{
display
:
inline-block
;
text-decoration
:
none
;
font-size
:
18px
;
font-size
:
14px
;
line-height
:
40px
;
color
:
#f3f3f3
;
margin-left
:
3px
;
cursor
:
pointer
;
}
.test-screenshots
{
margin-top
:
50px
;
.test-list
li
.active
{
background
:
#e43c59
;
}
.test-list
li
:hover
{
background
:
#162436
;
}
.test-list
li
>*
{
vertical-align
:
middle
;
display
:
inline-block
}
.test-screenshots
img
{
.test-list
.el-progress__text
{
font-size
:
12px
!important
;
}
.test-result
{
margin-top
:
80px
;
padding
:
0
20px
;
}
.test-result
img
{
/* height: 200px; */
width
:
100%
;
}
.test-result
h4
{
font-size
:
30px
;
font-weight
:
200
;
margin-left
:
-20px
;
}
::-webkit-scrollbar
{
height
:
8px
;
width
:
8px
;
transition
:
all
0.3s
ease-in-out
;
border-radius
:
2px
;
background
:
transparent
;
}
::-webkit-scrollbar-button
{
display
:
none
;
}
::-webkit-scrollbar-thumb
{
width
:
8px
;
min-height
:
15px
;
background
:
rgba
(
50
,
50
,
50
,
0.6
)
!important
;
transition
:
all
0.3s
ease-in-out
;
border-radius
:
2px
;
}
::-webkit-scrollbar-thumb:hover
{
background
:
rgba
(
0
,
0
,
0
,
0.5
)
!important
;
}
\ No newline at end of file
test/runTest/client/client.js
浏览文件 @
ea440f6b
const
socket
=
io
();
function
processTestsData
(
tests
)
{
tests
.
forEach
(
test
=>
{
let
passed
=
0
;
test
.
results
.
forEach
(
result
=>
{
// Threshold?
if
(
result
.
diffRatio
<
0.001
)
{
passed
++
;
}
});
test
.
percentage
=
passed
===
0
?
0
:
Math
.
round
(
passed
/
test
.
results
.
length
*
100
);
if
(
test
.
percentage
===
100
)
{
test
.
summary
=
'
success
'
;
}
else
if
(
test
.
percentage
<
50
)
{
test
.
summary
=
'
exception
'
;
}
else
{
test
.
summary
=
'
warning
'
}
test
.
selected
=
false
;
});
return
tests
;
}
socket
.
on
(
'
connect
'
,
()
=>
{
console
.
log
(
'
Connected
'
);
const
app
=
new
Vue
({
el
:
'
#app
'
,
data
:
{
tests
:
[],
selectedTestName
:
''
fullTests
:
[],
currentTestName
:
''
,
sortBy
:
'
name
'
,
searchString
:
''
,
running
:
false
,
allSelected
:
false
},
computed
:
{
selectedTest
()
{
let
selectedTest
=
this
.
tests
.
find
(
item
=>
item
.
name
===
this
.
selectedTestName
);
if
(
!
selectedTest
)
{
selectedTest
=
this
.
tests
[
0
];
tests
()
{
let
sortFunc
=
this
.
sortBy
===
'
name
'
?
(
a
,
b
)
=>
a
.
name
.
localeCompare
(
b
.
name
)
:
(
a
,
b
)
=>
a
.
percentage
-
b
.
percentage
;
if
(
!
this
.
searchString
)
{
return
this
.
fullTests
.
sort
(
sortFunc
);
}
return
this
.
fullTests
.
filter
(
test
=>
{
return
test
.
name
.
match
(
this
.
searchString
);
}).
sort
(
sortFunc
);
},
currentTest
()
{
let
currentTest
=
this
.
fullTests
.
find
(
item
=>
item
.
name
===
this
.
currentTestName
);
if
(
!
currentTest
)
{
currentTest
=
this
.
fullTests
[
0
];
}
return
currentTest
;
},
isSelectAllIndeterminate
()
{
if
(
!
this
.
tests
.
length
)
{
return
true
;
}
return
this
.
tests
.
some
(
test
=>
{
return
test
.
selected
!==
this
.
tests
[
0
].
selected
;
});
}
},
methods
:
{
goto
(
url
)
{
window
.
location
.
hash
=
'
#
'
+
url
;
},
toggleSort
()
{
this
.
sortBy
=
this
.
sortBy
===
'
name
'
?
'
percentage
'
:
'
name
'
;
},
handleSelectAllChange
(
val
)
{
// Only select filtered tests.
this
.
tests
.
forEach
(
test
=>
{
test
.
selected
=
val
;
});
this
.
isSelectAllIndeterminate
=
false
;
},
runSelectedTests
()
{
this
.
running
=
true
;
const
tests
=
this
.
fullTests
.
filter
(
test
=>
{
return
test
.
selected
;
}).
map
(
test
=>
{
return
test
.
name
});
if
(
tests
.
length
>
0
)
{
socket
.
emit
(
'
run
'
,
tests
);
}
return
selectedTest
;
},
stopTests
()
{
this
.
running
=
false
;
socket
.
emit
(
'
stop
'
);
}
}
});
app
.
$el
.
style
.
display
=
'
block
'
;
socket
.
on
(
'
broadcast
'
,
msg
=>
{
app
.
tests
=
msg
.
tests
;
app
.
fullTests
=
processTestsData
(
msg
.
tests
)
;
});
function
updateTestHash
()
{
let
testName
=
window
.
location
.
hash
.
slice
(
1
);
app
.
selected
TestName
=
testName
;
app
.
current
TestName
=
testName
;
}
updateTestHash
();
...
...
test/runTest/client/index.html
浏览文件 @
ea440f6b
...
...
@@ -8,22 +8,58 @@
<body>
<div
id=
"app"
style=
"display: none"
>
<el-container
id=
"main"
>
<el-header>
<h1>
Visual Regression Test
</h1>
<el-header
class=
"header"
height=
"50"
>
<div
id=
"logo"
>
<img
src=
"https://echarts.apache.org/zh/images/logo.png"
/>
<h1>
Visual Regression Test
</h1>
</div>
</el-header>
<el-container
style=
"min-height: 0"
>
<!-- https://juejin.im/post/5c642f2ff265da2de660ecfc -->
<el-aside
width=
"250px"
>
<el-menu
class=
"test-list"
>
<el-menu-item
v-for=
"test in tests"
>
<el-aside
width=
"300px"
>
<div
class=
"nav-toolbar"
>
<el-input
v-model=
"searchString"
size=
"mini"
placeholder=
"Filter Tests"
></el-input>
<div
class=
"controls"
>
<el-checkbox
:indeterminate=
"isSelectAllIndeterminate"
v-model=
"allSelected"
@
change=
"handleSelectAllChange"
></el-checkbox>
<el-button
style=
"margin-left: 10px"
title=
"Sort By Failue Percentage"
@
click=
"toggleSort"
circle
size=
"mini"
type=
"primary"
icon=
"el-icon-sort"
></el-button>
<!-- <el-button-group>
<el-button title="Select All" @click="selectAllTests" circle size="mini" type="primary" icon="el-icon-check"></el-button>
<el-button title="Unselect All" @click="unselectAllTests" circle size="mini" type="primary" icon="el-icon-close"></el-button>
</el-button-group> -->
<el-button-group>
<el-button
title=
"Run Selected"
@
click=
"runSelectedTests"
:loading=
"running"
circle
size=
"mini"
type=
"primary"
icon=
"el-icon-caret-right"
></el-button>
<el-button
v-if=
"running"
title=
"Run Selected"
@
click=
"stopTests"
circle
size=
"mini"
type=
"primary"
icon=
"el-icon-close"
></el-button>
</el-button-group>
</div>
</div>
<ul
class=
"test-list"
>
<li
v-for=
"test in tests"
:title=
"test.name"
:class=
"{active: currentTest && currentTest.name === test.name}"
@
click.self=
"goto(test.name)"
>
<el-checkbox
v-model=
"test.selected"
></el-checkbox>
<i
class=
"el-icon-loading"
v-if=
"test.status === 'pending' && running"
></i>
<el-progress
v-if=
"test.status === 'finished'"
type=
"circle"
:width=
"20"
:stroke-width=
"2"
:percentage=
"test.percentage"
:status=
"test.summary"
></el-progress>
<a
:href=
"'#' + test.name"
class=
"menu-link"
>
{{test.name}}
</a>
</el-menu-item>
</el-menu>
</li>
</ul>
</el-aside>
<el-main>
<div
v-if=
"
selected
Test"
>
<div
class=
"test-
screenshots"
v-for=
"result in selected
Test.results"
>
<h4
class=
"md-title"
>
{{
result.name}}
</h4>
<el-row
:gutter=
"
20
"
>
<div
v-if=
"
current
Test"
>
<div
class=
"test-
result"
v-for=
"result in current
Test.results"
>
<h4
>
{{result.desc ||
result.name}}
</h4>
<el-row
:gutter=
"
40"
class=
"screenshots
"
>
<el-col
:span=
"8"
>
<el-card>
<div
slot=
"header"
class=
"clearfix"
>
...
...
@@ -52,6 +88,10 @@
</el-col>
</el-row>
</div>
<div
class=
"test-result-nav"
>
</div>
</div>
</el-main>
</el-container>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录