qapytest 0.3.2__tar.gz → 0.3.4__tar.gz
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.
- {qapytest-0.3.2 → qapytest-0.3.4}/CHANGELOG.md +22 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/PKG-INFO +3 -3
- {qapytest-0.3.2 → qapytest-0.3.4}/README.md +2 -2
- {qapytest-0.3.2 → qapytest-0.3.4}/docs/CLI.md +2 -2
- {qapytest-0.3.2 → qapytest-0.3.4}/pyproject.toml +1 -1
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_assets/_log_tree.html.jinja2 +10 -2
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_assets/report.html.jinja2 +58 -13
- qapytest-0.3.4/qapytest/_assets/scripts.js +1201 -0
- qapytest-0.3.4/qapytest/_assets/styles.css +1255 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_internal.py +22 -7
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_plugin.py +97 -55
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_report.py +2 -2
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_internal_functions.py +19 -30
- {qapytest-0.3.2 → qapytest-0.3.4}/uv.lock +9 -1
- qapytest-0.3.2/qapytest/_assets/scripts.js +0 -442
- qapytest-0.3.2/qapytest/_assets/styles.css +0 -649
- {qapytest-0.3.2 → qapytest-0.3.4}/.gitignore +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/.pre-commit-config.yaml +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/NOTICE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/THIRD_PARTY_NOTICES.txt +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/demo.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/docs/API.md +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/faker.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/httpx.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/jinja2.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/jsonschema.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/playwright-python.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/pytest-playwright.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/pytest.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/python_dotenv.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/redis-py.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/licenses/sqlalchemy.LICENSE +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/__init__.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_attach.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_client_http.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_config.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_config_http.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_json_validation.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_redis.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_soft_assert.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_sql.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/_step.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/qapytest/py.typed +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/encoding.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_attach.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_graphql_client.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_http_client.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_integration.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_markers.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_redis_client.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_soft_assert.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_sql_client.py +0 -0
- {qapytest-0.3.2 → qapytest-0.3.4}/tests/test_step.py +0 -0
|
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.4] - 2025-11-23
|
|
9
|
+
|
|
10
|
+
### Enhanced
|
|
11
|
+
|
|
12
|
+
- 📊 **Interactive HTML Report** - significantly improved report interactivity with new features:
|
|
13
|
+
- **JSON Viewer** - interactive tree view for JSON attachments with search and expand/collapse capabilities
|
|
14
|
+
- **Log Filtering** - filter logs by logger name and level, with search functionality
|
|
15
|
+
- **Component Filtering** - easily filter test results by component
|
|
16
|
+
- **Step Management** - expand/collapse all steps with a single click
|
|
17
|
+
- **Navigation** - added "Scroll to top" button for easier navigation in long reports
|
|
18
|
+
- 🛠️ **Soft Assertions** - improved display of soft assertion failures in the report
|
|
19
|
+
|
|
20
|
+
## [0.3.3] - 2025-10-31
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- ⚙️ **CLI option renamed** - `--disable-unicode-terminal` renamed to `--disable-unicode`
|
|
25
|
+
- 🖥️ **Unicode display in IDE** - fixed Unicode rendering issues in integrated development environments
|
|
26
|
+
- 🔧 **Minor bug fixes** - resolved small issues to improve overall stability
|
|
27
|
+
|
|
8
28
|
## [0.3.2] - 2025-10-29
|
|
9
29
|
|
|
10
30
|
### Added
|
|
@@ -149,6 +169,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
149
169
|
- Configurable attachment size limits
|
|
150
170
|
- Professional report styling with responsive design
|
|
151
171
|
|
|
172
|
+
[0.3.4]: https://github.com/o73k51i/qapytest/releases/tag/v0.3.4
|
|
173
|
+
[0.3.3]: https://github.com/o73k51i/qapytest/releases/tag/v0.3.3
|
|
152
174
|
[0.3.2]: https://github.com/o73k51i/qapytest/releases/tag/v0.3.2
|
|
153
175
|
[0.3.1]: https://github.com/o73k51i/qapytest/releases/tag/v0.3.1
|
|
154
176
|
[0.3.0]: https://github.com/o73k51i/qapytest/releases/tag/v0.3.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qapytest
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A powerful testing framework based on pytest, specifically designed for QA engineers
|
|
5
5
|
Project-URL: Homepage, https://github.com/o73k51i/qapytest
|
|
6
6
|
Project-URL: Repository, https://github.com/o73k51i/qapytest
|
|
@@ -281,8 +281,8 @@ def test_user_login():
|
|
|
281
281
|
- **`--report-title NAME`** : set the HTML report title.
|
|
282
282
|
- **`--report-theme {light,dark,auto}`** : choose the report theme: `light`,
|
|
283
283
|
`dark` or `auto` (default).
|
|
284
|
-
- **`--disable-unicode
|
|
285
|
-
terminal for compatibility with older systems.
|
|
284
|
+
- **`--disable-unicode`** : disable Unicode character display in
|
|
285
|
+
terminal output for compatibility with older terminals or CI systems.
|
|
286
286
|
|
|
287
287
|
More about CLI options on the [documentation page](https://github.com/o73k51i/qapytest/blob/main/docs/CLI.md).
|
|
288
288
|
|
|
@@ -225,8 +225,8 @@ def test_user_login():
|
|
|
225
225
|
- **`--report-title NAME`** : set the HTML report title.
|
|
226
226
|
- **`--report-theme {light,dark,auto}`** : choose the report theme: `light`,
|
|
227
227
|
`dark` or `auto` (default).
|
|
228
|
-
- **`--disable-unicode
|
|
229
|
-
terminal for compatibility with older systems.
|
|
228
|
+
- **`--disable-unicode`** : disable Unicode character display in
|
|
229
|
+
terminal output for compatibility with older terminals or CI systems.
|
|
230
230
|
|
|
231
231
|
More about CLI options on the [documentation page](https://github.com/o73k51i/qapytest/blob/main/docs/CLI.md).
|
|
232
232
|
|
|
@@ -23,7 +23,7 @@ Below are the available options, their purpose, and usage examples.
|
|
|
23
23
|
`dark`, or `auto` (default).
|
|
24
24
|
- **`--max-attachment-bytes N`** : maximum attachment size (in bytes) to embed
|
|
25
25
|
in the HTML; larger files will be truncated (default is unlimited).
|
|
26
|
-
- **`--disable-unicode
|
|
26
|
+
- **`--disable-unicode`** : disable Unicode character display in
|
|
27
27
|
terminal output for compatibility with older terminals or CI systems.
|
|
28
28
|
|
|
29
29
|
### Behavior with `.env`
|
|
@@ -57,7 +57,7 @@ you can disable this feature:
|
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
59
|
# Disable Unicode character display in terminal
|
|
60
|
-
pytest --disable-unicode
|
|
60
|
+
pytest --disable-unicode --report-html
|
|
61
61
|
|
|
62
62
|
# Normal run with Unicode support (default)
|
|
63
63
|
pytest --report-html
|
|
@@ -4,9 +4,17 @@
|
|
|
4
4
|
{% for entry in log_list %}
|
|
5
5
|
{% if entry.type == 'step' %}
|
|
6
6
|
<li class="{{ 'step-passed' if entry.passed else 'step-failed' }}">
|
|
7
|
+
{% if entry.children %}
|
|
8
|
+
<span class="step-toggle collapsed">▼</span>
|
|
9
|
+
{% else %}
|
|
10
|
+
<span class="step-toggle-placeholder"></span>
|
|
11
|
+
{% endif %}
|
|
7
12
|
{{ '✔︎' if entry.passed else '✖︎' }} <strong>Step:</strong> {{ entry.message|e }}
|
|
8
|
-
{
|
|
9
|
-
|
|
13
|
+
{% if entry.children %}
|
|
14
|
+
<div class="step-children" hidden>
|
|
15
|
+
{{ render_log_tree(entry.children, test_index, attachment_counter, assert_counter) }}
|
|
16
|
+
</div>
|
|
17
|
+
{% endif %}
|
|
10
18
|
</li>
|
|
11
19
|
{% elif entry.type == 'assert' %}
|
|
12
20
|
{% set _ = assert_counter.update({'value': assert_counter.value + 1}) %}
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
<header class="header">
|
|
11
11
|
<div class="container">
|
|
12
12
|
<div class="title">{{ title|e }}</div>
|
|
13
|
-
<button id="theme-toggle" class="theme-toggle" title="Toggle theme">
|
|
14
|
-
<
|
|
13
|
+
<button id="theme-toggle" class="theme-toggle" title="Toggle theme" aria-label="Toggle theme">
|
|
14
|
+
<svg class="theme-icon-moon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
|
|
15
|
+
<svg class="theme-icon-sun" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>
|
|
15
16
|
</button>
|
|
16
17
|
<section class="cards">
|
|
17
18
|
<div class="card"><div class="label">Start</div><div class="value">{{ fmt_datetime(session_start) }}</div></div>
|
|
@@ -39,8 +40,23 @@
|
|
|
39
40
|
<th>#</th>
|
|
40
41
|
<th>Test</th>
|
|
41
42
|
<th>Status</th>
|
|
42
|
-
<th>
|
|
43
|
-
|
|
43
|
+
<th>
|
|
44
|
+
<div class="th-filter-wrapper">
|
|
45
|
+
<span>Component</span>
|
|
46
|
+
<button class="th-filter-toggle" title="Filter Components">▾</button>
|
|
47
|
+
<div class="th-filter-menu" hidden>
|
|
48
|
+
<input type="text" class="th-filter-search" placeholder="Filter..." />
|
|
49
|
+
<label class="th-filter-item"><input type="checkbox" value="all" checked> <span>All</span></label>
|
|
50
|
+
<div class="th-filter-list"></div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</th>
|
|
54
|
+
<th>
|
|
55
|
+
<div class="th-sort-wrapper" data-sort="duration">
|
|
56
|
+
<span>Duration (s)</span>
|
|
57
|
+
<span class="sort-icon">↕</span>
|
|
58
|
+
</div>
|
|
59
|
+
</th>
|
|
44
60
|
</tr>
|
|
45
61
|
</thead>
|
|
46
62
|
<tbody>
|
|
@@ -49,11 +65,11 @@
|
|
|
49
65
|
{% set test_index = loop.index %}
|
|
50
66
|
{% set params_str = parse_params_from_nodeid(result.nodeid) %}
|
|
51
67
|
{% set search_text = [result.nodeid, result.path, result.title, result.components|join(' ')]|join(' ')|e %}
|
|
52
|
-
<tr class="test-row" data-status="{{ result.outcome }}" data-text="{{ search_text }}" role="button" tabindex="0" aria-expanded="false" aria-controls="{{ details_id }}">
|
|
68
|
+
<tr class="test-row" data-status="{{ result.outcome }}" data-text="{{ search_text }}" data-duration="{{ result.duration }}" role="button" tabindex="0" aria-expanded="false" aria-controls="{{ details_id }}">
|
|
53
69
|
<td class="small">{{ loop.index }}</td>
|
|
54
70
|
<td>
|
|
55
71
|
<div class="mono">{{ decode_unicode_escapes(result.title)|e }}</div>
|
|
56
|
-
{% if params_str %}<div class="small">Parametrize: {{ params_str|e }}</div>{% endif %}
|
|
72
|
+
{% if params_str %}<div class="small">Parametrize: {{ decode_unicode_escapes(params_str)|e }}</div>{% endif %}
|
|
57
73
|
</td>
|
|
58
74
|
<td><span class="status {{ result.outcome }}">{{ result.outcome }}</span></td>
|
|
59
75
|
<td class="small">{{ (result.components or [])|join(', ')|e }}</td>
|
|
@@ -69,13 +85,20 @@
|
|
|
69
85
|
<button class="details-btn copy-btn" type="button" data-copy="#grid-{{ details_id }}" title="Copy details"><span>📋</span> Copy</button>
|
|
70
86
|
</div>
|
|
71
87
|
<div class="grid" id="grid-{{ details_id }}">
|
|
72
|
-
<div class="k">NodeID</div
|
|
88
|
+
<div class="k">NodeID</div>
|
|
89
|
+
<div class="v mono">{{ decode_unicode_escapes(result.nodeid)|e }}</div>
|
|
73
90
|
<div class="k">File</div><div class="v mono">{{ result.path|e }}</div>
|
|
74
91
|
{% if result.details.headline %}
|
|
75
92
|
<div class="k">Result</div><div class="v"><span class="status {{ result.outcome }}">{{ result.details.headline|e }}</span></div>
|
|
76
93
|
{% endif %}
|
|
77
94
|
{% if result.execution_log %}
|
|
78
|
-
<div class="k">
|
|
95
|
+
<div class="k">
|
|
96
|
+
Execution Log
|
|
97
|
+
<div style="margin-top: 4px;">
|
|
98
|
+
<button class="details-btn step-toggle-all-btn" type="button" data-expanded="false" style="font-size: 10px; padding: 2px 6px;">Expand All</button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="v mono">
|
|
79
102
|
{% import '_log_tree.html.jinja2' as log_helpers %}
|
|
80
103
|
{{ log_helpers.render_log_tree(result.execution_log, test_index, {'value': 0}, {'value': 0}) }}
|
|
81
104
|
</div>
|
|
@@ -96,25 +119,36 @@
|
|
|
96
119
|
</div>
|
|
97
120
|
</main>
|
|
98
121
|
|
|
99
|
-
{# --- Modals --- #}
|
|
100
122
|
{% for result in results %}
|
|
101
123
|
{% set details_id = 'details-' ~ loop.index %}
|
|
102
124
|
{% set test_index = loop.index %}
|
|
103
|
-
{# Render modals for logs #}
|
|
104
125
|
{% if result.details.captured_logs and result.details.captured_logs.strip() %}
|
|
105
126
|
<div class="modal" id="logs-modal-{{ details_id }}" hidden>
|
|
106
127
|
<div class="modal-overlay" data-modal-close></div>
|
|
107
128
|
<div class="modal-content">
|
|
108
129
|
<div class="modal-header">
|
|
109
130
|
<h3 class="mono">{{ decode_unicode_escapes(result.title)|e }}</h3>
|
|
110
|
-
<
|
|
131
|
+
<div class="modal-actions">
|
|
132
|
+
<div class="attachment-controls" style="display: none;">
|
|
133
|
+
<input type="text" class="attachment-search" placeholder="Highlight text..." />
|
|
134
|
+
</div>
|
|
135
|
+
<div class="log-filter-wrapper">
|
|
136
|
+
<button class="details-btn log-filter-toggle">Filter Loggers ▾</button>
|
|
137
|
+
<div class="log-filter-menu" hidden>
|
|
138
|
+
<input type="text" class="log-filter-search" placeholder="Filter..." />
|
|
139
|
+
<label class="log-filter-item"><input type="checkbox" value="all" checked> <span>All Loggers</span></label>
|
|
140
|
+
<div class="log-filter-list"></div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
<button class="details-btn log-copy-btn" title="Copy visible logs"><span>📋</span> Copy</button>
|
|
144
|
+
<button class="modal-close" data-modal-close>×</button>
|
|
145
|
+
</div>
|
|
111
146
|
</div>
|
|
112
147
|
<div class="modal-body"><pre><code>{{ result.details.captured_logs|e }}</code></pre></div>
|
|
113
148
|
</div>
|
|
114
149
|
</div>
|
|
115
150
|
{% endif %}
|
|
116
151
|
|
|
117
|
-
{# Render modals for attachments #}
|
|
118
152
|
{% for attachment in result.attachments %}
|
|
119
153
|
{% set modal_id = 'attachment-modal-' ~ test_index ~ '-' ~ loop.index %}
|
|
120
154
|
<div class="modal" id="{{ modal_id }}" hidden>
|
|
@@ -122,7 +156,14 @@
|
|
|
122
156
|
<div class="modal-content">
|
|
123
157
|
<div class="modal-header">
|
|
124
158
|
<h3>{{ attachment.label|e }}</h3>
|
|
125
|
-
<
|
|
159
|
+
<div class="modal-actions">
|
|
160
|
+
<div class="attachment-controls" style="display: none;">
|
|
161
|
+
<input type="text" class="attachment-search" placeholder="Highlight text..." />
|
|
162
|
+
<button class="details-btn attachment-toggle-all-btn" title="Expand/Collapse All" data-expanded="true">Collapse All</button>
|
|
163
|
+
</div>
|
|
164
|
+
<button class="details-btn attachment-copy-btn" type="button" title="Copy content"><span>📋</span> Copy</button>
|
|
165
|
+
<button class="modal-close" data-modal-close>×</button>
|
|
166
|
+
</div>
|
|
126
167
|
</div>
|
|
127
168
|
<div class="modal-body">
|
|
128
169
|
{% if attachment.content_type == "image" %}
|
|
@@ -136,6 +177,10 @@
|
|
|
136
177
|
{% endfor %}
|
|
137
178
|
{% endfor %}
|
|
138
179
|
|
|
180
|
+
<button id="scroll-to-top" class="scroll-to-top" title="Scroll to top" aria-label="Scroll to top">
|
|
181
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 15l-6-6-6 6"/></svg>
|
|
182
|
+
</button>
|
|
183
|
+
|
|
139
184
|
<script>{{ js_content }}</script>
|
|
140
185
|
</body>
|
|
141
186
|
</html>
|