HTTP请求组件支持传入请求头数据(参考PostMan),方便调试执行单个HTTP请求
https://gitee.com/azhengzz/api-automation-test/issues/I3E5Z5
This commit is contained in:
parent
60088e41e9
commit
c56d07c5c0
|
@ -1,10 +1,12 @@
|
|||
# coding=utf-8
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from app.models import Case, Dispatcher
|
||||
from app.cores.logger import DispatcherLogger
|
||||
from app.cores.dictionaries import DISPATCHER_TYPE, REPORT_RESULT
|
||||
from app.cores.dispatcher import AbstractCaseDispatcher
|
||||
from app.cores.case.http.request_util import handle_url
|
||||
from app.cores.case.http.request_util import handle_url, handle_headers
|
||||
from app.cores.case.http.http_cookie_pool_manager import HTTPCookiePoolManager
|
||||
from app.cores.case.http.http_request_header_pool_manager import HTTPRequestHeaderPoolManager
|
||||
from app.cores.case.base.script import exec_postprocessor_script, exec_preprocessor_script
|
||||
|
@ -40,8 +42,6 @@ class HTTPCaseDispatcher(AbstractCaseDispatcher):
|
|||
|
||||
# cookie数据
|
||||
self.rcj = None
|
||||
# http请求头
|
||||
self.headers = None
|
||||
|
||||
# http请求字段
|
||||
self.protocol = None
|
||||
|
@ -57,6 +57,7 @@ class HTTPCaseDispatcher(AbstractCaseDispatcher):
|
|||
self.parameters = None
|
||||
self.expectations = None
|
||||
self.file_upload = None
|
||||
self.headers = None
|
||||
|
||||
def set_up(self):
|
||||
super().set_up()
|
||||
|
@ -64,6 +65,8 @@ class HTTPCaseDispatcher(AbstractCaseDispatcher):
|
|||
self.rcj = HTTPCookiePoolManager.get_request_cookie_jar(type=self.dispatcher_type)
|
||||
# 获取HTTP请求头
|
||||
self.headers = HTTPRequestHeaderPoolManager.get_http_request_header(project_id=self.case.scene.module.project.id)
|
||||
self.headers = deepcopy(self.headers) # 后面会对请求头数据更新,但不要影响HTTPRequestHeaderPool中的数据
|
||||
|
||||
# 预处理脚本执行
|
||||
preprocessor_script = self.case.specific_case.preprocessor_script_
|
||||
exec_preprocessor_script(
|
||||
|
@ -87,6 +90,8 @@ class HTTPCaseDispatcher(AbstractCaseDispatcher):
|
|||
self.parameters = self.case.specific_case.parameters
|
||||
self.expectations = self.case.specific_case.expectations
|
||||
self.file_upload = self.case.specific_case.file_upload
|
||||
_headers = self.case.specific_case.headers
|
||||
self.headers.update(handle_headers(_headers)) # 将HTTPCase中定义的headers覆盖到HTTPRequestHeaderManagerTool中
|
||||
|
||||
def execute(self):
|
||||
super().execute()
|
||||
|
|
|
@ -31,6 +31,18 @@ def handle_params(params):
|
|||
return ret
|
||||
|
||||
|
||||
def handle_headers(headers):
|
||||
"""
|
||||
处理请求头数据
|
||||
:param headers: 请求头数据
|
||||
:type headers: List[HTTPCaseHeader]
|
||||
"""
|
||||
ret = {}
|
||||
for header in headers:
|
||||
ret[header.name_] = header.value_
|
||||
return ret
|
||||
|
||||
|
||||
def handle_data(params, content_type=None):
|
||||
"""
|
||||
处理请求参数,使其满足post请求的数据格式
|
||||
|
|
|
@ -1731,6 +1731,7 @@ class HTTPCase(db.Model):
|
|||
关系说明
|
||||
case: 案例组件 Case:HTTPCase is 1:1
|
||||
parameters: 案例参数 HTTPCase:HTTPCaseParameter is 1:N
|
||||
headers: 请求头参数 HTTPCase:HTTPCaseHeader is 1:N
|
||||
expectations: 案例期望 HTTPCase:HTTPCaseExpectation is 1:N
|
||||
file_upload: 文件上传参数 HTTPCase:HTTPCaseFileUpload is 1:N
|
||||
"""
|
||||
|
@ -1753,6 +1754,7 @@ class HTTPCase(db.Model):
|
|||
case_id = db.Column(db.Integer, db.ForeignKey('case.id'))
|
||||
case = db.relationship('Case')
|
||||
parameters = db.relationship('HTTPCaseParameter', back_populates='http_case', cascade='all, delete-orphan') # 解除与case的关系后删除
|
||||
headers = db.relationship('HTTPCaseHeader', back_populates='http_case', cascade='all, delete-orphan')
|
||||
expectations = db.relationship('HTTPCaseExpectation', back_populates='http_case', cascade='all, delete-orphan')
|
||||
file_upload = db.relationship('HTTPCaseFileUpload', back_populates='http_case', cascade='all, delete-orphan')
|
||||
|
||||
|
@ -1788,7 +1790,7 @@ class HTTPCase(db.Model):
|
|||
@classmethod
|
||||
def add(cls, name, description, scene_id, protocol, domain, port, method, path, encoding, expectation_logic,
|
||||
message_body, content_type, preprocessor_script, postprocessor_script, status=STATUS.NORMAL,
|
||||
parameters=None, file_upload=None, expectations=None):
|
||||
parameters=None, headers=None, file_upload=None, expectations=None):
|
||||
"""
|
||||
新增一条案例
|
||||
:param name: 案例名
|
||||
|
@ -1807,6 +1809,7 @@ class HTTPCase(db.Model):
|
|||
:param preprocessor_script: 预处理脚本
|
||||
:param postprocessor_script: 后处理脚本
|
||||
:param parameters: 参数数据
|
||||
:param headers: 请求头数据
|
||||
:param file_upload: 文件上传参数数据
|
||||
:param expectations: 期望数据
|
||||
"""
|
||||
|
@ -1832,6 +1835,7 @@ class HTTPCase(db.Model):
|
|||
)
|
||||
http_case.case = case
|
||||
http_case._update_parameters(parameters)
|
||||
http_case._update_headers(headers)
|
||||
http_case._update_expectations(expectations)
|
||||
http_case._update_file_upload(file_upload)
|
||||
db.session.add(case)
|
||||
|
@ -1841,8 +1845,8 @@ class HTTPCase(db.Model):
|
|||
|
||||
@classmethod
|
||||
def update(cls, id, name, description, protocol, domain, port, method, path, encoding, expectation_logic,
|
||||
message_body, content_type, preprocessor_script, postprocessor_script, params=None, file_upload=None,
|
||||
expectations=None):
|
||||
message_body, content_type, preprocessor_script, postprocessor_script, params=None, headers=None,
|
||||
file_upload=None, expectations=None):
|
||||
"""
|
||||
更新一条案例
|
||||
:param id: 案例编号
|
||||
|
@ -1860,6 +1864,7 @@ class HTTPCase(db.Model):
|
|||
:param preprocessor_script: 预处理脚本
|
||||
:param postprocessor_script: 后处理脚本
|
||||
:param params: 参数数据
|
||||
:param headers: 请求头数据
|
||||
:param file_upload: 文件上传参数
|
||||
:param expectations: 期望数据
|
||||
"""
|
||||
|
@ -1881,6 +1886,7 @@ class HTTPCase(db.Model):
|
|||
http_case.preprocessor_script = preprocessor_script
|
||||
http_case.postprocessor_script = postprocessor_script
|
||||
http_case._update_parameters(params)
|
||||
http_case._update_headers(headers)
|
||||
http_case._update_file_upload(file_upload)
|
||||
http_case._update_expectations(expectations)
|
||||
db.session.commit()
|
||||
|
@ -1911,6 +1917,7 @@ class HTTPCase(db.Model):
|
|||
preprocessor_script=self.preprocessor_script,
|
||||
postprocessor_script=self.postprocessor_script,
|
||||
parameters=self.parameters,
|
||||
headers=self.headers,
|
||||
expectations=self.expectations,
|
||||
file_upload=self.file_upload,
|
||||
)
|
||||
|
@ -1944,6 +1951,22 @@ class HTTPCase(db.Model):
|
|||
)
|
||||
self.parameters.append(parameter)
|
||||
|
||||
def _update_headers(self, headers):
|
||||
self.headers = []
|
||||
if headers is not None:
|
||||
for _header in headers:
|
||||
if hasattr(_header, 'get'):
|
||||
header = HTTPCaseHeader(
|
||||
name=_header.get('name'),
|
||||
value=_header.get('value'),
|
||||
)
|
||||
else: # copy_from_self func exec this branch
|
||||
header = HTTPCaseHeader(
|
||||
name=_header.name,
|
||||
value=_header.value,
|
||||
)
|
||||
self.headers.append(header)
|
||||
|
||||
def _update_expectations(self, expectations):
|
||||
self.expectations = []
|
||||
if expectations is not None:
|
||||
|
@ -2020,6 +2043,35 @@ class HTTPCaseParameter(db.Model):
|
|||
return _p(self.value)
|
||||
|
||||
|
||||
class HTTPCaseHeader(db.Model):
|
||||
"""
|
||||
字段说明
|
||||
name: 参数名
|
||||
value: 参数值
|
||||
关系说明
|
||||
http_case: 请求头所属HTTP案例 HTTPCase:HTTPCaseHeader is 1:N
|
||||
"""
|
||||
# 需要转换为json数据格式的字段
|
||||
render_field_list = ['name', 'value']
|
||||
# field
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(512), nullable=False, default='', server_default='')
|
||||
value = db.Column(db.String(512), nullable=False, default='', server_default='')
|
||||
|
||||
# relationship
|
||||
http_case_id = db.Column(db.Integer, db.ForeignKey('http_case.id'))
|
||||
http_case = db.relationship('HTTPCase', back_populates='headers')
|
||||
|
||||
# 解析处理
|
||||
@property
|
||||
def name_(self):
|
||||
return _p(self.name)
|
||||
|
||||
@property
|
||||
def value_(self):
|
||||
return _p(self.value)
|
||||
|
||||
|
||||
class HTTPCaseExpectation(db.Model):
|
||||
"""
|
||||
字段说明
|
||||
|
|
|
@ -54,6 +54,8 @@ def save_http_case():
|
|||
if not exist: return form_content_type
|
||||
exist, form_param_json = get_form_from_request(request, 'param_json')
|
||||
if not exist: return form_param_json
|
||||
exist, form_header_json = get_form_from_request(request, 'header_json')
|
||||
if not exist: return form_header_json
|
||||
exist, form_file_upload_json = get_form_from_request(request, 'file_upload_json')
|
||||
if not exist: return form_file_upload_json
|
||||
exist, form_expectation_json = get_form_from_request(request, 'expectation_json')
|
||||
|
@ -66,6 +68,7 @@ def save_http_case():
|
|||
if not exist: return form_postprocessor_script
|
||||
try:
|
||||
params = json.loads(form_param_json)
|
||||
headers = json.loads(form_header_json)
|
||||
file_upload = json.loads(form_file_upload_json)
|
||||
expectations = json.loads(form_expectation_json)
|
||||
if not Case.exist_and_status_not_delete(id=form_id):
|
||||
|
@ -85,6 +88,7 @@ def save_http_case():
|
|||
encoding=form_content_encoding,
|
||||
expectation_logic=form_expectation_logic,
|
||||
params=params,
|
||||
headers=headers,
|
||||
file_upload=file_upload,
|
||||
expectations=expectations,
|
||||
message_body=form_message_body_json,
|
||||
|
@ -2503,10 +2507,12 @@ def case():
|
|||
data_expectations = json.loads(render_to_json(case.specific_case.expectations))
|
||||
if case.case_type == CASE_TYPE.HTTP:
|
||||
data_parameters = json.loads(render_to_json(case.specific_case.parameters))
|
||||
data_headers = json.loads(render_to_json(case.specific_case.headers))
|
||||
data_file_upload = json.loads(render_to_json(case.specific_case.file_upload))
|
||||
table_cookie_manager_data = json.loads(render_to_json(case.specific_case.file_upload))
|
||||
else:
|
||||
data_parameters = []
|
||||
data_headers = []
|
||||
data_file_upload = []
|
||||
table_cookie_manager_data = []
|
||||
except Exception as e:
|
||||
|
@ -2524,6 +2530,7 @@ def case():
|
|||
'html_text': html_text,
|
||||
'data_expectations': data_expectations,
|
||||
'data_parameters': data_parameters,
|
||||
'data_headers': data_headers,
|
||||
'data_file_upload': data_file_upload,
|
||||
'table_cookie_manager_data': table_cookie_manager_data,
|
||||
})
|
||||
|
|
|
@ -276,16 +276,19 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
element.dom.$input_content_encoding = $(`#input-content-encoding-${case_id}`);
|
||||
element.dom.$input_content_type = $(`#input-content-type-${case_id}`);
|
||||
element.dom.$div_table_parameter_spinner = $(`#div-table-parameter-spinner-${case_id}`);
|
||||
element.dom.$div_table_header_spinner = $(`#div-table-header-spinner-${case_id}`);
|
||||
element.dom.$div_table_file_upload_spinner = $(`#div-table-file-upload-spinner-${case_id}`);
|
||||
element.dom.$nav_link_param_tab = $(`#param-tab-${case_id}`);
|
||||
element.dom.$nav_link_header_tab = $(`#header-tab-${case_id}`);
|
||||
element.dom.$nav_link_file_upload_tab = $(`#file-upload-tab-${case_id}`);
|
||||
|
||||
element.obj.table_parameter = null; // 请求参数表格
|
||||
element.obj.table_header = null; // 请求头表格
|
||||
element.obj.table_file_upload = null; // 文件上传表格
|
||||
element.obj.ace_message_body_editor = null; // 消息体数据格式化编辑器
|
||||
element.obj.splitterMinSize = [50, 70]; // splitter分割条最小长度
|
||||
|
||||
element.init = function (data_expectations, data_parameters, data_file_upload) {
|
||||
element.init = function (data_expectations, data_parameters, data_headers, data_file_upload) {
|
||||
// 参数
|
||||
// data_expectations: 案例期望数据
|
||||
// data_parameters: 案例请求参数数据
|
||||
|
@ -301,6 +304,8 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
renderAceEditor();
|
||||
// 渲染参数表格
|
||||
renderParameterTable(data_parameters);
|
||||
// 渲染请求头表格
|
||||
renderHeaderTable(data_headers);
|
||||
// 渲染文件上传表格
|
||||
renderFileUploadTable(data_file_upload);
|
||||
// 获取CookieManager对象并初始化
|
||||
|
@ -336,6 +341,7 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
// 事件绑定
|
||||
function eventBinding() {
|
||||
element.dom.$nav_link_param_tab.on('shown.bs.tab', clickParamTab);
|
||||
element.dom.$nav_link_header_tab.on('shown.bs.tab', clickHeaderTab);
|
||||
element.dom.$nav_link_file_upload_tab.on('shown.bs.tab', clickFileTab);
|
||||
|
||||
function clickParamTab() {
|
||||
|
@ -343,6 +349,11 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
$(`#table-parameter-${case_id}`).handsontable('getInstance').render();
|
||||
}
|
||||
|
||||
function clickHeaderTab() {
|
||||
// 渲染ht
|
||||
$(`#table-header-${case_id}`).handsontable('getInstance').render();
|
||||
}
|
||||
|
||||
function clickFileTab() {
|
||||
// 渲染ht
|
||||
$(`#table-file-upload-${case_id}`).handsontable('getInstance').render();
|
||||
|
@ -453,6 +464,72 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
}
|
||||
}
|
||||
|
||||
// 渲染请求头表格
|
||||
function renderHeaderTable(data_headers) {
|
||||
const option_table_header = {
|
||||
data: data_headers,
|
||||
rowHeaders: true,
|
||||
// colHeaders: true,
|
||||
licenseKey: 'non-commercial-and-evaluation',
|
||||
// 表格宽度
|
||||
// width: '95vw', // 不指定宽度使其自适应容器
|
||||
// 拉伸方式
|
||||
stretchH: 'all',
|
||||
// tab键自动换行切换
|
||||
autoWrapRow: true,
|
||||
height: '40vh',
|
||||
// 最大行数
|
||||
maxRows: 99,
|
||||
// 允许手工移动行或列
|
||||
manualRowResize: true,
|
||||
manualColumnResize: true,
|
||||
// 列名
|
||||
colHeaders: [
|
||||
'名称',
|
||||
'值',
|
||||
],
|
||||
// 为列设置默认值
|
||||
dataSchema: {
|
||||
name: '',
|
||||
value: '',
|
||||
url_encode: false,
|
||||
content_type: 'text/plain',
|
||||
include_equals: true,
|
||||
},
|
||||
// 设置列数据类型
|
||||
columns: [
|
||||
{
|
||||
data: 'name'
|
||||
},
|
||||
{
|
||||
data: 'value',
|
||||
},
|
||||
],
|
||||
// 列宽比例
|
||||
colWidths: [1, 1],
|
||||
manualRowMove: true,
|
||||
manualColumnMove: false,
|
||||
// 右键菜单
|
||||
contextMenu: ['row_above', 'row_below', '---------', 'remove_row', '---------', 'undo', 'redo', '---------', 'alignment', '---------', 'copy', 'cut'],
|
||||
// 列是否支持过滤
|
||||
filters: false,
|
||||
// 下拉菜单
|
||||
dropdownMenu: ['make_read_only', '---------', 'alignment'],
|
||||
// 语言
|
||||
language: 'zh-CN',
|
||||
// 是否允许无效数据 默认 true
|
||||
allowInvalid: false,
|
||||
afterLoadData: afterLoadDataHookForTableParam,
|
||||
};
|
||||
let $container = $(`#table-header-${case_id}`);
|
||||
element.obj.table_header = $container.handsontable(option_table_header).handsontable('getInstance');
|
||||
|
||||
// 数据加载完毕后隐藏spinner
|
||||
function afterLoadDataHookForTableParam() {
|
||||
element.dom.$div_table_header_spinner.css('display', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染文件上传表格
|
||||
function renderFileUploadTable(data_file_upload) {
|
||||
// const container_table_file_upload = document.getElementById(`table-file-upload-${case_id}`);
|
||||
|
@ -561,6 +638,7 @@ function getHTTPCaseElement(case_id, case_type) {
|
|||
expectation_logic: expectation_logic,
|
||||
content_type: content_type,
|
||||
param_json: JSON.stringify(element.obj.table_parameter.getSourceData()),
|
||||
header_json: JSON.stringify(element.obj.table_header.getSourceData()),
|
||||
file_upload_json: JSON.stringify(element.obj.table_file_upload.getSourceData()),
|
||||
expectation_json: JSON.stringify(element.obj.table_expectation.getSourceData()),
|
||||
message_body_json: message_body_json_str,
|
||||
|
|
|
@ -1330,6 +1330,7 @@ function showCase(case_id, case_type) {
|
|||
if(case_type === 'HTTP'){
|
||||
// 渲染ht
|
||||
$(`#table-parameter-${case_id}`).handsontable('getInstance').render();
|
||||
$(`#table-header-${case_id}`).handsontable('getInstance').render();
|
||||
$(`#table-file-upload-${case_id}`).handsontable('getInstance').render();
|
||||
}
|
||||
if(!element_case_first_show_flag[case_id]){ // 只在第一次打开案例组件时渲染
|
||||
|
@ -1850,7 +1851,7 @@ function addCaseElement(case_id, case_type) {
|
|||
element_case_first_show_flag[case_id] = false;
|
||||
}else if(data.case_type === 'HTTP'){
|
||||
let element = getHTTPCaseElement(case_id, data.case_type);
|
||||
element.init(data.data_expectations, data.data_parameters, data.data_file_upload);
|
||||
element.init(data.data_expectations, data.data_parameters, data.data_headers, data.data_file_upload);
|
||||
element_case_instance_dict[case_id] = element;
|
||||
element_case_first_show_flag[case_id] = false;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,9 @@
|
|||
<li class="nav-item">
|
||||
<a class="nav-link" id="message-body-tab-{{ case.id }}" data-toggle="tab" href="#tab-message-body-{{ case.id }}" role="tab">消息体数据</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="header-tab-{{ case.id }}" data-toggle="tab" href="#tab-header-{{ case.id }}" role="tab">请求头</a>
|
||||
</li>
|
||||
{# <li class="nav-item">#}
|
||||
{# <a class="nav-link" id="file-upload-tab-{{ case.id }}" data-toggle="tab" href="#tab-file-upload-{{ case.id }}" role="tab">文件上传</a>#}
|
||||
{# </li>#}
|
||||
|
@ -123,6 +126,13 @@
|
|||
<div class="tab-pane fade" id="tab-message-body-{{ case.id }}" role="tabpanel">
|
||||
<div class="container-fluid ace-message-body" id="div-ace-message-body-{{ case.id }}">{{ case.specific_case.message_body }}</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab-header-{{ case.id }}" role="tabpanel">
|
||||
<div id="table-header-{{ case.id }}" class="d-flex justify-content-center">
|
||||
<div id="div-table-header-spinner-{{ case.id }}" class="spinner-border text-primary m-5" role="status">
|
||||
<span class="sr-only">加载中Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab-file-upload-{{ case.id }}" role="tabpanel">
|
||||
<div id="table-file-upload-{{ case.id }}" class="d-flex justify-content-center">
|
||||
<div id="div-table-file-upload-spinner-{{ case.id }}" class="spinner-border text-primary m-5" role="status">
|
||||
|
|
Loading…
Reference in New Issue