编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

企业级UI自动化平台—运行脚本

wxchong 2024-06-19 22:24:31 开源技术 28 ℃ 0 评论

上节我们讲了如何添加脚本,这节我们继续实现如何运行脚本。

先梳理下整个需求实现,脚本运行我们需要获取所有对应部门及对应项目下的所有脚本数据,显示在前端;

脚本列表表头应包含脚本复选框,脚本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)})

总结:

  1. 表格初始化与分页:利用DataTables插件对表格进行初始化,并设置分页条数为5。
  2. 表格行排序:使表格的行可以通过鼠标拖动进行排序。
  3. 异步文件上传:点击"上传"按钮后,用户可以选择一个文件上传。文件上传完后,会给用户一个弹窗提示,告诉用户文件已经上传到了服务器的哪个目录下。
  4. 异步运行脚本:点击"运行"按钮后,会异步向服务器发送一个请求,请求服务器运行某个脚本。脚本运行过程中,会弹出一个模态框告诉用户脚本正在运行。脚本运行结束后,模态框会消失,同时页面上会显示出脚本的运行结果。
  5. 运行选中的所有脚本:用户可以勾选多个脚本,然后点击"运行选中脚本"按钮来运行他们。这个过程中有一个延时机制,每个脚本运行后,会暂停一段时间再继续运行下一个脚本。
  6. 查询筛选器:页面加载完成后,会异步向服务器请求筛选器数据,然后在页面上生成一个项目筛选器。用户可以通过这个筛选器来筛选想要看到的项目。
  7. 对页面上各种操作的反馈:网页中的各种操作都有明确的反馈,比如上传文件后的提示、运行脚本后的提示、筛选后的结果展示等。

综上:脚本运行逻辑开发完毕。

下一节:测试计划功能模块实现,敬请期待

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表