diff --git a/fastrunner/utils/parser.py b/fastrunner/utils/parser.py
index 473b25c..3505dcc 100644
--- a/fastrunner/utils/parser.py
+++ b/fastrunner/utils/parser.py
@@ -1,22 +1,18 @@
import datetime
import json
import logging
+import time
from concurrent.futures import ThreadPoolExecutor
+from enum import Enum
+from typing import Dict, Optional, Union
import json5
-import time
-
import requests
-from enum import Enum
-
from loguru import logger
from fastrunner import models
-from fastrunner.utils.tree import (
- get_tree_max_id,
- get_all_ycatid,
- get_tree_ycatid_mapping,
-)
+from fastrunner.utils.tree import (get_all_ycatid, get_tree_max_id,
+ get_tree_ycatid_mapping)
logger = logging.getLogger(__name__)
@@ -40,7 +36,7 @@ class Format(object):
解析标准HttpRunner脚本 前端->后端
"""
- def __init__(self, body, level="test"):
+ def __init__(self, body: Dict[str, Union[str, Dict]], level: str = "test"):
"""
body => {
header: header -> [{key:'', value:'', desc:''},],
@@ -59,76 +55,66 @@ def __init__(self, body, level="test"):
name: name -> string
}
"""
- try:
- self.name = body.pop("name")
-
- self.__headers = body["header"].pop("header")
- if level == "test":
- # 配置移除request参数
- self.__params = body["request"]["params"].pop("params")
- self.__data = body["request"]["form"].pop("data")
- self.__json = body["request"].pop("json")
- self.__files = body["request"]["files"].pop("files")
- else:
- self.__params = {}
- self.__data = {}
- self.__json = {}
- self.__files = {}
- self.__variables = body["variables"].pop("variables")
- self.__setup_hooks = body["hooks"].pop("setup_hooks")
- self.__teardown_hooks = body["hooks"].pop("teardown_hooks")
-
- if level == "test":
- self.__desc = {
- "header": body["header"].pop("desc"),
- "data": body["request"]["form"].pop("desc"),
- "files": body["request"]["files"].pop("desc"),
- "params": body["request"]["params"].pop("desc"),
- "variables": body["variables"].pop("desc"),
- }
- self.url = body.pop("url")
- self.method = body.pop("method")
-
- self.__times = body.pop("times")
- self.__extract = body["extract"].pop("extract")
- self.__validate = body.pop("validate").pop("validate")
- self.__desc["extract"] = body["extract"].pop("desc")
-
- elif level == "config":
- self.__desc = {
- "header": body["header"].pop("desc"),
- "variables": body["variables"].pop("desc"),
- }
+ self.name = body.pop("name", None)
- self.base_url = body.pop("base_url")
- self.is_default = body.pop("is_default")
- self.__parameters = body["parameters"].pop("parameters")
- self.__desc["parameters"] = body["parameters"].pop("desc")
+ self.__headers = body.get("header", {}).pop("header", None)
+ if level == "test":
+ self.__params = (
+ body.get("request", {}).get("params", {}).pop("params", None)
+ )
+ self.__data = body.get("request", {}).get("form", {}).pop("data", None)
+ self.__json = body.get("request", {}).pop("json", None)
+ self.__files = body.get("request", {}).get("files", {}).pop("files", None)
+ else:
+ self.__params = {}
+ self.__data = {}
+ self.__json = {}
+ self.__files = {}
+ self.__variables = body.get("variables", {}).pop("variables", None)
+ self.__setup_hooks = body.get("hooks", {}).pop("setup_hooks", None)
+ self.__teardown_hooks = body.get("hooks", {}).pop("teardown_hooks", None)
- self.__level = level
- self.testcase = None
+ if level == "test":
+ self.__desc = {
+ "header": body.get("header", {}).pop("desc", None),
+ "data": body.get("request", {}).get("form", {}).pop("desc", None),
+ "files": body.get("request", {}).get("files", {}).pop("desc", None),
+ "params": body.get("request", {}).get("params", {}).pop("desc", None),
+ "variables": body.get("variables", {}).pop("desc", None),
+ }
+ self.url = body.pop("url", None)
+ self.method = body.pop("method", None)
- self.project = body.pop("project")
- self.relation = body.pop("nodeId")
+ self.__times = body.pop("times", None)
+ self.__extract = body.get("extract", {}).pop("extract", None)
+ self.__validate = body.get("validate", {}).pop("validate", None)
+ self.__desc["extract"] = body.get("extract", {}).pop("desc", None)
- # FastRunner的API没有rig_id字段,需要兼容
- self.rig_id = body["rig_id"] if body.get("rig_id") else None
- self.rig_env = body["rig_env"] if body.get("rig_env") else 0
+ elif level == "config":
+ self.__desc = {
+ "header": body.get("header", {}).pop("desc", None),
+ "variables": body.get("variables", {}).pop("desc", None),
+ }
- except KeyError:
- # project or relation
- pass
+ self.base_url = body.pop("base_url", None)
+ self.is_default = body.pop("is_default", None)
+ self.__parameters = body.get("parameters", {}).pop("parameters", None)
+ self.__desc["parameters"] = body.get("parameters", {}).pop("desc", None)
+
+ self.__level = level
+ self.testcase = None
- def parse(self):
+ self.project = body.pop("project", None)
+ self.relation = body.pop("nodeId", None)
+
+ # FastRunner的API没有rig_id字段,需要兼容
+ self.rig_id = body.get("rig_id", None)
+ self.rig_env = body.get("rig_env", 0)
+
+ def parse(self) -> Optional[Dict[str, Union[str, Dict]]]:
"""
返回标准化HttpRunner "desc" 字段运行需去除
"""
- if not hasattr(self, "rig_id"):
- self.rig_id = None
-
- if not hasattr(self, "rig_env"):
- self.rig_env = 0
-
if self.__level == "test":
test = {
"name": self.name,
@@ -161,11 +147,8 @@ def parse(self):
test["request"]["params"] = self.__params
if self.__data:
test["request"]["data"] = self.__data
- if self.__json:
+ if self.__json or self.__json == {}:
test["request"]["json"] = self.__json
- # 兼容一些接口需要传空json
- if self.__json == {}:
- test["request"]["json"] = {}
if self.__files:
test["request"]["files"] = self.__files
if self.__variables:
@@ -184,32 +167,6 @@ class Parse(object):
"""
def __init__(self, body, level="test"):
- """
- body: => {
- "name": "get token with $user_agent, $os_platform, $app_version",
- "request": {
- "url": "/api/get-token",
- "method": "POST",
- "headers": {
- "app_version": "$app_version",
- "os_platform": "$os_platform",
- "user_agent": "$user_agent"
- },
- "json": {
- "sign": "${get_sign($user_agent, $device_sn, $os_platform, $app_version)}"
- },
- "extract": [
- {"token": "content.token"}
- ],
- "validate": [
- {"eq": ["status_code", 200]},
- {"eq": ["headers.Content-Type", "application/json"]},
- {"eq": ["content.success", true]}
- ],
- "setup_hooks": [],
- "teardown_hooks": []
- }
- """
self.name = body.get("name")
self.__request = body.get("request") # header files params json data
self.__variables = body.get("variables")
@@ -230,9 +187,6 @@ def __init__(self, body, level="test"):
@staticmethod
def __get_type(content):
- """
- 返回data_type 默认string
- """
var_type = {
"str": 1,
"int": 2,
@@ -245,7 +199,6 @@ def __get_type(content):
key = str(type(content).__name__)
- # 黑魔法,为了兼容值是int,但又是$引用变量的情况
if key == "str" and "$int" in content:
return var_type["int"], content
@@ -259,14 +212,9 @@ def __get_type(content):
return var_type[key], content
def parse_http(self):
- """
- 标准前端脚本格式
- """
init = [{"key": "", "value": "", "desc": ""}]
-
init_p = [{"key": "", "value": "", "desc": "", "type": 1}]
- # 初始化test结构
test = {
"name": self.name,
"header": init,
@@ -276,105 +224,91 @@ def parse_http(self):
}
if self.__level == "test":
- test["times"] = self.__times
- test["method"] = self.__request["method"]
- test["url"] = self.__request["url"]
- test["validate"] = [
- {"expect": "", "actual": "", "comparator": "equals", "type": 1}
- ]
- test["extract"] = init
+ self.parse_test_level(test)
+ elif self.__level == "config":
+ self.parse_config_level(test)
- if self.__extract:
- test["extract"] = []
- for content in self.__extract:
- for key, value in content.items():
- test["extract"].append(
- {
- "key": key,
- "value": value,
- "desc": self.__desc["extract"][key],
- }
- )
+ self.parse_request(test)
+ self.parse_variables(test)
+ self.parse_hooks(test)
- if self.__validate:
- test["validate"] = []
- for content in self.__validate:
- for key, value in content.items():
- obj = Parse.__get_type(value[1])
- # 兼容旧的断言
- desc = ""
- if len(value) >= 3:
- # value[2]为None时,设置为''
- desc = value[2] or ""
- test["validate"].append(
- {
- "expect": obj[1],
- "actual": value[0],
- "comparator": key,
- "type": obj[0],
- "desc": desc,
- }
- )
+ self.testcase = test
- elif self.__level == "config":
- test["base_url"] = self.__request["base_url"]
- test["parameters"] = init
+ def parse_test_level(self, test):
+ test["times"] = self.__times
+ test["method"] = self.__request["method"]
+ test["url"] = self.__request["url"]
+ test["validate"] = [
+ {"expect": "", "actual": "", "comparator": "equals", "type": 1}
+ ]
+ test["extract"] = [{"key": "", "value": "", "desc": ""}]
- if self.__parameters:
- test["parameters"] = []
- for content in self.__parameters:
- for key, value in content.items():
- test["parameters"].append(
- {
- "key": key,
- "value": Parse.__get_type(value)[1],
- "desc": self.__desc["parameters"][key],
- }
- )
+ if self.__extract:
+ test["extract"] = [
+ {"key": key, "value": value, "desc": self.__desc["extract"][key]}
+ for content in self.__extract
+ for key, value in content.items()
+ ]
- if self.__request.get("headers"):
- test["header"] = []
- for key, value in self.__request.pop("headers").items():
- test["header"].append(
- {"key": key, "value": value, "desc": self.__desc["header"][key]}
- )
+ if self.__validate:
+ test["validate"] = []
+ for content in self.__validate:
+ for key, value in content.items():
+ obj = Parse.__get_type(value[1])
+ desc = value[2] or "" if len(value) >= 3 else ""
+ test["validate"].append(
+ {
+ "expect": obj[1],
+ "actual": value[0],
+ "comparator": key,
+ "type": obj[0],
+ "desc": desc,
+ }
+ )
- if self.__request.get("data"):
- test["request"]["data"] = []
- for key, value in self.__request.pop("data").items():
- obj = Parse.__get_type(value)
+ def parse_config_level(self, test):
+ test["base_url"] = self.__request["base_url"]
+ test["parameters"] = [{"key": "", "value": "", "desc": ""}]
- test["request"]["data"].append(
- {
- "key": key,
- "value": obj[1],
- "type": obj[0],
- "desc": self.__desc["data"][key],
- }
- )
+ if self.__parameters:
+ test["parameters"] = [
+ {
+ "key": key,
+ "value": Parse.__get_type(value)[1],
+ "desc": self.__desc["parameters"][key],
+ }
+ for content in self.__parameters
+ for key, value in content.items()
+ ]
+
+ def parse_request(self, test):
+ if self.__request.get("headers"):
+ test["header"] = [
+ {"key": key, "value": value, "desc": self.__desc["header"][key]}
+ for key, value in self.__request.pop("headers").items()
+ ]
- # if self.__request.get('files'):
- # for key, value in self.__request.pop("files").items():
- # size = FileBinary.objects.get(name=value).size
- # test['request']['data'].append({
- # "key": key,
- # "value": value,
- # "size": size,
- # "type": 5,
- # "desc": self.__desc["files"][key]
- # })
+ if self.__request.get("data"):
+ test["request"]["data"] = [
+ {
+ "key": key,
+ "value": Parse.__get_type(value)[1],
+ "type": Parse.__get_type(value)[0],
+ "desc": self.__desc["data"][key],
+ }
+ for key, value in self.__request.pop("data").items()
+ ]
if self.__request.get("params"):
- test["request"]["params"] = []
- for key, value in self.__request.pop("params").items():
- test["request"]["params"].append(
- {
- "key": key,
- "value": value,
- "type": 1,
- "desc": self.__desc["params"][key],
- }
- )
+ test["request"]["params"] = [
+ {
+ "key": key,
+ "value": value,
+ "type": 1,
+ "desc": self.__desc["params"][key],
+ }
+ for key, value in self.__request.pop("params").items()
+ ]
if self.__request.get("json"):
test["request"]["json_data"] = json.dumps(
@@ -383,39 +317,43 @@ def parse_http(self):
separators=(",", ": "),
ensure_ascii=False,
)
+
+ def parse_variables(self, test):
if self.__variables:
- test["variables"] = []
- for content in self.__variables:
- for key, value in content.items():
- obj = Parse.__get_type(value)
- test["variables"].append(
- {
- "key": key,
- "value": obj[1],
- "desc": self.__desc["variables"][key],
- "type": obj[0],
- }
- )
+ test["variables"] = [
+ {
+ "key": key,
+ "value": Parse.__get_type(value)[1],
+ "desc": self.__desc["variables"][key],
+ "type": Parse.__get_type(value)[0],
+ }
+ for content in self.__variables
+ for key, value in content.items()
+ ]
+ def parse_hooks(self, test):
if self.__setup_hooks or self.__teardown_hooks:
test["hooks"] = []
if len(self.__setup_hooks) > len(self.__teardown_hooks):
for index in range(0, len(self.__setup_hooks)):
- teardown = ""
- if index < len(self.__teardown_hooks):
- teardown = self.__teardown_hooks[index]
+ teardown = (
+ self.__teardown_hooks[index]
+ if index < len(self.__teardown_hooks)
+ else ""
+ )
test["hooks"].append(
{"setup": self.__setup_hooks[index], "teardown": teardown}
)
else:
for index in range(0, len(self.__teardown_hooks)):
- setup = ""
- if index < len(self.__setup_hooks):
- setup = self.__setup_hooks[index]
+ setup = (
+ self.__setup_hooks[index]
+ if index < len(self.__setup_hooks)
+ else ""
+ )
test["hooks"].append(
{"setup": setup, "teardown": self.__teardown_hooks[index]}
)
- self.testcase = test
def format_json(value):
diff --git a/web/src/mixins/apiListMixin.js b/web/src/mixins/apiListMixin.js
new file mode 100644
index 0000000..926eb82
--- /dev/null
+++ b/web/src/mixins/apiListMixin.js
@@ -0,0 +1,27 @@
+// apiListMixin.js
+export default {
+ methods: {
+ getAPIList(params) {
+ this.$nextTick(() => {
+ const defaultParams = {
+ page: this.listCurrentPage || 1, // 提供默认值
+ node: this.node || this.currentNode, // 支持不同的命名
+ project: this.project,
+ search: this.search,
+ tag: this.visibleTag || this.tag,
+ rigEnv: this.rigEnv,
+ onlyMe: this.onlyMe,
+ showYAPI: this.showYAPI,
+ creator: this.selectUser
+ };
+
+ // 使用传入的参数覆盖默认参数
+ const apiParams = { ...defaultParams, ...params };
+
+ this.$api.apiList({ params: apiParams }).then(res => {
+ this.apiData = res;
+ });
+ });
+ }
+ }
+};
diff --git a/web/src/mixins/configMixin.js b/web/src/mixins/configMixin.js
new file mode 100644
index 0000000..5a5a431
--- /dev/null
+++ b/web/src/mixins/configMixin.js
@@ -0,0 +1,28 @@
+// configMixin.js
+export default {
+ data() {
+ return {
+ configOptions: [],
+ currentConfig: null
+ };
+ },
+ methods: {
+ getConfig({ addPlaceholder = false, setDefaultConfig = false } = {}) {
+ this.$api.getAllConfig(this.$route.params.id).then(resp => {
+ this.configOptions = resp;
+
+ // 根据配置决定是否添加占位符,并设置默认选项
+ if (addPlaceholder) {
+ const placeHolderOption = { name: '请选择' };
+ if (setDefaultConfig) {
+ this.configOptions.unshift(placeHolderOption);
+ const _config = this.configOptions.find(item => item.is_default === true);
+ this.currentConfig = _config || placeHolderOption;
+ } else {
+ this.configOptions.push(placeHolderOption);
+ }
+ }
+ });
+ }
+ }
+};
diff --git a/web/src/mixins/treeMixin.js b/web/src/mixins/treeMixin.js
new file mode 100644
index 0000000..3ac3ca1
--- /dev/null
+++ b/web/src/mixins/treeMixin.js
@@ -0,0 +1,15 @@
+// treeMixin.js
+export default {
+ methods: {
+ getTree(callback) {
+ this.$api.getTree(this.$route.params.id, { params: { type: 1 } }).then(resp => {
+ this.dataTree = resp['tree'];
+
+ // 如果有提供回调函数,则调用它
+ if (callback && typeof callback === 'function') {
+ callback(resp);
+ }
+ });
+ }
+ }
+};
diff --git a/web/src/pages/fastrunner/api/RecordApi.vue b/web/src/pages/fastrunner/api/RecordApi.vue
index 24fffdd..8b61049 100644
--- a/web/src/pages/fastrunner/api/RecordApi.vue
+++ b/web/src/pages/fastrunner/api/RecordApi.vue
@@ -1,5 +1,4 @@
-
@@ -228,26 +222,25 @@
ref="tree2"
@node-drag-end="handleDragEnd"
>
-
{{ node.label }}
-
-
-
-
+
+
+
+
-
-
-
@@ -265,7 +258,7 @@
-
-
diff --git a/web/src/pages/fastrunner/api/components/ApiList.vue b/web/src/pages/fastrunner/api/components/ApiList.vue
index 6fab1fb..7f57281 100644
--- a/web/src/pages/fastrunner/api/components/ApiList.vue
+++ b/web/src/pages/fastrunner/api/components/ApiList.vue
@@ -338,8 +338,11 @@