Merge branch 'initial-frontend' into next-gen
This commit is contained in:
commit
68c72c7223
|
@ -6,36 +6,34 @@ $border-width: 1px;
|
|||
|
||||
$spacing: 5px;
|
||||
|
||||
|
||||
|
||||
body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: $font-size-text;
|
||||
/* do not increase min-width as some may use split screens */
|
||||
min-width: 800px;
|
||||
color: #999;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: $font-size-text;
|
||||
/* do not increase min-width as some may use split screens */
|
||||
min-width: 800px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $font-size-h1;
|
||||
color: black;
|
||||
font-size: $font-size-h1;
|
||||
color: black;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $font-size-h2;
|
||||
color: black;
|
||||
font-size: $font-size-h2;
|
||||
color: black;
|
||||
}
|
||||
|
||||
p {
|
||||
color: black;
|
||||
color: black;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #999;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
/******************************
|
||||
|
@ -43,14 +41,19 @@ table {
|
|||
******************************/
|
||||
|
||||
#environment {
|
||||
td {
|
||||
padding: $spacing;
|
||||
border: $border-width solid #E6E6E6;
|
||||
}
|
||||
td {
|
||||
padding: $spacing;
|
||||
border: $border-width solid #e6e6e6;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
tr:nth-child(odd) {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************
|
||||
|
@ -58,7 +61,7 @@ table {
|
|||
******************************/
|
||||
span.passed,
|
||||
.passed .col-result {
|
||||
color: green;
|
||||
color: green;
|
||||
}
|
||||
|
||||
span.skipped,
|
||||
|
@ -67,7 +70,7 @@ span.rerun,
|
|||
.skipped .col-result,
|
||||
.xfailed .col-result,
|
||||
.rerun .col-result {
|
||||
color: orange;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
span.error,
|
||||
|
@ -76,9 +79,15 @@ span.xpassed,
|
|||
.error .col-result,
|
||||
.failed .col-result,
|
||||
.xpassed .col-result {
|
||||
color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.col-result {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.col-links__extra {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* RESULTS TABLE
|
||||
|
@ -94,21 +103,21 @@ span.xpassed,
|
|||
*------------------*/
|
||||
|
||||
#results-table {
|
||||
border: $border-width solid #e6e6e6;
|
||||
color: #999;
|
||||
font-size: $font-size-text;
|
||||
width: 100%;
|
||||
border: $border-width solid #e6e6e6;
|
||||
color: #999;
|
||||
font-size: $font-size-text;
|
||||
width: 100%;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: $spacing;
|
||||
border: $border-width solid #E6E6E6;
|
||||
text-align: left;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: $spacing;
|
||||
border: $border-width solid #e6e6e6;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
}
|
||||
th {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------
|
||||
|
@ -119,99 +128,159 @@ $extra-height: 240px;
|
|||
$extra-media-width: 320px;
|
||||
|
||||
.log {
|
||||
background-color: #e6e6e6;
|
||||
border: $border-width solid #e6e6e6;
|
||||
color: black;
|
||||
display: block;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
height: $extra-height - 2 * $spacing;
|
||||
overflow-y: scroll;
|
||||
padding: $spacing;
|
||||
white-space: pre-wrap;
|
||||
background-color: #e6e6e6;
|
||||
border: $border-width solid #e6e6e6;
|
||||
color: black;
|
||||
display: block;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
height: $extra-height - 2 * $spacing;
|
||||
overflow-y: scroll;
|
||||
padding: $spacing;
|
||||
white-space: pre-wrap;
|
||||
|
||||
&:only-child {
|
||||
height: inherit;
|
||||
}
|
||||
&:only-child {
|
||||
height: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
div.image {
|
||||
border: $border-width solid #e6e6e6;
|
||||
float: right;
|
||||
height: $extra-height;
|
||||
margin-left: $spacing;
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
border: $border-width solid #e6e6e6;
|
||||
float: right;
|
||||
height: $extra-height;
|
||||
margin-left: $spacing;
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
|
||||
img {
|
||||
width: $extra-media-width;
|
||||
}
|
||||
img {
|
||||
width: $extra-media-width;
|
||||
}
|
||||
}
|
||||
|
||||
div.video {
|
||||
border: $border-width solid #e6e6e6;
|
||||
float: right;
|
||||
height: $extra-height;
|
||||
margin-left: $spacing;
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
border: $border-width solid #e6e6e6;
|
||||
float: right;
|
||||
height: $extra-height;
|
||||
margin-left: $spacing;
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
|
||||
video {
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
height: $extra-height;
|
||||
}
|
||||
video {
|
||||
overflow: hidden;
|
||||
width: $extra-media-width;
|
||||
height: $extra-height;
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expander::after {
|
||||
content: " (show details)";
|
||||
color: #BBB;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
content: ' (show details)';
|
||||
color: #bbb;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapser::after {
|
||||
content: " (hide details)";
|
||||
color: #BBB;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
content: ' (hide details)';
|
||||
color: #bbb;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*------------------
|
||||
* 3. Sorting items
|
||||
*------------------*/
|
||||
.sortable {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
&.asc {
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: relative;
|
||||
left: 5px;
|
||||
bottom: -12.5px;
|
||||
border: 10px solid #4caf50;
|
||||
border-bottom: 0;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
&.desc {
|
||||
&:after {
|
||||
content: ' ';
|
||||
position: relative;
|
||||
left: 5px;
|
||||
bottom: 12.5px;
|
||||
border: 10px solid #4caf50;
|
||||
border-top: 0;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sort-icon {
|
||||
font-size: 0px;
|
||||
float: left;
|
||||
margin-right: $spacing;
|
||||
margin-top: $spacing;
|
||||
// font-size: 0px;
|
||||
// float: left;
|
||||
// margin-right: $spacing;
|
||||
// margin-top: $spacing;
|
||||
|
||||
/*triangle*/
|
||||
$triangle-width: 8px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: $triangle-width solid transparent;
|
||||
border-right: $triangle-width solid transparent;
|
||||
// /*triangle*/
|
||||
// $triangle-width: 8px;
|
||||
// width: 0;
|
||||
// height: 0;
|
||||
// border-left: $triangle-width solid transparent;
|
||||
// border-right: $triangle-width solid transparent;
|
||||
|
||||
.inactive & {
|
||||
/*finish triangle*/
|
||||
border-top: $triangle-width solid #E6E6E6;
|
||||
}
|
||||
// .asc {
|
||||
// /*finish triangle*/
|
||||
// border-bottom: $triangle-width solid #999;
|
||||
// }
|
||||
|
||||
.asc.active & {
|
||||
/*finish triangle*/
|
||||
border-bottom: $triangle-width solid #999;
|
||||
}
|
||||
|
||||
.desc.active & {
|
||||
/*finish triangle*/
|
||||
border-top: $triangle-width solid #999;
|
||||
}
|
||||
// .desc {
|
||||
// /*finish triangle*/
|
||||
// border-top: $triangle-width solid #999;
|
||||
// }
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.summary {
|
||||
display: flex;
|
||||
&__data {
|
||||
flex: 0 0 550px;
|
||||
}
|
||||
&__reload {
|
||||
flex: 1 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
&__button {
|
||||
flex: 0 0 300px;
|
||||
display: flex;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
background-color: #4caf50;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
&.hidden {
|
||||
@extend .hidden;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #46a049;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__spacer {
|
||||
flex: 0 0 550px;
|
||||
}
|
||||
}
|
||||
|
||||
input.filter {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"singleQuote": true
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
|
@ -0,0 +1,82 @@
|
|||
// const templateEnvRow = find('#template_environment_row');
|
||||
// const templateResult = find('#template_results-table__tbody');
|
||||
// const aTag = find('#template_a');
|
||||
// const aTagImg = find('#template_img');
|
||||
// const listHeader = find('#template_results-table__head');
|
||||
const dom = {
|
||||
getStaticRow: (key, value) => {
|
||||
var envRow = templateEnvRow.content.cloneNode(true);
|
||||
const isObj = typeof value === 'object' && value !== null;
|
||||
const values = isObj
|
||||
? Object.keys(value).map((k) => `${k}: ${value[k]}`)
|
||||
: null;
|
||||
|
||||
const valuesElement = htmlToElements(
|
||||
values
|
||||
? `<ul>${values.map((val) => `<li>${val}</li>`).join('')}<ul>`
|
||||
: `<div>${value}</div>`
|
||||
)[0];
|
||||
var td = findAll('td', envRow);
|
||||
td[0].textContent = key;
|
||||
td[1].appendChild(valuesElement);
|
||||
|
||||
return envRow;
|
||||
},
|
||||
getListHeader: () => {
|
||||
const header = listHeader.content.cloneNode(true);
|
||||
const sortAttr = localStorage.getItem('sort');
|
||||
const sortAsc = JSON.parse(localStorage.getItem('sortAsc'));
|
||||
const sortables = ['outcome', 'nodeid', 'duration'];
|
||||
|
||||
sortables.forEach((sortCol) => {
|
||||
if (sortCol === sortAttr) {
|
||||
find(`[data-column-type="${sortCol}"]`, header).classList.add(
|
||||
sortAsc ? 'desc' : 'asc'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return header;
|
||||
},
|
||||
getListHeaderEmpty: () => listHeaderEmpty.content.cloneNode(true),
|
||||
getResultTBody: ({ nodeid, longrepr, extras, duration }, outcome) => {
|
||||
const isFail = outcome === 'failed';
|
||||
const resultBody = templateResult.content.cloneNode(true);
|
||||
find('tbody', resultBody).classList.add(outcome);
|
||||
|
||||
find('.col-result', resultBody).innerText = outcome;
|
||||
find('.col-name', resultBody).innerText = nodeid;
|
||||
find('.col-duration', resultBody).innerText = `${(duration * 1000).toFixed(
|
||||
2
|
||||
)}s`;
|
||||
if (isFail) {
|
||||
find('.log', resultBody).innerText = longrepr
|
||||
? longrepr.reprtraceback.reprentries[0].data.lines.join('\n')
|
||||
: '';
|
||||
} else {
|
||||
find('.extras-row', resultBody).classList.add('hidden');
|
||||
}
|
||||
|
||||
extras &&
|
||||
extras.forEach(({ name, format_type, content }) => {
|
||||
const extraLink = aTag.content.cloneNode(true);
|
||||
const extraLinkItem = find('a', extraLink);
|
||||
const folderItems = ['image', 'video', 'text', 'html', 'json'];
|
||||
|
||||
extraLinkItem.href = `${
|
||||
folderItems.includes(format_type) ? 'assets/' : ''
|
||||
}${content}`;
|
||||
extraLinkItem.className = `col-links__extra ${format_type}`;
|
||||
extraLinkItem.innerText = name;
|
||||
find('.col-links', resultBody).appendChild(extraLinkItem);
|
||||
if (format_type === 'image') {
|
||||
const imgElTemp = aTagImg.content.cloneNode(true);
|
||||
find('a', imgElTemp).href = `assets/${content}`;
|
||||
find('img', imgElTemp).src = `assets/${content}`;
|
||||
find('.extra .image', resultBody).appendChild(imgElTemp);
|
||||
}
|
||||
});
|
||||
|
||||
return resultBody;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
const dispatchEvent = (type, detail) => {
|
||||
const newEvent = new CustomEvent(type, { detail });
|
||||
|
||||
document.dispatchEvent(newEvent);
|
||||
};
|
||||
|
||||
const doSort = (type) => {
|
||||
const newSortType = localStorage.getItem('sort') !== type;
|
||||
const currentAsc = JSON.parse(localStorage.getItem('sortAsc'));
|
||||
const ascending = newSortType ? true : !currentAsc;
|
||||
localStorage.setItem('sort', type);
|
||||
localStorage.setItem('sortAsc', ascending);
|
||||
dispatchEvent('sort', { type, ascending });
|
||||
};
|
||||
|
||||
document.addEventListener('sort', (e) => {
|
||||
const { type, ascending } = e.detail;
|
||||
const sortedList = genericSort(renderData.tests, type, ascending);
|
||||
renderData.tests = sortedList;
|
||||
initRender();
|
||||
});
|
||||
|
||||
const doFilter = (type, apply) => {
|
||||
const currentFilter = [
|
||||
...new Set(JSON.parse(localStorage.getItem('filter'))),
|
||||
];
|
||||
if (apply) {
|
||||
currentFilter.push(type);
|
||||
} else {
|
||||
const index = currentFilter.indexOf(type);
|
||||
currentFilter.splice(index, 1);
|
||||
}
|
||||
localStorage.setItem('filter', JSON.stringify(currentFilter));
|
||||
const filteredSubset = [];
|
||||
if (currentFilter.length) {
|
||||
currentFilter.forEach((filter) => {
|
||||
filteredSubset.push(
|
||||
...jsonData.tests.filter(({ outcome }) => outcome === filter)
|
||||
);
|
||||
});
|
||||
renderData.tests = filteredSubset;
|
||||
} else {
|
||||
renderData.tests = jsonData.tests;
|
||||
}
|
||||
initRender();
|
||||
};
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test Report</title>
|
||||
<link href="style.css" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<body onLoad="init()">
|
||||
<h1 id="title"></h1>
|
||||
<p>Report generated on 17-Dec-2020 at 14:02:36 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a> v1.22.0</p>
|
||||
<h2>Environment</h2>
|
||||
<table id="environment"><table>
|
||||
<!-- TEMPLATES -->
|
||||
<template id="template_environment_row">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</template>
|
||||
<template id="template_a">
|
||||
<a target="_blank"></a>
|
||||
</template>
|
||||
<template id="template_img">
|
||||
<a target="_blank">
|
||||
<img />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<template id="template_results-table__tbody">
|
||||
<tbody class="results-table-row">
|
||||
<tr>
|
||||
<td class="col-result"></td>
|
||||
<td class="col-name"></td>
|
||||
<td class="col-duration"></td>
|
||||
<td class="col-links"></td>
|
||||
</tr>
|
||||
<tr class="extras-row">
|
||||
<td class="extra" colspan="4">
|
||||
<div class="image"></div>
|
||||
<div class="log"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
<template id="template_results-table__head">
|
||||
<thead id="results-table-head">
|
||||
<tr>
|
||||
<th class="sortable" data-column-type="outcome">Result</th>
|
||||
<th class="sortable" data-column-type="nodeid">Test</th>
|
||||
<th class="sortable" data-column-type="duration">Duration</th>
|
||||
<th>Links</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</template>
|
||||
<template id="template_results-table__head--empty">
|
||||
<tr id="not-found-message">
|
||||
<th colspan="4">No results found. Try to check the filters</th>
|
||||
</tr>
|
||||
</template>
|
||||
<!-- END TEMPLATES -->
|
||||
<div class="summary">
|
||||
<div class="summary__data">
|
||||
<h2>Summary</h2>
|
||||
<p class="run-count"></p>
|
||||
<p class="filter">(Un)check the boxes to filter the results.</p>
|
||||
|
||||
<input checked="true" class="filter" data-test-result="error" name="filter_checkbox" type="checkbox"/><span class="error"></span>
|
||||
<input checked="true" class="filter" data-test-result="failed" name="filter_checkbox" type="checkbox"/><span class="failed"></span>
|
||||
<input checked="true" class="filter" data-test-result="rerun" name="filter_checkbox" type="checkbox"/><span class="rerun"></span>
|
||||
<input checked="true" class="filter" data-test-result="xfailed" name="filter_checkbox" type="checkbox"/><span class="xfailed"></span>
|
||||
<input checked="true" class="filter" data-test-result="xpassed" name="filter_checkbox" type="checkbox"/><span class="xpassed"></span>
|
||||
<input checked="true" class="filter" data-test-result="passed" name="filter_checkbox" type="checkbox"/><span class="passed"></span>
|
||||
<input checked="true" class="filter" data-test-result="skipped" name="filter_checkbox" type="checkbox"/><span class="skipped"></span>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="summary__reload">
|
||||
<div class="summary__reload__button" onclick="location.reload()">
|
||||
<div>There are still tests running. <br />Reload this page to ge the latest results!</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary__spacer">
|
||||
</div>
|
||||
</div>
|
||||
<h2>Results</h2>
|
||||
<table id="results-table">
|
||||
|
||||
</table>
|
||||
</body>
|
||||
<footer>
|
||||
<script src="events.js"></script>
|
||||
<script src="dom.js"></script>
|
||||
<script src="nextgendata.js"></script>
|
||||
<script src="sort.js"></script>
|
||||
<script src="index.js"></script>
|
||||
<script src="main.js"></script>
|
||||
</footer>
|
||||
</html>
|
|
@ -0,0 +1,134 @@
|
|||
function htmlToElements(html) {
|
||||
let temp = document.createElement('template');
|
||||
temp.innerHTML = html;
|
||||
return temp.content.childNodes;
|
||||
}
|
||||
const find = (selector, elem) => {
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return elem.querySelector(selector);
|
||||
};
|
||||
const findAll = (selector, elem) => {
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return toArray(elem.querySelectorAll(selector));
|
||||
};
|
||||
const templateEnvRow = find('#template_environment_row');
|
||||
const templateResult = find('#template_results-table__tbody');
|
||||
const aTag = find('#template_a');
|
||||
const aTagImg = find('#template_img');
|
||||
const listHeader = find('#template_results-table__head');
|
||||
const listHeaderEmpty = find('#template_results-table__head--empty');
|
||||
|
||||
const removeChildren = (node) => {
|
||||
while (node.firstChild) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
const getOutcome = ({ nodeid }, tests) => {
|
||||
const relatedOutcome = tests
|
||||
.filter((test) => test.nodeid === nodeid)
|
||||
.map(({ outcome }) => outcome);
|
||||
if (relatedOutcome.includes('failed')) {
|
||||
return 'failed';
|
||||
} else if (relatedOutcome.includes('error')) {
|
||||
return 'error';
|
||||
} else if (relatedOutcome.includes('xpassed')) {
|
||||
return 'xpassed';
|
||||
} else if (relatedOutcome.includes('xfailed')) {
|
||||
return 'xfailed';
|
||||
} else if (relatedOutcome.includes('skipped')) {
|
||||
return 'skipped';
|
||||
} else {
|
||||
return 'passed';
|
||||
}
|
||||
};
|
||||
|
||||
const renderStatic = (obj) => {
|
||||
find('#title').innerText = obj.title;
|
||||
const rows = Object.keys(obj.environment).map((key) =>
|
||||
dom.getStaticRow(key, obj.environment[key])
|
||||
);
|
||||
|
||||
const table = find('#environment');
|
||||
removeChildren(table);
|
||||
rows.forEach((row) => table.appendChild(row));
|
||||
};
|
||||
const renderContent = ({ tests }) => {
|
||||
const renderSet = tests.filter(({ when }) => when === 'call');
|
||||
|
||||
const rows = renderSet.map((test) =>
|
||||
dom.getResultTBody(test, getOutcome(test, tests))
|
||||
);
|
||||
const table = find('#results-table');
|
||||
removeChildren(table);
|
||||
const tableHeader = dom.getListHeader();
|
||||
if (!rows.length) {
|
||||
tableHeader.appendChild(dom.getListHeaderEmpty());
|
||||
}
|
||||
table.appendChild(tableHeader);
|
||||
|
||||
rows.forEach((row) => !!row && table.appendChild(row));
|
||||
};
|
||||
const renderDerrived = ({ tests, collectedItems }) => {
|
||||
const renderSet = tests.filter(({ when }) => when === 'call');
|
||||
|
||||
const possibleOutcomes = [
|
||||
'passed',
|
||||
'skipped',
|
||||
'failed',
|
||||
'error',
|
||||
'xfailed',
|
||||
'xpassed',
|
||||
'rerun',
|
||||
];
|
||||
possibleOutcomes.forEach((outcome) => {
|
||||
const count = renderSet.filter((test) => test.outcome === outcome).length;
|
||||
|
||||
find(`.${outcome}`).innerText = `${count} ${outcome}`;
|
||||
if (!count) {
|
||||
find(`input[data-test-result="${outcome}"]`).disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
let accTime = 0;
|
||||
if (collectedItems === renderSet.length) {
|
||||
tests.forEach(({ duration }) => (accTime += duration));
|
||||
accTime = accTime.toFixed(2);
|
||||
find(
|
||||
'.run-count'
|
||||
).innerText = `${renderSet.length} tests ran in ${accTime} seconds.`;
|
||||
find('.summary__reload__button').classList.add('hidden');
|
||||
} else {
|
||||
find(
|
||||
'.run-count'
|
||||
).innerText = `${renderSet.length} / ${collectedItems} tests done`;
|
||||
}
|
||||
};
|
||||
|
||||
const bindEvents = () => {
|
||||
findAll('.sortable').forEach((elem) => {
|
||||
elem.addEventListener('click', (evt) => {
|
||||
const { target: element } = evt;
|
||||
const { columnType } = element.dataset;
|
||||
|
||||
doSort(columnType);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const renderPage = (subset, full) => {
|
||||
renderStatic(jsonData);
|
||||
renderContent(renderData);
|
||||
renderDerrived(jsonData);
|
||||
};
|
||||
let renderData = { ...jsonData };
|
||||
const initRender = () => {
|
||||
setTimeout(() => {
|
||||
renderPage(renderData);
|
||||
bindEvents();
|
||||
}, 0);
|
||||
};
|
|
@ -2,235 +2,114 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function is_all_rows_hidden(value) {
|
||||
return value.hidden == false;
|
||||
}
|
||||
|
||||
function filter_table(elem) {
|
||||
var outcome_att = 'data-test-result';
|
||||
var outcome = elem.getAttribute(outcome_att);
|
||||
console.log(outcome);
|
||||
class_outcome = outcome + ' results-table-row';
|
||||
var outcome_rows = document.getElementsByClassName(class_outcome);
|
||||
|
||||
for (var i = 0; i < outcome_rows.length; i++) {
|
||||
outcome_rows[i].hidden = !elem.checked;
|
||||
}
|
||||
|
||||
var rows = find_all('.results-table-row').filter(is_all_rows_hidden);
|
||||
var all_rows_hidden = rows.length == 0 ? true : false;
|
||||
var not_found_message = document.getElementById('not-found-message');
|
||||
not_found_message.hidden = !all_rows_hidden;
|
||||
}
|
||||
|
||||
function toArray(iter) {
|
||||
if (iter === null) {
|
||||
return null;
|
||||
}
|
||||
return Array.prototype.slice.call(iter);
|
||||
if (iter === null) {
|
||||
return null;
|
||||
}
|
||||
return Array.prototype.slice.call(iter);
|
||||
}
|
||||
|
||||
function find(selector, elem) { // eslint-disable-line no-redeclare
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return elem.querySelector(selector);
|
||||
function showAllExtras() {
|
||||
// eslint-disable-line no-unused-vars
|
||||
findAll('.col-result').forEach(showExtras);
|
||||
}
|
||||
|
||||
function findAll(selector, elem) {
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return toArray(elem.querySelectorAll(selector));
|
||||
}
|
||||
|
||||
function sortColumn(elem) {
|
||||
toggleSortStates(elem);
|
||||
const colIndex = toArray(elem.parentNode.childNodes).indexOf(elem);
|
||||
let key;
|
||||
if (elem.classList.contains('result')) {
|
||||
key = keyResult;
|
||||
} else if (elem.classList.contains('links')) {
|
||||
key = keyLink;
|
||||
} else {
|
||||
key = keyAlpha;
|
||||
}
|
||||
sortTable(elem, key(colIndex));
|
||||
}
|
||||
|
||||
function showAllExtras() { // eslint-disable-line no-unused-vars
|
||||
findAll('.col-result').forEach(showExtras);
|
||||
}
|
||||
|
||||
function hideAllExtras() { // eslint-disable-line no-unused-vars
|
||||
findAll('.col-result').forEach(hideExtras);
|
||||
function hideAllExtras() {
|
||||
// eslint-disable-line no-unused-vars
|
||||
findAll('.col-result').forEach(hideExtras);
|
||||
}
|
||||
|
||||
function showExtras(colresultElem) {
|
||||
const extras = colresultElem.parentNode.nextElementSibling;
|
||||
const expandcollapse = colresultElem.firstElementChild;
|
||||
extras.classList.remove('collapsed');
|
||||
expandcollapse.classList.remove('expander');
|
||||
expandcollapse.classList.add('collapser');
|
||||
const extras = colresultElem.parentNode.nextElementSibling;
|
||||
const expandcollapse = colresultElem.firstElementChild;
|
||||
extras.classList.remove('collapsed');
|
||||
expandcollapse.classList.remove('expander');
|
||||
expandcollapse.classList.add('collapser');
|
||||
}
|
||||
|
||||
function hideExtras(colresultElem) {
|
||||
const extras = colresultElem.parentNode.nextElementSibling;
|
||||
const expandcollapse = colresultElem.firstElementChild;
|
||||
extras.classList.add('collapsed');
|
||||
expandcollapse.classList.remove('collapser');
|
||||
expandcollapse.classList.add('expander');
|
||||
}
|
||||
|
||||
function showFilters() {
|
||||
const filterItems = document.getElementsByClassName('filter');
|
||||
for (let i = 0; i < filterItems.length; i++)
|
||||
filterItems[i].hidden = false;
|
||||
const extras = colresultElem.parentNode.nextElementSibling;
|
||||
const expandcollapse = colresultElem.firstElementChild;
|
||||
extras.classList.add('collapsed');
|
||||
expandcollapse.classList.remove('collapser');
|
||||
expandcollapse.classList.add('expander');
|
||||
}
|
||||
|
||||
function addCollapse() {
|
||||
// Add links for show/hide all
|
||||
const resulttable = find('table#results-table');
|
||||
const showhideall = document.createElement('p');
|
||||
showhideall.innerHTML = '<a href="javascript:showAllExtras()">Show all details</a> / ' +
|
||||
'<a href="javascript:hideAllExtras()">Hide all details</a>';
|
||||
resulttable.parentElement.insertBefore(showhideall, resulttable);
|
||||
// Add links for show/hide all
|
||||
const resulttable = find('table#results-table');
|
||||
const showhideall = document.createElement('p');
|
||||
showhideall.innerHTML =
|
||||
'<a href="javascript:showAllExtras()">Show all details</a> / ' +
|
||||
'<a href="javascript:hideAllExtras()">Hide all details</a>';
|
||||
resulttable.parentElement.insertBefore(showhideall, resulttable);
|
||||
|
||||
// Add show/hide link to each result
|
||||
findAll('.col-result').forEach(function(elem) {
|
||||
const collapsed = getQueryParameter('collapsed') || 'Passed';
|
||||
const extras = elem.parentNode.nextElementSibling;
|
||||
const expandcollapse = document.createElement('span');
|
||||
if (extras.classList.contains('collapsed')) {
|
||||
expandcollapse.classList.add('expander');
|
||||
} else if (collapsed.includes(elem.innerHTML)) {
|
||||
extras.classList.add('collapsed');
|
||||
expandcollapse.classList.add('expander');
|
||||
} else {
|
||||
expandcollapse.classList.add('collapser');
|
||||
}
|
||||
elem.appendChild(expandcollapse);
|
||||
// Add show/hide link to each result
|
||||
findAll('.col-result').forEach(function (elem) {
|
||||
const collapsed = getQueryParameter('collapsed') || 'Passed';
|
||||
const extras = elem.parentNode.nextElementSibling;
|
||||
const expandcollapse = document.createElement('span');
|
||||
if (extras.classList.contains('collapsed')) {
|
||||
expandcollapse.classList.add('expander');
|
||||
} else if (collapsed.includes(elem.innerHTML)) {
|
||||
extras.classList.add('collapsed');
|
||||
expandcollapse.classList.add('expander');
|
||||
} else {
|
||||
expandcollapse.classList.add('collapser');
|
||||
}
|
||||
elem.appendChild(expandcollapse);
|
||||
|
||||
elem.addEventListener('click', function(event) {
|
||||
if (event.currentTarget.parentNode.nextElementSibling.classList.contains('collapsed')) {
|
||||
showExtras(event.currentTarget);
|
||||
} else {
|
||||
hideExtras(event.currentTarget);
|
||||
}
|
||||
});
|
||||
elem.addEventListener('click', function (event) {
|
||||
if (
|
||||
event.currentTarget.parentNode.nextElementSibling.classList.contains(
|
||||
'collapsed'
|
||||
)
|
||||
) {
|
||||
showExtras(event.currentTarget);
|
||||
} else {
|
||||
hideExtras(event.currentTarget);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getQueryParameter(name) {
|
||||
const match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||
const match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||
}
|
||||
function init() {
|
||||
// eslint-disable-line no-unused-vars
|
||||
setTimeout(() => {
|
||||
findAll('input[name="filter_checkbox"]').forEach((elem) => {
|
||||
elem.addEventListener('click', (evt) => {
|
||||
const { target: element } = evt;
|
||||
const { testResult } = element.dataset;
|
||||
|
||||
function init () { // eslint-disable-line no-unused-vars
|
||||
resetSortHeaders();
|
||||
|
||||
doFilter(testResult, element.checked);
|
||||
});
|
||||
});
|
||||
initRender();
|
||||
addCollapse();
|
||||
|
||||
showFilters();
|
||||
|
||||
sortColumn(find('.initial-sort'));
|
||||
|
||||
findAll('.sortable').forEach(function(elem) {
|
||||
elem.addEventListener('click',
|
||||
function() {
|
||||
sortColumn(elem);
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
function sortTable(clicked, keyFunc) {
|
||||
const rows = findAll('.results-table-row');
|
||||
const reversed = !clicked.classList.contains('asc');
|
||||
const sortedRows = sort(rows, keyFunc, reversed);
|
||||
/* Whole table is removed here because browsers acts much slower
|
||||
* when appending existing elements.
|
||||
*/
|
||||
const thead = document.getElementById('results-table-head');
|
||||
document.getElementById('results-table').remove();
|
||||
const parent = document.createElement('table');
|
||||
parent.id = 'results-table';
|
||||
parent.appendChild(thead);
|
||||
sortedRows.forEach(function(elem) {
|
||||
parent.appendChild(elem);
|
||||
});
|
||||
document.getElementsByTagName('BODY')[0].appendChild(parent);
|
||||
}
|
||||
|
||||
function sort(items, keyFunc, reversed) {
|
||||
const sortArray = items.map(function(item, i) {
|
||||
return [keyFunc(item), i];
|
||||
});
|
||||
|
||||
sortArray.sort(function(a, b) {
|
||||
const keyA = a[0];
|
||||
const keyB = b[0];
|
||||
|
||||
if (keyA == keyB) return 0;
|
||||
|
||||
if (reversed) {
|
||||
return keyA < keyB ? 1 : -1;
|
||||
} else {
|
||||
return keyA > keyB ? 1 : -1;
|
||||
}
|
||||
});
|
||||
|
||||
return sortArray.map(function(item) {
|
||||
const index = item[1];
|
||||
return items[index];
|
||||
});
|
||||
}
|
||||
|
||||
function keyAlpha(colIndex) {
|
||||
return function(elem) {
|
||||
return elem.childNodes[1].childNodes[colIndex].firstChild.data.toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
function keyLink(colIndex) {
|
||||
return function(elem) {
|
||||
const dataCell = elem.childNodes[1].childNodes[colIndex].firstChild;
|
||||
return dataCell == null ? '' : dataCell.innerText.toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
function keyResult(colIndex) {
|
||||
return function(elem) {
|
||||
const strings = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed',
|
||||
'Skipped', 'Passed'];
|
||||
return strings.indexOf(elem.childNodes[1].childNodes[colIndex].firstChild.data);
|
||||
};
|
||||
}
|
||||
|
||||
function resetSortHeaders() {
|
||||
findAll('.sort-icon').forEach(function(elem) {
|
||||
elem.parentNode.removeChild(elem);
|
||||
});
|
||||
findAll('.sortable').forEach(function(elem) {
|
||||
const icon = document.createElement('div');
|
||||
icon.className = 'sort-icon';
|
||||
icon.textContent = 'vvv';
|
||||
elem.insertBefore(icon, elem.firstChild);
|
||||
elem.classList.remove('desc', 'active');
|
||||
elem.classList.add('asc', 'inactive');
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSortStates(elem) {
|
||||
//if active, toggle between asc and desc
|
||||
if (elem.classList.contains('active')) {
|
||||
elem.classList.toggle('asc');
|
||||
elem.classList.toggle('desc');
|
||||
}
|
||||
|
||||
//if inactive, reset all other functions and add ascending active
|
||||
if (elem.classList.contains('inactive')) {
|
||||
resetSortHeaders();
|
||||
elem.classList.remove('inactive');
|
||||
elem.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function isAllRowsHidden(value) {
|
||||
return value.hidden == false;
|
||||
}
|
||||
|
||||
function filterTable(elem) { // eslint-disable-line no-unused-vars
|
||||
const outcomeAtt = 'data-test-result';
|
||||
const outcome = elem.getAttribute(outcomeAtt);
|
||||
const classOutcome = outcome + ' results-table-row';
|
||||
const outcomeRows = document.getElementsByClassName(classOutcome);
|
||||
|
||||
for(let i = 0; i < outcomeRows.length; i++){
|
||||
outcomeRows[i].hidden = !elem.checked;
|
||||
}
|
||||
|
||||
const rows = findAll('.results-table-row').filter(isAllRowsHidden);
|
||||
const allRowsHidden = rows.length == 0 ? true : false;
|
||||
const notFoundMessage = document.getElementById('not-found-message');
|
||||
notFoundMessage.hidden = !allRowsHidden;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,734 @@
|
|||
const jsonData = {
|
||||
title: 'Next Gen Report',
|
||||
collectedItems: 10,
|
||||
environment: {
|
||||
Python: '3.7.7',
|
||||
Platform: 'Darwin-19.6.0-x86_64-i386-64bit',
|
||||
Packages: { pytest: '6.1.2', py: '1.9.0', pluggy: '0.13.1' },
|
||||
Plugins: { metadata: '1.11.0', reportlog: '0.1.2', html: '2.1.2.dev78' },
|
||||
},
|
||||
tests: [
|
||||
{
|
||||
nodeid: 'test_html.py::test_url',
|
||||
location: ['test_html.py', 3, 'test_url'],
|
||||
keywords: { test_url: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.0001576979999999839,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url',
|
||||
location: ['test_html.py', 3, 'test_url'],
|
||||
keywords: { test_url: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'failed',
|
||||
extras: [
|
||||
{
|
||||
name: 'Snapshot',
|
||||
format_type: 'image',
|
||||
content: 'snapshot_of_what_went_wrong.png',
|
||||
mime_type: 'image/png',
|
||||
extension: '.png',
|
||||
},
|
||||
{
|
||||
name: 'Google',
|
||||
format_type: 'url',
|
||||
content: 'https://search.yahoo.com/',
|
||||
mime_type: null,
|
||||
extension: null,
|
||||
},
|
||||
],
|
||||
longrepr: {
|
||||
reprcrash: {
|
||||
path: '/Users/jimbrannlund/dev/pytest-dev/testing-html/test_html.py',
|
||||
lineno: 12,
|
||||
message: 'assert False',
|
||||
},
|
||||
reprtraceback: {
|
||||
reprentries: [
|
||||
{
|
||||
type: 'ReprEntry',
|
||||
data: {
|
||||
lines: [
|
||||
'universe = <pytest_setup.database.TestDataCollection object at 0x7fe2cf1c4dd8>',
|
||||
'driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="2c586c44-7cb6-8e48-86fd-ae2d2982a3bd")>',
|
||||
'',
|
||||
'@pytest.mark.user(name="Bob", account=\'Rolfs Account\')',
|
||||
"@pytest.mark.setup_data({'EnterpriseProject': [{'name': 'Dependencies', 'user': 'Bob'}]},",
|
||||
"{'Activity': [",
|
||||
"{'name': 'Move',",
|
||||
"'project': 'Dependencies',",
|
||||
"'user': 'Bob',",
|
||||
"'dates': {'start_date': 1, 'end_date': 7}},",
|
||||
"{'name': 'Nope',",
|
||||
"'project': 'Dependencies',",
|
||||
"'user': 'Bob',",
|
||||
"'dates': {'start_date': 8, 'end_date': 14}}]})",
|
||||
'def test_dependency_forces_date_change(universe, driver):',
|
||||
'from test_automation.tools.date_handling import convert_to_correct_date',
|
||||
' ',
|
||||
'_to_depend_on = "Move"',
|
||||
"_expected_dates = {'start_date': convert_to_correct_date(15), 'end_date': convert_to_correct_date(21)}",
|
||||
' ',
|
||||
"_user = universe.get('User', 'Bob')",
|
||||
"_act = universe.get('Activity', 'Move')",
|
||||
' ',
|
||||
'ActivityDetailsPane(driver).',
|
||||
"go_to_page(universe.get('User', 'Bob'),",
|
||||
"universe.get('EnterpriseProject', 'Dependencies'),",
|
||||
'universe.get("Activity", "Nope")). ',
|
||||
"open_activity('Move'). ",
|
||||
"> open_activity('Nope'). ",
|
||||
'open_widgets_section(). ',
|
||||
"get_widget('planletdependencies').",
|
||||
'add_predecessor(_to_depend_on).',
|
||||
"get_details_pane('activity').",
|
||||
'close_details_pane().',
|
||||
'click_planlet_checkbox(_act.id).',
|
||||
"get_widget('date').",
|
||||
'verify_dates(_expected_dates)',
|
||||
'',
|
||||
'test_automation/tests/ui_tests/plan_tests/activity_details_pane_test.py:121: ',
|
||||
'_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ',
|
||||
'test_automation/page_objects/details_panes/activity_details_pane.py:241: in open_widgets_section',
|
||||
'_wait_for_plus_sign()',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/decorators.py:112: in wait_handler',
|
||||
'value = func(*args, **kwargs)',
|
||||
'test_automation/page_objects/details_panes/activity_details_pane.py:236: in _wait_for_plus_sign',
|
||||
'if self.get_present_element(self._plus_sign_locator):',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/base_page.py:422: in get_present_element',
|
||||
'return self._get(locator, expected_condition, params, timeout, error_msg, parent)',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/base_page.py:569: in _get',
|
||||
'return WebDriverWait(_driver, timeout).until(exp_cond, error_msg)',
|
||||
'_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ',
|
||||
'',
|
||||
'self = <selenium.webdriver.support.wait.WebDriverWait (session="2c586c44-7cb6-8e48-86fd-ae2d2982a3bd")>',
|
||||
'method = <selenium.webdriver.support.expected_conditions.presence_of_element_located object at 0x7fe2cf1a7240>',
|
||||
'message = "Element was never present!\nLocator of type <CSS_SELECTOR> with selector <.pp-rounded-btn__icon.category-bck-3> with ...nExpected condition: <class \'selenium.webdriver.support.expected_conditions.presence_of_element_located\'>\nTimeout: 30"',
|
||||
'',
|
||||
"def until(self, method, message=''):",
|
||||
'"""Calls the method provided with the driver as an argument until the ',
|
||||
'return value is not False."""',
|
||||
'screen = None',
|
||||
'stacktrace = None',
|
||||
' ',
|
||||
'end_time = time.time() + self._timeout',
|
||||
'while True:',
|
||||
'try:',
|
||||
'value = method(self._driver)',
|
||||
'if value:',
|
||||
'return value',
|
||||
'except self._ignored_exceptions as exc:',
|
||||
"screen = getattr(exc, 'screen', None)",
|
||||
"stacktrace = getattr(exc, 'stacktrace', None)",
|
||||
'time.sleep(self._poll)',
|
||||
'if time.time() > end_time:',
|
||||
'break',
|
||||
'> raise TimeoutException(message, screen, stacktrace)',
|
||||
'E selenium.common.exceptions.TimeoutException: Message: Element was never present!',
|
||||
'E Locator of type <CSS_SELECTOR> with selector <.pp-rounded-btn__icon.category-bck-3> with params <None>',
|
||||
"E Expected condition: <class 'selenium.webdriver.support.expected_conditions.presence_of_element_located'>",
|
||||
'E Timeout: 30',
|
||||
'',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException',
|
||||
'------------------------------- pytest-selenium --------------------------------',
|
||||
'Driver log: /private/var/folders/nt/zg2hyyxj6k77sf_qk34xtqf40000gn/T/pytest-of-vgustafsson/pytest-12/test_dependency_forces_date_ch0/driver.log',
|
||||
'URL: https://local.rnd.projectplace.com/#project/79788/plan/28838',
|
||||
'WARNING: Failed to gather log types: Message: HTTP method not allowed',
|
||||
'',
|
||||
'----------------------------- Additional Reporting -----------------------------',
|
||||
'Window size: width <1680>, height <983>',
|
||||
"WARNING: Failed to get HAR: 'NoneType' object has no attribute 'har'",
|
||||
'Logs can be found here: http://elk.rnd.projectplace.com/goto/152df50b1a44ad0',
|
||||
],
|
||||
reprfuncargs: { args: [] },
|
||||
reprlocals: null,
|
||||
reprfileloc: {
|
||||
path: 'test_html.py',
|
||||
lineno: 12,
|
||||
message: 'AssertionError',
|
||||
},
|
||||
style: 'long',
|
||||
},
|
||||
},
|
||||
],
|
||||
extraline: null,
|
||||
style: 'long',
|
||||
},
|
||||
sections: [],
|
||||
chain: [
|
||||
[
|
||||
{
|
||||
reprentries: [
|
||||
{
|
||||
type: 'ReprEntry',
|
||||
data: {
|
||||
lines: [
|
||||
' def test_url():',
|
||||
' """',
|
||||
' bla bla bla bla',
|
||||
' alb alb alb',
|
||||
' @param: hello',
|
||||
' :param just',
|
||||
' """',
|
||||
' # driver.get("https://www.google.com")',
|
||||
'> assert False',
|
||||
'E assert False',
|
||||
],
|
||||
reprfuncargs: { args: [] },
|
||||
reprlocals: null,
|
||||
reprfileloc: {
|
||||
path: 'test_html.py',
|
||||
lineno: 12,
|
||||
message: 'AssertionError',
|
||||
},
|
||||
style: 'long',
|
||||
},
|
||||
},
|
||||
],
|
||||
extraline: null,
|
||||
style: 'long',
|
||||
},
|
||||
{
|
||||
path:
|
||||
'/Users/jimbrannlund/dev/pytest-dev/testing-html/test_html.py',
|
||||
lineno: 12,
|
||||
message: 'assert False',
|
||||
},
|
||||
null,
|
||||
],
|
||||
],
|
||||
},
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00020797699999997032,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url',
|
||||
location: ['test_html.py', 3, 'test_url'],
|
||||
keywords: { test_url: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.0001561270000000059,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url2',
|
||||
location: ['test_html.py', 14, 'test_url2'],
|
||||
keywords: { test_url2: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url2',
|
||||
location: ['test_html.py', 14, 'test_url2'],
|
||||
keywords: { test_url2: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url2',
|
||||
location: ['test_html.py', 14, 'test_url2'],
|
||||
keywords: { test_url2: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url4',
|
||||
location: ['test_html.py', 14, 'test_url4'],
|
||||
keywords: { test_url4: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url4',
|
||||
location: ['test_html.py', 14, 'test_url4'],
|
||||
keywords: { test_url4: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url4',
|
||||
location: ['test_html.py', 14, 'test_url4'],
|
||||
keywords: { test_url4: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url5',
|
||||
location: ['test_html.py', 14, 'test_url5'],
|
||||
keywords: { test_url5: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url5',
|
||||
location: ['test_html.py', 14, 'test_url5'],
|
||||
keywords: { test_url5: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url5',
|
||||
location: ['test_html.py', 14, 'test_url5'],
|
||||
keywords: { test_url5: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url6',
|
||||
location: ['test_html.py', 14, 'test_url6'],
|
||||
keywords: { test_url6: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url6',
|
||||
location: ['test_html.py', 14, 'test_url6'],
|
||||
keywords: { test_url6: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url6',
|
||||
location: ['test_html.py', 14, 'test_url6'],
|
||||
keywords: { test_url6: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url7',
|
||||
location: ['test_html.py', 14, 'test_url7'],
|
||||
keywords: { test_url7: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url7',
|
||||
location: ['test_html.py', 14, 'test_url7'],
|
||||
keywords: { test_url7: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url7',
|
||||
location: ['test_html.py', 14, 'test_url7'],
|
||||
keywords: { test_url7: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url8',
|
||||
location: ['test_html.py', 14, 'test_url8'],
|
||||
keywords: { test_url8: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url8',
|
||||
location: ['test_html.py', 14, 'test_url8'],
|
||||
keywords: { test_url8: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url8',
|
||||
location: ['test_html.py', 14, 'test_url8'],
|
||||
keywords: { test_url8: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url9',
|
||||
location: ['test_html.py', 14, 'test_url9'],
|
||||
keywords: { test_url9: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url9',
|
||||
location: ['test_html.py', 14, 'test_url9'],
|
||||
keywords: { test_url9: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url9',
|
||||
location: ['test_html.py', 14, 'test_url9'],
|
||||
keywords: { test_url9: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url10',
|
||||
location: ['test_html.py', 14, 'test_url10'],
|
||||
keywords: { test_url10: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00010436599999996687,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url10',
|
||||
location: ['test_html.py', 14, 'test_url10'],
|
||||
keywords: { test_url10: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00011543000000002746,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url10',
|
||||
location: ['test_html.py', 14, 'test_url10'],
|
||||
keywords: { test_url10: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 9.126600000003426,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url112',
|
||||
location: ['test_html.py', 3, 'test_url112'],
|
||||
keywords: { test_url112: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'setup',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.0001576979999999839,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url112',
|
||||
location: ['test_html.py', 3, 'test_url112'],
|
||||
keywords: { test_url112: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'failed',
|
||||
extras: [
|
||||
{
|
||||
name: 'Snapshot',
|
||||
format_type: 'image',
|
||||
content: 'snapshot_of_what_went_wrong.png',
|
||||
mime_type: 'image/png',
|
||||
extension: '.png',
|
||||
},
|
||||
{
|
||||
name: 'Google',
|
||||
format_type: 'url',
|
||||
content: 'https://search.yahoo.com/',
|
||||
mime_type: null,
|
||||
extension: null,
|
||||
},
|
||||
],
|
||||
longrepr: {
|
||||
reprcrash: {
|
||||
path: '/Users/jimbrannlund/dev/pytest-dev/testing-html/test_html.py',
|
||||
lineno: 12,
|
||||
message: 'assert False',
|
||||
},
|
||||
reprtraceback: {
|
||||
reprentries: [
|
||||
{
|
||||
type: 'ReprEntry',
|
||||
data: {
|
||||
lines: [
|
||||
'universe = <pytest_setup.database.TestDataCollection object at 0x7fe2cf1c4dd8>',
|
||||
'driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="2c586c44-7cb6-8e48-86fd-ae2d2982a3bd")>',
|
||||
'',
|
||||
'@pytest.mark.user(name="Bob", account=\'Rolfs Account\')',
|
||||
"@pytest.mark.setup_data({'EnterpriseProject': [{'name': 'Dependencies', 'user': 'Bob'}]},",
|
||||
"{'Activity': [",
|
||||
"{'name': 'Move',",
|
||||
"'project': 'Dependencies',",
|
||||
"'user': 'Bob',",
|
||||
"'dates': {'start_date': 1, 'end_date': 7}},",
|
||||
"{'name': 'Nope',",
|
||||
"'project': 'Dependencies',",
|
||||
"'user': 'Bob',",
|
||||
"'dates': {'start_date': 8, 'end_date': 14}}]})",
|
||||
'def test_dependency_forces_date_change(universe, driver):',
|
||||
'from test_automation.tools.date_handling import convert_to_correct_date',
|
||||
' ',
|
||||
'_to_depend_on = "Move"',
|
||||
"_expected_dates = {'start_date': convert_to_correct_date(15), 'end_date': convert_to_correct_date(21)}",
|
||||
' ',
|
||||
"_user = universe.get('User', 'Bob')",
|
||||
"_act = universe.get('Activity', 'Move')",
|
||||
' ',
|
||||
'ActivityDetailsPane(driver).',
|
||||
"go_to_page(universe.get('User', 'Bob'),",
|
||||
"universe.get('EnterpriseProject', 'Dependencies'),",
|
||||
'universe.get("Activity", "Nope")). ',
|
||||
"open_activity('Move'). ",
|
||||
"> open_activity('Nope'). ",
|
||||
'open_widgets_section(). ',
|
||||
"get_widget('planletdependencies').",
|
||||
'add_predecessor(_to_depend_on).',
|
||||
"get_details_pane('activity').",
|
||||
'close_details_pane().',
|
||||
'click_planlet_checkbox(_act.id).',
|
||||
"get_widget('date').",
|
||||
'verify_dates(_expected_dates)',
|
||||
'',
|
||||
'test_automation/tests/ui_tests/plan_tests/activity_details_pane_test.py:121: ',
|
||||
'_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ',
|
||||
'test_automation/page_objects/details_panes/activity_details_pane.py:241: in open_widgets_section',
|
||||
'_wait_for_plus_sign()',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/decorators.py:112: in wait_handler',
|
||||
'value = func(*args, **kwargs)',
|
||||
'test_automation/page_objects/details_panes/activity_details_pane.py:236: in _wait_for_plus_sign',
|
||||
'if self.get_present_element(self._plus_sign_locator):',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/base_page.py:422: in get_present_element',
|
||||
'return self._get(locator, expected_condition, params, timeout, error_msg, parent)',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/basepage/base_page.py:569: in _get',
|
||||
'return WebDriverWait(_driver, timeout).until(exp_cond, error_msg)',
|
||||
'_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ',
|
||||
'',
|
||||
'self = <selenium.webdriver.support.wait.WebDriverWait (session="2c586c44-7cb6-8e48-86fd-ae2d2982a3bd")>',
|
||||
'method = <selenium.webdriver.support.expected_conditions.presence_of_element_located object at 0x7fe2cf1a7240>',
|
||||
'message = "Element was never present!\nLocator of type <CSS_SELECTOR> with selector <.pp-rounded-btn__icon.category-bck-3> with ...nExpected condition: <class \'selenium.webdriver.support.expected_conditions.presence_of_element_located\'>\nTimeout: 30"',
|
||||
'',
|
||||
"def until(self, method, message=''):",
|
||||
'"""Calls the method provided with the driver as an argument until the ',
|
||||
'return value is not False."""',
|
||||
'screen = None',
|
||||
'stacktrace = None',
|
||||
' ',
|
||||
'end_time = time.time() + self._timeout',
|
||||
'while True:',
|
||||
'try:',
|
||||
'value = method(self._driver)',
|
||||
'if value:',
|
||||
'return value',
|
||||
'except self._ignored_exceptions as exc:',
|
||||
"screen = getattr(exc, 'screen', None)",
|
||||
"stacktrace = getattr(exc, 'stacktrace', None)",
|
||||
'time.sleep(self._poll)',
|
||||
'if time.time() > end_time:',
|
||||
'break',
|
||||
'> raise TimeoutException(message, screen, stacktrace)',
|
||||
'E selenium.common.exceptions.TimeoutException: Message: Element was never present!',
|
||||
'E Locator of type <CSS_SELECTOR> with selector <.pp-rounded-btn__icon.category-bck-3> with params <None>',
|
||||
"E Expected condition: <class 'selenium.webdriver.support.expected_conditions.presence_of_element_located'>",
|
||||
'E Timeout: 30',
|
||||
'',
|
||||
'/Users/vgustafsson/.virtualenvs/pytest/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException',
|
||||
'------------------------------- pytest-selenium --------------------------------',
|
||||
'Driver log: /private/var/folders/nt/zg2hyyxj6k77sf_qk34xtqf40000gn/T/pytest-of-vgustafsson/pytest-12/test_dependency_forces_date_ch0/driver.log',
|
||||
'URL: https://local.rnd.projectplace.com/#project/79788/plan/28838',
|
||||
'WARNING: Failed to gather log types: Message: HTTP method not allowed',
|
||||
'',
|
||||
'----------------------------- Additional Reporting -----------------------------',
|
||||
'Window size: width <1680>, height <983>',
|
||||
"WARNING: Failed to get HAR: 'NoneType' object has no attribute 'har'",
|
||||
'Logs can be found here: http://elk.rnd.projectplace.com/goto/152df50b1a44ad0',
|
||||
],
|
||||
reprfuncargs: { args: [] },
|
||||
reprlocals: null,
|
||||
reprfileloc: {
|
||||
path: 'test_html.py',
|
||||
lineno: 12,
|
||||
message: 'AssertionError',
|
||||
},
|
||||
style: 'long',
|
||||
},
|
||||
},
|
||||
],
|
||||
extraline: null,
|
||||
style: 'long',
|
||||
},
|
||||
sections: [],
|
||||
chain: [
|
||||
[
|
||||
{
|
||||
reprentries: [
|
||||
{
|
||||
type: 'ReprEntry',
|
||||
data: {
|
||||
lines: [
|
||||
' def test_url112():',
|
||||
' """',
|
||||
' bla bla bla bla',
|
||||
' alb alb alb',
|
||||
' @param: hello',
|
||||
' :param just',
|
||||
' """',
|
||||
' # driver.get("https://www.google.com")',
|
||||
'> assert False',
|
||||
'E assert False',
|
||||
],
|
||||
reprfuncargs: { args: [] },
|
||||
reprlocals: null,
|
||||
reprfileloc: {
|
||||
path: 'test_html.py',
|
||||
lineno: 12,
|
||||
message: 'AssertionError',
|
||||
},
|
||||
style: 'long',
|
||||
},
|
||||
},
|
||||
],
|
||||
extraline: null,
|
||||
style: 'long',
|
||||
},
|
||||
{
|
||||
path:
|
||||
'/Users/jimbrannlund/dev/pytest-dev/testing-html/test_html.py',
|
||||
lineno: 12,
|
||||
message: 'assert False',
|
||||
},
|
||||
null,
|
||||
],
|
||||
],
|
||||
},
|
||||
when: 'call',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.00020797699999997032,
|
||||
extra: [],
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
{
|
||||
nodeid: 'test_html.py::test_url112',
|
||||
location: ['test_html.py', 3, 'test_url112'],
|
||||
keywords: { test_url112: 1, 'testing-html': 1, 'test_html.py': 1 },
|
||||
outcome: 'passed',
|
||||
longrepr: null,
|
||||
when: 'teardown',
|
||||
user_properties: [],
|
||||
sections: [],
|
||||
duration: 0.0001561270000000059,
|
||||
$report_type: 'TestReport',
|
||||
},
|
||||
],
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
const genericSort = (list, key, ascending) => {
|
||||
const sorted = list.sort((a, b) =>
|
||||
a[key] === b[key] ? 0 : a[key] === b[key] ? 1 : -1
|
||||
);
|
||||
|
||||
if (ascending) {
|
||||
sorted.reverse();
|
||||
}
|
||||
return sorted;
|
||||
};
|
|
@ -33,11 +33,16 @@ table {
|
|||
******************************/
|
||||
#environment td {
|
||||
padding: 5px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border: 1px solid #e6e6e6;
|
||||
vertical-align: top;
|
||||
}
|
||||
#environment tr:nth-child(odd) {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
#environment ul {
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* TEST RESULT COLORS
|
||||
|
@ -65,6 +70,14 @@ span.xpassed,
|
|||
color: red;
|
||||
}
|
||||
|
||||
.col-result {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.col-links__extra {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* RESULTS TABLE
|
||||
*
|
||||
|
@ -85,7 +98,7 @@ span.xpassed,
|
|||
#results-table th,
|
||||
#results-table td {
|
||||
padding: 5px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border: 1px solid #e6e6e6;
|
||||
text-align: left;
|
||||
}
|
||||
#results-table th {
|
||||
|
@ -142,14 +155,14 @@ div.video video {
|
|||
|
||||
.expander::after {
|
||||
content: " (show details)";
|
||||
color: #BBB;
|
||||
color: #bbb;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapser::after {
|
||||
content: " (hide details)";
|
||||
color: #BBB;
|
||||
color: #bbb;
|
||||
font-style: italic;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -160,27 +173,61 @@ div.video video {
|
|||
.sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.sortable.asc:after {
|
||||
content: " ";
|
||||
position: relative;
|
||||
left: 5px;
|
||||
bottom: -12.5px;
|
||||
border: 10px solid #4caf50;
|
||||
border-bottom: 0;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
.sortable.desc:after {
|
||||
content: " ";
|
||||
position: relative;
|
||||
left: 5px;
|
||||
bottom: 12.5px;
|
||||
border: 10px solid #4caf50;
|
||||
border-top: 0;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
.sort-icon {
|
||||
font-size: 0px;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
/*triangle*/
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8px solid transparent;
|
||||
border-right: 8px solid transparent;
|
||||
.hidden, .summary__reload__button.hidden {
|
||||
display: none;
|
||||
}
|
||||
.inactive .sort-icon {
|
||||
/*finish triangle*/
|
||||
border-top: 8px solid #E6E6E6;
|
||||
|
||||
.summary {
|
||||
display: flex;
|
||||
}
|
||||
.asc.active .sort-icon {
|
||||
/*finish triangle*/
|
||||
border-bottom: 8px solid #999;
|
||||
.summary__data {
|
||||
flex: 0 0 550px;
|
||||
}
|
||||
.desc.active .sort-icon {
|
||||
/*finish triangle*/
|
||||
border-top: 8px solid #999;
|
||||
.summary__reload {
|
||||
flex: 1 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.summary__reload__button {
|
||||
flex: 0 0 300px;
|
||||
display: flex;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
background-color: #4caf50;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.summary__reload__button:hover {
|
||||
background-color: #46a049;
|
||||
}
|
||||
.summary__spacer {
|
||||
flex: 0 0 550px;
|
||||
}
|
||||
|
||||
input.filter {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue