上节我们讲了如何添加脚本,这节我们继续实现如何运行脚本。
先梳理下整个需求实现,脚本运行我们需要获取所有对应部门及对应项目下的所有脚本数据,显示在前端;
脚本列表表头应包含脚本复选框,脚本id,部门名称,项目名称,脚本名称,操作列(运行/删除/查看),运行结果,脚本类型。
详细前端实现效果如下:
此逻辑实现简单点讲,就是一通过获取生成脚本的数据表的数据,在前端展示,勾选单个或多个脚本运行,调用后端运行脚本路由,返回运行结果,生成测试报告。群内通知运行结果。
对应前端实现如下:
<table id="myTable" class="table table-bordered table-striped">
<select id="projectFilter" class="custom-select">
<option value="">所有项目</option>
<!-- 使用服务器返回的项目列表填充这个下拉菜单 -->
</select>
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th>部门名</th>
<th>项目名</th>
<th>脚本名</th>
<th>操作</th>
<th>运行结果</th>
<th>上传APK</th>
<th>脚本类型</th>
</tr>
</thead>
<tbody>
<!-- Dynamic content -->
{% for record in records %}
<tr>
<td><input type="checkbox" class="script-checkbox"></td>
<td>{{ record[0] }}</td>
<td>{{ record[1] }}</td>
<td>{{ record[2] }}</td>
<td>{{ record[3] }}</td>
<td>
<button class="btn btn-primary run-script-btn" data-department="{{ record[1] }}" data-project="{{ record[2] }}" data-script="{{ record[3] }}"><i class="fas fa-play"></i> 运行</button>
<!-- 其他按钮 -->
<!-- <button class="btn btn-warning upload-btn" data-id="{{ record[0] }}"><i class="fas fa-upload"></i> 上传</button>-->
<!-- <input type="file" class="file-input" accept=".apk" style="display: none;">-->
<button class="btn btn-danger delete-script-btn" data-id="{{ record[0] }}"><i class="fas fa-trash"></i> 删除</button>
<button class="btn btn-success view-report-btn" data-department="{{ record[1] }}" data-project="{{ record[2] }}" data-script="{{ record[3] }}"><i class="fas fa-eye"></i> 查看</button>
</td>
<td class="run-result">{{ record[4] }}</td>
<td> <!-- 新增的 "上传" 列 -->
<button class="btn btn-warning upload-btn" data-id="{{ record[0] }}"><i class="fas fa-upload"></i> 上传</button>
<input type="file" class="file-input" accept=".apk" style="display: none;">
</td>
<td>{{ record[5] }}</td>
</tr>
{% endfor %}
<!-- Add a static content row -->
</tbody>
</table>
<button class="btn btn-primary" id="run-selected-scripts-btn">运行选中脚本</button>
<!-- Modal -->
<div class="modal fade" id="runningModal" tabindex="-1" aria-labelledby="runningModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="runningModalLabel">脚本运行中...</h5>
</div>
<div class="modal-body">
请稍候,脚本正在运行...
</div>
</div>
</div>
</div>
<script>
//文件上传操作
$(".upload-btn").click(function() {
const fileInput = $(this).siblings(".file-input");
fileInput.click(); // 触发文件选择
});
$(".file-input").change(function() {
const file = this.files[0];
if (!file) {
return; // 用户未选择文件
}
const department = $(this).closest("tr").children(":nth-child(3)").text(); // 第3列是部门名
const project = $(this).closest("tr").children(":nth-child(4)").text(); // 第4列是项目名
const formData = new FormData();
formData.append("file", file);
formData.append("department", department);
formData.append("project", project);
$.ajax({
url: "/upload-file",
type: "POST",
data: formData,
processData: false, // 不处理数据
contentType: false, // 不设置内容类型
success: function(result) {
alert('文件已上传到 ' + result.filepath + ' 目录下');
},
error: function(error) {
console.log(error);
}
});
});
$(document).ready(function () {
//对表格进行初始化并定义分页条数为5
//这个是点击单独点击运行按钮触发的函数
$(".run-script-btn").click(function() {
// 获取脚本信息
const department = $(this).data("department");
const project = $(this).data("project");
const script = $(this).data("script");
const resultCell = $(this).closest("tr").find(".run-result");
const scriptType = $(this).closest("tr").children(":nth-child(9)").text(); // 第9列是脚本类型
// 显示运行中的模态框
$("#runningModal").modal("show");
$.ajax({
url: '/run-script',
method: 'POST',
data: {
department: department,
project: project,
script: script,
script_type: scriptType, // 新增脚本类型字段
},
dataType: "json", // Expect a JSON response
}).done(function(response) {
console.log(response); // Print the response
resultCell.text(response.last_run_result); // Show the last run result on the page
}).fail(function() {
resultCell.text("通讯错误");
}).always(function() {
$("#runningModal").modal("hide");
});
});
// 页面加载完成后,获取筛选器数据并进行一次筛选
$.get("/get-filters", function(data) {
var departments = data.departments;
var projects = data.projects;
projects.forEach(function(project) {
var opt = document.createElement('option');
opt.value = project;
opt.innerHTML = project;
$("#projectFilter").append(opt);
});
filterTable();
});
$("#departmentFilter, #projectFilter").change(filterTable);
function filterTable() {
var departmentFilter = $("#departmentFilter").val();
var projectFilter = $("#projectFilter").val();
// 遍历表格的每一行,根据部门名和项目名决定是否显示该行
$("table tbody tr").each(function () {
// var department = $(this).children(":nth-child(3)").text(); // 第3列是部门名
var project = $(this).children(":nth-child(4)").text(); // 第4列是项目名
// if ((departmentFilter === "" || department === departmentFilter) &&
// (projectFilter === "" || project === projectFilter)) {
if ((projectFilter === "" || project === projectFilter)) {
$(this).show(); // 如果该行的部门名和项目名满足筛选条件,则展示
} else {
$(this).hide(); // 否则,隐藏
}
});
}
$("#run-selected-scripts-btn").click(async function() {
//获取已经排序并选中的元素
const selectedRows = $('tbody').find('input.script-checkbox:checked').closest('tr');
console.log(selectedRows)
// 没有选择的话就警告
if (selectedRows.length === 0) {
alert("请至少选择一个脚本来运行");
return;
}
for (let i = 0; i < selectedRows.length; i++) {
const row = selectedRows[i];
const button = $(row).find('.run-script-btn');
const department = button.data("department");
const project = button.data("project");
const script = button.data("script");
const resultCell = button.closest("tr").find(".run-result");
const scriptType = $(row).children(":nth-child(9)").text(); // 第9列是脚本类型
// 显示运行中的模态框
$("#runningModal").modal("show");
console.log("Before ajax call")
$.ajax({
url: '/run-script',
method: 'POST',
data: {
department: department,
project: project,
script: script,
script_type: scriptType, // 新增脚本类型字段
},
dataType: "json", // Expect a JSON response
}).done(function(response) {
console.log(response);
// Check the "status" field in the response
if (response.status === "success") {
resultCell.text("成功");
} else {
resultCell.text("失败: " + response.message); // Show error message
}
}).fail(function() {
resultCell.text("通讯错误");
}).always(function() {
// Close the modal in any case
$("#runningModal").modal("hide");
});
//延时10秒。意思是每个脚本运行后,程序会暂停10秒再继续运行下一个脚本。
await new Promise((resolve, reject) => {
//set the delay here
setTimeout(() => {
resolve();
console.log('Waited for 15 seconds.');
}, 20000);
});
console.log("Delay End")
}
});
$("tbody").sortable({
items: "tr",
cursor: "move",
opacity: 0.6,
update: function() {
$("table tbody tr").each(function(index) {
$(this).find('th:first-child').text(index + 1);
});
$("table").hide().show(0); // Add it here
}
});
$('#myTable').DataTable({
"pageLength": 5,
"language": {
"lengthMenu": "显示 _MENU_ 条记录",
"zeroRecords": "没有找到记录",
"info": "第 _START_ 至 _END_ 条记录,总共 _TOTAL_ 条记录",
"infoEmpty": "没有找到记录",
"infoFiltered": "(filtered from _MAX_ total records)",
"sSearch": "搜索:",
"paginate": {
"first": "首页",
"last": "末页",
"next": "下一页",
"previous": "上一页"
},
}
});
});
</script>
</body>
里面做了分页逻辑显示。
对应后端运行脚本逻辑实现:
@app.route('/run-script', methods=['POST'])
def run_script(department=None, project=None, script=None,script_type=None):
if department is None:
department = request.form.get('department')
if project is None:
project = request.form.get('project')
if script is None:
script = request.form.get('script')
if script_type is None: # 新增
script_type = request.form.get('script_type') # 从 POST 请求中获取 script_type
#注意下这里的ied可自行文件的安装版本,不对的话执行不了
a_path = os.path.join(myide)
script_path = os.path.join(mysp)
log_path = f'{script_path}\\newlog'
device_command = ''
command = f'{a_path} runner {script_path} {device_command} --log {log_path}'
try:
result = subprocess.run(command, shell=True)
print('脚本执行结果: ', result)
if result.returncode == 0:
# send_dingdingSuccefull('all case test over pease to check it in http://192.168.32.88:9555')
update_last_run_result_to_DB(department, project, script, '成功')
return jsonify({'status': "success", 'message': "脚本执行成功!","last_run_result": "成功"})
else:
# send_dingdingSuccefull(''+script+'用例执行失败 pease to check it in http://192.168.32.59:9555')
update_last_run_result_to_DB(department, project, script, '失败')
return jsonify({'status': "fail", 'message': "脚本执行失败!","last_run_result": "失败"})
except Exception as e:
# send_dingdingSuccefull('all case test over pease to check it in http://192.168.32.59:9555')
update_last_run_result_to_DB(department, project, script, '错误: ' + str(e))
return jsonify({'status': "error", 'message': str(e)})
总结:
- 表格初始化与分页:利用DataTables插件对表格进行初始化,并设置分页条数为5。
- 表格行排序:使表格的行可以通过鼠标拖动进行排序。
- 异步文件上传:点击"上传"按钮后,用户可以选择一个文件上传。文件上传完后,会给用户一个弹窗提示,告诉用户文件已经上传到了服务器的哪个目录下。
- 异步运行脚本:点击"运行"按钮后,会异步向服务器发送一个请求,请求服务器运行某个脚本。脚本运行过程中,会弹出一个模态框告诉用户脚本正在运行。脚本运行结束后,模态框会消失,同时页面上会显示出脚本的运行结果。
- 运行选中的所有脚本:用户可以勾选多个脚本,然后点击"运行选中脚本"按钮来运行他们。这个过程中有一个延时机制,每个脚本运行后,会暂停一段时间再继续运行下一个脚本。
- 查询筛选器:页面加载完成后,会异步向服务器请求筛选器数据,然后在页面上生成一个项目筛选器。用户可以通过这个筛选器来筛选想要看到的项目。
- 对页面上各种操作的反馈:网页中的各种操作都有明确的反馈,比如上传文件后的提示、运行脚本后的提示、筛选后的结果展示等。
综上:脚本运行逻辑开发完毕。
下一节:测试计划功能模块实现,敬请期待
本文暂时没有评论,来添加一个吧(●'◡'●)