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.
Files changed (26) hide show
  1. robo_automation_test_kit/__init__.py +8 -0
  2. robo_automation_test_kit/hookspec.py +36 -0
  3. robo_automation_test_kit/plugin.py +867 -0
  4. robo_automation_test_kit/templates/email_report/email_template.html +0 -0
  5. robo_automation_test_kit/templates/html_report/components/category-chart.html +148 -0
  6. robo_automation_test_kit/templates/html_report/components/center-chart.html +97 -0
  7. robo_automation_test_kit/templates/html_report/components/phase-chart.html +148 -0
  8. robo_automation_test_kit/templates/html_report/components/results-table.html +240 -0
  9. robo_automation_test_kit/templates/html_report/components/status-center-chart.html +148 -0
  10. robo_automation_test_kit/templates/html_report/components/summary-chart.html +94 -0
  11. robo_automation_test_kit/templates/html_report/html_template.html +62 -0
  12. robo_automation_test_kit/templates/html_report/scripts/css/material-icons.css +20 -0
  13. robo_automation_test_kit/templates/html_report/scripts/css/report.css +714 -0
  14. robo_automation_test_kit/templates/html_report/scripts/css/robo-fonts.css +24 -0
  15. robo_automation_test_kit/templates/html_report/scripts/js/chart.js +14 -0
  16. robo_automation_test_kit/templates/html_report/scripts/js/report.js +319 -0
  17. robo_automation_test_kit/utils/RoboHelper.py +420 -0
  18. robo_automation_test_kit/utils/__init__.py +19 -0
  19. robo_automation_test_kit/utils/reports/EmailReportUtils.py +0 -0
  20. robo_automation_test_kit/utils/reports/HtmlReportUtils.py +154 -0
  21. robo_automation_test_kit/utils/reports/__init__.py +3 -0
  22. robo_automation_test_kit-1.0.0.dist-info/METADATA +132 -0
  23. robo_automation_test_kit-1.0.0.dist-info/RECORD +26 -0
  24. robo_automation_test_kit-1.0.0.dist-info/WHEEL +4 -0
  25. robo_automation_test_kit-1.0.0.dist-info/entry_points.txt +3 -0
  26. 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
+ });