mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-12 16:01:27 +08:00
refactor report template: display request and response data in popup table
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
__title__ = 'HttpRunner'
|
__title__ = 'HttpRunner'
|
||||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||||
__version__ = '1.3.9'
|
__version__ = '1.3.10'
|
||||||
__author__ = 'debugtalk'
|
__author__ = 'debugtalk'
|
||||||
__author_email__ = 'mail@debugtalk.com'
|
__author_email__ = 'mail@debugtalk.com'
|
||||||
__license__ = 'MIT'
|
__license__ = 'MIT'
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ def render_html_report(summary, html_report_name=None, html_report_template=None
|
|||||||
os.makedirs(report_dir_path)
|
os.makedirs(report_dir_path)
|
||||||
|
|
||||||
for record in summary.get("records"):
|
for record in summary.get("records"):
|
||||||
record["meta_data"] = make_json_serializable(record["meta_data"])
|
meta_data = record['meta_data']
|
||||||
|
stringify_body(meta_data, 'request')
|
||||||
|
stringify_body(meta_data, 'response')
|
||||||
|
|
||||||
with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
|
with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
|
||||||
template_content = fp_r.read()
|
template_content = fp_r.read()
|
||||||
@@ -103,26 +105,24 @@ def render_html_report(summary, html_report_name=None, html_report_template=None
|
|||||||
|
|
||||||
return report_path
|
return report_path
|
||||||
|
|
||||||
def make_json_serializable(raw_json):
|
def stringify_body(meta_data, request_or_response):
|
||||||
serializable_json = {}
|
headers = meta_data['{}_headers'.format(request_or_response)]
|
||||||
for key, value in raw_json.items():
|
body = meta_data.get('{}_body'.format(request_or_response))
|
||||||
if isinstance(value, bytes):
|
|
||||||
value = value.decode("utf-8")
|
|
||||||
elif isinstance(value, CaseInsensitiveDict):
|
|
||||||
value = dict(value)
|
|
||||||
elif not isinstance(value, (basestring, numeric_types, Iterable)):
|
|
||||||
# class instance, e.g. MultipartEncoder()
|
|
||||||
value = repr(value)
|
|
||||||
|
|
||||||
serializable_json[key] = escape(value)
|
if isinstance(body, CaseInsensitiveDict):
|
||||||
|
body = json.dumps(dict(body), ensure_ascii=False)
|
||||||
|
|
||||||
keyorder = ["url", "method", "request_headers", "request_body", "request_time",
|
elif isinstance(body, (dict, list)):
|
||||||
"status_code", "response_headers", "response_body",
|
body = json.dumps(body, ensure_ascii=False)
|
||||||
"content_size", "response_time(ms)", "elapsed(ms)"]
|
|
||||||
serializable_ordered_json = OrderedDict(
|
|
||||||
sorted(serializable_json.items(), key=lambda x:keyorder.index(x[0])))
|
|
||||||
|
|
||||||
return json.dumps(serializable_ordered_json, indent=2, ensure_ascii=False)
|
elif isinstance(body, bytes):
|
||||||
|
body = body.decode("utf-8")
|
||||||
|
|
||||||
|
elif not isinstance(body, (basestring, numeric_types, Iterable)):
|
||||||
|
# class instance, e.g. MultipartEncoder()
|
||||||
|
body = repr(body)
|
||||||
|
|
||||||
|
meta_data['{}_body'.format(request_or_response)] = body
|
||||||
|
|
||||||
|
|
||||||
class HtmlTestResult(unittest.TextTestResult):
|
class HtmlTestResult(unittest.TextTestResult):
|
||||||
@@ -138,7 +138,6 @@ class HtmlTestResult(unittest.TextTestResult):
|
|||||||
self.records.append({
|
self.records.append({
|
||||||
'name': test.shortDescription(),
|
'name': test.shortDescription(),
|
||||||
'status': status,
|
'status': status,
|
||||||
'response_time_ms': test.meta_data.get("response_time(ms)", 0),
|
|
||||||
'attachment': attachment,
|
'attachment': attachment,
|
||||||
"meta_data": test.meta_data
|
"meta_data": test.meta_data
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -86,10 +86,10 @@
|
|||||||
margin: 70px auto;
|
margin: 70px auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 5px;
|
border-radius: 10px;
|
||||||
width: 30%;
|
width: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 5s ease-in-out;
|
transition: all 3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup h2 {
|
.popup h2 {
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
color: #06d85f;
|
color: #06d85f;
|
||||||
}
|
}
|
||||||
.popup .content {
|
.popup .content {
|
||||||
max-height: 30%;
|
max-height: 80%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -180,28 +180,108 @@
|
|||||||
<tr id="record_{{loop.index}}">
|
<tr id="record_{{loop.index}}">
|
||||||
<th class="{{record.status}}" style="width:5em;">{{record.status}}</td>
|
<th class="{{record.status}}" style="width:5em;">{{record.status}}</td>
|
||||||
<td>{{record.name}}</td>
|
<td>{{record.name}}</td>
|
||||||
<td style="text-align:center;width:6em;">{{ '%0.1f'| format(record.response_time_ms|float) }} ms</td>
|
<td style="text-align:center;width:6em;">{{ record.meta_data["response_time(ms)"] }} ms</td>
|
||||||
<td class="detail">
|
<td class="detail">
|
||||||
|
|
||||||
<a class="button" href="#popup_log_{{loop.index}}">log</a>
|
<a class="button" href="#popup_log_{{loop.index}}">log</a>
|
||||||
<div id="popup_log_{{loop.index}}" class="overlay">
|
<div id="popup_log_{{loop.index}}" class="overlay">
|
||||||
<div class="popup">
|
<div class="popup">
|
||||||
<h2>Request and Response data</h2>
|
<h2>Request and Response data</h2>
|
||||||
<a class="close" href="#record_{{loop.index}}">×</a>
|
<a class="close" href="#record_{{loop.index}}">×</a>
|
||||||
<div class="content"><pre>{{ record.meta_data | safe }}</pre></div>
|
|
||||||
|
<!-- <div class="content"><pre>{{ record.meta_data | safe }}</pre></div> -->
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<h3>Request:</h3>
|
||||||
|
<div style="overflow: auto">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>url</th>
|
||||||
|
<td>{{ record.meta_data.url }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>method</th>
|
||||||
|
<td>{{ record.meta_data.method }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>headers</th>
|
||||||
|
<td>
|
||||||
|
{% for key, value in record.meta_data.request_headers.items() %}
|
||||||
|
<div>
|
||||||
|
<strong>{{ key }}</strong>: {{ value | safe }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>body</th>
|
||||||
|
<td>
|
||||||
|
<pre>{{ record.meta_data.request_body | safe }}</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Response:</h3>
|
||||||
|
<div style="overflow: auto">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>status_code</th>
|
||||||
|
<td>
|
||||||
|
{{ record.meta_data.status_code }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>headers</th>
|
||||||
|
<td>
|
||||||
|
{% for key, value in record.meta_data.response_headers.items() %}
|
||||||
|
<div>
|
||||||
|
<strong>{{ key }}</strong>: {{ value | safe }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>body</th>
|
||||||
|
<td>
|
||||||
|
<pre>{{ record.meta_data.response_body | safe }}</pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Statistics:</h3>
|
||||||
|
<div style="overflow: auto">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>content_size(bytes)</th>
|
||||||
|
<td>{{ record.meta_data["content_size"] }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>response_time(ms)</th>
|
||||||
|
<td>{{ record.meta_data["response_time(ms)"] }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>elapsed(ms)</th>
|
||||||
|
<td>{{ record.meta_data["elapsed(ms)"] }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if record.attachment %}
|
{% if record.attachment %}
|
||||||
<a class="button" href="#popup_attachment_{{loop.index}}">traceback</a>
|
<a class="button" href="#popup_attachment_{{loop.index}}">traceback</a>
|
||||||
<div id="popup_attachment_{{loop.index}}" class="overlay">
|
<div id="popup_attachment_{{loop.index}}" class="overlay">
|
||||||
<div class="popup">
|
<div class="popup">
|
||||||
<h2>Traceback Message</h2>
|
<h2>Traceback Message</h2>
|
||||||
<a class="close" href="#record_{{loop.index}}">×</a>
|
<a class="close" href="#record_{{loop.index}}">×</a>
|
||||||
<div class="content"><pre>{{ record.attachment }}</pre></div>
|
<div class="content"><pre>{{ record.attachment }}</pre></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user