Kea2-python 0.3.2__py3-none-any.whl → 0.3.4__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.
Potentially problematic release.
This version of Kea2-python might be problematic. Click here for more details.
- kea2/assets/quicktest.py +1 -1
- kea2/bug_report_generator.py +38 -1
- kea2/keaUtils.py +11 -6
- kea2/templates/bug_report_template.html +141 -124
- kea2/templates/merged_bug_report_template.html +47 -47
- kea2/u2Driver.py +11 -3
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/METADATA +16 -2
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/RECORD +12 -12
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/WHEEL +0 -0
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/entry_points.txt +0 -0
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {kea2_python-0.3.2.dist-info → kea2_python-0.3.4.dist-info}/top_level.txt +0 -0
kea2/assets/quicktest.py
CHANGED
|
@@ -52,7 +52,7 @@ class Omni_Notes_Sample(unittest.TestCase):
|
|
|
52
52
|
assert self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists()
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
URL = "https://
|
|
55
|
+
URL = "https://github.com/federicoiosue/Omni-Notes/releases/download/6.2.0_alpha/OmniNotes-alphaRelease-6.2.0.apk"
|
|
56
56
|
PACKAGE_NAME = "it.feio.android.omninotes.alpha"
|
|
57
57
|
FILE_NAME = "omninotes.apk"
|
|
58
58
|
|
kea2/bug_report_generator.py
CHANGED
|
@@ -388,6 +388,10 @@ class BugReportGenerator:
|
|
|
388
388
|
data["all_properties_count"] = len(self.test_result)
|
|
389
389
|
data["executed_properties_count"] = sum(1 for result in self.test_result.values() if result.get("executed", 0) > 0)
|
|
390
390
|
|
|
391
|
+
# Calculate detailed property statistics for table headers
|
|
392
|
+
property_stats_summary = self._calculate_property_stats_summary(self.test_result)
|
|
393
|
+
data["property_stats_summary"] = property_stats_summary
|
|
394
|
+
|
|
391
395
|
# Process coverage data
|
|
392
396
|
data["coverage_trend"] = self.cov_trend
|
|
393
397
|
|
|
@@ -567,7 +571,8 @@ class BugReportGenerator:
|
|
|
567
571
|
'property_execution_data': json.dumps(data["property_execution_trend"]),
|
|
568
572
|
'activity_count_history': data["activity_count_history"],
|
|
569
573
|
'crash_events': data["crash_events"],
|
|
570
|
-
'anr_events': data["anr_events"]
|
|
574
|
+
'anr_events': data["anr_events"],
|
|
575
|
+
'property_stats_summary': data["property_stats_summary"]
|
|
571
576
|
}
|
|
572
577
|
|
|
573
578
|
# Check if template exists, if not create it
|
|
@@ -822,6 +827,38 @@ class BugReportGenerator:
|
|
|
822
827
|
|
|
823
828
|
return property_execution_trend
|
|
824
829
|
|
|
830
|
+
def _calculate_property_stats_summary(self, test_result: TestResult) -> Dict[str, int]:
|
|
831
|
+
"""
|
|
832
|
+
Calculate summary statistics for property checking table headers
|
|
833
|
+
|
|
834
|
+
Args:
|
|
835
|
+
test_result: Test result data containing property statistics
|
|
836
|
+
|
|
837
|
+
Returns:
|
|
838
|
+
Dict: Summary statistics for each column
|
|
839
|
+
"""
|
|
840
|
+
stats_summary = {
|
|
841
|
+
"total_properties": 0,
|
|
842
|
+
"total_precond_satisfied": 0,
|
|
843
|
+
"total_executed": 0,
|
|
844
|
+
"total_fails": 0,
|
|
845
|
+
"total_errors": 0,
|
|
846
|
+
"properties_with_errors": 0
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
for property_name, result in test_result.items():
|
|
850
|
+
stats_summary["total_properties"] += 1
|
|
851
|
+
stats_summary["total_precond_satisfied"] += result.get("precond_satisfied", 0)
|
|
852
|
+
stats_summary["total_executed"] += result.get("executed", 0)
|
|
853
|
+
stats_summary["total_fails"] += result.get("fail", 0)
|
|
854
|
+
stats_summary["total_errors"] += result.get("error", 0)
|
|
855
|
+
|
|
856
|
+
# Count properties that have errors or fails
|
|
857
|
+
if result.get("fail", 0) > 0 or result.get("error", 0) > 0:
|
|
858
|
+
stats_summary["properties_with_errors"] += 1
|
|
859
|
+
|
|
860
|
+
return stats_summary
|
|
861
|
+
|
|
825
862
|
def _load_crash_dump_data(self) -> Tuple[List[Dict], List[Dict]]:
|
|
826
863
|
"""
|
|
827
864
|
Load crash and ANR events from crash-dump.log file
|
kea2/keaUtils.py
CHANGED
|
@@ -198,6 +198,9 @@ class PropStatistic:
|
|
|
198
198
|
executed: int = 0
|
|
199
199
|
fail: int = 0
|
|
200
200
|
error: int = 0
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
PBTTestResult = NewType("PBTTestResult", Dict[PropName, PropStatistic])
|
|
201
204
|
|
|
202
205
|
|
|
203
206
|
PropertyExecutionInfoStore = NewType("PropertyExecutionInfoStore", Deque["PropertyExecutionInfo"])
|
|
@@ -209,11 +212,6 @@ class PropertyExecutionInfo:
|
|
|
209
212
|
tb: str
|
|
210
213
|
|
|
211
214
|
|
|
212
|
-
class PBTTestResult(dict):
|
|
213
|
-
def __getitem__(self, key) -> PropStatistic:
|
|
214
|
-
return super().__getitem__(key)
|
|
215
|
-
|
|
216
|
-
|
|
217
215
|
def getFullPropName(testCase: TestCase):
|
|
218
216
|
return ".".join([
|
|
219
217
|
testCase.__module__,
|
|
@@ -277,10 +275,15 @@ class JsonResult(TextTestResult):
|
|
|
277
275
|
self.lastExecutedInfo.state = "pass"
|
|
278
276
|
|
|
279
277
|
self.executionInfoStore.append(self.lastExecutedInfo)
|
|
280
|
-
|
|
281
278
|
|
|
282
279
|
def getExcuted(self, test: TestCase):
|
|
283
280
|
return self.res[getFullPropName(test)].executed
|
|
281
|
+
|
|
282
|
+
def logSummary(self):
|
|
283
|
+
fails = sum(_.fail for _ in self.res.values())
|
|
284
|
+
errors = sum(_.error for _ in self.res.values())
|
|
285
|
+
|
|
286
|
+
logger.info(f"[Property Exectution Summary] Errors:{errors}, Fails:{fails}")
|
|
284
287
|
|
|
285
288
|
|
|
286
289
|
class KeaTestRunner(TextTestRunner):
|
|
@@ -465,6 +468,8 @@ class KeaTestRunner(TextTestRunner):
|
|
|
465
468
|
else:
|
|
466
469
|
self.stream.write("\n")
|
|
467
470
|
self.stream.flush()
|
|
471
|
+
|
|
472
|
+
result.logSummary()
|
|
468
473
|
return result
|
|
469
474
|
|
|
470
475
|
@property
|
|
@@ -211,35 +211,39 @@
|
|
|
211
211
|
text-align: left !important;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
/* Enhanced Error Details styling */
|
|
215
|
-
.table-custom
|
|
214
|
+
/* Enhanced Error Details styling for Property Statistics */
|
|
215
|
+
.table-custom tr.collapse {
|
|
216
216
|
position: relative;
|
|
217
217
|
z-index: 10;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
.table-custom td
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
.table-custom tr.collapse td {
|
|
221
|
+
border-top: none;
|
|
222
|
+
padding-top: 0;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
.table-custom
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
.table-custom tr.collapse .bg-light {
|
|
226
|
+
max-width: none;
|
|
227
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
228
|
+
border: 1px solid #e9ecef;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
.table-custom
|
|
232
|
-
max-height:
|
|
231
|
+
.table-custom tr.collapse pre {
|
|
232
|
+
max-height: 300px;
|
|
233
233
|
overflow-y: auto;
|
|
234
|
-
font-size: 0.
|
|
234
|
+
font-size: 0.85rem;
|
|
235
235
|
line-height: 1.4;
|
|
236
|
+
background-color: #f8f9fa;
|
|
237
|
+
border: 1px solid #e9ecef;
|
|
238
|
+
border-radius: 4px;
|
|
239
|
+
padding: 0.75rem;
|
|
236
240
|
}
|
|
237
241
|
|
|
238
|
-
.table-custom
|
|
242
|
+
.table-custom tr.collapse details {
|
|
239
243
|
margin-top: 0.5rem;
|
|
240
244
|
}
|
|
241
245
|
|
|
242
|
-
.table-custom
|
|
246
|
+
.table-custom tr.collapse summary {
|
|
243
247
|
cursor: pointer;
|
|
244
248
|
margin-bottom: 0.5rem;
|
|
245
249
|
}
|
|
@@ -1270,7 +1274,7 @@
|
|
|
1270
1274
|
<table class="table table-custom table-activities">
|
|
1271
1275
|
<thead>
|
|
1272
1276
|
<tr>
|
|
1273
|
-
<th>Activity Name</th>
|
|
1277
|
+
<th>Activity Name <span class="badge bg-primary ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ tested_activities_count }}/{{ total_activities_count }}</span></th>
|
|
1274
1278
|
<th>Visit Count <i class="bi bi-arrow-down-up text-muted sort-icon activities-sort-icon" id="visit-count-sort" data-column="visit-count" data-order="none" style="cursor: pointer;"></i></th>
|
|
1275
1279
|
</tr>
|
|
1276
1280
|
</thead>
|
|
@@ -1576,11 +1580,11 @@
|
|
|
1576
1580
|
<thead>
|
|
1577
1581
|
<tr>
|
|
1578
1582
|
<th>Index</th>
|
|
1579
|
-
<th>Property Name</th>
|
|
1580
|
-
<th>Precondition Satisfied</th>
|
|
1581
|
-
<th>Executed</th>
|
|
1582
|
-
<th>Fails <i class="bi bi-arrow-down-up text-muted sort-icon" id="fails-sort" data-column="fails" data-order="none" style="cursor: pointer;"></i></th>
|
|
1583
|
-
<th>Errors <i class="bi bi-arrow-down-up text-muted sort-icon" id="errors-sort" data-column="errors" data-order="none" style="cursor: pointer;"></i></th>
|
|
1583
|
+
<th>Property Name <span class="badge bg-primary ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_properties }}</span></th>
|
|
1584
|
+
<th>Precondition Satisfied <span class="badge bg-success ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_precond_satisfied }}</span></th>
|
|
1585
|
+
<th>Executed <span class="badge bg-info ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_executed }}</span></th>
|
|
1586
|
+
<th>Fails <span class="badge bg-danger ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_fails }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="fails-sort" data-column="fails" data-order="none" style="cursor: pointer;"></i></th>
|
|
1587
|
+
<th>Errors <span class="badge bg-warning ms-2" style="font-size: 0.9rem; font-weight: 600;">{{ property_stats_summary.total_errors }}</span> <i class="bi bi-arrow-down-up text-muted sort-icon" id="errors-sort" data-column="errors" data-order="none" style="cursor: pointer;"></i></th>
|
|
1584
1588
|
<th>Error Details</th>
|
|
1585
1589
|
</tr>
|
|
1586
1590
|
</thead>
|
|
@@ -1605,127 +1609,140 @@
|
|
|
1605
1609
|
{% set property_index = loop.index %}
|
|
1606
1610
|
{% if error_list|length == 1 %}
|
|
1607
1611
|
<!-- Single error - simple display -->
|
|
1608
|
-
<button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
|
|
1609
|
-
data-bs-target="#single-error-detail-{{ property_index }}" aria-expanded="false"
|
|
1612
|
+
<button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
|
|
1613
|
+
data-bs-target="#single-error-detail-{{ property_index }}" aria-expanded="false"
|
|
1610
1614
|
aria-controls="single-error-detail-{{ property_index }}">
|
|
1611
1615
|
<i class="bi bi-exclamation-triangle"></i> View Error
|
|
1612
1616
|
</button>
|
|
1613
|
-
<div class="collapse mt-2" id="single-error-detail-{{ property_index }}">
|
|
1614
|
-
<div class="card card-body bg-light">
|
|
1615
|
-
<div class="mb-2">
|
|
1616
|
-
<span class="badge bg-{{ 'danger' if error_list[0].state == 'fail' else 'warning' }}">
|
|
1617
|
-
{{ error_list[0].state|upper }}
|
|
1618
|
-
</span>
|
|
1619
|
-
{% if error_list[0].occurrence_count > 1 %}
|
|
1620
|
-
<span class="badge bg-info ms-2">
|
|
1621
|
-
Occurred {{ error_list[0].occurrence_count }} times
|
|
1622
|
-
</span>
|
|
1623
|
-
{% endif %}
|
|
1624
|
-
{% if error_list[0].startStepsCountList is defined and error_list[0].startStepsCountList|length > 0 %}
|
|
1625
|
-
<span class="badge bg-secondary ms-2">
|
|
1626
|
-
<i class="bi bi-step-forward"></i> Monkey Steps: {{ error_list[0].startStepsCountList|join(', ') }}
|
|
1627
|
-
</span>
|
|
1628
|
-
{% endif %}
|
|
1629
|
-
</div>
|
|
1630
|
-
{% if error_list[0].short_description %}
|
|
1631
|
-
<div class="mb-2">
|
|
1632
|
-
<strong>Error:</strong> <code>{{ error_list[0].short_description }}</code>
|
|
1633
|
-
</div>
|
|
1634
|
-
{% endif %}
|
|
1635
|
-
<details>
|
|
1636
|
-
<summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
|
|
1637
|
-
<pre class="text-danger mb-0" style="font-size: 0.85rem; white-space: pre-wrap;">{{ error_list[0].traceback }}</pre>
|
|
1638
|
-
</details>
|
|
1639
|
-
</div>
|
|
1640
|
-
</div>
|
|
1641
1617
|
{% else %}
|
|
1642
1618
|
<!-- Multiple errors - tabbed display -->
|
|
1643
|
-
<button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
|
|
1644
|
-
data-bs-target="#multi-error-detail-{{ property_index }}" aria-expanded="false"
|
|
1619
|
+
<button class="btn btn-sm btn-outline-danger" type="button" data-bs-toggle="collapse"
|
|
1620
|
+
data-bs-target="#multi-error-detail-{{ property_index }}" aria-expanded="false"
|
|
1645
1621
|
aria-controls="multi-error-detail-{{ property_index }}">
|
|
1646
1622
|
<i class="bi bi-exclamation-triangle"></i> View {{ error_list|length }} Errors
|
|
1647
1623
|
</button>
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1624
|
+
{% endif %}
|
|
1625
|
+
{% else %}
|
|
1626
|
+
<span class="text-muted">-</span>
|
|
1627
|
+
{% endif %}
|
|
1628
|
+
</td>
|
|
1629
|
+
</tr>
|
|
1630
|
+
{% if (test_result.fail|default(0) > 0 or test_result.error|default(0) > 0) and property_name in property_error_details %}
|
|
1631
|
+
{% set error_list = property_error_details[property_name] %}
|
|
1632
|
+
{% set property_index = loop.index %}
|
|
1633
|
+
{% if error_list|length == 1 %}
|
|
1634
|
+
<!-- Single error detail row -->
|
|
1635
|
+
<tr class="collapse" id="single-error-detail-{{ property_index }}">
|
|
1636
|
+
<td colspan="7">
|
|
1637
|
+
<div class="bg-light p-3 rounded">
|
|
1638
|
+
<div class="mb-2">
|
|
1639
|
+
<span class="badge bg-{{ 'danger' if error_list[0].state == 'fail' else 'warning' }}">
|
|
1640
|
+
{{ error_list[0].state|upper }}
|
|
1641
|
+
</span>
|
|
1642
|
+
{% if error_list[0].occurrence_count > 1 %}
|
|
1643
|
+
<span class="badge bg-info ms-2">
|
|
1644
|
+
Occurred {{ error_list[0].occurrence_count }} times
|
|
1645
|
+
</span>
|
|
1646
|
+
{% endif %}
|
|
1647
|
+
{% if error_list[0].startStepsCountList is defined and error_list[0].startStepsCountList|length > 0 %}
|
|
1648
|
+
<span class="badge bg-secondary ms-2">
|
|
1649
|
+
<i class="bi bi-step-forward"></i> Monkey Steps: {{ error_list[0].startStepsCountList|join(', ') }}
|
|
1650
|
+
</span>
|
|
1651
|
+
{% endif %}
|
|
1652
|
+
</div>
|
|
1653
|
+
{% if error_list[0].short_description %}
|
|
1654
|
+
<div class="mb-2">
|
|
1655
|
+
<strong>Error:</strong> <code>{{ error_list[0].short_description }}</code>
|
|
1664
1656
|
</div>
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
<
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
</li>
|
|
1683
|
-
{% endfor %}
|
|
1684
|
-
</ul>
|
|
1685
|
-
|
|
1686
|
-
<!-- Error content -->
|
|
1687
|
-
<div class="tab-content" id="multi-error-content-{{ property_index }}">
|
|
1657
|
+
{% endif %}
|
|
1658
|
+
<details>
|
|
1659
|
+
<summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
|
|
1660
|
+
<pre class="text-danger mb-0 text-start" style="font-size: 0.85rem; white-space: pre-wrap; text-align: left;">{{ error_list[0].traceback }}</pre>
|
|
1661
|
+
</details>
|
|
1662
|
+
</div>
|
|
1663
|
+
</td>
|
|
1664
|
+
</tr>
|
|
1665
|
+
{% else %}
|
|
1666
|
+
<!-- Multiple errors detail row -->
|
|
1667
|
+
<tr class="collapse" id="multi-error-detail-{{ property_index }}">
|
|
1668
|
+
<td colspan="7">
|
|
1669
|
+
<div class="bg-light p-3 rounded">
|
|
1670
|
+
<!-- Error summary -->
|
|
1671
|
+
<div class="mb-3">
|
|
1672
|
+
<h6 class="text-danger">Multiple Errors Detected</h6>
|
|
1673
|
+
<div class="d-flex flex-wrap gap-1">
|
|
1688
1674
|
{% for error in error_list %}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
aria-labelledby="multi-error-tab-{{ property_index }}-{{ loop.index }}">
|
|
1693
|
-
<div class="mb-2">
|
|
1694
|
-
<span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
|
|
1695
|
-
{{ error.state|upper }} #{{ loop.index }}
|
|
1696
|
-
</span>
|
|
1697
|
-
<small class="text-muted ms-2">Error {{ loop.index }} of {{ loop.length }}</small>
|
|
1698
|
-
{% if error.occurrence_count > 1 %}
|
|
1699
|
-
<span class="badge bg-info ms-2">
|
|
1700
|
-
{{ error.occurrence_count }} occurrences
|
|
1701
|
-
</span>
|
|
1702
|
-
{% endif %}
|
|
1675
|
+
<span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
|
|
1676
|
+
{{ error.state|upper }} #{{ loop.index }}
|
|
1677
|
+
{% if error.occurrence_count > 1 %} ({{ error.occurrence_count }}x){% endif %}
|
|
1703
1678
|
{% if error.startStepsCountList is defined and error.startStepsCountList|length > 0 %}
|
|
1704
|
-
|
|
1705
|
-
<i class="bi bi-step-forward"></i> Monkey Steps: {{ error.startStepsCountList|join(', ') }}
|
|
1706
|
-
</span>
|
|
1679
|
+
@{% if error.startStepsCountList|length == 1 %}{{ error.startStepsCountList[0] }}{% else %}{{ error.startStepsCountList[0] }}-{{ error.startStepsCountList[-1] }}{% endif %}
|
|
1707
1680
|
{% endif %}
|
|
1708
|
-
</
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1681
|
+
</span>
|
|
1682
|
+
{% endfor %}
|
|
1683
|
+
</div>
|
|
1684
|
+
</div>
|
|
1685
|
+
|
|
1686
|
+
<!-- Error tabs -->
|
|
1687
|
+
<ul class="nav nav-pills nav-fill mb-3" id="multi-error-tabs-{{ property_index }}" role="tablist">
|
|
1688
|
+
{% for error in error_list %}
|
|
1689
|
+
<li class="nav-item" role="presentation">
|
|
1690
|
+
<button class="nav-link {{ 'active' if loop.first else '' }} btn-sm"
|
|
1691
|
+
id="multi-error-tab-{{ property_index }}-{{ loop.index }}"
|
|
1692
|
+
data-bs-toggle="pill"
|
|
1693
|
+
data-bs-target="#multi-error-content-{{ property_index }}-{{ loop.index }}"
|
|
1694
|
+
type="button" role="tab"
|
|
1695
|
+
aria-controls="multi-error-content-{{ property_index }}-{{ loop.index }}"
|
|
1696
|
+
aria-selected="{{ 'true' if loop.first else 'false' }}">
|
|
1697
|
+
<span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }} me-1">
|
|
1698
|
+
{{ error.state|upper }}
|
|
1699
|
+
</span>
|
|
1700
|
+
#{{ loop.index }}
|
|
1701
|
+
</button>
|
|
1702
|
+
</li>
|
|
1703
|
+
{% endfor %}
|
|
1704
|
+
</ul>
|
|
1705
|
+
|
|
1706
|
+
<!-- Error content -->
|
|
1707
|
+
<div class="tab-content" id="multi-error-content-{{ property_index }}">
|
|
1708
|
+
{% for error in error_list %}
|
|
1709
|
+
<div class="tab-pane fade {{ 'show active' if loop.first else '' }}"
|
|
1710
|
+
id="multi-error-content-{{ property_index }}-{{ loop.index }}"
|
|
1711
|
+
role="tabpanel"
|
|
1712
|
+
aria-labelledby="multi-error-tab-{{ property_index }}-{{ loop.index }}">
|
|
1713
|
+
<div class="mb-2">
|
|
1714
|
+
<span class="badge bg-{{ 'danger' if error.state == 'fail' else 'warning' }}">
|
|
1715
|
+
{{ error.state|upper }} #{{ loop.index }}
|
|
1716
|
+
</span>
|
|
1717
|
+
<small class="text-muted ms-2">Error {{ loop.index }} of {{ loop.length }}</small>
|
|
1718
|
+
{% if error.occurrence_count > 1 %}
|
|
1719
|
+
<span class="badge bg-info ms-2">
|
|
1720
|
+
{{ error.occurrence_count }} occurrences
|
|
1721
|
+
</span>
|
|
1722
|
+
{% endif %}
|
|
1723
|
+
{% if error.startStepsCountList is defined and error.startStepsCountList|length > 0 %}
|
|
1724
|
+
<span class="badge bg-secondary ms-2">
|
|
1725
|
+
<i class="bi bi-step-forward"></i> Monkey Steps: {{ error.startStepsCountList|join(', ') }}
|
|
1726
|
+
</span>
|
|
1713
1727
|
{% endif %}
|
|
1714
|
-
<details>
|
|
1715
|
-
<summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
|
|
1716
|
-
<pre class="text-danger mb-0" style="font-size: 0.85rem; white-space: pre-wrap;">{{ error.traceback }}</pre>
|
|
1717
|
-
</details>
|
|
1718
1728
|
</div>
|
|
1719
|
-
{%
|
|
1729
|
+
{% if error.short_description %}
|
|
1730
|
+
<div class="mb-2">
|
|
1731
|
+
<strong>Error:</strong> <code>{{ error.short_description }}</code>
|
|
1732
|
+
</div>
|
|
1733
|
+
{% endif %}
|
|
1734
|
+
<details>
|
|
1735
|
+
<summary class="btn btn-sm btn-outline-secondary mb-2">Show Full Traceback</summary>
|
|
1736
|
+
<pre class="text-danger mb-0 text-start" style="font-size: 0.85rem; white-space: pre-wrap; text-align: left;">{{ error.traceback }}</pre>
|
|
1737
|
+
</details>
|
|
1720
1738
|
</div>
|
|
1739
|
+
{% endfor %}
|
|
1721
1740
|
</div>
|
|
1722
1741
|
</div>
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
</td>
|
|
1728
|
-
</tr>
|
|
1742
|
+
</td>
|
|
1743
|
+
</tr>
|
|
1744
|
+
{% endif %}
|
|
1745
|
+
{% endif %}
|
|
1729
1746
|
{% endfor %}
|
|
1730
1747
|
</tbody>
|
|
1731
1748
|
</table>
|
|
@@ -1208,9 +1208,55 @@
|
|
|
1208
1208
|
<div class="summary-card">
|
|
1209
1209
|
<h2 class="section-title">Test Summary</h2>
|
|
1210
1210
|
|
|
1211
|
+
<!-- Statistics Cards -->
|
|
1212
|
+
<div class="row g-4">
|
|
1213
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1214
|
+
<div class="text-center">
|
|
1215
|
+
<i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
|
|
1216
|
+
<span class="stat-value value-danger">{{ bugs_found }}</span>
|
|
1217
|
+
<span class="stat-label">Bugs Found</span>
|
|
1218
|
+
</div>
|
|
1219
|
+
</div>
|
|
1220
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1221
|
+
<div class="text-center">
|
|
1222
|
+
<i class="bi bi-x-circle text-danger" style="font-size: 2rem;"></i>
|
|
1223
|
+
<span class="stat-value value-danger">{{ total_crash_count|default(0) }}</span>
|
|
1224
|
+
<span class="stat-label">Crashes</span>
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1228
|
+
<div class="text-center">
|
|
1229
|
+
<i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
|
|
1230
|
+
<span class="stat-value value-warning">{{ total_anr_count|default(0) }}</span>
|
|
1231
|
+
<span class="stat-label">ANRs</span>
|
|
1232
|
+
</div>
|
|
1233
|
+
</div>
|
|
1234
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1235
|
+
<div class="text-center">
|
|
1236
|
+
<i class="bi bi-pie-chart text-info" style="font-size: 2rem;"></i>
|
|
1237
|
+
<span class="stat-value value-highlight">{{ "%.2f"|format(coverage_percent) }}%</span>
|
|
1238
|
+
<span class="stat-label">Activity Coverage</span>
|
|
1239
|
+
</div>
|
|
1240
|
+
</div>
|
|
1241
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1242
|
+
<div class="text-center">
|
|
1243
|
+
<i class="bi bi-list-check text-primary" style="font-size: 2rem;"></i>
|
|
1244
|
+
<span class="stat-value value-highlight">{{ all_properties_count }}</span>
|
|
1245
|
+
<span class="stat-label">All Properties</span>
|
|
1246
|
+
</div>
|
|
1247
|
+
</div>
|
|
1248
|
+
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1249
|
+
<div class="text-center">
|
|
1250
|
+
<i class="bi bi-check-square text-success" style="font-size: 2rem;"></i>
|
|
1251
|
+
<span class="stat-value value-success">{{ executed_properties_count }}</span>
|
|
1252
|
+
<span class="stat-label">Executed Properties</span>
|
|
1253
|
+
</div>
|
|
1254
|
+
</div>
|
|
1255
|
+
</div>
|
|
1256
|
+
|
|
1211
1257
|
<!-- Merge Information Section -->
|
|
1212
1258
|
{% if merge_info %}
|
|
1213
|
-
<div class="merge-info-section
|
|
1259
|
+
<div class="merge-info-section mt-4">
|
|
1214
1260
|
<div class="merge-info-card">
|
|
1215
1261
|
<!-- Collapsible Header -->
|
|
1216
1262
|
<div class="merge-info-header" data-bs-toggle="collapse" data-bs-target="#mergeInfoCollapse" aria-expanded="false" aria-controls="mergeInfoCollapse">
|
|
@@ -1261,52 +1307,6 @@
|
|
|
1261
1307
|
</div>
|
|
1262
1308
|
</div>
|
|
1263
1309
|
{% endif %}
|
|
1264
|
-
|
|
1265
|
-
<!-- Statistics Cards -->
|
|
1266
|
-
<div class="row g-4">
|
|
1267
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1268
|
-
<div class="text-center">
|
|
1269
|
-
<i class="bi bi-bug text-danger" style="font-size: 2rem;"></i>
|
|
1270
|
-
<span class="stat-value value-danger">{{ bugs_found }}</span>
|
|
1271
|
-
<span class="stat-label">Bugs Found</span>
|
|
1272
|
-
</div>
|
|
1273
|
-
</div>
|
|
1274
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1275
|
-
<div class="text-center">
|
|
1276
|
-
<i class="bi bi-x-circle text-danger" style="font-size: 2rem;"></i>
|
|
1277
|
-
<span class="stat-value value-danger">{{ total_crash_count|default(0) }}</span>
|
|
1278
|
-
<span class="stat-label">Crashes</span>
|
|
1279
|
-
</div>
|
|
1280
|
-
</div>
|
|
1281
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1282
|
-
<div class="text-center">
|
|
1283
|
-
<i class="bi bi-clock text-warning" style="font-size: 2rem;"></i>
|
|
1284
|
-
<span class="stat-value value-warning">{{ total_anr_count|default(0) }}</span>
|
|
1285
|
-
<span class="stat-label">ANRs</span>
|
|
1286
|
-
</div>
|
|
1287
|
-
</div>
|
|
1288
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1289
|
-
<div class="text-center">
|
|
1290
|
-
<i class="bi bi-pie-chart text-info" style="font-size: 2rem;"></i>
|
|
1291
|
-
<span class="stat-value value-highlight">{{ "%.2f"|format(coverage_percent) }}%</span>
|
|
1292
|
-
<span class="stat-label">Activity Coverage</span>
|
|
1293
|
-
</div>
|
|
1294
|
-
</div>
|
|
1295
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1296
|
-
<div class="text-center">
|
|
1297
|
-
<i class="bi bi-list-check text-primary" style="font-size: 2rem;"></i>
|
|
1298
|
-
<span class="stat-value value-highlight">{{ all_properties_count }}</span>
|
|
1299
|
-
<span class="stat-label">All Properties</span>
|
|
1300
|
-
</div>
|
|
1301
|
-
</div>
|
|
1302
|
-
<div class="col-lg-2 col-md-4 col-sm-6">
|
|
1303
|
-
<div class="text-center">
|
|
1304
|
-
<i class="bi bi-check-square text-success" style="font-size: 2rem;"></i>
|
|
1305
|
-
<span class="stat-value value-success">{{ executed_properties_count }}</span>
|
|
1306
|
-
<span class="stat-label">Executed Properties</span>
|
|
1307
|
-
</div>
|
|
1308
|
-
</div>
|
|
1309
|
-
</div>
|
|
1310
1310
|
</div>
|
|
1311
1311
|
</div>
|
|
1312
1312
|
</div>
|
kea2/u2Driver.py
CHANGED
|
@@ -220,7 +220,7 @@ class StaticXpathUiObject(u2.xpath.XPathSelector):
|
|
|
220
220
|
source = self.session.get_page_source()
|
|
221
221
|
return len(self.selector.all(source)) > 0
|
|
222
222
|
|
|
223
|
-
def __and__(self, value) -> '
|
|
223
|
+
def __and__(self, value) -> 'StaticXpathUiObject':
|
|
224
224
|
s = u2.xpath.XPathSelector(self.selector)
|
|
225
225
|
s._next_xpath = u2.xpath.XPathSelector.create(value.selector)
|
|
226
226
|
s._operator = u2.xpath.Operator.AND
|
|
@@ -288,7 +288,7 @@ class StaticXpathUiObject(u2.xpath.XPathSelector):
|
|
|
288
288
|
self.selector = new
|
|
289
289
|
return self
|
|
290
290
|
|
|
291
|
-
def get(self, timeout=None) -> "XMLElement":
|
|
291
|
+
def get(self, timeout=None) -> "u2.xpath.XMLElement":
|
|
292
292
|
"""
|
|
293
293
|
Get first matched element
|
|
294
294
|
|
|
@@ -343,7 +343,15 @@ class _HindenWidgetFilter:
|
|
|
343
343
|
self._nodes = []
|
|
344
344
|
|
|
345
345
|
self.idx = rtree.index.Index()
|
|
346
|
-
|
|
346
|
+
try:
|
|
347
|
+
self.set_covered_attr(root)
|
|
348
|
+
except Exception as e:
|
|
349
|
+
import traceback, uuid
|
|
350
|
+
traceback.print_exc()
|
|
351
|
+
logger.error(f"Error in setting covered widgets")
|
|
352
|
+
with open(f"kea2_error_tree_{uuid.uuid4().hex}.xml", "wb") as f:
|
|
353
|
+
xml_bytes = etree.tostring(root, pretty_print=True, encoding="utf-8", xml_declaration=True)
|
|
354
|
+
f.write(xml_bytes)
|
|
347
355
|
|
|
348
356
|
# xml_bytes = etree.tostring(root, pretty_print=True, encoding="utf-8", xml_declaration=True)
|
|
349
357
|
# with open("filtered_tree.xml", "wb") as f:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Kea2-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A python library for supporting and customizing automated UI testing for mobile apps
|
|
5
5
|
Author-email: Xixian Liang <xixian@stu.ecnu.edu.cn>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -39,6 +39,7 @@ The group has reached its capacity. Please contact Xixian Liang at [xixian@stu.e
|
|
|
39
39
|
<div align="center">
|
|
40
40
|
<a href="https://en.wikipedia.org/wiki/Kea">Kea2's logo: A large parrot skilled in finding "bugs"</a>
|
|
41
41
|
</div>
|
|
42
|
+
</br>
|
|
42
43
|
|
|
43
44
|
Kea2 is an easy-to-use tool for fuzzing mobile apps. Its key *novelty* is able to fuse automated UI testing with scripts (usually written by human), thus empowering automated UI testing with human intelligence for effectively finding *crashing bugs* as well as *non-crashing functional (logic) bugs*.
|
|
44
45
|
|
|
@@ -110,6 +111,11 @@ Find Kea2's options by running
|
|
|
110
111
|
kea2 -h
|
|
111
112
|
```
|
|
112
113
|
|
|
114
|
+
Upgrade Kea2 to its latest version if you already installed Kea2 before:
|
|
115
|
+
```bash
|
|
116
|
+
python3 -m pip install -U kea2-python
|
|
117
|
+
```
|
|
118
|
+
|
|
113
119
|
## Quick Test
|
|
114
120
|
|
|
115
121
|
Kea2 connects to and runs on Android devices. We recommend you to do a quick test to ensure that Kea2 is compatible with your devices.
|
|
@@ -235,7 +241,15 @@ For the preceding always-holding property, we can write the following script to
|
|
|
235
241
|
```
|
|
236
242
|
> We use [hypothesis](https://github.com/HypothesisWorks/hypothesis) to generate random texts.
|
|
237
243
|
|
|
238
|
-
You can run this example by using the similar command line in Feature 2.
|
|
244
|
+
You can run this example by using the similar command line in Feature 2.
|
|
245
|
+
|
|
246
|
+
## Test Reports(测试报告)
|
|
247
|
+
|
|
248
|
+
Kea2 automatically generates comprehensive HTML test reports after each testing session.
|
|
249
|
+
|
|
250
|
+
The reports support both single test runs and merged analysis of multiple test sessions, making it easy to track testing progress and identify issues.
|
|
251
|
+
|
|
252
|
+
- [View detailed test report documentation](docs/test_report_introduction.md)
|
|
239
253
|
|
|
240
254
|
## Documentations(更多文档)
|
|
241
255
|
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
kea2/__init__.py,sha256=JFJjqgf5KB4bXUFQ3upkEug0cFMFIk9p3OHV9vzulHw,75
|
|
2
2
|
kea2/absDriver.py,sha256=NzmsLs1Ojz-yEXctGAqj7aKBwAQW19zd83l65RABCe8,1288
|
|
3
3
|
kea2/adbUtils.py,sha256=zi0T0_g44xZQZe3XYzBsuh7VTHpdZ4dd6yKi-p7BTYI,19939
|
|
4
|
-
kea2/bug_report_generator.py,sha256=
|
|
4
|
+
kea2/bug_report_generator.py,sha256=gASx3AasGWAufb4A8T4dv0-22knu7h24Z9M9NBSzy24,44107
|
|
5
5
|
kea2/cli.py,sha256=MccJhY8VPZa1rMAbirm3dmbzDx1lf2w3zrpF1ZUq2m0,6481
|
|
6
6
|
kea2/fastbotManager.py,sha256=pGuAH-X26nOy2Qj6Hg5aoMxJx4KfsRk6bj6nhcPENGc,8158
|
|
7
|
-
kea2/keaUtils.py,sha256=
|
|
7
|
+
kea2/keaUtils.py,sha256=zfTmG23KmWmf5b71rrPTxwnpZhZ6gdlLD9eIhjAZv4Y,25834
|
|
8
8
|
kea2/kea_launcher.py,sha256=M9TMCdgkteCWO5iBxJRDRvb7dikanoPf3jdicCEurU8,6268
|
|
9
9
|
kea2/logWatcher.py,sha256=Dp6OzvLSuWYw0AqdcPDqfotaRZQgpF8S49LInGsAWp8,2599
|
|
10
10
|
kea2/report_merger.py,sha256=0b-g59pdrsJDwVNek02ouu1utuu_Sd_1oEMQa4e23xI,24884
|
|
11
11
|
kea2/resultSyncer.py,sha256=9kb3H0Innwj7oPboDDTf97nbjam7EP6HYxywR9B8SvM,2437
|
|
12
|
-
kea2/u2Driver.py,sha256=
|
|
12
|
+
kea2/u2Driver.py,sha256=k1HGH4MF5BbSpohMbK9yn-VpsDzGcYTQLjppHVzHx28,20182
|
|
13
13
|
kea2/utils.py,sha256=x0VTGweW-XShG9MuwZDMP13SBg8jQXYa7e0AXdwYX38,3270
|
|
14
14
|
kea2/assets/fastbot-thirdpart.jar,sha256=0SZ_OoZFWDGMnazgXKceHgKvXdUDoIa3Gb2bcifaikk,85664
|
|
15
15
|
kea2/assets/framework.jar,sha256=rTluOJJKj2DFwh7ascXso1udYdWv00BxBwSQ3Vmv-fw,1149240
|
|
16
16
|
kea2/assets/kea2-thirdpart.jar,sha256=HYdtG2gqDLuLb72dpK3lX-Y6QUNTrJ-bfQopU5aWpfo,359346
|
|
17
17
|
kea2/assets/monkeyq.jar,sha256=4_WLifmU9q5noqMofZWW15Gh8kcuVouNrI-Ca5_g-BM,113104
|
|
18
|
-
kea2/assets/quicktest.py,sha256=
|
|
18
|
+
kea2/assets/quicktest.py,sha256=BgTul5jfSBCh6hVSMRmur61M6_KNTkzIT6Bdff72TE4,3009
|
|
19
19
|
kea2/assets/fastbot_configs/abl.strings,sha256=Rn8_YEbVGOJqndIY_-kWnR5NaoFI-cuB-ij10Ddhl90,75
|
|
20
20
|
kea2/assets/fastbot_configs/awl.strings,sha256=-j4980GoWQxGOM9ijAwXPQmziCwFBZJFmuiv2tOEaYI,101
|
|
21
21
|
kea2/assets/fastbot_configs/max.config,sha256=rBgR4mdgBzqVPQ2lZaXqx2WN6tDzhe-FNizm4Y7tyA8,226
|
|
@@ -28,11 +28,11 @@ kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so,sha256=tAFrG73pJi7XakRxS
|
|
|
28
28
|
kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so,sha256=UV8bhaiPoPKdd3q0vj3kSZqPR9anllai_tz_2QkMMbQ,1335372
|
|
29
29
|
kea2/assets/fastbot_libs/x86/libfastbot_native.so,sha256=k-aw1gEXRWMKZRNHIggKNuZy0wC1y2BnveJGEIO6rbo,2036856
|
|
30
30
|
kea2/assets/fastbot_libs/x86_64/libfastbot_native.so,sha256=tiofhlf4uMQcU5WAvrdLgTBME0lb83hVUoGtTwxmE8A,2121416
|
|
31
|
-
kea2/templates/bug_report_template.html,sha256=
|
|
32
|
-
kea2/templates/merged_bug_report_template.html,sha256=
|
|
33
|
-
kea2_python-0.3.
|
|
34
|
-
kea2_python-0.3.
|
|
35
|
-
kea2_python-0.3.
|
|
36
|
-
kea2_python-0.3.
|
|
37
|
-
kea2_python-0.3.
|
|
38
|
-
kea2_python-0.3.
|
|
31
|
+
kea2/templates/bug_report_template.html,sha256=amZUwlJSg1jzpb1-RB0W6fzwXYZBQK-4SHdhj6LYSbo,152983
|
|
32
|
+
kea2/templates/merged_bug_report_template.html,sha256=iWoXxvN3YQzCabi7BTP4sGl2F6LQrR3_HcG0aD3fHtk,135668
|
|
33
|
+
kea2_python-0.3.4.dist-info/licenses/LICENSE,sha256=nM9PPjcsXVo5SzNsjRqWgA-gdJlwqZZcRDSC6Qf6bVE,2034
|
|
34
|
+
kea2_python-0.3.4.dist-info/METADATA,sha256=owA_RN6ZzlDdCqzVoNoAbsUcvpXNXixhFUiAwZpjKHQ,18983
|
|
35
|
+
kea2_python-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
kea2_python-0.3.4.dist-info/entry_points.txt,sha256=mFX06TyxXiUAJQ6JZn8QHzfn8n5R8_KJ5W-pTm_fRCA,39
|
|
37
|
+
kea2_python-0.3.4.dist-info/top_level.txt,sha256=TsgNH4PQoNOVhegpO7AcjutMVWp6Z4KDL1pBH9FnMmk,5
|
|
38
|
+
kea2_python-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|