通用技术 【Chrome 插件】TAPD 创建 bug、状态变更发送钉钉通知

中建电商-质量部 · 2021年04月02日 · 最后由 QingTian203 回复于 2021年04月18日 · 536 次阅读

背景:

公司使用 TAPD 作为项目、测试流程、测试用例、缺陷管理平台,而日常公司内部的交流工具为钉钉;TAPD 与钉钉无法在系统上进行很好的交互,在提交 bug 或者其他任务状态发生变化时,需要及时通知到相关的同事进行及时处理。

解决方案:

编写 Chrome 插件,对需要关注的任务、bug 进行状态监听;当状态发生流转时,能够通过插件调用钉钉机器人,及时的在工作群中通知到相关同事。

目前效果:


严重级别及以上、优先级为高及以上的 bug,状态流转至已解决的耗时由平均 4.8个小时提升至平均 2.9个小时。极大程度上提高了 bug 的解决效率和测试效率。

原理:

Chrome 插件编写 Java Script 对按钮进行监听,判断字段发生变化并且满足条件时,调用 XMLHttpRequest 对已设置好的钉钉群机器人发送消息,即可实现像上图一样的效果。是不是很 easy!

代码:

// var dingdingUrl = "https://oapi.dingtalk.com/robot/send?access_token=842de0b90ff76bfce0830ab71097dee74fad0a17ba0963a56a3fffa7a940449b";

$(function () {
    isSend();

    //提交缺陷
    $('#_view').click(function () {
        localStorage.setItem('preUrl', window.location.href);
    });

    //bug状态流转
    $('#update_status_btn').click(function (){
        localStorage.setItem('preUrl', window.location.href);
    });

    //从缓存拿上个页面地址进行对比,并进行发送
    async function isSend() { 
        var _preUrl = localStorage.getItem('preUrl');
        var _referrer = document.referrer;
        if (_preUrl == _referrer) {
            var _bugPriority = $('#ContentPriority').attr('data-editable-value');
            var _bugSeverity = $('#ContentSeverity').attr('data-editable-value');
            var _bugStatus = $('a[workflow-status-change=entityViewStatusChange]').attr('title');
            //根据bug等级、状态、优先级决定是否进行发送钉钉
            if(_bugSeverity == "致命" || _bugSeverity == "严重" || _bugPriority == "紧急" || _bugPriority == ""){
                if(_bugStatus != "已关闭" && _bugStatus != "接受/处理" ){
                    sendingMsg(await setBugParams())
                }
            }

            localStorage.removeItem('preUrl');
        }
    }

    async function setBugParams(){
        var _bugUrl = getBugUrl(location.href);
        var _bugTitle = $('#bug_title_view .editable-value').attr('title');
        var _bugPriority = $('#ContentPriority').attr('data-editable-value');
        var _bugSeverity = $('#ContentSeverity').attr('data-editable-value');
        var _bugModule = $('#Content所属模块').attr('data-editable-value');
        var _bugStatus = $('a[workflow-status-change=entityViewStatusChange]').attr('title');
        var _bugOwners = $('#ContentCurrentOwner').text();
        _bugOwners = _bugOwners.replace(/\(.*?\)/g,'');
        var _bugPriority = $('#ContentPriority').attr('data-editable-value');
        var _bugSeverity = $('#ContentSeverity').attr('data-editable-value');
        var _mobileList =await getMobiles(_bugOwners);

        var params = {
            "msgtype": "text",
            "text": {
            "content": "BUG:" + _bugTitle + 
            "\n状态:" + _bugStatus + 
            "\n优先级:" + _bugPriority + 
            "\n级别:" + _bugSeverity + 
            "\n所属模块:" + _bugModule + 
            "\n链接:" + _bugUrl
            },
            "at":{
                "atMobiles": _mobileList,
                "isAtAll": false
            }

        };
        return params;
    }

    //发送消息XMLHTTP
    function sendingMsg(params) {
        if (params == 0){
            return;
        }
        var xhr = new XMLHttpRequest();
        xhr.open("POST", dingdingUrl, true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if (window.Notification) {
                    chrome.extension.sendRequest({ type: 1, name: "发送钉钉通知", msg: xhr.responseText }, function (response) {
                        console.log(response);
                    });
                } else { alert('消息已发送,当前浏览器不支持推送消息'); }
            }
        }
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.send(JSON.stringify(params));
    }
    //拼接bug URL
    function getBugUrl(url){
        var tmpList1 = splitStr(url,"?");
        var tmpList2 = splitStr(tmpList1[1],"&");
        var bugUrl = tmpList1[0] + "?";
        for(var i=0;i<tmpList2.length;i++){
            console.log(tmpList2[i]);
            if(tmpList2[i].match("bug_id=")){
                bugUrl = bugUrl + tmpList2[i];
                break;
            }
        }
        return bugUrl;
    }
    //获取处理人联系电话
    async function getMobiles(bugOwners){
        var mobileList = splitStr(bugOwners,";").filter((v) => v)
        for(let i=0;i<mobileList.length;i++){
            //后端封装了个简单的接口,用于获取通知人的电话
            url='http://easytest.yzw.cn/user/getPhone?tapdUserAccount='+mobileList[i];
            mobileList[i] = await getMobile(url);
        }
        return mobileList;
    }
    //单个获取电话号码
    async function getMobile(url){
        return await fetch(url).then(response=>response.text())
    }

    //字符串解析分割
    function splitStr(str,regx){
        var result = str.split(regx);
        return result;
    }

});

