Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
139
Merge Requests
139
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
erp5
Commits
578c1a32
Commit
578c1a32
authored
Oct 03, 2018
by
Jérome Perrin
Browse files
Options
Browse Files
Download
Plain Diff
Tests for graphs on support request frontpage
/reviewed-on
nexedi/erp5!763
parents
81e17101
5c24cfdc
Changes
26
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
9329 additions
and
121 deletions
+9329
-121
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_appcache.xml
...m/web_page_module/gadget_field_graph_echarts_appcache.xml
+3
-3
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_html.html
...Item/web_page_module/gadget_field_graph_echarts_html.html
+2
-4
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_html.xml
...eItem/web_page_module/gadget_field_graph_echarts_html.xml
+4
-4
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_js.js
...lateItem/web_page_module/gadget_field_graph_echarts_js.js
+78
-45
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_js.xml
...ateItem/web_page_module/gadget_field_graph_echarts_js.xml
+4
-4
bt5/erp5_officejs_support_request_ui/PathTemplateItem/web_page_module/gadget_supportrequest_homepage_html.html
.../web_page_module/gadget_supportrequest_homepage_html.html
+1
-1
bt5/erp5_officejs_support_request_ui/SkinTemplateItem/portal_skins/erp5_officejs_support_request/Folder_searchFolderSortByReferenceDescending.py
...t_request/Folder_searchFolderSortByReferenceDescending.py
+6
-1
bt5/erp5_officejs_support_request_ui/SkinTemplateItem/portal_skins/erp5_officejs_support_request/SupportRequest_getSupportRequestStatisticsAsJson.py
...quest/SupportRequest_getSupportRequestStatisticsAsJson.py
+9
-11
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity-reference-snapshot-1.png.png
...geDashboardLastMonthActivity-reference-snapshot-1.png.png
+0
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity-reference-snapshot-1.png.xml
...geDashboardLastMonthActivity-reference-snapshot-1.png.xml
+36
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity.xml
...uest_ui_zuite/testFrontPageDashboardLastMonthActivity.xml
+58
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity.zpt
...uest_ui_zuite/testFrontPageDashboardLastMonthActivity.zpt
+162
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe-reference-snapshot-1.png.png
...eDashboardSupportRequestPipe-reference-snapshot-1.png.png
+0
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe-reference-snapshot-1.png.xml
...eDashboardSupportRequestPipe-reference-snapshot-1.png.xml
+36
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe.xml
...est_ui_zuite/testFrontPageDashboardSupportRequestPipe.xml
+58
-0
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe.zpt
...est_ui_zuite/testFrontPageDashboardSupportRequestPipe.zpt
+164
-0
bt5/erp5_officejs_support_request_ui_test/SkinTemplateItem/portal_skins/erp5_officejs_support_request_test/ERP5Site_createSupportRequestUITestDataSet.py
...equest_test/ERP5Site_createSupportRequestUITestDataSet.py
+41
-2
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/Zuite_updateReferenceImage.py
...tal_skins/erp5_ui_test_core/Zuite_updateReferenceImage.py
+19
-0
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/Zuite_updateReferenceImage.xml
...al_skins/erp5_ui_test_core/Zuite_updateReferenceImage.xml
+62
-0
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/user-extensions.js.js
...Item/portal_skins/erp5_ui_test_core/user-extensions.js.js
+248
-0
bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_echarts_js.js
...rjs_ui/PathTemplateItem/web_page_module/rjs_echarts_js.js
+22
-38
bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_echarts_js.xml
...js_ui/PathTemplateItem/web_page_module/rjs_echarts_js.xml
+6
-8
product/Zelenium/selenium/core/TestRunner.hta
product/Zelenium/selenium/core/TestRunner.hta
+2
-0
product/Zelenium/selenium/core/TestRunner.html
product/Zelenium/selenium/core/TestRunner.html
+2
-0
product/Zelenium/selenium/core/lib/html2canvas.js
product/Zelenium/selenium/core/lib/html2canvas.js
+7274
-0
product/Zelenium/selenium/core/lib/resemble.js
product/Zelenium/selenium/core/lib/resemble.js
+1032
-0
No files found.
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_appcache.xml
View file @
578c1a32
...
...
@@ -112,7 +112,7 @@
<item>
<key>
<string>
text_content
</string>
</key>
<value>
<string>
CACHE MANIFEST\n
# v1.1.
0
\n
# v1.1.
1
\n
CACHE:\n
gadget_field_graph_echarts.html/echarts-all.js\n
gadget_field_graph_echarts.html/gadget_global.js\n
...
...
@@ -279,8 +279,8 @@ NETWORK:\n
</tuple>
<state>
<tuple>
<float>
15
06590312.39
</float>
<string>
UTC
</string>
<float>
15
38646068.83
</float>
<string>
GMT+9
</string>
</tuple>
</state>
</object>
...
...
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_html.html
View file @
578c1a32
<!DOCTYPE html>
<!--html style="height: 100%"-->
<html
manifest=
"gadget_field_graph_echarts.appcache"
style=
"height: 300px"
>
<head>
<meta
http-equiv=
"Content-type"
content=
"text/html; charset=utf-8"
/>
...
...
@@ -9,7 +7,7 @@
<!-- interfaces -->
<link
rel=
"http://www.renderjs.org/rel/interface"
href=
"gadget_field_graph_interface.html"
>
<!-- renderjs -->
<script
src=
"rsvp.js"
type=
"text/javascript"
></script>
<script
src=
"renderjs.js"
type=
"text/javascript"
></script>
...
...
@@ -23,7 +21,7 @@
</head>
<body
style=
"height: 100%; margin: 0"
>
<div
class=
"graph-content"
style=
"height: 95%; width: 95%"
>
<div
class=
"graph-content"
style=
"height: 95%; width: 95%"
disabled
>
</div>
</body>
</html>
\ No newline at end of file
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_html.xml
View file @
578c1a32
...
...
@@ -228,7 +228,7 @@
</item>
<item>
<key>
<string>
actor
</string>
</key>
<value>
<string>
zop
e
</string>
</value>
<value>
<string>
ERP5TypeTestCas
e
</string>
</value>
</item>
<item>
<key>
<string>
comment
</string>
</key>
...
...
@@ -242,7 +242,7 @@
</item>
<item>
<key>
<string>
serial
</string>
</key>
<value>
<string>
9
62.25420.32482.53094
</string>
</value>
<value>
<string>
9
70.25483.20924.1058
</string>
</value>
</item>
<item>
<key>
<string>
state
</string>
</key>
...
...
@@ -260,8 +260,8 @@
</tuple>
<state>
<tuple>
<float>
15
06590298.97
</float>
<string>
UTC
</string>
<float>
15
38645729.6
</float>
<string>
GMT+9
</string>
</tuple>
</state>
</object>
...
...
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_js.js
View file @
578c1a32
...
...
@@ -31,12 +31,12 @@
title
=
layout
.
title
;
// title
// The position of the title in plotly was fixed, like the "x:center" in echarts.
// The position of the title in plotly was fixed, like the "x:center" in echarts.
// For now, every graph have to provide a title.
if
(
title
===
undefined
)
{
throw
new
Error
(
"
No title provided
"
,
data
);
}
graph_data_and_parameter
.
title
=
{
text
:
title
,
x
:
"
center
"
};
graph_data_and_parameter
.
title
=
{
text
:
title
,
x
:
"
center
"
};
// tooltip
// ECharts have to enable the tooltip manually.
...
...
@@ -56,10 +56,13 @@
for
(
i
=
0
;
i
<
data
.
length
;
i
=
i
+
1
)
{
trace
=
data
[
i
];
trace_type
=
trace
.
type
||
'
bar
'
;
trace_type
=
trace
.
type
||
"
bar
"
;
type_list
.
push
(
trace_type
);
trace_value_dict
=
trace
.
value_dict
||
{};
if
(
trace_value_dict
[
0
]
===
undefined
||
trace_value_dict
[
1
]
===
undefined
)
{
if
(
trace_value_dict
[
0
]
===
undefined
||
trace_value_dict
[
1
]
===
undefined
)
{
throw
new
Error
(
"
Unexpected data for ECharts
"
,
data
);
}
...
...
@@ -69,16 +72,16 @@
// If the graph type is pie, set the pie radius
// plotly doesn't have this option.
if
(
trace_type
===
'
pie
'
)
{
dataset
.
radius
=
'
55%
'
;
dataset
.
center
=
[
'
50%
'
,
'
60%
'
];
if
(
trace_type
===
"
pie
"
)
{
dataset
.
radius
=
"
55%
"
;
dataset
.
center
=
[
"
50%
"
,
"
60%
"
];
}
// For pie graph, the legend labels come from each item's title(aka trace.title)
// For graph which contains the axis, the legend labels come from the item's value_dict[0].
// See the trace_value_dict in below. But the duplicated value_dict[0] seems for 2D graph
// seems is redandunt.
if
(
trace
.
type
!==
'
pie
'
)
{
if
(
trace
.
type
!==
"
pie
"
)
{
graph_data_and_parameter
.
legend
.
data
.
push
(
dataset
.
name
);
}
...
...
@@ -91,21 +94,21 @@
// Value
for
(
j
=
0
;
j
<
trace_value_dict
[
1
].
length
;
j
=
j
+
1
)
{
dataset
.
data
.
push
(
{
value
:
trace_value_dict
[
1
][
j
],
name
:
label_list
[
j
],
itemStyle
:
null
}
);
dataset
.
data
.
push
({
value
:
trace_value_dict
[
1
][
j
],
name
:
label_list
[
j
],
itemStyle
:
null
});
// Handle the colors in different ways. Maybe enhanced latter
if
(
trace
.
colors
)
{
// In the pie graph, set the color each individual "data" item.
if
(
trace
.
type
===
'
pie
'
)
{
dataset
.
data
[
j
].
itemStyle
=
{
normal
:
{
color
:
trace
.
colors
[
j
]}};
if
(
trace
.
type
===
"
pie
"
)
{
dataset
.
data
[
j
].
itemStyle
=
{
normal
:
{
color
:
trace
.
colors
[
j
]
}
};
}
else
{
// In other types of graph, set the color for each group.
dataset
.
itemStyle
=
{
normal
:
{
color
:
trace
.
colors
[
0
]}
};
dataset
.
itemStyle
=
{
normal
:
{
color
:
trace
.
colors
[
0
]
}
};
}
}
}
...
...
@@ -113,15 +116,21 @@
}
// For the pie graph, the legend label is the value_dict[0]
if
(
trace
.
type
===
'
pie
'
)
{
if
(
trace
.
type
===
"
pie
"
)
{
graph_data_and_parameter
.
legend
.
data
=
label_list
;
}
// Axis
if
(
trace
.
type
!==
'
pie
'
)
{
// if not value type provided, set it as "value".
graph_data_and_parameter
.
yAxis
.
push
({
type
:
'
value
'
,
name
:
layout
.
axis_dict
[
1
].
title
});
graph_data_and_parameter
.
xAxis
.
push
({
data
:
label_list
,
name
:
layout
.
axis_dict
[
0
].
title
});
if
(
trace
.
type
!==
"
pie
"
)
{
// if not value type provided, set it as "value".
graph_data_and_parameter
.
yAxis
.
push
({
type
:
"
value
"
,
name
:
layout
.
axis_dict
[
1
].
title
});
graph_data_and_parameter
.
xAxis
.
push
({
data
:
label_list
,
name
:
layout
.
axis_dict
[
0
].
title
});
}
else
{
graph_data_and_parameter
.
xAxis
=
null
;
graph_data_and_parameter
.
yAxis
=
null
;
...
...
@@ -140,9 +149,6 @@
/////////////////////////////////////////////////////////////////
// ready
/////////////////////////////////////////////////////////////////
.
ready
(
function
(
gadget
)
{
gadget
.
property_dict
=
{};
})
/////////////////////////////////////////////////////////////////
// published methods
...
...
@@ -155,42 +161,69 @@
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.
declareMethod
(
'
render
'
,
function
(
option_dict
)
{
.
declareMethod
(
"
render
"
,
function
(
option_dict
)
{
var
gadget
=
this
;
//delegate rendering to onStateChange to avoid redrawing the graph
//every time render is called (a form might call render every time
//some other fields needs update)
gadget
.
changeState
({
value
:
option_dict
.
value
});
gadget
.
changeState
({
value
:
option_dict
.
value
});
})
.
onStateChange
(
function
(
modification_dict
)
{
var
gadget
=
this
,
container
,
graph_data_and_parameter
,
chart
;
container
=
gadget
.
element
.
querySelector
(
"
.graph-content
"
);
chart
=
echarts
.
init
(
container
);
graph_data_and_parameter
=
getGraphDataAndParameterFromConfiguration
(
modification_dict
.
value
);
chart
.
setOption
(
graph_data_and_parameter
);
this
.
listenToClickEventOnTheChart
(
chart
);
gadget
.
property_dict
.
chart
=
chart
;
// the gadget is ready when both the graph is rendered and the click handler is attached.
if
(
modification_dict
.
hasOwnProperty
(
"
clickHandlerReady
"
)
||
modification_dict
.
hasOwnProperty
(
"
chartRendered
"
)
)
{
if
(
gadget
.
state
.
clickHandlerReady
&&
gadget
.
state
.
chartRendered
)
{
gadget
.
element
.
querySelector
(
"
.graph-content
"
).
removeAttribute
(
"
disabled
"
);
}
else
{
gadget
.
element
.
querySelector
(
"
.graph-content
"
).
setAttribute
(
"
disabled
"
);
}
}
if
(
modification_dict
.
hasOwnProperty
(
"
value
"
))
{
chart
=
echarts
.
getInstanceByDom
(
gadget
.
element
.
querySelector
(
"
.graph-content
"
)
);
graph_data_and_parameter
=
getGraphDataAndParameterFromConfiguration
(
modification_dict
.
value
);
chart
.
on
(
"
finished
"
,
function
onFinished
()
{
gadget
.
changeState
({
chartRendered
:
true
});
chart
.
off
(
"
finish
"
,
onFinished
);
});
chart
.
setOption
(
graph_data_and_parameter
);
gadget
.
changeState
({
chartRendered
:
false
});
this
.
listenToClickEventOnTheChart
(
chart
);
}
})
.
declareService
(
function
()
{
var
gadget
=
this
;
return
loopEventListener
(
window
,
"
resize
"
,
{
passive
:
true
},
function
()
{
gadget
.
property_dict
.
chart
.
resize
();
},
false
);
var
gadget
=
this
,
chart
=
echarts
.
init
(
gadget
.
element
.
querySelector
(
"
.graph-content
"
));
return
loopEventListener
(
window
,
"
resize
"
,
{
passive
:
true
},
function
()
{
chart
.
resize
();
},
false
);
})
.
declareJob
(
'
listenToClickEventOnTheChart
'
,
function
(
chart
)
{
.
declareJob
(
"
listenToClickEventOnTheChart
"
,
function
(
chart
)
{
var
gadget
=
this
,
defer
=
RSVP
.
defer
();
// XXX https://lab.nexedi.com/nexedi/renderjs/blob/master/renderjs.js#L25
chart
.
on
(
'
click
'
,
function
(
params
)
{
return
gadget
.
chartItemClick
([
params
.
name
,
params
.
seriesName
])
chart
.
on
(
"
click
"
,
function
(
params
)
{
return
gadget
.
chartItemClick
([
params
.
name
,
params
.
seriesName
])
.
push
(
undefined
,
defer
.
reject
);
});
gadget
.
changeState
({
clickHandlerReady
:
true
});
return
defer
.
promise
;
});
}(
window
,
rJS
,
RSVP
,
echarts
,
loopEventListener
));
bt5/erp5_officejs/PathTemplateItem/web_page_module/gadget_field_graph_echarts_js.xml
View file @
578c1a32
...
...
@@ -228,7 +228,7 @@
</item>
<item>
<key>
<string>
actor
</string>
</key>
<value>
<string>
zop
e
</string>
</value>
<value>
<string>
ERP5TypeTestCas
e
</string>
</value>
</item>
<item>
<key>
<string>
comment
</string>
</key>
...
...
@@ -242,7 +242,7 @@
</item>
<item>
<key>
<string>
serial
</string>
</key>
<value>
<string>
9
61.52409.12026.48179
</string>
</value>
<value>
<string>
9
70.25488.14039.8704
</string>
</value>
</item>
<item>
<key>
<string>
state
</string>
</key>
...
...
@@ -260,8 +260,8 @@
</tuple>
<state>
<tuple>
<float>
15
04517195.47
</float>
<string>
UTC
</string>
<float>
15
38645846.68
</float>
<string>
GMT+9
</string>
</tuple>
</state>
</object>
...
...
bt5/erp5_officejs_support_request_ui/PathTemplateItem/web_page_module/gadget_supportrequest_homepage_html.html
View file @
578c1a32
...
...
@@ -38,7 +38,7 @@
</div>
<div
class=
"bottom"
>
<input
type=
"submit"
class=
"ui-disabled"
data-i18n=
"[value]Res
tore Filter"
value=
"Restore
Filter"
disabled
/>
<input
type=
"submit"
class=
"ui-disabled"
data-i18n=
"[value]Res
et Filter"
value=
"Reset
Filter"
disabled
/>
</div>
<div
data-gadget-url=
"gadget_erp5_page_form.html"
data-gadget-scope=
"last"
></div>
...
...
bt5/erp5_officejs_support_request_ui/SkinTemplateItem/portal_skins/erp5_officejs_support_request/Folder_searchFolderSortByReferenceDescending.py
View file @
578c1a32
if
'sort_on'
in
kw
:
del
kw
[
'sort_on'
]
return
context
.
searchFolder
(
sort_on
=
[(
'modification_date'
,
'descending'
)],
**
kw
)
return
context
.
searchFolder
(
sort_on
=
[
(
'modification_date'
,
'descending'
),
# XXX to get stable test result, we also sort by start date (because modification date
# has a one second precision)
(
'delivery.start_date'
,
'descending'
),
],
**
kw
)
bt5/erp5_officejs_support_request_ui/SkinTemplateItem/portal_skins/erp5_officejs_support_request/SupportRequest_getSupportRequestStatisticsAsJson.py
View file @
578c1a32
from
datetime
import
timedelta
from
json
import
dumps
portal
=
context
.
getPortalObject
()
# Get the split date
now_date
=
DateTime
()
date_2
=
now_date
-
2
date_7
=
now_date
-
7
date_30
=
now_date
-
30
# we can not use str.join...
date_2_midnight
=
DateTime
(
str
(
date_2
.
year
())
+
"-"
+
str
(
date_2
.
month
())
+
"-"
+
str
(
date_2
.
day
()))
date_7_midnight
=
DateTime
(
str
(
date_7
.
year
())
+
"-"
+
str
(
date_7
.
month
())
+
"-"
+
str
(
date_7
.
day
()))
date_30_midnight
=
DateTime
(
str
(
date_30
.
year
())
+
"-"
+
str
(
date_30
.
month
())
+
"-"
+
str
(
date_30
.
day
()))
now_date
=
DateTime
().
asdatetime
()
date_2_midnight
=
DateTime
(
now_date
-
timedelta
(
days
=
2
)).
earliestTime
()
date_7_midnight
=
DateTime
(
now_date
-
timedelta
(
days
=
7
)).
earliestTime
()
date_30_midnight
=
DateTime
(
now_date
-
timedelta
(
days
=
30
)).
earliestTime
()
support_request_list
=
portal
.
portal_catalog
(
portal_type
=
"Support Request"
,
select_list
=
[
'simulation_state'
,
'start_date'
],
**
{
"delivery.start_date"
:
{
"query"
:
now_date
,
"range"
:
"ngt"
}}
**
{
"delivery.start_date"
:
{
"query"
:
DateTime
(
now_date
)
,
"range"
:
"ngt"
}}
)
count_by_state
=
{}
count_by_date
=
{
"le2"
:
{},
"2to7"
:
{},
"7to30"
:
{},
"gt30"
:
{}}
for
sr
in
support_request_list
:
sr_date
=
sr
.
start_date
sr_state
=
sr
.
getProperty
(
"simulation_state"
)
sr
=
sr
.
getObject
()
sr_date
=
sr
.
getStartDate
()
sr_state
=
sr
.
getSimulationState
()
if
sr_state
not
in
count_by_state
:
count_by_state
[
sr_state
]
=
0
...
...
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity-reference-snapshot-1.png.png
0 → 100644
View file @
578c1a32
17.5 KB
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity-reference-snapshot-1.png.xml
0 → 100644
View file @
578c1a32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Image"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
testFrontPageDashboardLastMonthActivity-reference-snapshot-1.png
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
image/png
</string>
</value>
</item>
<item>
<key>
<string>
height
</string>
</key>
<value>
<int>
285
</int>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
width
</string>
</key>
<value>
<int>
390
</int>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity.xml
0 → 100644
View file @
578c1a32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ZopePageTemplate"
module=
"Products.PageTemplates.ZopePageTemplate"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_bind_names
</string>
</key>
<value>
<object>
<klass>
<global
name=
"NameAssignments"
module=
"Shared.DC.Scripts.Bindings"
/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key>
<string>
_asgns
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
name_subpath
</string>
</key>
<value>
<string>
traverse_subpath
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
text/html
</string>
</value>
</item>
<item>
<key>
<string>
expand
</string>
</key>
<value>
<int>
0
</int>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
testFrontPageDashboardLastMonthActivity
</string>
</value>
</item>
<item>
<key>
<string>
output_encoding
</string>
</key>
<value>
<string>
utf-8
</string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<unicode>
Last Month Activity on Front Page Dashboard
</unicode>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardLastMonthActivity.zpt
0 → 100644
View file @
578c1a32
<html>
<head>
<title
tal:content=
"template/title"
></title>
<meta
http-equiv=
"content-type"
content=
"text/html;charset=utf-8"
>
</head>
<body>
<table
cellpadding=
"1"
cellspacing=
"1"
border=
"1"
>
<thead>
<tr><td
colspan=
"3"
tal:content=
"template/title"
></td></tr>
</thead><tbody>
<tal:block
metal:use-macro=
"here/Zuite_CommonTemplate/macros/init"
/>
<tal:block
metal:use-macro=
"here/Zuite_SupportRequestUITemplate/macros/cleanup_module"
/>
<tal:block
metal:use-macro=
"here/Zuite_SupportRequestUITemplate/macros/create_data"
/>
<tr><td>
open
</td>
<td>
${base_url}/web_site_module/erp5_officejs_support_request_ui/
</td><td></td></tr>
<!-- reset filter is disabled -->
<tr><td>
waitForElementPresent
</td>
<td>
//input[@data-i18n="[value]Reset Filter" and @disabled]
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
css=#wrap2 iframe
</td><td></td></tr>
<tr><td>
selectFrame
</td>
<td>
css=#wrap2 iframe
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
//canvas
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
//div[@class="graph-content" and not(@disabled)]
</td><td></td></tr>
<tr><td>
storeEval
</td>
<td>
selenium.browserbot.getCurrentWindow().echarts.getInstanceByDom(
selenium.browserbot.findElement("css=.graph-content"))
</td>
<td>
graph_instance
</td></tr>
<tr><td>
assertEval
</td>
<td>
(function(){
var series = storedVars['graph_instance'].getOption()['series'],
title = storedVars['graph_instance'].getOption()['title'][0].text;
Assert.equals("Last Month Activity", title);
Assert.equals(1, series.length);
Assert.equals("pie", series[0]["type"]);
Assert.equals("Support Request", series[0]["name"]);
Assert.equals(
JSON.stringify([
{name: "Opened", value: 3},
{name: "Submitted", value: 2},
{name: "Suspended", value: 0},
{name: "Closed", value: 0}]),
JSON.stringify(series[0]["data"].map(e => {return {name: e.name, value: e.value}; })));
return "ok";
})()
</td>
<td>
ok
</td></tr>
<tr><td
colspan=
"3"
><b>
Verify the rendering of the graph matches our reference snapshot
</b></td></tr>
<tr><td>
verifyImageMatchSnapshot
</td>
<td>
//canvas
</td>
<td>
20
</td></tr>
<tr><td
colspan=
"3"
><b>
Clicking on a serie filter the listbox of recent updates
</b></td></tr>
<!--
In the last month, we have 4 Opened and 3 Submitted. The pie shows submitted on the right
and opened on the left.
0 x 100%
0 --------------------------------------- ... >
| Last Month Activity
| [ ] Opened [ ] Submitted ....
|
| _____
| Submitted .-' | '-.
| \ .' | '.
y | \ / | \
| ;\ X | ;
| | \ / ---|---- Opened
| ; / ;
| \ / /
| './ .'
| '-._____.-'
.
.
V 100%
We click in the `Submitted` zone, where's there's a X in this ascii art.
debugging tips:
selenium.browserbot.findElement('//canvas').addEventListener(
'click',
function(e) {
canvasSize = {
x: selenium.browserbot.findElement('//canvas').clientWidth,
y: selenium.browserbot.findElement('//canvas').clientHeight }
console.log(
`${e.clientX} x ${e.clientY}\n${(e.clientX / canvasSize.x * 100).toFixed(2)}% ${(e.clientY / canvasSize.y * 100).toFixed(2)}%`
)
})
or use conditional breakpoint on "clientToLocal" from echarts-all.js :
(e.type == "click" || e.type == "mousedown") && console.log(e.type +" at", e.clientX, e.clientY, (e.clientX / document.querySelector('canvas').clientWidth * 100).toFixed(2), (e.clientY / document.querySelector('canvas').clientHeight * 100).toFixed(2))
and compare real click with simulated clicks.
-->
<tr><td>
storeEval
</td>
<!-- 49% of the horizontal axis -->
<td>
Math.floor(selenium.browserbot.findElement('//canvas').clientWidth * 0.49)
</td>
<td>
x
</td></tr>
<tr><td>
storeEval
</td>
<!-- 40% of of vertical axis -->
<td>
Math.floor(selenium.browserbot.findElement('//canvas').clientHeight * 0.4)
</td>
<td>
y
</td></tr>
<tr><td>
assertEval
</td>
<!-- echarts ignore the click without a mousedown on the element before -->
<td>
var e = new MouseEvent("mousedown", {});
/* echarts will adjust the location with browser based heuristics
https://github.com/ecomfe/zrender/blob/4.0.5/src/core/event.js#L20
to make this easier, we precalculate the coordinates in a way that should
be cross browser compatible. */
e.zrX = storedVars.x;
e.zrY = storedVars.y;
selenium.browserbot.findElement("//canvas/..").dispatchEvent(e)
</td>
<td>
true
</td></tr>
<tr><td>
assertEval
</td>
<td>
var e = new MouseEvent("click", {});
e.zrX = storedVars.x;
e.zrY = storedVars.y;
selenium.browserbot.findElement("//canvas/..").dispatchEvent(e)
</td>
<td>
true
</td></tr>
<!-- XXX shouldn't selenium "clickAt" do this ?
<tr><td>clickAt</td>
<td>//canvas/..</td>
<td>${x},${y}</td></tr> -->
<tr><td
colspan=
"3"
><b>
Recent updates listbox is updated with the clicked series.
</b></td>
<tr><td>
selectFrame
</td>
<td>
relative=top
</td><td></td></tr>
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]
</td>
<td>
Recent Updates (3)
</td></tr>
<!-- FIXME: this should be 2 here. 123dsfa is not "last month" -->
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]/../..//td[1]/a
</td>
<td>
Yesterday - RobotMaking - Submitted
</td></tr>
<!-- reset filter is now enabled -->
<tr><td>
waitForElementPresent
</td>
<td>
//input[@data-i18n="[value]Reset Filter" and not(@disabled)]
</td><td></td></tr>
<tr><td>
click
</td>
<td>
//input[@data-i18n="[value]Reset Filter"]
</td><td></td></tr>
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]
</td>
<td>
glob:Recent Updates (1 - 5 / *)
</td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe-reference-snapshot-1.png.png
0 → 100644
View file @
578c1a32
12.6 KB
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe-reference-snapshot-1.png.xml
0 → 100644
View file @
578c1a32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Image"
module=
"OFS.Image"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
__name__
</string>
</key>
<value>
<string>
testFrontPageDashboardSupportRequestPipe-reference-snapshot-1.png
</string>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
image/png
</string>
</value>
</item>
<item>
<key>
<string>
height
</string>
</key>
<value>
<int>
285
</int>
</value>
</item>
<item>
<key>
<string>
precondition
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
width
</string>
</key>
<value>
<int>
404
</int>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe.xml
0 → 100644
View file @
578c1a32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ZopePageTemplate"
module=
"Products.PageTemplates.ZopePageTemplate"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_bind_names
</string>
</key>
<value>
<object>
<klass>
<global
name=
"NameAssignments"
module=
"Shared.DC.Scripts.Bindings"
/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key>
<string>
_asgns
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
name_subpath
</string>
</key>
<value>
<string>
traverse_subpath
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
content_type
</string>
</key>
<value>
<string>
text/html
</string>
</value>
</item>
<item>
<key>
<string>
expand
</string>
</key>
<value>
<int>
0
</int>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
testFrontPageDashboardSupportRequestPipe
</string>
</value>
</item>
<item>
<key>
<string>
output_encoding
</string>
</key>
<value>
<string>
utf-8
</string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<unicode>
Support Request Pipe on Front Page Dashboard
</unicode>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_officejs_support_request_ui_test/PathTemplateItem/portal_tests/officejs_support_request_ui_zuite/testFrontPageDashboardSupportRequestPipe.zpt
0 → 100644
View file @
578c1a32
<html>
<head>
<title
tal:content=
"template/title"
></title>
<meta
http-equiv=
"content-type"
content=
"text/html;charset=utf-8"
>
</head>
<body>
<table
cellpadding=
"1"
cellspacing=
"1"
border=
"1"
>
<thead>
<tr><td
colspan=
"3"
tal:content=
"template/title"
></td></tr>
</thead><tbody>
<tal:block
metal:use-macro=
"here/Zuite_CommonTemplate/macros/init"
/>
<tal:block
metal:use-macro=
"here/Zuite_SupportRequestUITemplate/macros/cleanup_module"
/>
<tal:block
metal:use-macro=
"here/Zuite_SupportRequestUITemplate/macros/create_data"
/>
<tr><td>
open
</td>
<td>
${base_url}/web_site_module/erp5_officejs_support_request_ui/
</td><td></td></tr>
<!-- reset filter is disabled -->
<tr><td>
waitForElementPresent
</td>
<td>
//input[@data-i18n="[value]Reset Filter" and @disabled]
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
css=#wrap1 iframe
</td><td></td></tr>
<tr><td>
selectFrame
</td>
<td>
css=#wrap1 iframe
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
//canvas
</td><td></td></tr>
<tr><td>
waitForElementPresent
</td>
<td>
//div[@class="graph-content" and not(@disabled)]
</td><td></td></tr>
<tr><td>
storeEval
</td>
<td>
selenium.browserbot.getCurrentWindow().echarts.getInstanceByDom(
selenium.browserbot.findElement("css=.graph-content"))
</td>
<td>
graph_instance
</td></tr>
<tr><td>
assertEval
</td>
<td>
(function(){
var series = storedVars['graph_instance'].getOption()['series'],
title = storedVars['graph_instance'].getOption()['title'][0].text;
Assert.equals("Support Request Pipe", title);
Assert.equals(3, series.length);
Assert.equals("bar", series[0]["type"]);
Assert.equals("Opened", series[0]["name"]);
Assert.equals(
JSON.stringify([
{name: "
<
2
",
value:
1
},
{
name:
"
2-7
",
value:
2
},
{
name:
"
7-30
",
value:
0
},
{
name:
"
>
30", value: 1}]),
JSON.stringify(series[0]["data"].map(e => {return {name: e.name, value: e.value}; })));
Assert.equals("Submitted", series[1]["name"]);
Assert.equals(
JSON.stringify([
{name: "
<
2
",
value:
1
},
{
name:
"
2-7
",
value:
0
},
{
name:
"
7-30
",
value:
1
},
{
name:
"
>
30", value: 1}]),
JSON.stringify(series[1]["data"].map(e => {return {name: e.name, value: e.value}; })));
Assert.equals("Suspended", series[2]["name"]);
Assert.equals(
JSON.stringify([
{name: "
<
2
",
value:
0
},
{
name:
"
2-7
",
value:
0
},
{
name:
"
7-30
",
value:
0
},
{
name:
"
>
30", value: 1}]),
JSON.stringify(series[2]["data"].map(e => {return {name: e.name, value: e.value}; })));
return "ok";
})()
</td>
<td>
ok
</td></tr>
<tr><td
colspan=
"3"
><b>
Verify the rendering of the graph matches our reference snapshot
</b></td></tr>
<tr><td>
verifyImageMatchSnapshot
</td>
<td>
//canvas
</td>
<td>
20
</td></tr>
<tr><td
colspan=
"3"
><b>
Clicking on a serie filter the listbox of recent updates
</b></td></tr>
<!--
Click on the first series (Open < 2), which should be the easiest to hit,
0 x 100%
0 ----------------------------------------------------- ... >
| Support Request Pipe
| [ ] Opened [ ] Submitted ....
|
|
| <-XXX ->
| __
| |//|
| we click |//|
y | on this X |//|
| V |//|
| __ __ |//|
| | | |//| |//|
| | X| |//| |//|
| | | |//| |//|
| | | |//| |//|
| | | |//| |//|
.----------------------|--------------- ....
. < 2 2-7
.
V 100%
The width of the XXX area depends on the total available width, so it's really hard to
estimate where to click.
On a 409x285 canvas (959x703 outer window), 20% is OK.
On a 639x285 canvas (1666x703 outer window), 30% is OK.
The approximated formula (by trial and error, so it migth be just wrong) is:
( 15% + (height/with ratio) * 10% ) of height
-->
<tr><td>
storeEval
</td>
<td>
Math.floor(
( selenium.browserbot.findElement('//canvas').clientHeight/
selenium.browserbot.findElement('//canvas').clientWidth) * 0.1 +
selenium.browserbot.findElement('//canvas').clientWidth * 0.15)
</td>
<td>
x
</td></tr>
<tr><td>
storeEval
</td>
<!-- 70% of of vertical axis -->
<td>
Math.floor(selenium.browserbot.findElement('//canvas').clientHeight * 0.7)
</td>
<td>
y
</td></tr>
<tr><td>
assertEval
</td>
<!-- echarts ignore the click without a mousedown on the element before -->
<td>
var e = new MouseEvent("mousedown", {});
e.zrX = storedVars.x;
e.zrY = storedVars.y;
selenium.browserbot.findElement("//canvas/..").dispatchEvent(e)
</td>
<td>
true
</td></tr>
<tr><td>
assertEval
</td>
<td>
var e = new MouseEvent("click", {});
e.zrX = storedVars.x;
e.zrY = storedVars.y;
selenium.browserbot.findElement("//canvas/..").dispatchEvent(e)
</td>
<td>
true
</td></tr>
<tr><td
colspan=
"3"
><b>
Recent updates listbox is updated with the clicked series.
</b></td>
<tr><td>
selectFrame
</td>
<td>
relative=top
</td><td></td></tr>
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]
</td>
<td>
Recent Updates (1)
</td></tr>
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]/../..//td[1]/a
</td>
<td>
Yesterday - PlaneMaking - Open
</td></tr>
<!-- reset filter is now enabled -->
<tr><td>
waitForElementPresent
</td>
<td>
//input[@data-i18n="[value]Reset Filter" and not(@disabled)]
</td><td></td></tr>
<tr><td>
click
</td>
<td>
//input[@data-i18n="[value]Reset Filter"]
</td><td></td></tr>
<tr><td>
waitForText
</td>
<td>
//h1[@data-i18n="Recent Updates"]
</td>
<td>
glob:Recent Updates (1 - 5 / *)
</td></tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
bt5/erp5_officejs_support_request_ui_test/SkinTemplateItem/portal_skins/erp5_officejs_support_request_test/ERP5Site_createSupportRequestUITestDataSet.py
View file @
578c1a32
"""Create some data for support request UI test.
Logged in user needs to be Assignee / Assignor on the support requests
*
Logged in user needs to be Assignee / Assignor on the support requests
included in business template.
* Some "static" data is already in business template, but because the dashboard
display statistics about recent support requests (like "less than 2 days from now"),
we need to generate support requests at a date relative from now.
"""
from
DateTime
import
DateTime
from
datetime
import
timedelta
portal
=
context
.
getPortalObject
()
now
=
DateTime
().
asdatetime
()
for
support_request
in
portal
.
support_request_module
.
contentValues
():
if
support_request
.
getId
().
startswith
(
'erp5_officejs_support_request_ui_test'
):
...
...
@@ -11,6 +18,38 @@ for support_request in portal.support_request_module.contentValues():
portal
.
portal_membership
.
getAuthenticatedMember
().
getId
(),
[
'Assignee'
,
'Assignor'
])
support_request
.
reindexObject
()
portal
.
portal_caches
.
clearAllCache
()
portal
.
support_request_module
.
newContent
(
portal_type
=
'Support Request'
,
title
=
"Two Weeks ago - PlaneMaking - Submitted"
,
start_date
=
DateTime
(
now
-
timedelta
(
days
=
15
)),
source_project_value
=
portal
.
project_module
.
erp5_officejs_support_request_ui_test_project_001
,
).
submit
()
portal
.
support_request_module
.
newContent
(
portal_type
=
'Support Request'
,
title
=
"Last Week 2 - RobotMaking - Open"
,
start_date
=
DateTime
(
now
-
timedelta
(
days
=
5
)),
source_project_value
=
portal
.
project_module
.
erp5_officejs_support_request_ui_test_project_001
,
).
validate
()
portal
.
support_request_module
.
newContent
(
portal_type
=
'Support Request'
,
title
=
"Last Week - RobotMaking - Open"
,
start_date
=
DateTime
(
now
-
timedelta
(
days
=
4
)),
source_project_value
=
portal
.
project_module
.
erp5_officejs_support_request_ui_test_project_001
,
).
validate
()
portal
.
support_request_module
.
newContent
(
portal_type
=
'Support Request'
,
title
=
"Yesterday - RobotMaking - Submitted"
,
start_date
=
DateTime
(
now
-
timedelta
(
days
=
1
)),
source_project_value
=
portal
.
project_module
.
erp5_officejs_support_request_ui_test_project_001
,
).
submit
()
portal
.
support_request_module
.
newContent
(
portal_type
=
'Support Request'
,
title
=
"Yesterday - PlaneMaking - Open"
,
start_date
=
DateTime
(
now
-
timedelta
(
days
=
1
)),
source_project_value
=
portal
.
project_module
.
erp5_officejs_support_request_ui_test_project_001
,
).
validate
()
return
"Done."
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/Zuite_updateReferenceImage.py
0 → 100644
View file @
578c1a32
from
StringIO
import
StringIO
portal
=
context
.
getPortalObject
()
image_file
=
StringIO
(
image_data
.
replace
(
'data:image/png;base64,'
,
''
).
decode
(
'base64'
))
image_path
=
image_path
.
split
(
'/'
)
existing
=
portal
.
restrictedTraverse
(
image_path
,
None
)
if
existing
is
None
:
container
=
portal
.
restrictedTraverse
(
image_path
[:
-
1
])
container
.
manage_addProduct
[
'OFSP'
].
manage_addImage
(
image_path
[
-
1
],
image_file
,
''
)
else
:
existing
.
manage_upload
(
image_file
)
return
"reference image at {} updated"
.
format
(
'/'
.
join
(
image_path
))
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/Zuite_updateReferenceImage.xml
0 → 100644
View file @
578c1a32
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"PythonScript"
module=
"Products.PythonScripts.PythonScript"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
Script_magic
</string>
</key>
<value>
<int>
3
</int>
</value>
</item>
<item>
<key>
<string>
_bind_names
</string>
</key>
<value>
<object>
<klass>
<global
name=
"NameAssignments"
module=
"Shared.DC.Scripts.Bindings"
/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key>
<string>
_asgns
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
name_container
</string>
</key>
<value>
<string>
container
</string>
</value>
</item>
<item>
<key>
<string>
name_context
</string>
</key>
<value>
<string>
context
</string>
</value>
</item>
<item>
<key>
<string>
name_m_self
</string>
</key>
<value>
<string>
script
</string>
</value>
</item>
<item>
<key>
<string>
name_subpath
</string>
</key>
<value>
<string>
traverse_subpath
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
image_data, image_path
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
Zuite_updateReferenceImage
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/erp5_ui_test_core/SkinTemplateItem/portal_skins/erp5_ui_test_core/user-extensions.js.js
View file @
578c1a32
...
...
@@ -82,3 +82,251 @@ Selenium.prototype.assertElementPositionRangeTop = function(locator, range){
Assert
.
fail
(
positionTop
+
"
is not between
"
+
minimumPositionTop
+
"
and
"
+
maximumPositionTop
);
}
};
// a memo test pathname => image counter
// TODO: reset this on testSuite.reset(), because we cannot re-run a test.
imageMatchReference
=
new
Map
();
function
getReferenceImageCounter
(
testPathName
)
{
var
counter
=
imageMatchReference
.
get
(
testPathName
);
if
(
counter
!==
undefined
)
{
return
counter
;
}
counter
=
imageMatchReference
.
size
+
1
;
imageMatchReference
.
set
(
testPathName
,
counter
);
return
counter
;
}
function
getReferenceImageURL
(
testPathName
)
{
var
imageCounter
=
getReferenceImageCounter
(
testPathName
);
return
testPathName
+
'
-reference-snapshot-
'
+
imageCounter
+
'
.png
'
;
}
/**
*
* Helper function to generate a DOM elements
*
* @param {string} tagName name of the element
* @param {Node?} childList list of child elements
* @param {Map<string,any>?} attributeDict attributes
* @param {string?} textContent
* @return {Node}
*/
function
generateElement
(
tagName
,
childList
,
attributeDict
,
textContent
)
{
var
element
=
document
.
createElement
(
tagName
);
if
(
attributeDict
)
{
for
(
var
attr
in
attributeDict
)
{
element
.
setAttribute
(
attr
,
attributeDict
[
attr
]);
}
}
if
(
childList
)
{
childList
.
map
(
child
=>
{
element
.
appendChild
(
child
);
});
}
return
element
;
}
/**
* Generate an HTML form to update the reference snapshot
*
* @param {string} referenceImageURL relative URL of the reference image
* @param {string} newImageData the new image data, base64 encoded
* @param {Map<string,any>?} attributeDict attributes
* @return {Promise<string>} the base64 encoded html form
*/
function
generateUpdateForm
(
referenceImageURL
,
newImageData
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
var
fr
=
new
FileReader
();
fr
.
onerror
=
reject
;
fr
.
onload
=
()
=>
resolve
(
fr
.
result
);
fr
.
readAsDataURL
(
new
Blob
(
[
generateElement
(
'
html
'
,
[
generateElement
(
'
body
'
,
[
generateElement
(
'
p
'
,
[
document
.
createTextNode
(
'
Replacing this old snapshot:
'
),
generateElement
(
'
br
'
),
generateElement
(
'
img
'
,
[],
{
src
:
location
.
origin
+
referenceImageURL
,
alt
:
'
reference image
'
}),
generateElement
(
'
br
'
),
document
.
createTextNode
(
'
with this new snapshot:
'
),
generateElement
(
'
br
'
),
generateElement
(
'
img
'
,
[],
{
src
:
newImageData
,
alt
:
'
new image
'
})
]),
generateElement
(
'
form
'
,
[
generateElement
(
'
input
'
,
[],
{
type
:
'
hidden
'
,
name
:
'
image_data
'
,
value
:
newImageData
}),
generateElement
(
'
input
'
,
[],
{
type
:
'
hidden
'
,
name
:
'
image_path
'
,
value
:
referenceImageURL
}),
generateElement
(
'
input
'
,
[],
{
type
:
'
submit
'
,
value
:
'
Update Reference Snapshot
'
})
],
{
action
:
location
.
origin
+
'
/
'
+
referenceImageURL
.
split
(
'
/
'
)[
1
]
+
// ERP5 portal
'
/Zuite_updateReferenceImage
'
,
method
:
'
POST
'
}
)
])
]).
innerHTML
],
{
type
:
'
text/html
'
}
)
);
});
}
/**
* verify that the rendering of the element `locator` matches the previously saved reference.
*
* Arguments:
* locator - an element locator
* misMatchTolerance - the percentage of mismatch allowed. If this is 0, the
* images must be exactly same. If more than 0, image will also be resized.
*/
Selenium
.
prototype
.
doVerifyImageMatchSnapshot
=
(
locator
,
misMatchTolerance
)
=>
{
// XXX this is a do* method and not a assert* method because only do* methods are
// asynchronous.
// The asynchronicity of do* method is as follow Selenium.prototype.doXXX
// returns a function and this function will be called again and again until:
// * function returns true, which means step is successfull
// * function returns false, which means step is not finished and function will be called again
// * an execption is raised, in that case the step is failed
// * global timeout is reached.
// we implement the state management with similar approach as what's discussed
// https://stackoverflow.com/questions/30564053/how-can-i-synchronously-determine-a-javascript-promises-state
var
promiseState
,
rejectionValue
,
canvasPromise
;
return
function
assertCanvasImage
()
{
if
(
promiseState
===
'
pending
'
)
{
return
false
;
}
if
(
promiseState
===
'
resolved
'
)
{
return
true
;
}
if
(
promiseState
===
'
rejected
'
)
{
Assert
.
fail
(
rejectionValue
);
}
misMatchTolerance
=
parseFloat
(
misMatchTolerance
);
if
(
isNaN
(
misMatchTolerance
))
{
misMatchTolerance
=
0
;
}
promiseState
=
'
pending
'
;
element
=
selenium
.
browserbot
.
findElement
(
locator
);
if
(
element
.
nodeName
==
'
CANVAS
'
/* instanceof HTMLCanvasElement XXX ? */
)
{
canvasPromise
=
Promise
.
resolve
(
element
);
}
else
{
canvasPromise
=
html2canvas
(
element
);
}
canvasPromise
.
then
(
canvas
=>
{
return
canvas
.
toDataURL
();
})
.
then
(
actual
=>
{
var
referenceImageURL
=
getReferenceImageURL
(
testFrame
.
getCurrentTestCase
().
pathname
);
return
fetch
(
referenceImageURL
)
.
then
(
response
=>
{
if
(
response
.
status
===
200
)
{
return
response
.
blob
();
}
throw
new
Error
(
'
Feching reference failed
'
+
response
.
statusText
);
})
.
then
(
blob
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
var
fr
=
new
FileReader
();
fr
.
onload
=
d
=>
resolve
(
fr
.
result
);
fr
.
onerror
=
reject
;
fr
.
readAsDataURL
(
blob
);
});
},
e
=>
{
// fetching reference was not found, return empty image instead, it will be different
return
document
.
createElement
(
'
canvas
'
).
toDataURL
();
}
)
.
then
(
expected
=>
{
return
new
Promise
(
resolve
=>
{
var
comparator
=
resemble
(
actual
)
.
outputSettings
({
useCrossOrigin
:
false
})
.
compareTo
(
expected
);
if
(
misMatchTolerance
>
0
)
{
comparator
=
comparator
.
scaleToSameSize
();
}
comparator
.
onComplete
(
resolve
);
});
})
.
then
(
diff
=>
{
if
(
diff
.
rawMisMatchPercentage
<=
misMatchTolerance
)
{
promiseState
=
'
resolved
'
;
}
else
{
return
generateUpdateForm
(
referenceImageURL
,
actual
).
then
(
updateReferenceImageForm
=>
{
htmlTestRunner
.
currentTest
.
currentRow
.
trElement
.
querySelector
(
'
td
'
)
.
appendChild
(
generateElement
(
'
div
'
,
[
document
.
createTextNode
(
'
Image differences:
'
),
generateElement
(
'
br
'
),
generateElement
(
'
img
'
,
[],
{
src
:
diff
.
getImageDataUrl
(),
alt
:
'
Image differences
'
}),
generateElement
(
'
br
'
),
document
.
createTextNode
(
'
Click
'
),
generateElement
(
'
a
'
,
[
document
.
createTextNode
(
'
here
'
)],
{
href
:
updateReferenceImageForm
}
),
document
.
createTextNode
(
'
to update reference snapshot.
'
)
])
);
promiseState
=
'
rejected
'
;
rejectionValue
=
'
Images are
'
+
diff
.
misMatchPercentage
+
'
% different
'
;
}
);
}
});
})
.
catch
(
error
=>
{
console
.
error
(
error
);
promiseState
=
'
rejected
'
;
rejectionValue
=
'
Error computing image differences
'
+
error
;
});
};
};
bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_echarts_js.js
View file @
578c1a32
This diff is collapsed.
Click to expand it.
bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_echarts_js.xml
View file @
578c1a32
...
...
@@ -66,9 +66,7 @@
<item>
<key>
<string>
categories
</string>
</key>
<value>
<tuple>
<string>
classification/collaborative/team
</string>
</tuple>
<tuple/>
</value>
</item>
<item>
...
...
@@ -111,7 +109,7 @@
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
001
</string>
</value>
<value>
<string>
4.1.0
</string>
</value>
</item>
<item>
<key>
<string>
workflow_history
</string>
</key>
...
...
@@ -224,7 +222,7 @@
</item>
<item>
<key>
<string>
actor
</string>
</key>
<value>
<string>
zop
e
</string>
</value>
<value>
<string>
ERP5TypeTestCas
e
</string>
</value>
</item>
<item>
<key>
<string>
comment
</string>
</key>
...
...
@@ -238,7 +236,7 @@
</item>
<item>
<key>
<string>
serial
</string>
</key>
<value>
<string>
9
61.1917.49098.19712
</string>
</value>
<value>
<string>
9
70.25572.29237.55057
</string>
</value>
</item>
<item>
<key>
<string>
state
</string>
</key>
...
...
@@ -256,8 +254,8 @@
</tuple>
<state>
<tuple>
<float>
15
04260717.22
</float>
<string>
UTC
</string>
<float>
15
37448123.64
</float>
<string>
GMT+9
</string>
</tuple>
</state>
</object>
...
...
product/Zelenium/selenium/core/TestRunner.hta
View file @
578c1a32
...
...
@@ -48,6 +48,8 @@ to work-around a bug in IE on Win2K whereby the HTA application doesn't function
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/dom.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/xpath.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/javascript-xpath-0.1.11.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"lib/resemble.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"lib/html2canvas.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"scripts/user-extensions.js"
></script>
</head>
...
...
product/Zelenium/selenium/core/TestRunner.html
View file @
578c1a32
...
...
@@ -48,6 +48,8 @@ to work-around a bug in IE on Win2K whereby the HTA application doesn't function
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/dom.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/xpath.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"xpath/javascript-xpath-0.1.11.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"lib/resemble.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"lib/html2canvas.js"
></script>
<script
language=
"JavaScript"
type=
"text/javascript"
src=
"scripts/user-extensions.js"
></script>
</head>
...
...
product/Zelenium/selenium/core/lib/html2canvas.js
0 → 100644
View file @
578c1a32
This diff is collapsed.
Click to expand it.
product/Zelenium/selenium/core/lib/resemble.js
0 → 100644
View file @
578c1a32
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment