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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
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