说明:本插件脚本中,封装了获取 TAPD 用户电话号码的接口,因为要实现在钉钉中 @ 到某一个人。TAPD 的用户名跟钉钉的电话号码是维护在一个表里头,用接口进行返回。如果不需要接口的方式,也可以简单的用 Map 的方式在脚本中维护即可;如果不需要实现 @ 到某个人,那么也可以不用获取电话号码。

脚本写好后,需要以插件的形式安装到 Chrome 中。以下介绍下整体插件文件目录以及安装过程:

插件文件目录:

写好之后压缩了发给同事们吧~

## 安装步骤:

  • 1. 解压插件压缩包
  • 2. 打开 Chrome 浏览器-->扩展程序
  • 3. 加载插件
  • 4. 确保插件是打开状态
  • 5. 在需要通知的钉钉群中,增加群助手 机器人 将上图中生成的 webhook url 复制到脚本中;后续就会在该群中同步消息 ### 全部设置完成后,即可实现上文效果展示中的样子;当然,除了 bug 还可以监听其他内容,根据自己的需要进行扩展吧~ Done!
共收到 12 条回复 时间 点赞

TAPD 的状态变化通知至钉钉 仅是应用的一种;chrome 插件可以实现多种多样的功能扩展:比如 web 测试的辅助 -- 表单自动填写;比如自动检查页面上的一些元素;比如...很多很多,希望能帮到大家

这个思路挺强的,没想到通过 chrome 插件来弄。
我的做法是通过 tapd 的 api 做定时任务来获取缺陷变更记录,根据状态的变化通知到相应的人,确实不如插件来的直接。

MarvinWu 回复

tapd 的 api 我们也在调用,但主要是用于数据统计。后续会介绍到我们怎么去基于 TAPD 去做各个维度的质量看板(项目维度、团队维度、个人维度),让数据为质量说话,让过程与结果透明化、公平化

涨知识了,期待后续介绍。

仅楼主可见

请问一下楼主,企业微信也可以吗

插件化是一种思路,但是建议是做内部服务,tapd 做一个 saas,包装 buginfo,关键场景等等定义一系列数据结构。钉钉 api 做一个 saas,中间层一个 pm 服务的 saas(包含多少时间未处理提醒和流转状态等等),这个 saas 去统一调用二边。企业微信等价 tapd,稍微麻烦点,需要拿组织架构权限和再申请一个应用。

桑七昂 回复

企业微信应该本身就能够很好的支持通知机制吧?毕竟都是腾讯的

大佬可以把完整的发一下吗?或者我私聊您

QingTian203 回复

留邮箱

1374150767@qq.com 邮箱地址 感谢大佬

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册