orionis 0.291.0__py3-none-any.whl → 0.293.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.
- orionis/metadata/framework.py +1 -1
- orionis/test/suites/test_unit.py +60 -10
- orionis/test/view/render.py +128 -0
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/METADATA +1 -1
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/RECORD +9 -9
- orionis/test/view/index.html +0 -127
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/WHEEL +0 -0
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/top_level.txt +0 -0
- {orionis-0.291.0.dist-info → orionis-0.293.0.dist-info}/zip-safe +0 -0
orionis/metadata/framework.py
CHANGED
orionis/test/suites/test_unit.py
CHANGED
@@ -25,6 +25,8 @@ from orionis.test.exceptions.test_failure_exception import OrionisTestFailureExc
|
|
25
25
|
from orionis.test.exceptions.test_value_error import OrionisTestValueError
|
26
26
|
from orionis.test.logs.history import TestHistory
|
27
27
|
from orionis.test.suites.contracts.test_unit import IUnitTest
|
28
|
+
from orionis.test.view.render import TestingResultRender
|
29
|
+
from rich.text import Text
|
28
30
|
|
29
31
|
class UnitTest(IUnitTest):
|
30
32
|
"""
|
@@ -757,6 +759,15 @@ class UnitTest(IUnitTest):
|
|
757
759
|
if self.persistent:
|
758
760
|
self._persistTestResults(report)
|
759
761
|
|
762
|
+
# Handle Web Report Rendering
|
763
|
+
path = self._webReport(report)
|
764
|
+
|
765
|
+
# Elegant invitation to view the results, with underlined path
|
766
|
+
invite_text = Text("Test results saved. ", style="green")
|
767
|
+
invite_text.append("View report: ", style="bold green")
|
768
|
+
invite_text.append(str(path), style="underline blue")
|
769
|
+
self.rich_console.print(invite_text)
|
770
|
+
|
760
771
|
# Return the summary
|
761
772
|
return {
|
762
773
|
"total_tests": result.testsRun,
|
@@ -769,6 +780,45 @@ class UnitTest(IUnitTest):
|
|
769
780
|
"test_details": test_details
|
770
781
|
}
|
771
782
|
|
783
|
+
def _webReport(self, summary: Dict[str, Any]) -> None:
|
784
|
+
"""
|
785
|
+
Generates a web report for the test results summary.
|
786
|
+
|
787
|
+
Parameters
|
788
|
+
----------
|
789
|
+
summary : dict
|
790
|
+
The summary of test results to generate a web report for.
|
791
|
+
|
792
|
+
Returns
|
793
|
+
-------
|
794
|
+
str
|
795
|
+
The path to the generated web report.
|
796
|
+
|
797
|
+
Notes
|
798
|
+
-----
|
799
|
+
- Determines the storage path based on the current working directory and base_path.
|
800
|
+
- Uses TestingResultRender to generate the report.
|
801
|
+
- If persistence is enabled and the driver is 'sqlite', the report is marked as persistent.
|
802
|
+
- Returns the path to the generated report for further use.
|
803
|
+
"""
|
804
|
+
# Determine the absolute path for storing results
|
805
|
+
project = os.path.basename(os.getcwd())
|
806
|
+
storage_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
|
807
|
+
|
808
|
+
# Only use storage_path if project is recognized
|
809
|
+
if project not in ['framework', 'orionis']:
|
810
|
+
storage_path = None
|
811
|
+
|
812
|
+
# Create the TestingResultRender instance with the storage path and summary
|
813
|
+
render = TestingResultRender(
|
814
|
+
storage_path=storage_path,
|
815
|
+
result=summary,
|
816
|
+
persist=self.persistent and self.persistent_driver == 'sqlite'
|
817
|
+
)
|
818
|
+
|
819
|
+
# Render the report and return the path
|
820
|
+
return render.render()
|
821
|
+
|
772
822
|
def _persistTestResults(self, summary: Dict[str, Any]) -> None:
|
773
823
|
"""
|
774
824
|
Persist the test results summary using the configured persistent driver.
|
@@ -793,13 +843,13 @@ class UnitTest(IUnitTest):
|
|
793
843
|
"""
|
794
844
|
|
795
845
|
try:
|
796
|
-
|
846
|
+
# Determine the absolute path for storing results
|
847
|
+
project = os.getcwd().split(os.sep)[-1]
|
848
|
+
storage_path = None
|
849
|
+
if project in ['framework', 'orionis']:
|
850
|
+
storage_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
|
797
851
|
|
798
|
-
|
799
|
-
project = os.getcwd().split(os.sep)[-1]
|
800
|
-
storage_path = None
|
801
|
-
if project in ['framework', 'orionis']:
|
802
|
-
storage_path = os.path.abspath(os.path.join(os.getcwd(), self.base_path))
|
852
|
+
if self.persistent_driver == 'sqlite':
|
803
853
|
|
804
854
|
# Initialize the TestHistory class for database operations
|
805
855
|
history = TestHistory(
|
@@ -813,14 +863,14 @@ class UnitTest(IUnitTest):
|
|
813
863
|
|
814
864
|
elif self.persistent_driver == 'json':
|
815
865
|
|
866
|
+
# Ensure the base path exists and write the summary to a JSON file
|
867
|
+
os.makedirs(storage_path, exist_ok=True)
|
868
|
+
|
816
869
|
# Get the current timestamp for the log file name
|
817
870
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
818
871
|
|
819
|
-
# Ensure the base path exists and write the summary to a JSON file
|
820
|
-
os.makedirs(self.base_path, exist_ok=True)
|
821
|
-
|
822
872
|
# Create the log file path with the timestamp
|
823
|
-
log_path = os.path.join(
|
873
|
+
log_path = os.path.abspath(os.path.join(storage_path, f'test_{timestamp}.json'))
|
824
874
|
|
825
875
|
# Write the summary to the JSON file
|
826
876
|
with open(log_path, 'w', encoding='utf-8') as log:
|
@@ -0,0 +1,128 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from pathlib import Path
|
4
|
+
from orionis.services.environment.env import Env
|
5
|
+
from orionis.test.logs.history import TestHistory
|
6
|
+
|
7
|
+
class TestingResultRender:
|
8
|
+
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
result,
|
12
|
+
storage_path:str = None,
|
13
|
+
persist=False
|
14
|
+
):
|
15
|
+
"""
|
16
|
+
Initialize the TestingResultRender object.
|
17
|
+
|
18
|
+
Parameters
|
19
|
+
----------
|
20
|
+
result : Any
|
21
|
+
The test result data to be processed or stored.
|
22
|
+
storage_path : str, optional
|
23
|
+
Custom path to store the test report. If not provided, uses the environment variable
|
24
|
+
'TEST_REPORT_PATH' or defaults to a local storage path.
|
25
|
+
persist : bool, optional
|
26
|
+
Whether to persist the report. Defaults to False.
|
27
|
+
|
28
|
+
Notes
|
29
|
+
-----
|
30
|
+
- Determines the file path for the test report based on the provided storage_path, environment variable,
|
31
|
+
or a default location.
|
32
|
+
- Ensures the parent directory for the report exists.
|
33
|
+
- Stores the resolved report path in the environment variable 'TEST_REPORT_PATH'.
|
34
|
+
"""
|
35
|
+
|
36
|
+
# Initialize instance variables
|
37
|
+
self.__filename = 'test-results.html'
|
38
|
+
self.__result = result
|
39
|
+
self.__persist = persist
|
40
|
+
|
41
|
+
# Determine file path
|
42
|
+
db_path = None
|
43
|
+
if storage_path:
|
44
|
+
db_path = Path(storage_path).expanduser().resolve()
|
45
|
+
if db_path.is_dir():
|
46
|
+
db_path = db_path / self.__filename
|
47
|
+
else:
|
48
|
+
env_path = Env.get("TEST_REPORT_PATH", None)
|
49
|
+
if env_path:
|
50
|
+
db_path = Path(env_path).expanduser().resolve()
|
51
|
+
if db_path.is_dir():
|
52
|
+
db_path = db_path / self.__filename
|
53
|
+
else:
|
54
|
+
db_path = Path.cwd() / 'storage/framework/testing' / self.__filename
|
55
|
+
|
56
|
+
# Ensure parent directory exists
|
57
|
+
db_path.parent.mkdir(parents=True, exist_ok=True)
|
58
|
+
|
59
|
+
# Store path in environment
|
60
|
+
Env.set("TEST_REPORT_PATH", str(db_path), 'path')
|
61
|
+
self.__report_path = db_path
|
62
|
+
|
63
|
+
def render(self):
|
64
|
+
"""
|
65
|
+
Otherwise, uses the current test result stored in memory. The method replaces placeholders in a
|
66
|
+
template file with the test results and the persistence mode, then writes the rendered content
|
67
|
+
to a report file.
|
68
|
+
|
69
|
+
Parameters
|
70
|
+
----------
|
71
|
+
None
|
72
|
+
|
73
|
+
Returns
|
74
|
+
-------
|
75
|
+
str
|
76
|
+
The full path to the generated report file.
|
77
|
+
|
78
|
+
Notes
|
79
|
+
-----
|
80
|
+
- If persistence is enabled, the last 10 reports are fetched from the SQLite database.
|
81
|
+
- If persistence is not enabled, only the current test result in memory is used.
|
82
|
+
- The method reads a template file, replaces placeholders with the test results and persistence mode,
|
83
|
+
and writes the final content to the report file.
|
84
|
+
"""
|
85
|
+
|
86
|
+
# Determine the source of test results based on persistence mode
|
87
|
+
if self.__persist:
|
88
|
+
# If persistence is enabled, fetch the last 10 reports from SQLite
|
89
|
+
logs = TestHistory()
|
90
|
+
reports = logs.get(last=10)
|
91
|
+
# Parse each report's JSON data into a list
|
92
|
+
results_list = [json.loads(report[1]) for report in reports]
|
93
|
+
else:
|
94
|
+
# If not persistent, use only the current in-memory result
|
95
|
+
results_list = [self.__result]
|
96
|
+
|
97
|
+
# Set placeholder values for the template
|
98
|
+
persistence_mode = 'SQLite' if self.__persist else 'Static'
|
99
|
+
test_results_json = json.dumps(results_list, ensure_ascii=False, indent=None)
|
100
|
+
|
101
|
+
# Locate the HTML template file
|
102
|
+
template_path = Path(__file__).parent / 'report.stub'
|
103
|
+
|
104
|
+
# Read the template content
|
105
|
+
with open(template_path, 'r', encoding='utf-8') as template_file:
|
106
|
+
template_content = template_file.read()
|
107
|
+
|
108
|
+
# Replace placeholders with actual values
|
109
|
+
rendered_content = template_content.replace(
|
110
|
+
'{{orionis-testing-result}}',
|
111
|
+
test_results_json
|
112
|
+
).replace(
|
113
|
+
'{{orionis-testing-persistent}}',
|
114
|
+
persistence_mode
|
115
|
+
)
|
116
|
+
|
117
|
+
# Write the rendered HTML report to the specified path
|
118
|
+
with open(self.__report_path, 'w', encoding='utf-8') as report_file:
|
119
|
+
report_file.write(rendered_content)
|
120
|
+
|
121
|
+
# Open the generated report in the default web browser if running on Windows or macOS.
|
122
|
+
# This provides immediate feedback to the user after report generation.
|
123
|
+
if os.name == 'nt' or os.name == 'posix' and sys.platform == 'darwin':
|
124
|
+
import webbrowser
|
125
|
+
webbrowser.open(self.__report_path.as_uri())
|
126
|
+
|
127
|
+
# Return the absolute path to the generated report
|
128
|
+
return str(self.__report_path)
|
@@ -226,7 +226,7 @@ orionis/foundation/config/testing/entities/testing.py,sha256=m_i9jZlOXs_AzNKNNf0
|
|
226
226
|
orionis/foundation/config/testing/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
227
227
|
orionis/foundation/config/testing/enums/test_mode.py,sha256=IbFpauu7J-iSAfmC8jDbmTEYl8eZr-AexL-lyOh8_74,337
|
228
228
|
orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
229
|
-
orionis/metadata/framework.py,sha256=
|
229
|
+
orionis/metadata/framework.py,sha256=QmC-g5i6UhTE0QWIF78bMyfW6Dm4d4521_PuYknYoGQ,4960
|
230
230
|
orionis/metadata/package.py,sha256=tqLfBRo-w1j_GN4xvzUNFyweWYFS-qhSgAEc-AmCH1M,5452
|
231
231
|
orionis/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
orionis/patterns/singleton/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -345,13 +345,13 @@ orionis/test/output/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
345
345
|
orionis/test/output/contracts/dumper.py,sha256=5OqGc4GEXCXX76sCX185giQMyKwwZvlOv3I7tTwV2fQ,1324
|
346
346
|
orionis/test/suites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
347
347
|
orionis/test/suites/test_suite.py,sha256=fdVmC56PJfWDuYeekY7oN-04AEHMqxwLI5mZNJAuOZI,5261
|
348
|
-
orionis/test/suites/test_unit.py,sha256=
|
348
|
+
orionis/test/suites/test_unit.py,sha256=JAla82Uc2OEvvBTE8oI8BT0hxeb03FJB1bdKU7G2xlA,51293
|
349
349
|
orionis/test/suites/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
350
350
|
orionis/test/suites/contracts/test_suite.py,sha256=eluzYwkNBbKjxYStj_tHN_Fm3YDPpGQdqMu5eiluh-E,1059
|
351
351
|
orionis/test/suites/contracts/test_unit.py,sha256=l1LQllODyvcSByXMl1lGrUkoLsXbBHZZLWZI4A-mlQg,5881
|
352
352
|
orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
353
|
-
orionis/test/view/
|
354
|
-
orionis-0.
|
353
|
+
orionis/test/view/render.py,sha256=jXZkbITBknbUwm_mD8bcTiwLDvsFkrO9qrf0ZgPwqxc,4903
|
354
|
+
orionis-0.293.0.dist-info/licenses/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
|
355
355
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
356
356
|
tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
357
357
|
tests/example/test_example.py,sha256=byd_lI6tVDgGPEIrr7PLZbBu0UoZOymmdmyA_4u-QUw,601
|
@@ -455,8 +455,8 @@ tests/support/inspection/fakes/fake_reflection_instance_with_abstract.py,sha256=
|
|
455
455
|
tests/testing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
456
456
|
tests/testing/test_testing_result.py,sha256=MrGK3ZimedL0b5Ydu69Dg8Iul017AzLTm7VPxpXlpfU,4315
|
457
457
|
tests/testing/test_testing_unit.py,sha256=A6QkiOkP7GPC1Szh_GqsrV7GxjWjK8cIwFez6YfrzmM,7683
|
458
|
-
orionis-0.
|
459
|
-
orionis-0.
|
460
|
-
orionis-0.
|
461
|
-
orionis-0.
|
462
|
-
orionis-0.
|
458
|
+
orionis-0.293.0.dist-info/METADATA,sha256=VYamMjDShBXxI6Quu-380uo1bp772T2nDaTlWcmJdwI,4772
|
459
|
+
orionis-0.293.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
460
|
+
orionis-0.293.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
461
|
+
orionis-0.293.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
|
462
|
+
orionis-0.293.0.dist-info/RECORD,,
|
orionis/test/view/index.html
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html lang="en">
|
3
|
-
|
4
|
-
<head>
|
5
|
-
<meta charset="UTF-8" />
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7
|
-
<title>Orionis Test Dashboard</title>
|
8
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
9
|
-
<link rel="icon" href="https://orionis-framework.com/svg/logo.svg" />
|
10
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
11
|
-
</head>
|
12
|
-
|
13
|
-
<body class="bg-gray-100 text-gray-800 font-sans">
|
14
|
-
<div class="max-w-7xl mx-auto px-4 sm:px-6 py-8">
|
15
|
-
|
16
|
-
<!-- Header -->
|
17
|
-
<header class="bg-gradient-to-r from-blue-900 to-cyan-400 text-white rounded-2xl shadow-xl p-6 mb-10">
|
18
|
-
<div class="flex flex-col md:flex-row justify-between items-center gap-4">
|
19
|
-
<div class="flex items-center gap-4">
|
20
|
-
<img src="https://orionis-framework.com/svg/logo.svg" alt="Orionis Logo"
|
21
|
-
class="h-10 brightness-0 invert" />
|
22
|
-
<h1 class="text-2xl font-light tracking-wider">Orionis Testing Results Dashboard</h1>
|
23
|
-
</div>
|
24
|
-
<div id="timestamp" class="text-sm text-white/90"></div>
|
25
|
-
</header>
|
26
|
-
|
27
|
-
<!-- Execution Summary Card -->
|
28
|
-
<div class="w-full mb-10">
|
29
|
-
<div class="bg-white rounded-2xl shadow-lg p-6 border-t-4 border-indigo-500 flex flex-col sm:flex-row items-center justify-between gap-4">
|
30
|
-
<div>
|
31
|
-
<div class="text-xs font-semibold text-gray-500 uppercase">Resumen de Ejecución</div>
|
32
|
-
<div class="text-lg font-bold text-gray-800 mt-2" id="execution-summary-title">Ejecución Completa</div>
|
33
|
-
<div class="text-sm text-gray-600 mt-1" id="execution-summary-desc">Todos los tests han sido ejecutados correctamente.</div>
|
34
|
-
</div>
|
35
|
-
<div class="flex items-center gap-4">
|
36
|
-
<div class="flex items-center gap-1 text-gray-700">
|
37
|
-
<i class="bi bi-clock-history text-xl text-indigo-500"></i>
|
38
|
-
<span id="execution-time">Duración: 00:00:00</span>
|
39
|
-
</div>
|
40
|
-
</div>
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<!-- Summary Cards -->
|
45
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 mb-10">
|
46
|
-
|
47
|
-
<div class="bg-white rounded-2xl shadow-lg p-6 border-t-4 border-green-500">
|
48
|
-
<div class="text-xs font-semibold text-gray-500 uppercase">Passed</div>
|
49
|
-
<div class="text-4xl font-bold text-gray-800 mt-2" id="passed">0</div>
|
50
|
-
<div class="mt-4 bg-gray-200 rounded-full h-2">
|
51
|
-
<div class="bg-green-500 h-2 rounded-full" id="passed-progress" style="width: 0%"></div>
|
52
|
-
</div>
|
53
|
-
</div>
|
54
|
-
|
55
|
-
<div class="bg-white rounded-2xl shadow-lg p-6 border-t-4 border-red-500">
|
56
|
-
<div class="text-xs font-semibold text-gray-500 uppercase">Failed</div>
|
57
|
-
<div class="text-4xl font-bold text-gray-800 mt-2" id="failed">0</div>
|
58
|
-
</div>
|
59
|
-
|
60
|
-
<div class="bg-white rounded-2xl shadow-lg p-6 border-t-4 border-yellow-500">
|
61
|
-
<div class="text-xs font-semibold text-gray-500 uppercase">Errors</div>
|
62
|
-
<div class="text-4xl font-bold text-gray-800 mt-2" id="errors">0</div>
|
63
|
-
</div>
|
64
|
-
|
65
|
-
<div class="bg-white rounded-2xl shadow-lg p-6 border-t-4 border-blue-500">
|
66
|
-
<div class="text-xs font-semibold text-gray-500 uppercase">Skipped</div>
|
67
|
-
<div class="text-4xl font-bold text-gray-800 mt-2" id="skipped">0</div>
|
68
|
-
</div>
|
69
|
-
|
70
|
-
</div>
|
71
|
-
|
72
|
-
<!-- Download Buttons & Select -->
|
73
|
-
<div class="flex flex-wrap justify-between items-center mb-10 gap-4">
|
74
|
-
<!-- Buttons to the left -->
|
75
|
-
<div class="flex flex-wrap gap-4">
|
76
|
-
<button id="download-json"
|
77
|
-
class="flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded shadow">
|
78
|
-
<i class="bi bi-file-earmark-code-fill text-lg"></i>
|
79
|
-
<span>Download JSON</span>
|
80
|
-
</button>
|
81
|
-
<button id="download-excel"
|
82
|
-
class="flex items-center gap-2 bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded shadow">
|
83
|
-
<i class="bi bi-file-earmark-excel-fill text-lg"></i>
|
84
|
-
<span>Download Excel</span>
|
85
|
-
</button>
|
86
|
-
<button id="download-pdf"
|
87
|
-
class="flex items-center gap-2 bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded shadow">
|
88
|
-
<i class="bi bi-file-earmark-pdf-fill text-lg"></i>
|
89
|
-
<span>Download PDF</span>
|
90
|
-
</button>
|
91
|
-
</div>
|
92
|
-
<!-- Elegant Select to the right -->
|
93
|
-
<div>
|
94
|
-
<select
|
95
|
-
class="appearance-none bg-white border border-gray-300 text-gray-700 py-2 px-4 pr-10 rounded-lg shadow focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-blue-400 transition text-base font-medium">
|
96
|
-
<option selected disabled>Selecciona una opción</option>
|
97
|
-
<option>Opción 1</option>
|
98
|
-
<option>Opción 2</option>
|
99
|
-
<option>Opción 3</option>
|
100
|
-
</select>
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
|
104
|
-
<!-- JSON Viewer Panel -->
|
105
|
-
<div class="bg-white rounded-2xl shadow-xl p-6">
|
106
|
-
<h2 class="text-xl font-semibold mb-4">Test Report JSON</h2>
|
107
|
-
<pre id="json-data"
|
108
|
-
class="whitespace-pre-wrap text-sm text-gray-800 bg-gray-100 p-4 rounded-xl overflow-x-auto"></pre>
|
109
|
-
</div>
|
110
|
-
|
111
|
-
<!-- Footer -->
|
112
|
-
<footer class="mt-12 text-center text-gray-500 text-sm py-6">
|
113
|
-
Developed with the power of
|
114
|
-
<a href="https://orionis-framework.com/" target="_blank" rel="noopener"
|
115
|
-
class="font-semibold text-blue-700 hover:underline">
|
116
|
-
Orionis Framework
|
117
|
-
</a>
|
118
|
-
<i class="bi bi-stars text-yellow-400 align-middle ml-1"></i>
|
119
|
-
</footer>
|
120
|
-
|
121
|
-
<script>
|
122
|
-
// Placeholder JS logic
|
123
|
-
document.getElementById("timestamp").textContent = new Date().toLocaleString();
|
124
|
-
</script>
|
125
|
-
</body>
|
126
|
-
|
127
|
-
</html>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|