首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

界面自动化测试录制工具,让python selenium自动化测试脚本开发更加方便

编程知识
2024年07月29日 10:03

自动化测试中,QTP和selenium IDE都支持浏览器录制与回放功能,简单的来说就像一个记录操作步骤的机器人,可以按照记录的步骤重新执行一遍,这就是脚本录制。
个人觉得传统录制工具有些弊端,加上要定制支持我自己的自动化框架(python单机版自动化测试框架源代码),所以自己用javascript写了一个录制工具,在控制台打印记录的python脚本如下:

 

代码如下(初稿,还在不断调试完善中):

var click_textContent = '
    var father_level = 0;
    var child_ctl = "";
    var child_ctl_tmp = "";
    var next_focusedElement = null;
    window.clickedElement = null;
    
    document.addEventListener("click", function(event) {
    window.clickedElement = event.target;
    console.log(window.clickedElement);
    father_level = 0;
    myDispose_click(window.clickedElement);
    });
    
    function myDispose_click(focusedElement) {
        console.log(`开始 父${father_level} -------------------------`);
        let tag_name = focusedElement.tagName.toLowerCase();
        let outerHTML = focusedElement.outerHTML;
        console.log(outerHTML);
        
        if (tag_name === "body") {
            let xpath = getElementfullXPath(next_focusedElement);
            let elements = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            if (elements && elements.snapshotLength === 1) {
                console.log(`self.myWtClickEx(driver, By.XPATH, "${xpath}")`);
                console.log("结束:tag名称为body");
                console.log(`结束 父${father_level} -------------------------`);
                return xpath;
            } else {
                console.log("结束:tag名称为body");
                console.log(`结束 父${father_level} -------------------------`);
                return null;
            }
        }

        let my_all_value = "";
        let text = focusedElement.textContent.trim().replace(/"/g, "\\\"");
        if (text !== "" && !text.includes("\\n")) {
            my_all_value = `contains(text(),\'${text}\')`;
            if (myDispose_count_number(text, "text", tag_name)) {
                let xpath = `//${tag_name}[${my_all_value}]`;
                let parameter = `driver, By.XPATH, "${xpath}"`;
                myDispose_success(parameter);
                return parameter;
            }
        } else {
            text = ""
        }

        let attributes = focusedElement.attributes;
        console.log(`属性名称列表: ${Array.from(attributes).map(attr => attr.name).join(",")}`);

        for (let i = 0; i < attributes.length; i++) {
            let attribute_name = attributes[i].name;
            let attribute_value = attributes[i].value;

            if (attribute_name === "class") {
                let class_value_list = attribute_value.split(" ");
                console.log(`class列表:${class_value_list}`);
                if (class_value_list.includes("focusing")) {
                    class_value_list = class_value_list.filter(value => value !== "focusing");
                }

                for (let class_value of class_value_list) {
                    if (my_all_value === "") {
                        my_all_value = `contains(@class,"${class_value}")`;
                    } else {
                        my_all_value += ` and contains(@class,"${class_value}")`;
                    }
                
                    if (myDispose_count_number(class_value, attribute_name, tag_name)) {
                        let parameter = `driver, By.CLASS_NAME, "${class_value}"`;
                        myDispose_success(parameter);
                        return parameter;
                    }
                    
                    let xpath = "";
                    if (text === "") {
                        xpath = `//${tag_name}[${my_all_value}]`;
                    } else {
                        xpath = `//${tag_name}[contains(text(),\'${text}\') and ${my_all_value}]`;
                    }
                    let result = myDispose_count_evaluate(xpath);
                    if (result) { 
                        let parameter = `driver, By.XPATH, "${xpath}"`;
                        myDispose_success(parameter);
                        return parameter;
                    }
                }
            } else {
                /*if (attribute_value === "" || /\d/.test(attribute_value)) {*/
                if (attribute_value === "" || (attribute_name !== "src" && attribute_value.match(/[0-9]/))) {
                    continue;
                }

                if (my_all_value === "") {
                    my_all_value = `contains(@${attribute_name}, "${attribute_value}")`;
                } else {
                    my_all_value += ` and contains(@${attribute_name}, "${attribute_value}")`;
                }
                
                if (myDispose_count_number(attribute_value, attribute_name, tag_name)) { 
                    let xpath = `//${tag_name}[contains(@${attribute_name}, "${attribute_value}")]`;
                    let parameter = `driver, By.XPATH, "${xpath}"`;
                    myDispose_success(parameter);
                    return parameter;
                }
                
                let xpath = "";
                if (text === "") {
                    xpath = `//${tag_name}[${my_all_value}]`;
                } else {
                    xpath = `//${tag_name}[contains(text(),\'${text}\') and ${my_all_value}]`;
                }
                let result = myDispose_count_evaluate(xpath);
                if (result) {
                    let parameter = `driver, By.XPATH, "${xpath}"`;
                    myDispose_success(parameter);
                    return parameter;
                }
            }
        }

        if (my_all_value !== "") {
            let xpath = `//${tag_name}[${my_all_value}]`;
            let result = myDispose_count_evaluate(xpath);
            if (result) {
                let parameter = `driver, By.XPATH, "${xpath}"`;
                myDispose_success(parameter);
                return parameter;
            } else {
                let textStr = `self.myWtClickEx(driver, By.XPATH, "${xpath}")`;
                console.log("# 不是1");
                console.log(textStr);
                console.log(`结束 父${father_level} -------------------------`);
                
                if (father_level === 0) {
                    child_ctl = `father, By.XPATH, ".${xpath}"`;
                    child_ctl_tmp = `.${xpath}`;
                    next_focusedElement = focusedElement;
                }

                let father = focusedElement.parentElement;
                if (father) {
                    father_level++;
                    myDispose_click(father);
                }
            }
        }
        return null;
    }

    function myDispose_success(parameter) {
        if (father_level === 0) {
            console.log(`self.myWtClickEx(${parameter})`);
        } else {
            console.log(`father = self.myWtFindElement(${parameter})`);
            console.log(`self.myWtClickEx(${child_ctl})`);
        }
        console.log(`结束 父${father_level} -------------------------`);
    }

    function myDispose_count_evaluate(xpath) {
        let elements = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        if (father_level === 0) {
            if (elements.snapshotLength === 1) {
                return true
            } else {
                return null
            }
        } else {
            if (elements.snapshotLength === 1) {
                let firstElement = elements.snapshotItem(0);
                let result = document.evaluate(child_ctl_tmp, firstElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
                if (result.snapshotLength === 1) {
                    return true
                } else {
                    return null
                }
            } else {
                return null
            }
        }
    }

    function myDispose_count_number(attribute_value, attribute_name, tag_name) {
        if (attribute_value === "") {
            return null;
        };
        if (attribute_name !== "text" && attribute_name !== "src" && attribute_value.match(/[0-9]/)) {
            return null;
        };

        let xpath;
        if (attribute_name !== "text") {
            xpath = `//${tag_name}[contains(@${attribute_name}, "${attribute_value}")]`;
        } else {
            xpath = `//${tag_name}[contains(text(), \'${attribute_value}\')]`;
        };
        
        let result = myDispose_count_evaluate(xpath);

        if (result) {
            console.log(`${attribute_name}:"${attribute_value}" 在网页中出现1次`);
            return true;
        } else {
            console.log(`${attribute_name}:"${attribute_value}" 在网页中出现了多次`);
            return null;
        };
    }

    function getElementfullXPath(element) {
        if (element && element.id)
            if (!element.id.match(/[0-9]/)) {
                return \'//*[@id="\' + element.id + \'"]\';
            }
            
        if (element==null)
            return "";
    
        var index = 0;
        var loacl_tagName = element.tagName;
        var sibling = element.previousSibling;
        var sibling_tagName = null;
        if (sibling) {
            sibling_tagName = sibling.tagName;
        }
        while (sibling && sibling.nodeType === 1 && loacl_tagName === sibling_tagName) {
            index++;
            sibling = sibling.previousSibling;
            if (sibling) {
                sibling_tagName = sibling.tagName;
            } else {
                sibling_tagName = null;
            }
        }
        
        parent = element.parentNode;
        if (parent) {
            var xpath = getElementfullXPath(parent);
            if (xpath === "undefined") {
                return "";
            } else {
                if (index === 0) {
                    xpath += "/" + element.tagName.toLowerCase();
                } else {
                    xpath += "/" + element.tagName.toLowerCase() + "[" + (index+1) + "]";
                }
                return xpath;
            }
        } else {
            return "";
        }
    }
';


var input_textContent = '
    let inputs = document.querySelectorAll(`input[type="text"]`);
    inputs.forEach(input => {
        input.addEventListener("input", function(event) {
            console.log(this.value);
            let parameter = myDispose_click(event.target);
            if (parameter !== null) {
                let textStr = `self.myWtSendKeysWebEx(${parameter}, "${this.value}")`;
                console.log(textStr);
            }
        });
    }); 
';


/*iframe*/
let iframes = document.getElementsByTagName('iframe');
for (let i = 0; i < iframes.length; i++) {
    let iframe = iframes[i];
    if (iframe.contentWindow && iframe.contentWindow.document) {
        let script = iframe.contentWindow.document.createElement('script');
        script.type = 'text/javascript';
        script.textContent = click_textContent;
        iframe.contentWindow.document.head.appendChild(script);
        let inputs = iframe.contentWindow.document.querySelectorAll(`input[type="text"]`);
        inputs.forEach(input => {
            input.addEventListener("input", function(event) {
                console.log(this.value);
                let parameter = myDispose_click(event.target);
                if (parameter !== null) {
                    let textStr = `self.myWtSendKeysWebEx(${parameter}, "${this.value}")`;
                    console.log(textStr);
                }
            });
        });
    }
}


/*非iframe*/
let script = document.createElement('script');
script.type = 'text/javascript';
script.textContent = click_textContent + input_textContent;
document.head.appendChild(script);

 

From:https://www.cnblogs.com/rmticocean/p/18329662
本文地址: http://www.shuzixingkong.net/article/540
0评论
提交 加载更多评论
其他文章 基于 SASL/SCRAM 让 Kafka 实现动态授权认证
一、说明 在大数据处理和分析中 Apache Kafka 已经成为了一个核心组件。然而在生产环境中部署 Kafka 时,安全性是一个必须要考虑的重要因素。SASL(简单认证与安全层)和 SCRAM(基于密码的认证机制的盐化挑战响应认证机制)提供了一种方法来增强 Kafka 集群的安全性。 本文将从零
基于 SASL/SCRAM 让 Kafka 实现动态授权认证
一键语法错误增强工具 ChineseErrorCorrector
一键语法错误增强工具 欢迎使用我最近开源的使用一键语法错误增强工具,该工具可以进行14种语法错误的增强,不同行业可以根据自己的数据进行错误替换,来训练自己的语法和拼写模型,希望推动行业文本纠错的发展,欢迎Star,14种错误如下所示: 每种错误类型,对应的使用方法,如下所示: 环境的安装 pip i
一键语法错误增强工具 ChineseErrorCorrector
70%的人都答错了的面试题,vue3的ref是如何实现响应式的?
最近在我的vue源码交流群有位面试官分享了一道他的面试题:vue3的ref是如何实现响应式的?下面有不少小伙伴回答的是Proxy,其实这些小伙伴只回答对了一半。
70%的人都答错了的面试题,vue3的ref是如何实现响应式的? 70%的人都答错了的面试题,vue3的ref是如何实现响应式的? 70%的人都答错了的面试题,vue3的ref是如何实现响应式的?
这才是 PHP 高性能框架 Workerman 的立命之本
在这个大家都崇尚高性能的时代,程序员的谈笑间句句都离不开高性能,仿佛嘴角边不挂着「高性能」三个字都会显得自己很 Low,其中众所皆知的 Nginx 就是高性能的代表。
这才是 PHP 高性能框架 Workerman 的立命之本
Qt+OpenCascade开发笔记(二):windows开发环境搭建(二):Qt引入occ库,搭建基础工程模板Demo和发布Demo
前言 Open CASCADE是由Open Cascade SAS公司开发和支持的开源软件开发平台,旨在为特定领域快速开发程序而设计。它是一个面向对象的C++类库,提供了丰富的几何造型、数据交换和可视化等功能,成为许多CAD软件的核心组件。 本篇描述搭建Qt开发occ环境过程。 Demo 注意:用的
Qt+OpenCascade开发笔记(二):windows开发环境搭建(二):Qt引入occ库,搭建基础工程模板Demo和发布Demo Qt+OpenCascade开发笔记(二):windows开发环境搭建(二):Qt引入occ库,搭建基础工程模板Demo和发布Demo Qt+OpenCascade开发笔记(二):windows开发环境搭建(二):Qt引入occ库,搭建基础工程模板Demo和发布Demo
上周热点回顾(7.22-7.28)
热点随笔: &#183;&#160;周边上新,T恤上星:博客园T恤幸运闪系列,上架预售,上照预览&#160;(博客园团队)&#183;&#160;强烈推荐!!!阿里旗下10款顶级开源项目&#160;(程序员晓凡)&#183;&#160;给园子的会员送送优惠,和你的数据库聊聊天:会员权益「Chat2D
keycloak~为微信二维码添加动态kc认可的动态state
本实例将通过keycloak社区登录实现微信二维码的登录,并且二微码不是keycloak动态生成,而是通过微信提供的js生成的,在页面上直接输出的方式实现的。 动态state 在Keycloak中使用微信二维码登录时,state参数确实是由后端生成的,并且用于确保登录过程的安全性,防止CSRF攻击等
keycloak~为微信二维码添加动态kc认可的动态state
Pulsar客户端消费模式揭秘:Go 语言实现 ZeroQueueConsumer
前段时间在 pulsar-client-go 社区里看到这么一个 issue: import &quot;github.com/apache/pulsar-client-go/pulsar&quot; client, err := pulsar.NewClient(pulsar.ClientOpti
Pulsar客户端消费模式揭秘:Go 语言实现 ZeroQueueConsumer Pulsar客户端消费模式揭秘:Go 语言实现 ZeroQueueConsumer Pulsar客户端消费模式揭秘:Go 语言实现 ZeroQueueConsumer