2023-10-13 12:32:41 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
|
|
<meta http-equiv="Expires" content="-1">
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
|
<meta content="Robot Framework 6.1.1 (Python 3.11.4 on win32)" name="Generator">
|
|
|
|
<link rel="icon" type="image/x-icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKcAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAqAAAAAAAAAAAAAAAAAAAALIAAAD/AAAA4AAAANwAAADcAAAA3AAAANwAAADcAAAA3AAAANwAAADcAAAA4AAAAP8AAACxAAAAAAAAAKYAAAD/AAAAuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/AAAA/wAAAKkAAAD6AAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN8AAAD/AAAA+gAAAMMAAAAAAAAAAgAAAGsAAABrAAAAawAAAGsAAABrAAAAawAAAGsAAABrAAAADAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAIsAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAANEAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAAAAAAAAMgAAADIAAAAyAAAAMgAAADIAAAAyAAAAMgAAADIAAAAFAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAADwAAAB8AAAAAAAAAGAAAABcAAAAAAAAAH8AAABKAAAAAAAAAAAAAAAAAAAA2gAAAP8AAAD6AAAAwwAAAAAAAADCAAAA/wAAACkAAADqAAAA4QAAAAAAAAD7AAAA/wAAALAAAAAGAAAAAAAAANoAAAD/AAAA+gAAAMMAAAAAAAAAIwAAAP4AAAD/AAAA/wAAAGAAAAAAAAAAAAAAAMkAAAD/AAAAigAAAAAAAADaAAAA/wAAAPoAAADDAAAAAAAAAAAAAAAIAAAAcAAAABkAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAA2gAAAP8AAAD7AAAAywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN4AAAD/AAAAqwAAAP8AAACvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALIAAAD/AAAAsgAAAAAAAAC5AAAA/wAAAMoAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMkAAAD/AAAAvAAAAAAAAAAAAAAAAAAAAKwAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAArQAAAAAAAAAAwAMAAIABAAAf+AAAP/wAAD/8AAAgBAAAP/wAAD/8AAA//AAAJIwAADHEAAA//AAAP/wAAB/4AACAAQAAwAMAAA==">
|
|
|
|
<style media="all" type="text/css">
|
|
|
|
/* Generic and misc styles */
|
|
|
|
body {
|
|
|
|
font-family: Helvetica, sans-serif;
|
|
|
|
font-size: 0.8em;
|
|
|
|
color: black;
|
|
|
|
padding: 6px;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
table {
|
|
|
|
table-layout: fixed;
|
|
|
|
word-wrap: break-word;
|
|
|
|
empty-cells: show;
|
|
|
|
font-size: 1em;
|
|
|
|
}
|
|
|
|
th, td {
|
|
|
|
vertical-align: top;
|
|
|
|
}
|
|
|
|
br {
|
|
|
|
mso-data-placement: same-cell; /* maintain line breaks in Excel */
|
|
|
|
}
|
|
|
|
hr {
|
|
|
|
background: #ccc;
|
|
|
|
height: 1px;
|
|
|
|
border: 0;
|
|
|
|
}
|
|
|
|
a, a:link, a:visited {
|
|
|
|
text-decoration: none;
|
|
|
|
color: #15c;
|
|
|
|
}
|
|
|
|
a > img {
|
|
|
|
border: 1px solid #15c !important;
|
|
|
|
}
|
|
|
|
a:hover, a:active {
|
|
|
|
text-decoration: underline;
|
|
|
|
color: #61c;
|
|
|
|
}
|
|
|
|
.parent-name {
|
|
|
|
font-size: 0.7em;
|
|
|
|
letter-spacing: -0.07em;
|
|
|
|
}
|
|
|
|
.message {
|
|
|
|
white-space: pre-wrap;
|
|
|
|
}
|
|
|
|
/* Headers */
|
|
|
|
#header {
|
|
|
|
width: 65em;
|
|
|
|
height: 3em;
|
|
|
|
margin: 6px 0;
|
|
|
|
}
|
|
|
|
h1 {
|
|
|
|
float: left;
|
|
|
|
margin: 0 0 0.5em 0;
|
|
|
|
width: 75%;
|
|
|
|
}
|
|
|
|
h2 {
|
|
|
|
clear: left;
|
|
|
|
}
|
|
|
|
#generated {
|
|
|
|
float: right;
|
|
|
|
text-align: right;
|
|
|
|
font-size: 0.9em;
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
|
|
|
/* Documentation headers */
|
|
|
|
.doc > h2 {
|
|
|
|
font-size: 1.2em;
|
|
|
|
}
|
|
|
|
.doc > h3 {
|
|
|
|
font-size: 1.1em;
|
|
|
|
}
|
|
|
|
.doc > h4 {
|
|
|
|
font-size: 1.0em;
|
|
|
|
}
|
|
|
|
/* Status text colors -- !important allows using them in links */
|
|
|
|
.fail {
|
|
|
|
color: #ce3e01 !important;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.pass {
|
|
|
|
color: #098a09 !important;
|
|
|
|
}
|
|
|
|
.skip {
|
|
|
|
color: #927201 !important;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.label {
|
|
|
|
padding: 2px 5px;
|
|
|
|
font-size: 0.75em;
|
|
|
|
letter-spacing: 1px;
|
|
|
|
white-space: nowrap;
|
|
|
|
color: black;
|
|
|
|
background-color: #ddd;
|
|
|
|
border-radius: 3px;
|
|
|
|
}
|
|
|
|
.label.debug, .label.trace, .label.error, .label.keyword {
|
|
|
|
letter-spacing: 0;
|
|
|
|
}
|
|
|
|
.label.pass, .label.fail, .label.error, .label.skip, .label.warn {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.label.pass {
|
|
|
|
background-color: #97bd61;
|
|
|
|
color: #000 !important;
|
|
|
|
}
|
|
|
|
.label.fail, .label.error {
|
|
|
|
background-color: #ce3e01;
|
|
|
|
color: #fff !important;
|
|
|
|
}
|
|
|
|
.label.skip, .label.warn {
|
|
|
|
background-color: #fed84f;
|
|
|
|
color: #000 !important;
|
|
|
|
}
|
|
|
|
/* Top right header */
|
|
|
|
#top-right-header {
|
|
|
|
position: fixed;
|
|
|
|
top: 0;
|
|
|
|
right: 0;
|
|
|
|
z-index: 1000;
|
|
|
|
width: 12em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
#report-or-log-link a {
|
|
|
|
display: block;
|
|
|
|
background: black;
|
|
|
|
color: white;
|
|
|
|
text-decoration: none;
|
|
|
|
font-weight: bold;
|
|
|
|
letter-spacing: 0.1em;
|
|
|
|
padding: 0.3em 0;
|
|
|
|
border-bottom-left-radius: 4px;
|
|
|
|
}
|
|
|
|
#report-or-log-link a:hover {
|
|
|
|
color: #ddd;
|
|
|
|
}
|
|
|
|
#log-level-selector {
|
|
|
|
padding: 0.3em 0;
|
|
|
|
font-size: 0.9em;
|
|
|
|
border-bottom-left-radius: 4px;
|
|
|
|
background: #ddd;
|
|
|
|
}
|
|
|
|
/* Statistics table */
|
|
|
|
.statistics {
|
|
|
|
width: 65em;
|
|
|
|
border-collapse: collapse;
|
|
|
|
empty-cells: show;
|
|
|
|
margin-bottom: 1em;
|
|
|
|
}
|
|
|
|
.statistics tr:hover {
|
|
|
|
background: #f4f4f4;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.statistics th, .statistics td {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
padding: 0.1em 0.3em;
|
|
|
|
}
|
|
|
|
.statistics th {
|
|
|
|
background-color: #ddd;
|
|
|
|
padding: 0.2em 0.3em;
|
|
|
|
}
|
|
|
|
.statistics td {
|
|
|
|
vertical-align: middle;
|
|
|
|
}
|
|
|
|
.stats-col-stat {
|
|
|
|
width: 4.5em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.stats-col-elapsed {
|
|
|
|
width: 5.5em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.stats-col-graph {
|
|
|
|
width: 9em;
|
|
|
|
}
|
|
|
|
th.stats-col-graph:hover {
|
|
|
|
cursor: default;
|
|
|
|
}
|
|
|
|
.stat-name {
|
|
|
|
float: left;
|
|
|
|
}
|
|
|
|
.stat-name a, .stat-name span {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.tag-links {
|
|
|
|
font-size: 0.9em;
|
|
|
|
float: right;
|
|
|
|
margin-top: 0.05em;
|
|
|
|
}
|
|
|
|
.tag-links span {
|
|
|
|
margin-left: 0.2em;
|
|
|
|
}
|
|
|
|
/* Statistics graph */
|
|
|
|
.graph, .empty-graph {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
width: auto;
|
|
|
|
height: 7px;
|
|
|
|
padding: 0;
|
|
|
|
background: #aaa;
|
|
|
|
}
|
|
|
|
.empty-graph {
|
|
|
|
background: #eee;
|
|
|
|
}
|
|
|
|
.pass-bar, .fail-bar, .skip-bar {
|
|
|
|
float: left;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
.fail-bar {
|
|
|
|
background: #ce3e01;
|
|
|
|
}
|
|
|
|
.pass-bar {
|
|
|
|
background: #97bd61;
|
|
|
|
}
|
|
|
|
.skip-bar {
|
|
|
|
background: #fed84f;
|
|
|
|
}
|
|
|
|
/* Tablesorter - adapted from provided Blue Skin */
|
|
|
|
.tablesorter-header {
|
|
|
|
background-image: url(data:image/gif;base64,R0lGODlhCwAJAIAAAH9/fwAAACH5BAEAAAEALAAAAAALAAkAAAIRjAOnBr3cnIr0WUjTrC9e9BQAOw==);
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
background-position: center right;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.tablesorter-header:hover {
|
|
|
|
background-color: #ccc;
|
|
|
|
}
|
|
|
|
.tablesorter-headerAsc {
|
|
|
|
background-image: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlBWnFr3cnIr0WQOyBmvzp13CpxQAOw==);
|
|
|
|
background-color: #ccc !important;
|
|
|
|
}
|
|
|
|
.tablesorter-headerDesc {
|
|
|
|
background-image: url(data:image/gif;base64,R0lGODlhCwAJAKEAAAAAAH9/fwAAAAAAACH5BAEAAAIALAAAAAALAAkAAAIUlAWnBr3cnIr0WROyDmvzp13CpxQAOw==);
|
|
|
|
background-color: #ccc !important;
|
|
|
|
}
|
|
|
|
.sorter-false {
|
|
|
|
background-image: none;
|
|
|
|
cursor: default;
|
|
|
|
}
|
|
|
|
.sorter-false:hover {
|
|
|
|
background-color: #ddd;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<style media="all" type="text/css">
|
|
|
|
/* Generic table styles */
|
|
|
|
table {
|
|
|
|
margin: 0 1px;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
tr {
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
th {
|
|
|
|
background: #ddd;
|
|
|
|
color: black;
|
|
|
|
}
|
|
|
|
/* Summary and total/tag/suite details */
|
|
|
|
.details {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
border-spacing: 0.2em;
|
|
|
|
clear: both;
|
|
|
|
width: 65em;
|
|
|
|
margin-bottom: 1em;
|
|
|
|
}
|
|
|
|
.details th {
|
|
|
|
background: white;
|
|
|
|
width: 11em;
|
|
|
|
text-align: left;
|
|
|
|
vertical-align: top;
|
|
|
|
}
|
|
|
|
.details td {
|
|
|
|
vertical-align: top;
|
|
|
|
}
|
|
|
|
.selector th, .selector td {
|
|
|
|
padding-top: 0.5em;
|
|
|
|
padding-bottom: 0.5em;
|
|
|
|
white-space: normal;
|
|
|
|
}
|
|
|
|
.first-selector th, .first-selector td{
|
|
|
|
padding-bottom: 0.2em;
|
|
|
|
}
|
|
|
|
.middle-selector th, .middle-selector td {
|
|
|
|
padding-top: 0.2em;
|
|
|
|
padding-bottom: 0.2em;
|
|
|
|
}
|
|
|
|
.last-selector th, .last-selector td{
|
|
|
|
padding-top: 0.2em;
|
|
|
|
}
|
|
|
|
#print-selector {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
/* Search */
|
|
|
|
#search-suite, #search-test, #search-include, #search-exclude {
|
|
|
|
width: 25em;
|
|
|
|
}
|
|
|
|
#search a:hover {
|
|
|
|
text-decoration: none;
|
|
|
|
}
|
|
|
|
#search-help div {
|
|
|
|
margin: 0.5em 0.5em 0.7em 0;
|
|
|
|
padding: 0.7em;
|
|
|
|
background: #eee;
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
border-radius: 3px;
|
|
|
|
}
|
|
|
|
#search-help h3, #search-help p {
|
|
|
|
margin: 0 0 0.7em 0;
|
|
|
|
}
|
|
|
|
.search-help-examples {
|
|
|
|
table-layout: auto;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
.search-help-examples, .search-help-examples tr,
|
|
|
|
.search-help-examples th, .search-help-examples td {
|
|
|
|
background: transparent;
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
.search-help-examples th, .search-help-examples td {
|
|
|
|
padding: 0.2em 0.7em 0.2em 0;
|
|
|
|
}
|
|
|
|
.help-item {
|
|
|
|
width: 10%;
|
|
|
|
}
|
|
|
|
.help-explanation {
|
|
|
|
width: 65%;
|
|
|
|
}
|
|
|
|
.help-examples {
|
|
|
|
width: 25%;
|
|
|
|
}
|
|
|
|
/* Tabs - adapted from http://www.htmldog.com/articles/tabs */
|
|
|
|
#detail-tabs {
|
|
|
|
list-style: none;
|
|
|
|
padding: 0;
|
|
|
|
margin: 0 1em;
|
|
|
|
}
|
|
|
|
.detail-tab {
|
|
|
|
float: left;
|
|
|
|
background: #ddd;
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
border-bottom-width: 0;
|
|
|
|
margin: 0 0.5em 0 0;
|
|
|
|
padding-top: 0.1em;
|
|
|
|
border-radius: 3px 3px 0 0;
|
|
|
|
}
|
|
|
|
.detail-tab:hover {
|
|
|
|
background: #ccc;
|
|
|
|
}
|
|
|
|
.detail-tab a {
|
|
|
|
color: black;
|
|
|
|
text-decoration: none;
|
|
|
|
font-weight: bold;
|
|
|
|
padding: 0 1em;
|
|
|
|
}
|
|
|
|
.detail-tab-selected {
|
|
|
|
position: relative;
|
|
|
|
top: 1px;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
.detail-tab-selected:hover {
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
/* Test details table */
|
|
|
|
#test-details {
|
|
|
|
width: 100%;
|
|
|
|
border-spacing: 1px;
|
|
|
|
background-color: #ccc;
|
|
|
|
}
|
|
|
|
#test-details > tbody > tr:hover {
|
|
|
|
background: #f4f4f4;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
#test-details th, #test-details td {
|
|
|
|
padding: 0.2em;
|
|
|
|
}
|
|
|
|
.details-limited {
|
|
|
|
max-height: 20em;
|
|
|
|
overflow: auto;
|
|
|
|
}
|
|
|
|
.details-col-header {
|
|
|
|
padding-right: 1em;
|
|
|
|
}
|
|
|
|
.details-col-toggle {
|
|
|
|
float: left;
|
|
|
|
color: #6c6c6c; /* same as in sort icon */
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.details-col-toggle:hover {
|
|
|
|
color: black;
|
|
|
|
}
|
|
|
|
.details-col-name {
|
|
|
|
min-width: 20em;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.details-col-doc {
|
|
|
|
min-width: 10em;
|
|
|
|
}
|
|
|
|
.details-col-tags {
|
|
|
|
min-width: 10em;
|
|
|
|
}
|
|
|
|
.details-col-crit {
|
|
|
|
width: 3.5em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.details-col-status {
|
|
|
|
width: 4.5em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.details-col-msg {
|
|
|
|
min-width: 20em;
|
|
|
|
}
|
|
|
|
.details-col-elapsed {
|
|
|
|
width: 7em;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.details-col-times {
|
|
|
|
width: 11em;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
.hidden .details-col-header, td.hidden > div {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
.hidden {
|
|
|
|
width: 13px;
|
|
|
|
min-width: 0;
|
|
|
|
background-image: none;
|
|
|
|
}
|
|
|
|
th.hidden:hover {
|
|
|
|
background-color: #ccc;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<style media="print" type="text/css">
|
|
|
|
body {
|
|
|
|
background: white !important;
|
|
|
|
padding: 0;
|
|
|
|
font-size: 8pt;
|
|
|
|
}
|
|
|
|
a:link, a:visited {
|
|
|
|
color: black;
|
|
|
|
}
|
|
|
|
#header {
|
|
|
|
width: auto;
|
|
|
|
}
|
|
|
|
.details, .statistics {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
#generated-ago, #top-right-header, #normal-selector, #search-buttons,
|
|
|
|
.folding-button, .expand, .hidden, .details-col-toggle {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
.element-header-text, .children {
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
#test-details {
|
|
|
|
border-collapse: collapse;
|
|
|
|
background: white;
|
|
|
|
}
|
|
|
|
#test-details th, #test-details td {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
}
|
|
|
|
.details-col-header {
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
#print-selector {
|
|
|
|
display: table-cell;
|
|
|
|
}
|
|
|
|
.tablesorter-header {
|
|
|
|
background-image: none;
|
|
|
|
background: #ddd !important;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<style media="all" type="text/css">
|
|
|
|
#javascript-disabled {
|
|
|
|
width: 600px;
|
|
|
|
margin: 100px auto 0 auto;
|
|
|
|
padding: 20px;
|
|
|
|
color: black;
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
background: #eee;
|
|
|
|
}
|
|
|
|
#javascript-disabled h1 {
|
|
|
|
width: 100%;
|
|
|
|
float: none;
|
|
|
|
}
|
|
|
|
#javascript-disabled ul {
|
|
|
|
font-size: 1.2em;
|
|
|
|
}
|
|
|
|
#javascript-disabled li {
|
|
|
|
margin: 0.5em 0;
|
|
|
|
}
|
|
|
|
#javascript-disabled b {
|
|
|
|
font-style: italic;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<style media="all" type="text/css">
|
|
|
|
.doc > * {
|
|
|
|
margin: 0.7em 1em 0.1em 1em;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
.doc > p, .doc > h1, .doc > h2, .doc > h3, .doc > h4 {
|
|
|
|
margin: 0.7em 0 0.1em 0;
|
|
|
|
}
|
|
|
|
.doc > *:first-child {
|
|
|
|
margin-top: 0.1em;
|
|
|
|
}
|
|
|
|
.doc table {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
background: transparent;
|
|
|
|
border-collapse: collapse;
|
|
|
|
empty-cells: show;
|
|
|
|
font-size: 0.9em;
|
|
|
|
}
|
|
|
|
.doc table th, .doc table td {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
background: transparent;
|
|
|
|
padding: 0.1em 0.3em;
|
|
|
|
height: 1.2em;
|
|
|
|
}
|
|
|
|
.doc table th {
|
|
|
|
text-align: center;
|
|
|
|
letter-spacing: 0.1em;
|
|
|
|
}
|
|
|
|
.doc pre {
|
|
|
|
font-size: 1.1em;
|
|
|
|
letter-spacing: 0.05em;
|
|
|
|
background: #f4f4f4;
|
|
|
|
}
|
|
|
|
.doc code {
|
|
|
|
padding: 0 0.2em;
|
|
|
|
letter-spacing: 0.05em;
|
|
|
|
background: #eee;
|
|
|
|
}
|
|
|
|
.doc li {
|
|
|
|
list-style-position: inside;
|
|
|
|
list-style-type: square;
|
|
|
|
}
|
|
|
|
.doc img {
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
}
|
|
|
|
.doc hr {
|
|
|
|
background: #ccc;
|
|
|
|
height: 1px;
|
|
|
|
border: 0;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
<script type="text/javascript">
|
|
|
|
/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */
|
|
|
|
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
/*
|
|
|
|
* jQuery Templates Plugin 1.0.0pre
|
|
|
|
* http://github.com/jquery/jquery-tmpl
|
|
|
|
* Requires jQuery 1.4.2
|
|
|
|
*
|
|
|
|
* Copyright Software Freedom Conservancy, Inc.
|
|
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
|
|
* http://jquery.org/license
|
|
|
|
*/
|
|
|
|
(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(e){"use strict";var t=e.tablesorter={version:"2.30.5",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssIconDisabled:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(r,o){if(r&&r.tHead&&0!==r.tBodies.length&&!0!==r.hasInitialized){var s="",a=e(r),n=e.metadata;r.hasInitialized=!1,r.isProcessing=!0,r.config=o,e.data(r,"tablesorter",o),t.debug(o,"core")&&(console[console.group?"group":"log"]("Initializing tablesorter v"+t.version),e.data(r,"startoveralltimer",new Date)),o.supportsDataObject=function(e){return e[0]=parseInt(e[0],10),e[0]>1||1===e[0]&&parseInt(e[1],10)>=4}(e.fn.jquery.split(".")),o.emptyTo=o.emptyTo.toLowerCase(),o.stringTo=o.stringTo.toLowerCase(),o.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(a.attr("class"))||(s=""!==o.theme?" tablesorter-"+o.theme:""),o.namespace?o.namespace="."+o.namespace.replace(t.regex.nonWord,""):o.namespace=".tablesorter"+Math.random().toString(16).slice(2),o.table=r,o.$table=a.addClass(t.css.table+" "+o.tableClass+s+" "+o.namespace.slice(1)).attr("role","grid"),o.$headers=a.find(o.selectorHeaders),o.$table.children().children("tr").attr("role","row"),o.$tbodies=a.children("tbody:not(."+o.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),o.$table.children("caption").length&&((s=o.$table.children("caption")[0]).id||(s.id=o.namespace.slice(1)+"caption"),o.$table.attr("aria-labelledby",s.id)),o.widgetInit={},o.textExtraction=o.$table.attr("data-text-extraction")||o.textExtraction||"basic
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
/*
|
|
|
|
Copyright 2008-2013
|
|
|
|
Matthias Ehmann,
|
|
|
|
Michael Gerhaeuser,
|
|
|
|
Carsten Miller,
|
|
|
|
Bianca Valentin,
|
|
|
|
Alfred Wassermann,
|
|
|
|
Peter Wilfahrt
|
|
|
|
Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with JSXCompressor. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
You should have received a copy of the Apache License along with JSXCompressor.
|
|
|
|
If not, see <http://www.apache.org/licenses/>.
|
|
|
|
*/
|
|
|
|
(function(){var e,r,n;(function(t){function o(e,r){return C.call(e,r)}function i(e,r){var n,t,o,i,a,u,c,f,s,l,p=r&&r.split("/"),h=k.map,d=h&&h["*"]||{};if(e&&"."===e.charAt(0))if(r){for(p=p.slice(0,p.length-1),e=p.concat(e.split("/")),f=0;e.length>f;f+=1)if(l=e[f],"."===l)e.splice(f,1),f-=1;else if(".."===l){if(1===f&&(".."===e[2]||".."===e[0]))break;f>0&&(e.splice(f-1,2),f-=2)}e=e.join("/")}else 0===e.indexOf("./")&&(e=e.substring(2));if((p||d)&&h){for(n=e.split("/"),f=n.length;f>0;f-=1){if(t=n.slice(0,f).join("/"),p)for(s=p.length;s>0;s-=1)if(o=h[p.slice(0,s).join("/")],o&&(o=o[t])){i=o,a=f;break}if(i)break;!u&&d&&d[t]&&(u=d[t],c=f)}!i&&u&&(i=u,a=c),i&&(n.splice(0,a,i),e=n.join("/"))}return e}function a(e,r){return function(){return h.apply(t,v.call(arguments,0).concat([e,r]))}}function u(e){return function(r){return i(r,e)}}function c(e){return function(r){b[e]=r}}function f(e){if(o(m,e)){var r=m[e];delete m[e],y[e]=!0,p.apply(t,r)}if(!o(b,e)&&!o(y,e))throw Error("No "+e);return b[e]}function s(e){var r,n=e?e.indexOf("!"):-1;return n>-1&&(r=e.substring(0,n),e=e.substring(n+1,e.length)),[r,e]}function l(e){return function(){return k&&k.config&&k.config[e]||{}}}var p,h,d,g,b={},m={},k={},y={},C=Object.prototype.hasOwnProperty,v=[].slice;d=function(e,r){var n,t=s(e),o=t[0];return e=t[1],o&&(o=i(o,r),n=f(o)),o?e=n&&n.normalize?n.normalize(e,u(r)):i(e,r):(e=i(e,r),t=s(e),o=t[0],e=t[1],o&&(n=f(o))),{f:o?o+"!"+e:e,n:e,pr:o,p:n}},g={require:function(e){return a(e)},exports:function(e){var r=b[e];return r!==void 0?r:b[e]={}},module:function(e){return{id:e,uri:"",exports:b[e],config:l(e)}}},p=function(e,r,n,i){var u,s,l,p,h,k,C=[];if(i=i||e,"function"==typeof n){for(r=!r.length&&n.length?["require","exports","module"]:r,h=0;r.length>h;h+=1)if(p=d(r[h],i),s=p.f,"require"===s)C[h]=g.require(e);else if("exports"===s)C[h]=g.exports(e),k=!0;else if("module"===s)u=C[h]=g.module(e);else if(o(b,s)||o(m,s)||o(y,s))C[h]=f(s);else{if(!p.p)throw Error(e+" missing "+s);p.p.load(p.n,a(i,!0),c(s),{}),C[h]=b[s]}l=n.apply(b[e],C),e&&(u&&u.exports!==t&&u.exports!==b[e]?b[e]=u.exports:l===t&&k||(b[e]=l))}else e&&(b[e]=n)},e=r=h=function(e,r,n,o,i){return"string"==typeof e?g[e]?g[e](r):f(d(e,r).f):(e.splice||(k=e,r.splice?(e=r,r=n,n=null):e=t),r=r||function(){},"function"==typeof n&&(n=o,o=i),o?p(t,e,r,n):setTimeout(function(){p(t,e,r,n)},4),h)},h.config=function(e){return k=e,k.deps&&h(k.deps,k.callback),h},n=function(e,r,n){r.splice||(n=r,r=[]),o(b,e)||o(m,e)||(m[e]=[e,r,n])},n.amd={jQuery:!0}})(),n("../node_modules/almond/almond",function(){}),n("jxg",[],function(){var e={};return"object"!=typeof JXG||JXG.extend||(e=JXG),e.extend=function(e,r,n,t){var o,i;n=n||!1,t=t||!1;for(o in r)(!n||n&&r.hasOwnProperty(o))&&(i=t?o.toLowerCase():o,e[i]=r[o])},e.extend(e,{boards:{},readers:{},elements:{},registerElement:function(e,r){e=e.toLowerCase(),this.elements[e]=r},registerReader:function(e,r){var n,t;for(n=0;r.length>n;n++)t=r[n].toLowerCase(),"function"!=typeof this.readers[t]&&(this.readers[t]=e)},shortcut:function(e,r){return function(){return e[r].apply(this,arguments)}},getRef:function(e,r){return e.select(r)},getReference:function(e,r){return e.select(r)},debugInt:function(){var e,r;for(e=0;arguments.length>e;e++)r=arguments[e],"object"==typeof window&&window.console&&console.log?console.log(r):"object"==typeof document&&document.getElementById("debug")&&(document.getElementById("debug").innerHTML+=r+"<br/>")},debugWST:function(){var r=Error();e.debugInt.apply(this,arguments),r&&r.stack&&(e.debugInt("stacktrace"),e.debugInt(r.stack.split("\n").slice(1).join("\n")))},debugLine:function(){var r=Error();e.debugInt.apply(this,arguments),r&&r.stack&&e.debugInt("Called from",r.stack.split("\n").slice(2,3).join("\n"))},debug:function(){e.debugInt.apply(this,arguments)}}),e}),n("utils/zip",["jxg"],function(e){var r=[0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.fileLoading = (function () {
|
|
|
|
var fileLoadingCallbacks = {};
|
|
|
|
var timestamp = new Date().getTime();
|
|
|
|
function loadKeywordsFile(filename, callback) {
|
|
|
|
fileLoadingCallbacks[filename] = callback;
|
|
|
|
var script = document.createElement('script');
|
|
|
|
script.type = 'text/javascript';
|
|
|
|
// timestamp as an argument to prevent browsers from caching scripts
|
|
|
|
// see: http://stackoverflow.com/questions/866619/how-to-force-ie-to-reload-javascript
|
|
|
|
script.src = filename+'?time='+timestamp;
|
|
|
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|
|
|
}
|
|
|
|
function getCallbackHandlerForKeywords(parent) {
|
|
|
|
var callableList = [];
|
|
|
|
return function (callable) {
|
|
|
|
if (!parent.isChildrenLoaded) {
|
|
|
|
callableList.push(callable);
|
|
|
|
if (callableList.length == 1) {
|
|
|
|
loadKeywordsFile(parent.childFileName, function () {
|
|
|
|
parent.isChildrenLoaded = true;
|
|
|
|
for (var i = 0; i < callableList.length; i++) {
|
|
|
|
callableList[i]();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
callable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function notifyFileLoaded(filename) {
|
|
|
|
fileLoadingCallbacks[filename]();
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
getCallbackHandlerForKeywords: getCallbackHandlerForKeywords,
|
|
|
|
notify: notifyFileLoaded
|
|
|
|
}
|
|
|
|
}());
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.model = (function () {
|
|
|
|
function Suite(data) {
|
|
|
|
var suite = createModelObject(data);
|
|
|
|
suite.source = data.source;
|
|
|
|
suite.relativeSource = data.relativeSource;
|
|
|
|
suite.fullName = data.parent ? data.parent.fullName + '.' + data.name : data.name;
|
|
|
|
suite.type = 'suite';
|
|
|
|
suite.template = 'suiteTemplate';
|
|
|
|
setStats(suite, data.statistics);
|
|
|
|
suite.metadata = data.metadata;
|
|
|
|
suite.populateKeywords = createIterablePopulator('Keyword');
|
|
|
|
suite.populateTests = createIterablePopulator('Test');
|
|
|
|
suite.populateSuites = createIterablePopulator('Suite');
|
|
|
|
suite.childrenNames = ['keyword', 'suite', 'test'];
|
|
|
|
suite.callWhenChildrenReady = function (callable) { callable(); };
|
|
|
|
suite.message = data.message;
|
|
|
|
suite.children = function () {
|
|
|
|
return suite.keywords().concat(suite.tests()).concat(suite.suites());
|
|
|
|
};
|
|
|
|
suite.searchTests = function (predicate) {
|
|
|
|
var tests = [];
|
|
|
|
var suites = this.suites();
|
|
|
|
for (var i in suites)
|
|
|
|
tests = tests.concat(suites[i].searchTests(predicate));
|
|
|
|
return tests.concat(util.filter(this.tests(), predicate));
|
|
|
|
};
|
|
|
|
suite.searchTestsInSuite = function (pattern, matcher) {
|
|
|
|
if (!matcher)
|
|
|
|
matcher = util.Matcher(pattern);
|
|
|
|
if (matcher.matchesAny([suite.fullName, suite.name]))
|
|
|
|
return suite.allTests();
|
|
|
|
var tests = [];
|
|
|
|
var suites = this.suites();
|
|
|
|
for (var i in suites)
|
|
|
|
tests = tests.concat(suites[i].searchTestsInSuite(pattern, matcher));
|
|
|
|
return tests;
|
|
|
|
};
|
|
|
|
suite.searchTestsByTag = function (tag) {
|
|
|
|
return suite.searchTests(function (test) {
|
|
|
|
if (tag.combined)
|
|
|
|
return containsTagPattern(test.tags, tag.combined);
|
|
|
|
return containsTag(test.tags, tag.label);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
suite.findSuiteByName = function (name) {
|
|
|
|
return findSuiteByName(suite, name);
|
|
|
|
};
|
|
|
|
suite.allTests = function () {
|
|
|
|
return suite.searchTests(function (test) {
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
return suite;
|
|
|
|
}
|
|
|
|
function containsTag(testTags, tagname) {
|
|
|
|
testTags = util.map(testTags, util.normalize);
|
|
|
|
return util.contains(testTags, util.normalize(tagname));
|
|
|
|
}
|
|
|
|
function containsTagPattern(testTags, pattern) {
|
|
|
|
var patterns;
|
|
|
|
if (pattern.indexOf('NOT') != -1) {
|
|
|
|
patterns = pattern.split('NOT');
|
|
|
|
if (!util.normalize(patterns[0]))
|
|
|
|
return util.all(util.map(patterns.slice(1), function (p) {
|
|
|
|
return !containsTagPattern(testTags, p);
|
|
|
|
}));
|
|
|
|
return containsTagPattern(testTags, patterns[0]) &&
|
|
|
|
util.all(util.map(patterns.slice(1), function (p) {
|
|
|
|
return !containsTagPattern(testTags, p);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
if (pattern.indexOf('OR') != -1) {
|
|
|
|
patterns = pattern.split('OR');
|
|
|
|
return util.any(util.map(patterns, function (p) {
|
|
|
|
return containsTagPattern(testTags, p);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
if (pattern.indexOf('AND') != -1) {
|
|
|
|
patterns = pattern.split('AND');
|
|
|
|
return util.all(util.map(patterns, function (p) {
|
|
|
|
return containsTagPattern(testTags, p);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
return util.Matcher(pattern).matchesAny(testTags);
|
|
|
|
}
|
|
|
|
function findSuiteByName(suite, name) {
|
|
|
|
if (suite.fullName == name)
|
|
|
|
return suite;
|
|
|
|
var subSuites = suite.suites();
|
|
|
|
for (var i in subSuites) {
|
|
|
|
var match = findSuiteByName(subSuites[i], name);
|
|
|
|
if (match)
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
function setStats(suite, stats) {
|
|
|
|
for (var name in stats) {
|
|
|
|
suite[name] = stats[name];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function createModelObject(data) {
|
|
|
|
return {
|
|
|
|
name: data.name,
|
|
|
|
doc: data.doc,
|
|
|
|
status: data.status,
|
|
|
|
times: data.times,
|
|
|
|
id: data.parent ? data.parent.id + '-' + data.id : data.id
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function Test(data) {
|
|
|
|
var test = createModelObject(data);
|
|
|
|
test.type = 'test';
|
|
|
|
test.template = 'testTemplate';
|
|
|
|
test.fullName = data.parent.fullName + '.' + test.name;
|
|
|
|
test.formatParentName = function () { return util.formatParentName(test); };
|
|
|
|
test.timeout = data.timeout;
|
|
|
|
test.populateKeywords = createIterablePopulator('Keyword');
|
|
|
|
test.childrenNames = ['keyword'];
|
|
|
|
test.isChildrenLoaded = data.isChildrenLoaded;
|
|
|
|
test.callWhenChildrenReady = window.fileLoading.getCallbackHandlerForKeywords(test);
|
|
|
|
test.children = function () {
|
|
|
|
if (test.isChildrenLoaded)
|
|
|
|
return test.keywords();
|
|
|
|
};
|
|
|
|
test.tags = data.tags;
|
|
|
|
test.message = data.message;
|
|
|
|
test.matchesTagPattern = function (pattern) {
|
|
|
|
return containsTagPattern(test.tags, pattern);
|
|
|
|
};
|
|
|
|
test.matchesNamePattern = function (pattern) {
|
|
|
|
return util.Matcher(pattern).matchesAny([test.name, test.fullName]);
|
|
|
|
};
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
function Keyword(data) {
|
|
|
|
var kw = createModelObject(data);
|
|
|
|
var flatTypes = ['RETURN', 'BREAK', 'CONTINUE'];
|
|
|
|
kw.libname = data.libname;
|
|
|
|
kw.fullName = (kw.libname ? kw.libname + '.' : '') + kw.name;
|
|
|
|
kw.type = data.type;
|
|
|
|
kw.template = 'keywordTemplate';
|
|
|
|
kw.arguments = data.args;
|
|
|
|
kw.assign = data.assign + (data.assign ? ' =' : '');
|
|
|
|
kw.tags = data.tags;
|
|
|
|
kw.timeout = data.timeout;
|
|
|
|
kw.populateKeywords = createIterablePopulator('Keyword');
|
|
|
|
kw.childrenNames = ['keyword'];
|
|
|
|
kw.isChildrenLoaded = data.isChildrenLoaded;
|
|
|
|
kw.callWhenChildrenReady = window.fileLoading.getCallbackHandlerForKeywords(kw);
|
|
|
|
kw.children = function () {
|
|
|
|
if (kw.isChildrenLoaded)
|
|
|
|
return kw.keywords();
|
|
|
|
};
|
|
|
|
return kw;
|
|
|
|
}
|
|
|
|
function Message(level, date, text, link) {
|
|
|
|
var message = {
|
|
|
|
type: 'message',
|
|
|
|
template: 'messageTemplate',
|
|
|
|
level: level,
|
|
|
|
time: util.timeFromDate(date),
|
|
|
|
date: util.dateFromDate(date),
|
|
|
|
text: text,
|
|
|
|
link: link
|
|
|
|
};
|
|
|
|
message.callWhenChildrenReady = function (callable) { callable(); };
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
function Times(timedata) {
|
|
|
|
var start = timedata[0];
|
|
|
|
var end = timedata[1];
|
|
|
|
var elapsed = timedata[2];
|
|
|
|
return {
|
|
|
|
elapsedMillis: elapsed,
|
|
|
|
elapsedTime: util.formatElapsed(elapsed),
|
|
|
|
startTime: util.dateTimeFromDate(start),
|
|
|
|
endTime: util.dateTimeFromDate(end)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function createIterablePopulator(name) {
|
|
|
|
return function (populator) {
|
|
|
|
populateIterable(this, name, populator);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function populateIterable(obj, name, populator) {
|
|
|
|
name = name.toLowerCase() + 's';
|
|
|
|
obj[name] = createGetAllFunction(populator.numberOfItems, populator.creator);
|
|
|
|
}
|
|
|
|
function createGetAllFunction(numberOfElements, creator) {
|
|
|
|
var cached = null;
|
|
|
|
return function () {
|
|
|
|
if (cached === null) {
|
|
|
|
cached = [];
|
|
|
|
for (var i = 0; i < numberOfElements(); i++) {
|
|
|
|
cached.push(creator(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cached;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
Suite: Suite,
|
|
|
|
Test: Test,
|
|
|
|
Keyword: Keyword,
|
|
|
|
Message: Message,
|
|
|
|
Times: Times,
|
|
|
|
containsTag: containsTag, // Exposed for tests
|
|
|
|
containsTagPattern: containsTagPattern // Exposed for tests
|
|
|
|
};
|
|
|
|
}());
|
|
|
|
window.stats = (function () {
|
|
|
|
function Statistics(totalElems, tagElems, suiteElems) {
|
|
|
|
return {total: util.map(totalElems, totalStatElem),
|
|
|
|
tag: util.map(tagElems, tagStatElem),
|
|
|
|
suite: util.map(suiteElems, suiteStatElem)};
|
|
|
|
}
|
|
|
|
function statElem(stat) {
|
|
|
|
stat.total = stat.pass + stat.fail + stat.skip;
|
|
|
|
var percents = calculatePercents(stat.total, stat.pass, stat.fail, stat.skip);
|
|
|
|
stat.passPercent = percents[0];
|
|
|
|
stat.skipPercent = percents[1];
|
|
|
|
stat.failPercent = percents[2];
|
|
|
|
var widths = calculateWidths(stat.passPercent, stat.skipPercent, stat.failPercent);
|
|
|
|
stat.passWidth = widths[0];
|
|
|
|
stat.skipWidth = widths[1];
|
|
|
|
stat.failWidth = widths[2];
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
function totalStatElem(data) {
|
|
|
|
var stat = statElem(data);
|
|
|
|
stat.type = 'all';
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
function tagStatElem(data) {
|
|
|
|
var stat = statElem(data);
|
|
|
|
stat.links = parseLinks(stat.links);
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
function suiteStatElem(data) {
|
|
|
|
var stat = statElem(data);
|
|
|
|
stat.fullName = stat.label;
|
|
|
|
stat.formatParentName = function () { return util.formatParentName(stat); };
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
function parseLinks(linksData) {
|
|
|
|
if (!linksData)
|
|
|
|
return [];
|
|
|
|
return util.map(linksData.split(':::'), function (link) {
|
|
|
|
var index = link.indexOf(':');
|
|
|
|
return {title: link.slice(0, index), url: link.slice(index+1)};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function calculatePercents(total, passed, failed, skipped) {
|
|
|
|
if (total == 0) {
|
|
|
|
return [0.0, 0.0, 0.0];
|
|
|
|
}
|
|
|
|
var pass = 100.0 * passed / total;
|
|
|
|
var skip = 100.0 * skipped / total;
|
|
|
|
var fail = 100.0 * failed / total;
|
|
|
|
if (pass > 0 && pass < 0.1)
|
|
|
|
pass = 0.1
|
|
|
|
if (fail > 0 && fail < 0.1)
|
|
|
|
fail = 0.1
|
|
|
|
if (skip > 0 && skip < 0.1)
|
|
|
|
skip = 0.1
|
|
|
|
if (pass > 99.95 && pass < 100)
|
|
|
|
pass = 99.9
|
|
|
|
if (fail > 99.95 && fail < 100)
|
|
|
|
fail = 99.9
|
|
|
|
if (skip > 99.95 && skip < 100)
|
|
|
|
skip = 99.9
|
|
|
|
return [Math.round(pass*10)/10, Math.round(skip*10)/10, Math.round(fail*10)/10];
|
|
|
|
}
|
|
|
|
function calculateWidths(num1, num2, num3) {
|
|
|
|
if (num1 + num2 + num3 === 0)
|
|
|
|
return [0.0, 0.0, 0.0];
|
|
|
|
// Make small percentages better visible
|
|
|
|
if (num1 > 0 && num1 < 1)
|
|
|
|
num1 = 1
|
|
|
|
if (num2 > 0 && num2 < 1)
|
|
|
|
num2 = 1
|
|
|
|
if (num3 > 0 && num3 < 1)
|
|
|
|
num3 = 1
|
|
|
|
// Handle situation where some are rounded up
|
|
|
|
while (num1 + num2 + num3 > 100) {
|
|
|
|
if (num1 > num2 && num1 > num3)
|
|
|
|
num1 -= 0.1;
|
|
|
|
else if (num2 > num1 && num2 > num3)
|
|
|
|
num2 -= 0.1;
|
|
|
|
else if (num3 > num1 && num3 > num2)
|
|
|
|
num3 -= 0.1;
|
|
|
|
else if (num1 > num3 && num1 == num2) {
|
|
|
|
num1 -= 0.1;
|
|
|
|
num2 -= 0.1;
|
|
|
|
}
|
|
|
|
else if (num1 > num2 && num1 == num3) {
|
|
|
|
num1 -= 0.1;
|
|
|
|
num3 -= 0.1;
|
|
|
|
}
|
|
|
|
else if (num2 > num1 && num2 == num3) {
|
|
|
|
num2 -= 0.1;
|
|
|
|
num3 -= 0.1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [Math.ceil(num1*10)/10, Math.ceil(num2*10)/10, Math.ceil(num3*10)/10];
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
Statistics: Statistics
|
|
|
|
};
|
|
|
|
}());
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.util = function () {
|
|
|
|
function map(elems, func) {
|
|
|
|
var ret = [];
|
|
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
|
|
ret[i] = func(elems[i]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
function filter(elems, predicate) {
|
|
|
|
var ret = [];
|
|
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
|
|
if (predicate(elems[i]))
|
|
|
|
ret.push(elems[i]);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
function all(elems) {
|
|
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
|
|
if (!elems[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
function any(elems) {
|
|
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
|
|
if (elems[i])
|
|
|
|
return elems[i];
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
function contains(elems, e) {
|
|
|
|
for (var i = 0, len = elems.length; i < len; i++) {
|
|
|
|
if (elems[i] == e)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
function last(items) {
|
|
|
|
return items[items.length-1];
|
|
|
|
}
|
|
|
|
function unescape(string) {
|
|
|
|
return string.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
|
|
|
}
|
|
|
|
function escape(string) {
|
|
|
|
return string.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
|
|
}
|
|
|
|
function normalize(string) {
|
|
|
|
return string.toLowerCase().replace(/ /g, '').replace(/_/g, '');
|
|
|
|
}
|
|
|
|
function regexpEscape(string) {
|
|
|
|
return string.replace(/[-[\]{}()+?*.,\\^$|#]/g, "\\$&");
|
|
|
|
}
|
|
|
|
function Matcher(pattern) {
|
|
|
|
pattern = regexpEscape(normalize(pattern));
|
|
|
|
var rePattern = '^' + pattern.replace(/\\\?/g, '.').replace(/\\\*/g, '[\\s\\S]*') + '$';
|
|
|
|
var regexp = new RegExp(rePattern);
|
|
|
|
function matches(string) {
|
|
|
|
return regexp.test(normalize(string));
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
matches: matches,
|
|
|
|
matchesAny: function (strings) {
|
|
|
|
for (var i = 0, len = strings.length; i < len; i++)
|
|
|
|
if (matches(strings[i]))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function formatParentName(item) {
|
|
|
|
var parentName = item.fullName.slice(0, item.fullName.length - item.name.length);
|
|
|
|
return parentName.replace(/\./g, ' . ');
|
|
|
|
}
|
|
|
|
function timeFromDate(date) {
|
|
|
|
if (!date)
|
|
|
|
return 'N/A';
|
|
|
|
return formatTime(date.getHours(), date.getMinutes(),
|
|
|
|
date.getSeconds(), date.getMilliseconds());
|
|
|
|
}
|
|
|
|
function dateFromDate(date) {
|
|
|
|
if (!date)
|
|
|
|
return 'N/A';
|
|
|
|
return padTo(date.getFullYear(), 4) +
|
|
|
|
padTo(date.getMonth() + 1, 2) +
|
|
|
|
padTo(date.getDate(), 2);
|
|
|
|
}
|
|
|
|
function dateTimeFromDate(date) {
|
|
|
|
if (!date)
|
|
|
|
return 'N/A';
|
|
|
|
return dateFromDate(date) + ' ' + timeFromDate(date);
|
|
|
|
}
|
|
|
|
function formatTime(hours, minutes, seconds, milliseconds) {
|
|
|
|
return padTo(hours, 2) + ':' +
|
|
|
|
padTo(minutes, 2) + ':' +
|
|
|
|
padTo(seconds, 2) + '.' +
|
|
|
|
padTo(milliseconds, 3);
|
|
|
|
}
|
|
|
|
function formatElapsed(elapsed) {
|
|
|
|
var millis = elapsed;
|
|
|
|
var hours = Math.floor(millis / (60 * 60 * 1000));
|
|
|
|
millis -= hours * 60 * 60 * 1000;
|
|
|
|
var minutes = Math.floor(millis / (60 * 1000));
|
|
|
|
millis -= minutes * 60 * 1000;
|
|
|
|
var seconds = Math.floor(millis / 1000);
|
|
|
|
millis -= seconds * 1000;
|
|
|
|
return formatTime(hours, minutes, seconds, millis);
|
|
|
|
}
|
|
|
|
function padTo(number, len) {
|
|
|
|
var numString = number + "";
|
|
|
|
while (numString.length < len) numString = "0" + numString;
|
|
|
|
return numString;
|
|
|
|
}
|
|
|
|
function timestamp(millis) {
|
|
|
|
// used also by tools that do not set window.output.baseMillis
|
|
|
|
var base = window.output ? window.output.baseMillis : 0;
|
|
|
|
return new Date(base + millis);
|
|
|
|
}
|
|
|
|
function createGeneratedString(timestamp) {
|
|
|
|
var date = new Date(timestamp);
|
|
|
|
var dt = dateTimeFromDate(date).slice(0, 17); // drop millis
|
|
|
|
var offset = date.getTimezoneOffset();
|
|
|
|
var sign = offset > 0 ? '-' : '+';
|
|
|
|
var hh = Math.floor(Math.abs(offset) / 60);
|
|
|
|
var mm = Math.abs(offset) % 60;
|
|
|
|
return dt + ' UTC' + sign + padTo(hh, 2) + ':' + padTo(mm, 2);
|
|
|
|
}
|
|
|
|
function createGeneratedAgoString(timestamp) {
|
|
|
|
function timeString(time, shortUnit) {
|
|
|
|
var unit = {y: 'year', d: 'day', h: 'hour', m: 'minute',
|
|
|
|
s: 'second'}[shortUnit];
|
|
|
|
var end = time == 1 ? ' ' : 's ';
|
|
|
|
return time + ' ' + unit + end;
|
|
|
|
}
|
|
|
|
function compensateLeapYears(days, years) {
|
|
|
|
// Not a perfect algorithm but ought to be enough
|
|
|
|
return days - Math.floor(years / 4);
|
|
|
|
}
|
|
|
|
var generated = Math.round(timestamp / 1000);
|
|
|
|
var current = Math.round(new Date().getTime() / 1000);
|
|
|
|
var elapsed = current - generated;
|
|
|
|
var prefix = '';
|
|
|
|
if (elapsed < 0) {
|
|
|
|
prefix = '- ';
|
|
|
|
elapsed = Math.abs(elapsed);
|
|
|
|
}
|
|
|
|
var secs = elapsed % 60;
|
|
|
|
var mins = Math.floor(elapsed / 60) % 60;
|
|
|
|
var hours = Math.floor(elapsed / (60*60)) % 24;
|
|
|
|
var days = Math.floor(elapsed / (60*60*24)) % 365;
|
|
|
|
var years = Math.floor(elapsed / (60*60*24*365));
|
|
|
|
if (years) {
|
|
|
|
days = compensateLeapYears(days, years);
|
|
|
|
return prefix + timeString(years, 'y') + timeString(days, 'd');
|
|
|
|
} else if (days) {
|
|
|
|
return prefix + timeString(days, 'd') + timeString(hours, 'h');
|
|
|
|
} else if (hours) {
|
|
|
|
return prefix + timeString(hours, 'h') + timeString(mins, 'm');
|
|
|
|
} else if (mins) {
|
|
|
|
return prefix + timeString(mins, 'm') + timeString(secs, 's');
|
|
|
|
} else {
|
|
|
|
return prefix + timeString(secs, 's');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function parseQueryString(query) {
|
|
|
|
var result = {};
|
|
|
|
if (!query)
|
|
|
|
return result;
|
|
|
|
var params = query.split('&');
|
|
|
|
var parts;
|
|
|
|
function decode(item) {
|
|
|
|
return decodeURIComponent(item.replace('+', ' '));
|
|
|
|
}
|
|
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
|
|
parts = params[i].split('=');
|
|
|
|
result[decode(parts.shift())] = decode(parts.join('='));
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
map: map,
|
|
|
|
filter: filter,
|
|
|
|
all: all,
|
|
|
|
any: any,
|
|
|
|
contains: contains,
|
|
|
|
last: last,
|
|
|
|
escape: escape,
|
|
|
|
unescape: unescape,
|
|
|
|
normalize: normalize,
|
|
|
|
regexpEscape: regexpEscape,
|
|
|
|
Matcher: Matcher,
|
|
|
|
formatParentName: formatParentName,
|
|
|
|
timeFromDate: timeFromDate,
|
|
|
|
dateFromDate: dateFromDate,
|
|
|
|
dateTimeFromDate: dateTimeFromDate,
|
|
|
|
formatElapsed: formatElapsed,
|
|
|
|
timestamp: timestamp,
|
|
|
|
createGeneratedString: createGeneratedString,
|
|
|
|
createGeneratedAgoString: createGeneratedAgoString,
|
|
|
|
parseQueryString: parseQueryString
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.testdata = function () {
|
|
|
|
var elementsById = {};
|
|
|
|
var idCounter = 0;
|
|
|
|
var _statistics = null;
|
|
|
|
var LEVELS = ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FAIL', 'SKIP'];
|
|
|
|
var STATUSES = ['FAIL', 'PASS', 'SKIP', 'NOT RUN'];
|
|
|
|
var KEYWORD_TYPES = ['KEYWORD', 'SETUP', 'TEARDOWN', 'FOR', 'ITERATION', 'IF', 'ELSE IF', 'ELSE', 'RETURN',
|
|
|
|
'TRY', 'EXCEPT', 'FINALLY', 'WHILE', 'CONTINUE', 'BREAK', 'ERROR'];
|
|
|
|
function addElement(elem) {
|
|
|
|
if (!elem.id)
|
|
|
|
elem.id = uniqueId();
|
|
|
|
elementsById[elem.id] = elem;
|
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
function uniqueId() {
|
|
|
|
idCounter++;
|
|
|
|
return 'element-id-' + idCounter;
|
|
|
|
}
|
|
|
|
function times(stats) {
|
|
|
|
var startMillis = stats[1];
|
|
|
|
var elapsed = stats[2];
|
|
|
|
if (startMillis === null)
|
|
|
|
return [null, null, elapsed];
|
|
|
|
return [util.timestamp(startMillis),
|
|
|
|
util.timestamp(startMillis + elapsed),
|
|
|
|
elapsed];
|
|
|
|
}
|
|
|
|
function createMessage(element, strings) {
|
|
|
|
return model.Message(LEVELS[element[1]],
|
|
|
|
util.timestamp(element[0]),
|
|
|
|
strings.get(element[2]),
|
|
|
|
strings.get(element[3]));
|
|
|
|
}
|
|
|
|
function parseStatus(stats) {
|
|
|
|
return STATUSES[stats[0]];
|
|
|
|
}
|
|
|
|
function childCreator(parent, childType) {
|
|
|
|
return function (elem, strings, index) {
|
|
|
|
return addElement(childType(parent, elem, strings, index));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function createBodyItem(parent, element, strings, index) {
|
|
|
|
if (element.length < 5)
|
|
|
|
return createMessage(element, strings);
|
|
|
|
var messages = util.filter(parent.children(), function (child) {
|
|
|
|
return child.type == 'message';
|
|
|
|
})
|
|
|
|
return createKeyword(parent, element, strings, index - messages.length);
|
|
|
|
}
|
|
|
|
function createKeyword(parent, element, strings, index) {
|
|
|
|
var kw = model.Keyword({
|
|
|
|
parent: parent,
|
|
|
|
type: KEYWORD_TYPES[element[0]],
|
|
|
|
id: 'k' + (index + 1),
|
|
|
|
name: strings.get(element[1]),
|
|
|
|
libname: strings.get(element[2]),
|
|
|
|
timeout: strings.get(element[3]),
|
|
|
|
args: strings.get(element[5]),
|
|
|
|
assign: strings.get(element[6]),
|
|
|
|
tags: strings.get(element[7]),
|
|
|
|
doc: function () {
|
|
|
|
var doc = strings.get(element[4]);
|
|
|
|
this.doc = function () { return doc; };
|
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
status: parseStatus(element[8], strings),
|
|
|
|
times: model.Times(times(element[8])),
|
|
|
|
isChildrenLoaded: typeof(element[9]) !== 'number'
|
|
|
|
});
|
|
|
|
lazyPopulateKeywordsFromFile(kw, element[9], strings);
|
|
|
|
return kw;
|
|
|
|
}
|
|
|
|
function lazyPopulateKeywordsFromFile(parent, modelOrIndex, strings) {
|
|
|
|
var model, index, populator;
|
|
|
|
var creator = childCreator(parent, createBodyItem);
|
|
|
|
if (parent.isChildrenLoaded) {
|
|
|
|
model = modelOrIndex;
|
|
|
|
populator = Populator(model, strings, creator);
|
|
|
|
} else {
|
|
|
|
index = modelOrIndex;
|
|
|
|
parent.childFileName = window.settings['splitLogBase'] + '-' + index + '.js';
|
|
|
|
populator = SplitLogPopulator(index, creator);
|
|
|
|
}
|
|
|
|
parent.populateKeywords(populator);
|
|
|
|
}
|
|
|
|
function tags(taglist, strings) {
|
|
|
|
return util.map(taglist, strings.get);
|
|
|
|
}
|
|
|
|
function createTest(parent, element, strings, index) {
|
|
|
|
var status = element[4];
|
|
|
|
var test = model.Test({
|
|
|
|
parent: parent,
|
|
|
|
id: 't' + (index + 1),
|
|
|
|
name: strings.get(element[0]),
|
|
|
|
doc: function () {
|
|
|
|
var doc = strings.get(element[2]);
|
|
|
|
this.doc = function () { return doc; };
|
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
timeout: strings.get(element[1]),
|
|
|
|
status: parseStatus(status),
|
|
|
|
message: function () {
|
|
|
|
var msg = status.length == 4 ? strings.get(status[3]) : '';
|
|
|
|
this.message = function () { return msg; };
|
|
|
|
return msg;
|
|
|
|
},
|
|
|
|
times: model.Times(times(status)),
|
|
|
|
tags: tags(element[3], strings),
|
|
|
|
isChildrenLoaded: typeof(element[5]) !== 'number'
|
|
|
|
});
|
|
|
|
lazyPopulateKeywordsFromFile(test, element[5], strings);
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
function createSuite(parent, element, strings, index) {
|
|
|
|
var status = element[5];
|
|
|
|
var suite = model.Suite({
|
|
|
|
parent: parent,
|
|
|
|
id: 's' + ((index || 0) + 1),
|
|
|
|
name: strings.get(element[0]),
|
|
|
|
source: strings.get(element[1]),
|
|
|
|
relativeSource: strings.get(element[2]),
|
|
|
|
doc: function () {
|
|
|
|
var doc = strings.get(element[3]);
|
|
|
|
this.doc = function () { return doc; };
|
|
|
|
return doc;
|
|
|
|
},
|
|
|
|
status: parseStatus(status),
|
|
|
|
message: function () {
|
|
|
|
var msg = status.length == 4 ? strings.get(status[3]) : '';
|
|
|
|
this.message = function () { return msg; };
|
|
|
|
return msg;
|
|
|
|
},
|
|
|
|
times: model.Times(times(status)),
|
|
|
|
statistics: suiteStats(util.last(element)),
|
|
|
|
metadata: parseMetadata(element[4], strings)
|
|
|
|
});
|
|
|
|
suite.populateKeywords(Populator(element[8], strings, childCreator(suite, createKeyword)));
|
|
|
|
suite.populateTests(Populator(element[7], strings, childCreator(suite, createTest)));
|
|
|
|
suite.populateSuites(Populator(element[6], strings, childCreator(suite, createSuite)));
|
|
|
|
return suite;
|
|
|
|
}
|
|
|
|
function parseMetadata(data, strings) {
|
|
|
|
var metadata = [];
|
|
|
|
for (var i=0; i<data.length; i+=2) {
|
|
|
|
metadata.push([strings.get(data[i]), strings.get(data[i+1])]);
|
|
|
|
}
|
|
|
|
return metadata;
|
|
|
|
}
|
|
|
|
function suiteStats(stats) {
|
|
|
|
return {
|
|
|
|
total: stats[0],
|
|
|
|
pass: stats[1],
|
|
|
|
fail: stats[2],
|
|
|
|
skip: stats[3]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function Populator(items, strings, creator) {
|
|
|
|
return {
|
|
|
|
numberOfItems: function () {
|
|
|
|
return items.length;
|
|
|
|
},
|
|
|
|
creator: function (index) {
|
|
|
|
return creator(items[index], strings, index);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function SplitLogPopulator(structureIndex, creator) {
|
|
|
|
return {
|
|
|
|
numberOfItems: function () {
|
|
|
|
return window['keywords'+structureIndex].length;
|
|
|
|
},
|
|
|
|
creator: function (index) {
|
|
|
|
return creator(window['keywords'+structureIndex][index],
|
|
|
|
StringStore(window['strings'+structureIndex]),
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function suite() {
|
|
|
|
var elem = window.output.suite;
|
|
|
|
if (elementsById[elem.id])
|
|
|
|
return elem;
|
|
|
|
var root = addElement(createSuite(null, elem, StringStore(window.output.strings)));
|
|
|
|
window.output.suite = root;
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
function findLoaded(id) {
|
|
|
|
return elementsById[id];
|
|
|
|
}
|
|
|
|
function ensureLoaded(id, callback) {
|
|
|
|
var ids = id.split('-');
|
|
|
|
var root = suite();
|
|
|
|
ids.shift();
|
|
|
|
loadItems(ids, root, [root.id], callback);
|
|
|
|
}
|
|
|
|
function loadItems(ids, current, result, callback) {
|
|
|
|
if (!ids.length) {
|
|
|
|
callback(result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
current.callWhenChildrenReady(function () {
|
|
|
|
var id = ids.shift();
|
|
|
|
var type = id[0];
|
|
|
|
var index = parseInt(id.substring(1)) - 1;
|
|
|
|
var item = selectFrom(current, type, index);
|
|
|
|
if (item)
|
|
|
|
result.push(item.id);
|
|
|
|
else // Invalid id. Should this be reported somewhere?
|
|
|
|
ids = [];
|
|
|
|
loadItems(ids, item, result, callback);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function selectFrom(element, type, index) {
|
|
|
|
if (type === 'k') {
|
|
|
|
var keywords = util.filter(element.keywords(), function (kw) {
|
|
|
|
return kw.type != 'message';
|
|
|
|
});
|
|
|
|
return keywords[index];
|
|
|
|
} else if (type === 't') {
|
|
|
|
return element.tests()[index];
|
|
|
|
} else {
|
|
|
|
return element.suites()[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function errorIterator() {
|
|
|
|
return {
|
|
|
|
next: function () {
|
|
|
|
return addElement(createMessage(window.output.errors.shift(),
|
|
|
|
StringStore(window.output.strings)));
|
|
|
|
},
|
|
|
|
hasNext: function () {
|
|
|
|
return window.output.errors.length > 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
function statistics() {
|
|
|
|
if (!_statistics) {
|
|
|
|
var statData = window.output.stats;
|
|
|
|
_statistics = stats.Statistics(statData[0], statData[1], statData[2]);
|
|
|
|
}
|
|
|
|
return _statistics;
|
|
|
|
}
|
|
|
|
function StringStore(strings) {
|
|
|
|
function getText(id) {
|
|
|
|
var text = strings[id];
|
|
|
|
if (!text)
|
|
|
|
return '';
|
|
|
|
if (text[0] == '*')
|
|
|
|
return text.substring(1);
|
|
|
|
var extracted = extract(text);
|
|
|
|
strings[id] = '*' + extracted;
|
|
|
|
return extracted;
|
|
|
|
}
|
|
|
|
function extract(text) {
|
|
|
|
var decoded = JXG.Util.Base64.decodeAsArray(text);
|
|
|
|
var extracted = (new JXG.Util.Unzip(decoded)).unzip()[0][0];
|
|
|
|
return JXG.Util.UTF8.decode(extracted);
|
|
|
|
}
|
|
|
|
function get(id) {
|
|
|
|
if (id === null) return null;
|
|
|
|
return getText(id);
|
|
|
|
}
|
|
|
|
return {get: get};
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
suite: suite,
|
|
|
|
errorIterator: errorIterator,
|
|
|
|
findLoaded: findLoaded,
|
|
|
|
ensureLoaded: ensureLoaded,
|
|
|
|
statistics: statistics,
|
|
|
|
StringStore: StringStore, // exposed for tests
|
|
|
|
LEVELS: LEVELS
|
|
|
|
};
|
|
|
|
}();
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
function removeJavaScriptDisabledWarning() {
|
|
|
|
// Not using jQuery here for maximum speed
|
|
|
|
document.getElementById('javascript-disabled').style.display = 'none';
|
|
|
|
}
|
|
|
|
function addJavaScriptDisabledWarning(error) {
|
|
|
|
if (window.console)
|
|
|
|
console.error('Opening failed: ' + error.name + ': ' + error.message);
|
|
|
|
document.getElementById('javascript-disabled').style.display = 'block';
|
|
|
|
}
|
|
|
|
function initLayout(suiteName, type) {
|
|
|
|
parseTemplates();
|
|
|
|
setTitle(suiteName, type);
|
|
|
|
addHeader();
|
|
|
|
addReportOrLogLink(type);
|
|
|
|
}
|
|
|
|
function parseTemplates() {
|
|
|
|
$('script[type="text/x-jquery-tmpl"]').map(function (idx, elem) {
|
|
|
|
$.template(elem.id, elem.text);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function testOrTask(text) {
|
|
|
|
return text.replace(/{(.*)}/, function (match, group, offset, string) {
|
|
|
|
if (!window.settings.rpa)
|
|
|
|
return group;
|
|
|
|
return {'TEST': 'TASK', 'Test': 'Task', 'test': 'task'}[group];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function setTitle(suiteName, type) {
|
|
|
|
var givenTitle = window.settings.title;
|
|
|
|
var title = givenTitle ? givenTitle : suiteName + " " + type;
|
|
|
|
document.title = util.unescape(title);
|
|
|
|
}
|
|
|
|
function addHeader() {
|
|
|
|
var generated = util.timestamp(window.output.generated);
|
|
|
|
$.tmpl('<h1>${title}</h1>' +
|
|
|
|
'<div id="generated">' +
|
|
|
|
'<span>Generated<br>${generated}</span><br>' +
|
|
|
|
'<span id="generated-ago">${ago} ago</span>' +
|
|
|
|
'</div>' +
|
|
|
|
'<div id="top-right-header">' +
|
|
|
|
'<div id="report-or-log-link"><a href="#"></a></div>' +
|
|
|
|
'</div>', {
|
|
|
|
generated: util.createGeneratedString(generated),
|
|
|
|
ago: util.createGeneratedAgoString(generated),
|
|
|
|
title: document.title
|
|
|
|
}).appendTo($('#header'));
|
|
|
|
}
|
|
|
|
function addReportOrLogLink(myType) {
|
|
|
|
var url;
|
|
|
|
var text;
|
|
|
|
var container = $('#report-or-log-link');
|
|
|
|
if (myType == 'Report') {
|
|
|
|
url = window.settings.logURL;
|
|
|
|
text = 'LOG';
|
|
|
|
} else {
|
|
|
|
url = window.settings.reportURL;
|
|
|
|
text = 'REPORT';
|
|
|
|
}
|
|
|
|
if (url) {
|
|
|
|
container.find('a').attr('href', url);
|
|
|
|
container.find('a').text(text);
|
|
|
|
} else {
|
|
|
|
container.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function addStatistics() {
|
|
|
|
var statHeaders =
|
|
|
|
'<th class="stats-col-stat">Total</th>' +
|
|
|
|
'<th class="stats-col-stat">Pass</th>' +
|
|
|
|
'<th class="stats-col-stat">Fail</th>' +
|
|
|
|
'<th class="stats-col-stat">Skip</th>' +
|
|
|
|
'<th class="stats-col-elapsed">Elapsed</th>' +
|
|
|
|
'<th class="stats-col-graph">Pass / Fail / Skip</th>';
|
|
|
|
var statTable =
|
|
|
|
'<h2>{Test} Statistics</h2>' +
|
|
|
|
'<table class="statistics" id="total-stats"><thead><tr>' +
|
|
|
|
'<th class="stats-col-name">Total Statistics</th>' + statHeaders +
|
|
|
|
'</tr></thead></table>' +
|
|
|
|
'<table class="statistics" id="tag-stats"><thead><tr>' +
|
|
|
|
'<th class="stats-col-name">Statistics by Tag</th>' + statHeaders +
|
|
|
|
'</tr></thead></table>' +
|
|
|
|
'<table class="statistics" id="suite-stats"><thead><tr>' +
|
|
|
|
'<th class="stats-col-name">Statistics by Suite</th>' + statHeaders +
|
|
|
|
'</tr></thead></table>';
|
|
|
|
$(testOrTask(statTable)).appendTo('#statistics-container');
|
|
|
|
util.map(['total', 'tag', 'suite'], addStatTable);
|
|
|
|
addTooltipsToElapsedTimes();
|
|
|
|
enableStatisticsSorter();
|
|
|
|
}
|
|
|
|
function addTooltipsToElapsedTimes() {
|
|
|
|
$('.stats-col-elapsed').attr('title',
|
|
|
|
testOrTask('Total execution time of these {test}s. ') +
|
|
|
|
'Excludes suite setups and teardowns.');
|
|
|
|
$('#suite-stats').find('.stats-col-elapsed').attr('title',
|
|
|
|
'Total execution time of this suite.');
|
|
|
|
}
|
|
|
|
function enableStatisticsSorter() {
|
|
|
|
$.tablesorter.addParser({
|
|
|
|
id: 'statName',
|
|
|
|
type: 'numeric',
|
|
|
|
is: function(s) {
|
|
|
|
return false; // do not auto-detect
|
|
|
|
},
|
|
|
|
format: function(string, table, cell, cellIndex) {
|
|
|
|
// Rows have class in format 'row-<index>'.
|
|
|
|
var index = $(cell).parent().attr('class').substring(4);
|
|
|
|
return parseInt(index);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$(".statistics").tablesorter({
|
|
|
|
sortInitialOrder: 'desc',
|
|
|
|
headers: {0: {sorter: 'statName', sortInitialOrder: 'asc'},
|
|
|
|
6: {sorter: false}}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function addStatTable(tableName) {
|
|
|
|
var stats = window.testdata.statistics()[tableName];
|
|
|
|
if (tableName == 'tag' && stats.length == 0) {
|
|
|
|
renderNoTagStatTable();
|
|
|
|
} else {
|
|
|
|
renderStatTable(tableName, stats);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function renderNoTagStatTable() {
|
|
|
|
$('<tbody><tr class="row-0">' +
|
|
|
|
'<td class="stats-col-name">No Tags</td>' +
|
|
|
|
'<td class="stats-col-stat"></td>' +
|
|
|
|
'<td class="stats-col-stat"></td>' +
|
|
|
|
'<td class="stats-col-stat"></td>' +
|
|
|
|
'<td class="stats-col-stat"></td>' +
|
|
|
|
'<td class="stats-col-elapsed"></td>' +
|
|
|
|
'<td class="stats-col-graph">' +
|
|
|
|
'<div class="empty-graph"></div>' +
|
|
|
|
'</td>' +
|
|
|
|
'</tr></tbody>').appendTo('#tag-stats');
|
|
|
|
}
|
|
|
|
function renderStatTable(tableName, stats) {
|
|
|
|
var template = tableName + 'StatisticsRowTemplate';
|
|
|
|
var tbody = $('<tbody></tbody>');
|
|
|
|
for (var i = 0, len = stats.length; i < len; i++) {
|
|
|
|
$.tmpl(template, stats[i], {index: i}).appendTo(tbody);
|
|
|
|
}
|
|
|
|
tbody.appendTo('#' + tableName + '-stats');
|
|
|
|
}
|
|
|
|
$.template('statColumnsTemplate',
|
|
|
|
'<td class="stats-col-stat">${total}</td>' +
|
|
|
|
'<td class="stats-col-stat">${pass}</td>' +
|
|
|
|
'<td class="stats-col-stat">${fail}</td>' +
|
|
|
|
'<td class="stats-col-stat">${skip}</td>' +
|
|
|
|
'<td class="stats-col-elapsed">${elapsed}</td>' +
|
|
|
|
'<td class="stats-col-graph">' +
|
|
|
|
'{{if total}}' +
|
|
|
|
'<div class="graph">' +
|
|
|
|
'<div class="pass-bar" style="width: ${passWidth}%" title="${passPercent}%"></div>' +
|
|
|
|
'<div class="fail-bar" style="width: ${failWidth}%" title="${failPercent}%"></div>' +
|
|
|
|
'<div class="skip-bar" style="width: ${skipWidth}%" title="${skipPercent}%"></div>' +
|
|
|
|
'</div>' +
|
|
|
|
'{{else}}' +
|
|
|
|
'<div class="empty-graph"></div>' +
|
|
|
|
'{{/if}}' +
|
|
|
|
'</td>'
|
|
|
|
);
|
|
|
|
$.template('suiteStatusMessageTemplate',
|
|
|
|
'${total} {{= testOrTask("{test}")}}{{if total != 1}}s{{/if}} total, ' +
|
|
|
|
'${pass} passed, ${fail} failed, ${skip} skipped'
|
|
|
|
);
|
|
|
|
// For complete cross-browser experience..
|
|
|
|
// http://www.quirksmode.org/js/events_order.html
|
|
|
|
function stopPropagation(event) {
|
|
|
|
var event = event || window.event;
|
|
|
|
event.cancelBubble = true;
|
|
|
|
if (event.stopPropagation)
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
storage = function () {
|
|
|
|
var prefix = 'robot-framework-';
|
|
|
|
var storage;
|
|
|
|
function init(user) {
|
|
|
|
prefix += user + '-';
|
|
|
|
storage = getStorage();
|
|
|
|
}
|
|
|
|
function getStorage() {
|
|
|
|
// Use localStorage if it's accessible, normal object otherwise.
|
|
|
|
// Inspired by https://stackoverflow.com/questions/11214404
|
|
|
|
try {
|
|
|
|
localStorage.setItem(prefix, prefix);
|
|
|
|
localStorage.removeItem(prefix);
|
|
|
|
return localStorage;
|
|
|
|
} catch (exception) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function get(name, defaultValue) {
|
|
|
|
var value = storage[prefix + name];
|
|
|
|
if (typeof value === 'undefined')
|
|
|
|
return defaultValue;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
function set(name, value) {
|
|
|
|
storage[prefix + name] = value;
|
|
|
|
}
|
|
|
|
return {init: init, get: get, set: set};
|
|
|
|
}();
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.output = {};
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
2023-10-14 07:28:27 +00:00
|
|
|
window.output["suite"] = [1,2,3,0,[],[1,0,22192],[],[[4,0,0,[],[1,426,21764],[]]],[],[1,1,0,0]];
|
2023-10-13 12:32:41 +00:00
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.output["strings"] = [];
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
2023-10-14 07:28:27 +00:00
|
|
|
window.output["strings"] = window.output["strings"].concat(["*","*Inputbox","*C:\\Users\\lukas\\Mega\\Data\\GitHub\\Robot_Framework\\RobotSelenium\\Techie\\TestCases\\Inputbox.robot","*TestCases/Inputbox.robot","*TestingInputBox"]);
|
2023-10-13 12:32:41 +00:00
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
2023-10-14 07:28:27 +00:00
|
|
|
window.output["stats"] = [[{"elapsed":"00:00:22","fail":0,"label":"All Tests","pass":1,"skip":0}],[],[{"elapsed":"00:00:22","fail":0,"id":"s1","label":"Inputbox","name":"Inputbox","pass":1,"skip":0}]];
|
2023-10-13 12:32:41 +00:00
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
2023-10-14 07:28:27 +00:00
|
|
|
window.output["baseMillis"] = 1697232114719;
|
2023-10-13 12:32:41 +00:00
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
2023-10-14 07:28:27 +00:00
|
|
|
window.output["generated"] = 22204;
|
2023-10-13 12:32:41 +00:00
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.output["expand_keywords"] = null;
|
|
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
window.settings = {"background":{"fail":"#f66","pass":"#9e9","skip":"#fed84f"},"logURL":"log.html","rpa":false,"title":""};
|
|
|
|
</script>
|
|
|
|
<title></title>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="javascript-disabled">
|
|
|
|
<h1>Opening Robot Framework report failed</h1>
|
|
|
|
<ul>
|
|
|
|
<li>Verify that you have <b>JavaScript enabled</b> in your browser.</li>
|
|
|
|
<li>Make sure you are using a <b>modern enough browser</b>. If using Internet Explorer, version 11 is required.</li>
|
|
|
|
<li>Check are there messages in your browser's <b>JavaScript error log</b>. Please report the problem if you suspect you have encountered a bug.</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
<script type="text/javascript">removeJavaScriptDisabledWarning();</script>
|
|
|
|
|
|
|
|
<div id="header"></div>
|
|
|
|
<div id="statistics-container"></div>
|
|
|
|
<div id="test-details-container"></div>
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
|
|
$(document).ready(function () {
|
|
|
|
try {
|
|
|
|
var topsuite = window.testdata.suite();
|
|
|
|
} catch (error) {
|
|
|
|
addJavaScriptDisabledWarning(error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
window.prevLocationHash = '';
|
|
|
|
setBackground(topsuite);
|
|
|
|
initLayout(topsuite.name, 'Report');
|
|
|
|
storage.init('report');
|
|
|
|
addSummary(topsuite);
|
|
|
|
addStatistics();
|
|
|
|
addDetails();
|
|
|
|
window.onhashchange = showDetailsByHash;
|
|
|
|
});
|
|
|
|
|
|
|
|
function setBackground(topsuite) {
|
|
|
|
var color;
|
|
|
|
if (topsuite.fail)
|
|
|
|
color = window.settings.background.fail;
|
|
|
|
else if (topsuite.pass)
|
|
|
|
color = window.settings.background.pass;
|
|
|
|
else
|
|
|
|
color = window.settings.background.skip;
|
|
|
|
$('body').css('background-color', color);
|
|
|
|
}
|
|
|
|
|
|
|
|
function addSummary(topsuite) {
|
|
|
|
var opts = {logURL: window.settings.logURL};
|
|
|
|
$.tmpl('summaryTableTemplate', topsuite, opts).insertAfter($('#header'));
|
|
|
|
}
|
|
|
|
|
|
|
|
function addDetails() {
|
|
|
|
addCustomSortersForDetails();
|
|
|
|
if (window.location.hash)
|
|
|
|
showDetailsByHash();
|
|
|
|
else
|
|
|
|
renderSearchSelector();
|
|
|
|
}
|
|
|
|
|
|
|
|
function addCustomSortersForDetails() {
|
|
|
|
$.tablesorter.addParser({
|
|
|
|
id: 'status',
|
|
|
|
type: 'numeric',
|
|
|
|
is: function(s) {
|
|
|
|
return false; // do not auto-detect
|
|
|
|
},
|
|
|
|
format: function(s) {
|
|
|
|
return {'FAIL': -1, 'SKIP': 0, 'PASS': 1}[s];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
$.tablesorter.addParser({
|
|
|
|
id: 'times',
|
|
|
|
type: 'text',
|
|
|
|
is: function(s) {
|
|
|
|
return false; // do not auto-detect
|
|
|
|
},
|
|
|
|
format: function(s) {
|
|
|
|
return s.substring(0, 21); // return only start time
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function showDetailsByHash() {
|
|
|
|
// Cannot use window.location.hash because Firefox incorrectly decodes it:
|
|
|
|
// http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash
|
|
|
|
var hash = window.location.href.split('#').slice(1).join('#');
|
|
|
|
if (!hash || hash == window.prevLocationHash)
|
|
|
|
return;
|
|
|
|
var parts = hash.split('?');
|
|
|
|
var name = parts.shift();
|
|
|
|
var query = parts.join('?');
|
|
|
|
if (name == 'search') {
|
|
|
|
var params = util.parseQueryString(query);
|
|
|
|
searchExecuted(params.suite || '', params.test || '',
|
|
|
|
params.include || '', params.exclude || '');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
query = decodeURIComponent(query);
|
|
|
|
var action = {'totals': totalDetailSelected,
|
|
|
|
'tags': tagDetailSelected,
|
|
|
|
'suites': suiteDetailSelected}[name];
|
|
|
|
if (action)
|
|
|
|
action(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
function totalDetailSelected() {
|
|
|
|
renderTotalSelector();
|
|
|
|
scrollToSelector('totals', name);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTotalSelector() {
|
|
|
|
var args = {linkTarget: 'totals',
|
|
|
|
totalTabStatus: 'detail-tab-selected'};
|
|
|
|
renderSelector(args, 'totalDetailsSelectorTemplate');
|
|
|
|
updatePrintSelector(testOrTask('All {Test}s'));
|
|
|
|
renderTotalDetails();
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTotalDetails() {
|
|
|
|
var stat = window.testdata.statistics().total[0];
|
|
|
|
var tests = window.testdata.suite().allTests().sort(sortByStatus)
|
|
|
|
stat.totalTime = calculateTotalTime(tests);
|
|
|
|
$.tmpl('tagOrTotalDetailsTemplate', stat).appendTo('#details-header');
|
|
|
|
drawTestDetailsTable(tests, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
function updatePrintSelector(name, info) {
|
|
|
|
if (info)
|
|
|
|
name += ' (' + info + ')';
|
|
|
|
$('#print-selector').html(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
function tagDetailSelected(name) {
|
|
|
|
renderTagSelector(name);
|
|
|
|
if (name) {
|
|
|
|
var tag = findTag(name);
|
|
|
|
if (tag) {
|
|
|
|
renderTagDetails(tag);
|
|
|
|
updatePrintSelector(name, tag.info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
scrollToSelector('tags', name);
|
|
|
|
}
|
|
|
|
|
|
|
|
function findTag(name) {
|
|
|
|
var tags = window.testdata.statistics().tag;
|
|
|
|
for (var i = 0, len = tags.length; i < len; i++) {
|
|
|
|
if (tags[i].label == name)
|
|
|
|
return tags[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTagSelector(name) {
|
|
|
|
var args = {linkTarget: (name) ? 'tags?'+name : 'tags',
|
|
|
|
tagTabStatus: 'detail-tab-selected'};
|
|
|
|
var stats = {tags: window.testdata.statistics().tag, selected: name};
|
|
|
|
renderSelector(args, 'tagDetailsSelectorTemplate', stats);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTagDetails(tag) {
|
|
|
|
var tests = getTestsHavingTag(tag);
|
|
|
|
tag.totalTime = calculateTotalTime(tests);
|
|
|
|
$.tmpl('tagOrTotalDetailsTemplate', tag).appendTo('#details-header');
|
|
|
|
drawTestDetailsTable(tests, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
function suiteDetailSelected(id) {
|
|
|
|
renderSuiteSelector(id);
|
|
|
|
if (id)
|
|
|
|
renderSuiteDetails(id);
|
|
|
|
scrollToSelector('suites', id);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderSuiteSelector(id) {
|
|
|
|
var args = {linkTarget: (id) ? 'suites?'+id : 'suites',
|
|
|
|
suiteTabStatus: 'detail-tab-selected'};
|
|
|
|
var stats = {suites: window.testdata.statistics().suite,
|
|
|
|
selected: id};
|
|
|
|
renderSelector(args, 'suiteDetailsSelectorTemplate', stats);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderSuiteDetails(id) {
|
|
|
|
window.testdata.ensureLoaded(id, function (ids) {
|
|
|
|
var suite = window.testdata.findLoaded(id);
|
|
|
|
var opts = {logURL: window.settings.logURL};
|
|
|
|
$.tmpl('suiteDetailsTemplate', suite, opts).appendTo('#details-header');
|
|
|
|
drawTestDetailsTable(suite.allTests(), false);
|
|
|
|
updatePrintSelector(suite.fullName);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function searchExecuted(suite, test, include, exclude) {
|
|
|
|
renderSearchSelector(suite, test, include, exclude);
|
|
|
|
if (suite || test || include || exclude) {
|
|
|
|
renderSearchDetails(suite, test, include, exclude);
|
|
|
|
scrollToSelector('search' +
|
|
|
|
'?suite=' + encodeURIComponent(suite) +
|
|
|
|
'&test=' + encodeURIComponent(test) +
|
|
|
|
'&include=' + encodeURIComponent(include) +
|
|
|
|
'&exclude=' + encodeURIComponent(exclude));
|
|
|
|
} else {
|
|
|
|
scrollToSelector('search');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderSearchSelector(suite, test, include, exclude) {
|
|
|
|
var args = {linkTarget: (suite || test || include || exclude) ?
|
|
|
|
('search?suite=' + suite + '&test=' + test + '&include=' + include + '&exclude=' + exclude) :
|
|
|
|
'search',
|
|
|
|
searchTabStatus: 'detail-tab-selected'};
|
|
|
|
var search = {suite: suite, test: test, include: include, exclude: exclude};
|
|
|
|
renderSelector(args, 'searchSelectorTemplate', search);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderSearchDetails(suite, test, include, exclude) {
|
|
|
|
var tests = searchTests(util.escape(suite), util.escape(test),
|
|
|
|
util.escape(include), util.escape(exclude));
|
|
|
|
var stats = calculateStats(tests);
|
|
|
|
stats.totalTime = calculateTotalTime(tests);
|
|
|
|
$.tmpl('tagOrTotalDetailsTemplate', stats).appendTo('#details-header');
|
|
|
|
drawTestDetailsTable(tests, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
function searchTests(suitePattern, testPattern, includePattern, excludePattern) {
|
|
|
|
var tests;
|
|
|
|
if (suitePattern)
|
|
|
|
tests = window.testdata.suite().searchTestsInSuite(suitePattern);
|
|
|
|
else
|
|
|
|
tests = window.testdata.suite().allTests();
|
|
|
|
return util.filter(tests, function (test) {
|
|
|
|
if (testPattern && !test.matchesNamePattern(testPattern))
|
|
|
|
return false;
|
|
|
|
if (includePattern && !test.matchesTagPattern(includePattern))
|
|
|
|
return false;
|
|
|
|
return !(excludePattern && test.matchesTagPattern(excludePattern));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function scrollToSelector(base, query) {
|
|
|
|
$('#test-details-container').css('min-height', $(window).height());
|
|
|
|
var anchor = query ? base + '?' + encodeURIComponent(query) : base;
|
|
|
|
window.location.hash = window.prevLocationHash = anchor;
|
|
|
|
document.getElementById('test-details-container').scrollIntoView();
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderSelector(args, template, stats) {
|
|
|
|
window.elementsToRender = [];
|
|
|
|
var container = $('#test-details-container');
|
|
|
|
container.empty();
|
|
|
|
$.tmpl('detailsHeaderTemplate', args).appendTo(container);
|
|
|
|
$.tmpl(template, stats).appendTo(container);
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawTestDetailsTable(tests, sortByStatus) {
|
|
|
|
if (!tests.length)
|
|
|
|
return;
|
|
|
|
renderTestDetailsHeader();
|
|
|
|
window.elementsToRender = tests;
|
|
|
|
var target = $('#test-details').find('tbody');
|
|
|
|
renderTestDetails(sortByStatus, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTestDetailsHeader() {
|
|
|
|
var header = $.tmpl('testDetailsTableTemplate');
|
|
|
|
hideHiddenDetailsColumns(header);
|
|
|
|
header.appendTo('#test-details-container');
|
|
|
|
}
|
|
|
|
|
|
|
|
function sortByStatus(t1, t2) {
|
|
|
|
if (t1.status == t2.status)
|
|
|
|
return t1.fullName < t2.fullName ? -1 : 1;
|
|
|
|
statuses = {'FAIL': -1, 'SKIP': 0, 'PASS': 1};
|
|
|
|
return statuses[t1.status] < statuses[t2.status] ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTestsHavingTag(tag) {
|
|
|
|
return window.testdata.suite().searchTestsByTag(tag).sort(sortByStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
function calculateTotalTime(tests) {
|
|
|
|
var total = 0;
|
|
|
|
for (var i = 0, len = tests.length; i < len; i++)
|
|
|
|
total += tests[i].times.elapsedMillis;
|
|
|
|
return util.formatElapsed(total);
|
|
|
|
}
|
|
|
|
|
|
|
|
function calculateStats(tests) {
|
|
|
|
var passed = util.filter(tests, function (test) {
|
|
|
|
return test.status == 'PASS';
|
|
|
|
});
|
|
|
|
var failed = util.filter(tests, function (test) {
|
|
|
|
return test.status == 'FAIL';
|
|
|
|
});
|
|
|
|
return {
|
|
|
|
total: tests.length,
|
|
|
|
pass: passed.length,
|
|
|
|
fail: failed.length,
|
|
|
|
skip: tests.length - passed.length - failed.length
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTestDetails(sortByStatus, target) {
|
|
|
|
if (!window.elementsToRender.length)
|
|
|
|
return;
|
|
|
|
var tests = popUpTo(window.elementsToRender, 50);
|
|
|
|
renderTestDetailsRows(tests, target);
|
|
|
|
if (window.elementsToRender.length)
|
|
|
|
setTimeout(function () {renderTestDetails(sortByStatus, target);}, 0);
|
|
|
|
else
|
|
|
|
configureTableSorter(sortByStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderTestDetailsRows(tests, target) {
|
|
|
|
var rows = $.tmpl('testDetailsTableRowTemplate', tests,
|
|
|
|
{logURL: window.settings.logURL});
|
|
|
|
rows.find('a').click(stopPropagation);
|
|
|
|
hideHiddenDetailsColumns(rows);
|
|
|
|
rows.appendTo(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
function configureTableSorter(sortByStatus) {
|
|
|
|
var config = {headers: {3: {sorter: 'status'},
|
|
|
|
5: {sortInitialOrder: 'desc'},
|
|
|
|
6: {sorter: 'times'}},
|
|
|
|
selectorSort: '.details-col-header'};
|
|
|
|
if (sortByStatus)
|
|
|
|
config['sortList'] = [[3, 0]];
|
|
|
|
$('#test-details').tablesorter(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
function popUpTo(list, upTo) {
|
|
|
|
var result = [];
|
|
|
|
while (list.length > 0 && result.length < upTo)
|
|
|
|
result.push(list.shift());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleDetailsColumn(name) {
|
|
|
|
var column = $('.details-col-' + name);
|
|
|
|
column.toggleClass('hidden');
|
|
|
|
var hidden = column.hasClass('hidden');
|
|
|
|
storage.set(name, hidden ? 'hidden' : 'visible');
|
|
|
|
column.find('.details-col-toggle').html(hidden ? '…' : '×');
|
|
|
|
}
|
|
|
|
|
|
|
|
function hideHiddenDetailsColumns(elem) {
|
|
|
|
var names = ['doc', 'tags', 'msg', 'elapsed', 'times'];
|
|
|
|
for (var i = 0; i < names.length; i++) {
|
|
|
|
var name = names[i];
|
|
|
|
if (storage.get(name, 'visible') == 'hidden') {
|
|
|
|
var column = elem.find('.details-col-' + name);
|
|
|
|
column.addClass('hidden');
|
|
|
|
column.find('.details-col-toggle').html('…');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="summaryTableTemplate">
|
|
|
|
<h2>Summary Information</h2>
|
|
|
|
<table class="details">
|
|
|
|
<tr>
|
|
|
|
<th>Status:</th>
|
|
|
|
{{if fail}}
|
|
|
|
<td><a href="#totals" onclick="totalDetailSelected()"
|
|
|
|
class="fail">${fail} {{= testOrTask('{test}')}}{{if fail != 1}}s{{/if}} failed</a></td>
|
|
|
|
{{else pass && skip}}
|
|
|
|
<td><a href="#totals" onclick="totalDetailSelected()"
|
|
|
|
class="pass">${pass} {{= testOrTask('{test}')}}{{if pass != 1}}s{{/if}} passed,
|
|
|
|
${skip} {{= testOrTask('{test}')}}{{if skip != 1}}s{{/if}} skipped</a></td>
|
|
|
|
{{else pass}}
|
|
|
|
<td><a href="#totals" onclick="totalDetailSelected()"
|
|
|
|
class="pass">All {{= testOrTask('{test}')}}s passed</a></td>
|
|
|
|
{{else}}
|
|
|
|
<td><a href="#totals" onclick="totalDetailSelected()"
|
|
|
|
class="skip">All {{= testOrTask('{test}')}}s skipped</a></td>
|
|
|
|
{{/if}}
|
|
|
|
</tr>
|
|
|
|
{{if doc()}}
|
|
|
|
<tr>
|
|
|
|
<th>Documentation:</th>
|
|
|
|
<td class="doc">{{html doc()}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
{{each metadata}}
|
|
|
|
<tr>
|
|
|
|
<th>{{html $value[0]}}:</th>
|
|
|
|
<td class="doc">{{html $value[1]}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/each}}
|
|
|
|
{{if times.startTime != 'N/A'}}
|
|
|
|
<tr>
|
|
|
|
<th>Start Time:</th>
|
|
|
|
<td>${times.startTime}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
{{if times.endTime != 'N/A'}}
|
|
|
|
<tr>
|
|
|
|
<th>End Time:</th>
|
|
|
|
<td>${times.endTime}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
<tr>
|
|
|
|
<th>Elapsed Time:</th>
|
|
|
|
<td>${times.elapsedTime}</td>
|
|
|
|
</tr>
|
|
|
|
{{if $item.logURL}}
|
|
|
|
<tr>
|
|
|
|
<th>Log File:</th>
|
|
|
|
<td><a href="${$item.logURL}">${$item.logURL}</a></td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
</table>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="totalStatisticsRowTemplate">
|
|
|
|
<tr onclick="totalDetailSelected('all')" class="row-${$item.index}">
|
|
|
|
<td class="stats-col-name">
|
|
|
|
<div class="stat-name">
|
|
|
|
<a href="#totals">{{html label}}</a>
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
{{tmpl($data) 'statColumnsTemplate'}}
|
|
|
|
</tr>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="tagStatisticsRowTemplate">
|
|
|
|
<tr onclick="tagDetailSelected('${label}')" class="row-${$item.index}">
|
|
|
|
<td class="stats-col-name" title="{{html doc}}">
|
|
|
|
<div class="stat-name">
|
|
|
|
<a href="#tags?${label}">{{html label}}</a>
|
|
|
|
{{if info}}(${info}){{/if}}
|
|
|
|
</div>
|
|
|
|
<div class="tag-links">
|
|
|
|
{{each links}}
|
|
|
|
<span>[<a href="{{html $value.url}}" onclick="stopPropagation(event)"
|
|
|
|
title="{{html $value.url}}">{{html $value.title}}</a>]</span>
|
|
|
|
{{/each}}
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
{{tmpl($data) 'statColumnsTemplate'}}
|
|
|
|
</tr>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="suiteStatisticsRowTemplate">
|
|
|
|
<tr onclick="suiteDetailSelected('${id}')" class="row-${$item.index}">
|
|
|
|
<td class="stats-col-name" title="{{html label}}">
|
|
|
|
<div class="stat-name">
|
|
|
|
<a href="#suites?${id}"><span class="parent-name">{{html formatParentName}}</span>{{html name}}</a>
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
{{tmpl($data) 'statColumnsTemplate'}}
|
|
|
|
</tr>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="detailsHeaderTemplate">
|
|
|
|
<h2 id="${linkTarget}">{{= testOrTask('{Test} Details')}}</h2>
|
|
|
|
<ul id="detail-tabs">
|
|
|
|
<li class="${totalTabStatus} detail-tab">
|
|
|
|
<a href="#totals" onclick="renderTotalSelector()"
|
|
|
|
title="{{= testOrTask('Show all {tests}')}}">All</a>
|
|
|
|
</li>
|
|
|
|
<li class="${tagTabStatus} detail-tab">
|
|
|
|
<a href="#tags" onclick="renderTagSelector()"
|
|
|
|
title="{{= testOrTask('Show {tests} by tag')}}">Tags</a>
|
|
|
|
</li>
|
|
|
|
<li class="${suiteTabStatus} detail-tab">
|
|
|
|
<a href="#suites" onclick="renderSuiteSelector()"
|
|
|
|
title="{{= testOrTask('Show {tests} by suite')}}">Suites</a>
|
|
|
|
</li>
|
|
|
|
<li class="${searchTabStatus} detail-tab">
|
|
|
|
<a href="#search" onclick="renderSearchSelector()"
|
|
|
|
title="{{= testOrTask('Free {test} search')}}">Search</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="totalDetailsSelectorTemplate">
|
|
|
|
<table class="details" id="details-header">
|
|
|
|
</table>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="tagDetailsSelectorTemplate">
|
|
|
|
<table class="details" id="details-header">
|
|
|
|
<tr class="selector">
|
|
|
|
<th>Tag:</th>
|
|
|
|
<td id="normal-selector">
|
|
|
|
<select id="tag-detail-selector" title="Tag selector"
|
|
|
|
onchange="tagDetailSelected(this.options[this.selectedIndex].value)">
|
|
|
|
<option selected disabled hidden>-- Select --</option>
|
|
|
|
{{each tags}}
|
|
|
|
<option value="${$value.label}"
|
|
|
|
{{if $value.label == selected}}selected="selected"{{/if}}>
|
|
|
|
{{html $value.label}} {{if $value.info}}(${$value.info}){{/if}}
|
|
|
|
</option>
|
|
|
|
{{/each}}
|
|
|
|
</select>
|
|
|
|
</td>
|
|
|
|
<td id="print-selector"></td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="suiteDetailsSelectorTemplate">
|
|
|
|
<table class="details" id="details-header">
|
|
|
|
<tr class="selector">
|
|
|
|
<th>Suite:</th>
|
|
|
|
<td id="normal-selector">
|
|
|
|
<select id="suite-detail-selector" title="Suite selector"
|
|
|
|
onchange="suiteDetailSelected(this.options[this.selectedIndex].value)">
|
|
|
|
<option selected disabled hidden>-- Select --</option>
|
|
|
|
{{each suites}}
|
|
|
|
<option value="${$value.id}"
|
|
|
|
{{if $value.id == selected}}selected="selected"{{/if}}>
|
|
|
|
{{html $value.label}}
|
|
|
|
</option>
|
|
|
|
{{/each}}
|
|
|
|
</select>
|
|
|
|
</td>
|
|
|
|
<td id="print-selector"></td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="searchSelectorTemplate">
|
|
|
|
<form action="javascript:void(0)">
|
|
|
|
<table class="details" id="details-header">
|
|
|
|
<tr class="selector first-selector">
|
|
|
|
<th><label for="search-suite">Suite:</label></th>
|
|
|
|
<td><input id="search-suite" type="text" value="${suite}"></td>
|
|
|
|
</tr>
|
|
|
|
<tr class="selector middle-selector">
|
|
|
|
<th><label for="search-test">{{= testOrTask('{Test}')}}:</label></th>
|
|
|
|
<td><input id="search-test" type="text" value="${test}"></td>
|
|
|
|
</tr>
|
|
|
|
<tr class="selector middle-selector">
|
|
|
|
<th><label for="search-include">Include:</label></th>
|
|
|
|
<td><input id="search-include" type="text" value="${include}"></td>
|
|
|
|
</tr>
|
|
|
|
<tr class="selector middle-selector">
|
|
|
|
<th><label for="search-exclude">Exclude:</label></th>
|
|
|
|
<td><input id="search-exclude" type="text" value="${exclude}"></td>
|
|
|
|
</tr>
|
|
|
|
<tr class="selector last-selector" id="search-buttons">
|
|
|
|
<th></th>
|
|
|
|
<td>
|
|
|
|
<input type="submit" value="Search"
|
|
|
|
onclick="searchExecuted($('#search-suite').val(),
|
|
|
|
$('#search-test').val(),
|
|
|
|
$('#search-include').val(),
|
|
|
|
$('#search-exclude').val());
|
|
|
|
return false;">
|
|
|
|
<input type="button" value="Clear"
|
|
|
|
onclick="$('#search-suite').val('');
|
|
|
|
$('#search-test').val('');
|
|
|
|
$('#search-include').val('');
|
|
|
|
$('#search-exclude').val('');">
|
|
|
|
<a href="javascript:void(0)" onclick="$('#search-help').toggle()"
|
|
|
|
title="Toggle search help.">Help</a>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr id="search-help" style="display: none">
|
|
|
|
<th></th>
|
|
|
|
<td>
|
|
|
|
<div>
|
|
|
|
<h3>Search fields</h3>
|
|
|
|
<p>
|
|
|
|
{{= testOrTask('{Test}')}}s can be searched based on suite and
|
|
|
|
{{= testOrTask('{test}')}} names as well as based on tags. If
|
|
|
|
multiple search criteria are used, only
|
|
|
|
{{= testOrTask('{test}')}}s matching all of them are included.
|
|
|
|
Search fields have same semantics as
|
|
|
|
<em>‑‑suite</em>,
|
|
|
|
<em>‑‑{{= testOrTask('{test}')}}</em>,
|
|
|
|
<em>‑‑include</em> and
|
|
|
|
<em>‑‑exclude</em> command line options, respectively.
|
|
|
|
</p>
|
|
|
|
<table class="search-help-examples">
|
|
|
|
<col class="help-item">
|
|
|
|
<col class="help-explanation">
|
|
|
|
<col class="help-examples>
|
|
|
|
<tr>
|
|
|
|
<th>Field</th>
|
|
|
|
<th>Explanation</th>
|
|
|
|
<th>Examples</th>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Suite</td>
|
|
|
|
<td>
|
|
|
|
{{= testOrTask('{Test}')}}s in matching suites are included.
|
|
|
|
The pattern can match either suite's name or its full name
|
|
|
|
that contains also parent suite names.
|
|
|
|
</td>
|
|
|
|
<td>My Suite<br>Root.Parent.Sui*</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>{{= testOrTask('{Test}')}}</td>
|
|
|
|
<td>
|
|
|
|
Matching {{= testOrTask('{test}')}}s are included. The
|
|
|
|
pattern can match either {{= testOrTask('{test}')}}'s name
|
|
|
|
or its full name that contains also parent suite names.
|
|
|
|
</td>
|
|
|
|
<td>Example Name<br>Root.Pa*.T???</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Include</td>
|
|
|
|
<td>
|
|
|
|
{{= testOrTask('{Test}')}}s that contain matching tags are
|
|
|
|
included.
|
|
|
|
</td>
|
|
|
|
<td>smoke<br>bug-*</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>Exclude</td>
|
|
|
|
<td>
|
|
|
|
{{= testOrTask('{Test}')}}s that contain matching tags are
|
|
|
|
not included.
|
|
|
|
</td>
|
|
|
|
<td>slow<br>feature-4?</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<h3>Patterns</h3>
|
|
|
|
<p>
|
|
|
|
All searches support <em>*</em> and <em>?</em> wildcards and are
|
|
|
|
case, space and underscore insensitive. Tag related searches also
|
|
|
|
support <em>AND</em>, <em>OR</em> and <em>NOT</em> (case-sensitive)
|
|
|
|
combining operators. If operators are used together, their
|
|
|
|
precedence, from highest to lowest, is <em>AND</em>, <em>OR</em>,
|
|
|
|
<em>NOT</em>. See <em>Simple patterns</em> and
|
|
|
|
<em>Tag patterns</em> sections in
|
|
|
|
<a href="http://robotframework.org/robotframework/#user-guide">Robot
|
|
|
|
Framework User Guide</a> for more details.
|
|
|
|
</p>
|
|
|
|
<table class="search-help-examples">
|
|
|
|
<col class="help-item">
|
|
|
|
<col class="help-explanation">
|
|
|
|
<col class="help-examples>
|
|
|
|
<tr>
|
|
|
|
<th>Pattern</th>
|
|
|
|
<th>Explanation</th>
|
|
|
|
<th>Examples</th>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>*</td>
|
|
|
|
<td>Matches anything, even an empty string.</td>
|
|
|
|
<td>f*<br>sprint-*</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>?</td>
|
|
|
|
<td>Matches any single character.</td>
|
|
|
|
<td>f??<br>sprint-1?</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>AND</td>
|
|
|
|
<td>Matches if all patterns match.</td>
|
|
|
|
<td>foo AND bar<br>x AND y* AND z??</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>OR</td>
|
|
|
|
<td>Matches if any pattern matches.</td>
|
|
|
|
<td>foo OR bar<br>x OR y* OR z1 AND z2</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>NOT</td>
|
|
|
|
<td>
|
|
|
|
Matches if (optional) pattern before matches and pattern
|
|
|
|
after does not.
|
|
|
|
</td>
|
|
|
|
<td>foo NOT bar<br>* NOT id-* AND smoke<br>NOT bar</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</form>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="tagOrTotalDetailsTemplate">
|
|
|
|
<tr>
|
|
|
|
<th>Status:</th>
|
|
|
|
<td>{{tmpl($data) 'suiteStatusMessageTemplate'}}</td>
|
|
|
|
</tr>
|
|
|
|
{{if doc}}
|
|
|
|
<tr>
|
|
|
|
<th>Documentation:</th>
|
|
|
|
<td>{{html doc}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
{{if combined}}
|
|
|
|
<tr>
|
|
|
|
<th>Pattern:</th>
|
|
|
|
<td>{{html combined}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
{{if links}}{{if links.length}}
|
|
|
|
<tr>
|
|
|
|
<th>Links:</th>
|
|
|
|
<td>{{each links}}<a href="{{html $value.url}}"
|
|
|
|
title="{{html $value.url}}">{{html $value.title}}</a> {{/each}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}{{/if}}
|
|
|
|
<tr>
|
|
|
|
<th>Total Time:</th>
|
|
|
|
<td>${totalTime}</td>
|
|
|
|
</tr>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="suiteDetailsTemplate">
|
|
|
|
<tr>
|
|
|
|
<th>Status:</th>
|
|
|
|
<td>{{tmpl($data) 'suiteStatusMessageTemplate'}}</td>
|
|
|
|
</tr>
|
|
|
|
{{if doc()}}
|
|
|
|
<tr>
|
|
|
|
<th>Documentation:</th>
|
|
|
|
<td class="doc">{{html doc()}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
{{each metadata}}
|
|
|
|
<tr>
|
|
|
|
<th>{{html $value[0]}}:</th>
|
|
|
|
<td class="doc">{{html $value[1]}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/each}}
|
|
|
|
{{if message()}}
|
|
|
|
<tr>
|
|
|
|
<th>Message:</th>
|
|
|
|
<td class="message">{{html message()}}</td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
<tr>
|
|
|
|
<th>Start / End Time:</th>
|
|
|
|
<td>${times.startTime} / ${times.endTime}</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Elapsed Time:</th>
|
|
|
|
<td>${times.elapsedTime}</td>
|
|
|
|
</tr>
|
|
|
|
{{if $item.logURL}}
|
|
|
|
<tr>
|
|
|
|
<th>Log File:</th>
|
|
|
|
<td><a href="${$item.logURL}#${id}"
|
|
|
|
title="{{html fullName}}">${$item.logURL}#${id}</a></td>
|
|
|
|
</tr>
|
|
|
|
{{/if}}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="testDetailsTableTemplate">
|
|
|
|
<table id="test-details">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th class="details-col-name" title="Name">
|
|
|
|
<div class='details-col-header'>Name</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-doc" title="Documentation">
|
|
|
|
<div class='details-col-toggle' onclick="toggleDetailsColumn('doc')">×</div>
|
|
|
|
<div class='details-col-header'>Documentation</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-tags" title="Tags">
|
|
|
|
<div class='details-col-toggle' onclick="toggleDetailsColumn('tags')">×</div>
|
|
|
|
<div class='details-col-header'>Tags</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-status" title="Status">
|
|
|
|
<div class='details-col-header'>Status</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-msg" title="Message">
|
|
|
|
<div class='details-col-toggle' onclick="toggleDetailsColumn('msg')">×</div>
|
|
|
|
<div class='details-col-header'>Message</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-elapsed" title="Elapsed Time">
|
|
|
|
<div class='details-col-toggle' onclick="toggleDetailsColumn('elapsed')">×</div>
|
|
|
|
<div class='details-col-header'>Elapsed</div>
|
|
|
|
</th>
|
|
|
|
<th class="details-col-times" title="Start Time / End Time">
|
|
|
|
<div class='details-col-toggle' onclick="toggleDetailsColumn('times')">×</div>
|
|
|
|
<div class='details-col-header'>Start / End</div>
|
|
|
|
</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody></tbody>
|
|
|
|
</table>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<script type="text/x-jquery-tmpl" id="testDetailsTableRowTemplate">
|
|
|
|
{{if $item.logURL}}
|
|
|
|
<tr onclick="location = '${$item.logURL}#${id}'" title="{{html fullName}}">
|
|
|
|
<td class="details-col-name">
|
|
|
|
<div><a href="${$item.logURL}#${id}"><span class="parent-name">{{html formatParentName}}</span>{{html name}}</a></div>
|
|
|
|
</td>
|
|
|
|
{{else}}
|
|
|
|
<tr title="{{html fullName}}">
|
|
|
|
<td class="details-col-name">
|
|
|
|
<div><span class="parent-name">{{html formatParentName}}</span>{{html name}}</div>
|
|
|
|
</td>
|
|
|
|
{{/if}}
|
|
|
|
<td class="details-col-doc"><div class="doc details-limited">{{html doc()}}</div></td>
|
|
|
|
<td class="details-col-tags"><div>{{html tags.join(', ')}}</div></td>
|
|
|
|
<td class="details-col-status"><div><span class="label ${status.toLowerCase()}">${status}</span></div></td>
|
|
|
|
<td class="details-col-msg"><div class="message details-limited">{{html message()}}</div></td>
|
|
|
|
<td class="details-col-elapsed"><div>${times.elapsedTime}</div></td>
|
|
|
|
<td class="details-col-times"><div>${times.startTime}<br>${times.endTime}</div></td>
|
|
|
|
</tr>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
</html>
|