robo-automation-test-kit 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robo_automation_test_kit/__init__.py +8 -0
- robo_automation_test_kit/hookspec.py +36 -0
- robo_automation_test_kit/plugin.py +867 -0
- robo_automation_test_kit/templates/email_report/email_template.html +0 -0
- robo_automation_test_kit/templates/html_report/components/category-chart.html +148 -0
- robo_automation_test_kit/templates/html_report/components/center-chart.html +97 -0
- robo_automation_test_kit/templates/html_report/components/phase-chart.html +148 -0
- robo_automation_test_kit/templates/html_report/components/results-table.html +240 -0
- robo_automation_test_kit/templates/html_report/components/status-center-chart.html +148 -0
- robo_automation_test_kit/templates/html_report/components/summary-chart.html +94 -0
- robo_automation_test_kit/templates/html_report/html_template.html +62 -0
- robo_automation_test_kit/templates/html_report/scripts/css/material-icons.css +20 -0
- robo_automation_test_kit/templates/html_report/scripts/css/report.css +714 -0
- robo_automation_test_kit/templates/html_report/scripts/css/robo-fonts.css +24 -0
- robo_automation_test_kit/templates/html_report/scripts/js/chart.js +14 -0
- robo_automation_test_kit/templates/html_report/scripts/js/report.js +319 -0
- robo_automation_test_kit/utils/RoboHelper.py +420 -0
- robo_automation_test_kit/utils/__init__.py +19 -0
- robo_automation_test_kit/utils/reports/EmailReportUtils.py +0 -0
- robo_automation_test_kit/utils/reports/HtmlReportUtils.py +154 -0
- robo_automation_test_kit/utils/reports/__init__.py +3 -0
- robo_automation_test_kit-1.0.0.dist-info/METADATA +132 -0
- robo_automation_test_kit-1.0.0.dist-info/RECORD +26 -0
- robo_automation_test_kit-1.0.0.dist-info/WHEEL +4 -0
- robo_automation_test_kit-1.0.0.dist-info/entry_points.txt +3 -0
- robo_automation_test_kit-1.0.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Merged JavaScript: Table sorting, filtering, and modal logic
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// UTILITY FUNCTIONS FOR CHARTS
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
// Utility to lighten or darken a hex color
|
|
10
|
+
function shadeColor(color, percent) {
|
|
11
|
+
let R = parseInt(color.substring(1,3),16);
|
|
12
|
+
let G = parseInt(color.substring(3,5),16);
|
|
13
|
+
let B = parseInt(color.substring(5,7),16);
|
|
14
|
+
R = Math.min(255, Math.max(0, R + Math.round(255 * percent)));
|
|
15
|
+
G = Math.min(255, Math.max(0, G + Math.round(255 * percent)));
|
|
16
|
+
B = Math.min(255, Math.max(0, B + Math.round(255 * percent)));
|
|
17
|
+
return `rgb(${R},${G},${B})`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Utility to add 3D shadow effect to Chart.js charts
|
|
21
|
+
function add3DEffect(ctx, chartType, baseColors) {
|
|
22
|
+
if (chartType === 'pie' || chartType === 'doughnut') {
|
|
23
|
+
return baseColors.map((color, i) => {
|
|
24
|
+
const grad = ctx.createRadialGradient(90, 90, 10, 90, 90, 90);
|
|
25
|
+
grad.addColorStop(0, shadeColor(color, 0.15));
|
|
26
|
+
grad.addColorStop(0.6, color);
|
|
27
|
+
grad.addColorStop(1, shadeColor(color, -0.15));
|
|
28
|
+
return grad;
|
|
29
|
+
});
|
|
30
|
+
} else if (chartType === 'bar') {
|
|
31
|
+
return baseColors.map((color, i) => {
|
|
32
|
+
const grad = ctx.createLinearGradient(0, 0, 0, 300);
|
|
33
|
+
grad.addColorStop(0, shadeColor(color, 0.15));
|
|
34
|
+
grad.addColorStop(0.5, color);
|
|
35
|
+
grad.addColorStop(1, shadeColor(color, -0.15));
|
|
36
|
+
return grad;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return baseColors;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Material Design color palette
|
|
43
|
+
const statusTypes = ['PASSED', 'FAILED', 'SKIPPED'];
|
|
44
|
+
const statusColors = {
|
|
45
|
+
'PASSED': '#43a047', // Material Green 600
|
|
46
|
+
'FAILED': '#e53935', // Material Red 600
|
|
47
|
+
'SKIPPED': '#fbc02d' // Material Yellow 700
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Material palette for center/doughnut charts
|
|
51
|
+
const centerPalette = [
|
|
52
|
+
'#1e88e5', // Blue 600
|
|
53
|
+
'#8e24aa', // Purple 600
|
|
54
|
+
'#00acc1', // Cyan 600
|
|
55
|
+
'#fb8c00', // Orange 600
|
|
56
|
+
'#6d4c41', // Brown 600
|
|
57
|
+
'#3949ab', // Indigo 600
|
|
58
|
+
'#c0ca33' // Lime 600
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Export globals for component modules
|
|
62
|
+
window.shadeColor = shadeColor;
|
|
63
|
+
window.add3DEffect = add3DEffect;
|
|
64
|
+
window.statusColors = statusColors;
|
|
65
|
+
window.centerPalette = centerPalette;
|
|
66
|
+
window.statusTypes = statusTypes;
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// TABLE SORTING AND FILTERING FUNCTIONS
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
function sortTable(header, table) {
|
|
73
|
+
const columnType = header.getAttribute('data-column-type');
|
|
74
|
+
const tbody = table.querySelector('tbody');
|
|
75
|
+
const rows = Array.from(tbody.querySelectorAll('tr'));
|
|
76
|
+
|
|
77
|
+
// Determine column index
|
|
78
|
+
let columnIndex = 0;
|
|
79
|
+
const headers = table.querySelectorAll('th');
|
|
80
|
+
headers.forEach((h, index) => {
|
|
81
|
+
if (h === header) {
|
|
82
|
+
columnIndex = index;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Toggle sort direction
|
|
87
|
+
const isAscending = !header.classList.contains('sorted-asc');
|
|
88
|
+
|
|
89
|
+
// Remove sort indicators from all headers
|
|
90
|
+
headers.forEach(h => {
|
|
91
|
+
h.classList.remove('sorted-asc', 'sorted-desc');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Add sort indicator to current header
|
|
95
|
+
if (isAscending) {
|
|
96
|
+
header.classList.add('sorted-asc');
|
|
97
|
+
} else {
|
|
98
|
+
header.classList.add('sorted-desc');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Sort rows (but don't sort by the # column itself)
|
|
102
|
+
if (columnIndex !== 0) {
|
|
103
|
+
rows.sort((a, b) => {
|
|
104
|
+
const cellA = a.cells[columnIndex];
|
|
105
|
+
const cellB = b.cells[columnIndex];
|
|
106
|
+
|
|
107
|
+
// Check for data-value attribute (used for numeric columns like duration)
|
|
108
|
+
let aValue = cellA.getAttribute('data-value') || cellA.textContent.trim();
|
|
109
|
+
let bValue = cellB.getAttribute('data-value') || cellB.textContent.trim();
|
|
110
|
+
|
|
111
|
+
// Try to parse as number
|
|
112
|
+
const aNum = parseFloat(aValue);
|
|
113
|
+
const bNum = parseFloat(bValue);
|
|
114
|
+
|
|
115
|
+
if (!isNaN(aNum) && !isNaN(bNum)) {
|
|
116
|
+
return isAscending ? aNum - bNum : bNum - aNum;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// String comparison
|
|
120
|
+
return isAscending
|
|
121
|
+
? aValue.localeCompare(bValue)
|
|
122
|
+
: bValue.localeCompare(aValue);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Re-append sorted rows
|
|
127
|
+
rows.forEach(row => {
|
|
128
|
+
tbody.appendChild(row);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Reindex all rows after sorting
|
|
132
|
+
rows.forEach((row, index) => {
|
|
133
|
+
if (row.cells && row.cells[0]) {
|
|
134
|
+
const oldValue = row.cells[0].textContent;
|
|
135
|
+
const newValue = index + 1;
|
|
136
|
+
row.cells[0].textContent = newValue;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Reindex the row numbers based on visible rows
|
|
142
|
+
function reindexVisibleRows(table) {
|
|
143
|
+
if (!table) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const tbody = table.querySelector('tbody');
|
|
148
|
+
if (!tbody) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const rows = tbody.querySelectorAll('tr');
|
|
153
|
+
let visibleIndex = 1;
|
|
154
|
+
|
|
155
|
+
rows.forEach((row, i) => {
|
|
156
|
+
// Check if row is visible (display is not 'none')
|
|
157
|
+
const computedStyle = window.getComputedStyle(row);
|
|
158
|
+
const isVisible = computedStyle.display !== 'none';
|
|
159
|
+
|
|
160
|
+
if (isVisible && row.cells && row.cells[0]) {
|
|
161
|
+
const oldValue = row.cells[0].textContent;
|
|
162
|
+
row.cells[0].textContent = visibleIndex;
|
|
163
|
+
visibleIndex++;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Filter table based on status checkboxes and search input
|
|
169
|
+
function setupTableFilters() {
|
|
170
|
+
const statusFilters = document.querySelectorAll('.status-filter');
|
|
171
|
+
const searchInput = document.getElementById('resultsTableFilter');
|
|
172
|
+
const table = document.getElementById('resultsTable');
|
|
173
|
+
|
|
174
|
+
if (!table || statusFilters.length === 0) return;
|
|
175
|
+
|
|
176
|
+
function filterTable() {
|
|
177
|
+
const selectedStatuses = Array.from(statusFilters)
|
|
178
|
+
.filter(f => f.checked)
|
|
179
|
+
.map(f => f.value.toUpperCase());
|
|
180
|
+
|
|
181
|
+
const searchTerm = searchInput ? searchInput.value.toLowerCase() : '';
|
|
182
|
+
const rows = table.querySelectorAll('tbody tr');
|
|
183
|
+
|
|
184
|
+
rows.forEach((row, index) => {
|
|
185
|
+
const statusCell = row.cells[1];
|
|
186
|
+
if (!statusCell) return;
|
|
187
|
+
|
|
188
|
+
const status = statusCell.textContent.trim().toUpperCase();
|
|
189
|
+
|
|
190
|
+
// Only show rows that match CHECKED statuses (if any are checked)
|
|
191
|
+
// If no statuses are checked, hide all rows
|
|
192
|
+
const matchesStatus = selectedStatuses.length > 0 && selectedStatuses.includes(status);
|
|
193
|
+
|
|
194
|
+
// Check if row text matches search term
|
|
195
|
+
const rowText = Array.from(row.cells).map(c => c.textContent.toLowerCase()).join(' ');
|
|
196
|
+
const matchesSearch = searchTerm === '' || rowText.includes(searchTerm);
|
|
197
|
+
|
|
198
|
+
const shouldShow = matchesStatus && matchesSearch;
|
|
199
|
+
row.style.display = shouldShow ? '' : 'none';
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Reindex visible rows after filtering
|
|
203
|
+
reindexVisibleRows(table);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Attach change listeners to checkboxes
|
|
207
|
+
statusFilters.forEach(filter => {
|
|
208
|
+
filter.addEventListener('change', filterTable);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Attach input listener to search box
|
|
212
|
+
if (searchInput) {
|
|
213
|
+
searchInput.addEventListener('input', filterTable);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Apply filter on initial load
|
|
217
|
+
filterTable();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// ERROR MODAL FUNCTIONS
|
|
222
|
+
// ============================================================================
|
|
223
|
+
|
|
224
|
+
window.showErrorDetails = function(row) {
|
|
225
|
+
document.querySelectorAll('.results-table tr.selected').forEach(tr => tr.classList.remove('selected'));
|
|
226
|
+
row.classList.add('selected');
|
|
227
|
+
const testName = row.getAttribute('data-test-name') || 'Unknown Test';
|
|
228
|
+
const outcome = row.getAttribute('data-outcome') || 'Unknown';
|
|
229
|
+
const error = row.getAttribute('data-error') || 'No error details available';
|
|
230
|
+
document.getElementById('errorModalTitle').textContent = `${testName} - ${outcome.toUpperCase()}`;
|
|
231
|
+
document.getElementById('errorMessage').textContent = error;
|
|
232
|
+
document.getElementById('errorModal').style.display = 'block';
|
|
233
|
+
document.getElementById('expandIcon').style.display = '';
|
|
234
|
+
document.getElementById('minimizeIcon').style.display = 'none';
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
window.closeErrorModal = function() {
|
|
238
|
+
document.getElementById('errorModal').style.display = 'none';
|
|
239
|
+
document.getElementById('errorModalContent').classList.remove('fullscreen');
|
|
240
|
+
document.querySelectorAll('.results-table tr.selected').forEach(tr => tr.classList.remove('selected'));
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
window.toggleFullscreen = function() {
|
|
244
|
+
const modalContent = document.getElementById('errorModalContent');
|
|
245
|
+
const expandIcon = document.getElementById('expandIcon');
|
|
246
|
+
const minimizeIcon = document.getElementById('minimizeIcon');
|
|
247
|
+
const isFullscreen = modalContent.classList.toggle('fullscreen');
|
|
248
|
+
if (isFullscreen) {
|
|
249
|
+
expandIcon.style.display = 'none';
|
|
250
|
+
minimizeIcon.style.display = '';
|
|
251
|
+
} else {
|
|
252
|
+
expandIcon.style.display = '';
|
|
253
|
+
minimizeIcon.style.display = 'none';
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
window.onclick = function(event) {
|
|
258
|
+
const modal = document.getElementById('errorModal');
|
|
259
|
+
if (event.target === modal) {
|
|
260
|
+
window.closeErrorModal();
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
document.addEventListener('keydown', function(event) {
|
|
265
|
+
if (event.key === 'Escape') {
|
|
266
|
+
const modal = document.getElementById('errorModal');
|
|
267
|
+
if (modal && modal.style.display === 'block') {
|
|
268
|
+
window.closeErrorModal();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// ============================================================================
|
|
274
|
+
// CHART INITIALIZATION (components handle chart rendering now)
|
|
275
|
+
// ============================================================================
|
|
276
|
+
|
|
277
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
278
|
+
// Setup table sorting event listeners
|
|
279
|
+
const table = document.querySelector('.results-table');
|
|
280
|
+
if (table) {
|
|
281
|
+
const headers = table.querySelectorAll('th.sortable');
|
|
282
|
+
headers.forEach(header => {
|
|
283
|
+
header.style.cursor = 'pointer';
|
|
284
|
+
header.addEventListener('click', function() {
|
|
285
|
+
sortTable(this, table);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Default sort by test_case_name (2nd sortable column)
|
|
290
|
+
const testCaseNameHeader = table.querySelector('th.test_case_name');
|
|
291
|
+
if (testCaseNameHeader) {
|
|
292
|
+
sortTable(testCaseNameHeader, table);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Setup table filters
|
|
297
|
+
setupTableFilters();
|
|
298
|
+
|
|
299
|
+
// Attach click event to table rows for error popup
|
|
300
|
+
var resultsTable = document.getElementById('resultsTable');
|
|
301
|
+
if (resultsTable) {
|
|
302
|
+
resultsTable.querySelectorAll('tbody tr').forEach(function(row) {
|
|
303
|
+
row.addEventListener('click', function() {
|
|
304
|
+
showErrorDetails(row);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Ensure reindexing happens after page fully loads and filters are applied
|
|
311
|
+
window.addEventListener('load', function() {
|
|
312
|
+
const table = document.getElementById('resultsTable');
|
|
313
|
+
if (table) {
|
|
314
|
+
// Delay to ensure filters have been applied
|
|
315
|
+
setTimeout(function() {
|
|
316
|
+
reindexVisibleRows(table);
|
|
317
|
+
}, 200);
|
|
318
|
+
}
|
|
319
|
+
});
|