自动化测试中,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);

界面自动化测试录制工具,让python selenium自动化测试脚本开发更加方便的更多相关文章

  1. Jenkins持续集成项目搭建与实践——基于Python Selenium自动化测试(自由风格)

    Jenkins简介 Jenkins是Java编写的非常流行的持续集成(CI)服务,起源于Hudson项目.所以Jenkins和Hudson功能相似. Jenkins支持各种版本的控制工具,如CVS.S ...

  2. Python+selenium自动化测试中Windows窗口跳转方法

    Python+selenium自动化测试中Windows窗口跳转方法 #第一种方法 #获得当前窗口 nowhandle=driver.current_window_handle #打开弹窗 drive ...

  3. 从零开始到设计Python+Selenium自动化测试框架-如何开始

    如何开始学习web ui自动化测试?如何选择一门脚本语言?选择什么自动化测试工具? 本人已经做测试快5年,很惭愧,感觉积累不够,很多测试都不会,三年多功能测试,最近两年才开始接触和学习自动化测试.打算 ...

  4. 第一章 python+selenium自动化测试实战

    @序章 自动化测试是软件测试的主流方向之一: 教程从测试的根本需求出发,讲解如何开展自动化测试. 首先,我们要明白,自动化仅仅是满足我们某种需求的一种工具:没有必要花费时间把它全部弄懂:我们只需要学会 ...

  5. python selenium 自动化测试web

    如何使用python完成自动化测试web页面呢?首选selenium   那基于python的selenium如何使用,下面看一段测试案例: 基于python的selenium 安装方法: pip i ...

  6. python+selenium 自动化测试实战

    一.前言: 之前的文章说过, 要写一篇自动化实战的文章, 这段时间比较忙再加回家过11一直没有更新博客,今天整理一下实战项目的代码共大家学习.(注:项目是针对我们公司内部系统的测试,只能内部网络访问, ...

  7. 在公司内部网络如何搭建Python+selenium自动化测试环境

    在公司内部安装Python+selenium测试环境,由于不能连外网所以不能使用pip命令进行安装,经过多次尝试终于安装成功,现总结如下分享给大家,也希望跟大家一起学习和交流自动化网页测试时遇到的问题 ...

  8. python+selenium自动化测试_1

    前言 回顾一下python+selenium基础,并整理相关知识点,分享给有需要,在前进道路上的朋友. print打印 #打印Hello World print("Hello World&q ...

  9. 《一头扎进》系列之Python+Selenium自动化测试框架实战篇6 - 价值好几K的框架,呦!这个框架还真牛叉哦!!!

    1. 简介 本文开始介绍如何通过unittest来管理和执行测试用例,这一篇主要是介绍unittest下addTest()方法来加载测试用例到测试套件中去.用addTest()方法来加载我们测试用例到 ...

  10. python+selenium自动化测试环境搭建

    selenium 是一个web的自动化测试工具,不少学习功能自动化的同学开始首选selenium ,相因为它相比QTP有诸多有点: *  免费,也不用再为破解QTP而大伤脑筋 *  小巧,对于不同的语 ...

随机推荐

  1. 用Python脚本迁移MongoDB数据到金仓-kingbase数据库

    1.首先需要明确MongoDB与kingbase的对应关系,collection相当于table,filed相当于字段,根据这个对应关系创建表: 此次迁移的MongoDB里的数据字段是:_id(自动生 ...

  2. Java中Calendar类与SimpleDateFormat类的介绍

    目录 Calendar类(关于日期的一些方法) get(Calendar.XXX); get(Calendar.Year) get(Calendar.MONTH) get(Calendar.DAY_O ...

  3. flutter3-weos手机OS系统|Flutter3.22+Getx仿ios桌面管理OA应用

    原创自研flutter3.x+getx仿制ios手机桌面UI管理系统模板Flutter3-OS. flutter3-osx基于最新跨平台技术Flutter3.22+Dart3.4+GetX+fl_ch ...

  4. proteus 器件名称被软件篡改bug的解决方案

    proteus v7.8 器件名称被软件篡改bug 的解决方案 BUG描述 在做单片机实验时,发现从某一个时间保存的设计图文件开始,在添加新的电子元件时会出现部分旧元件的名称被捆绑替换为新元件的名称, ...

  5. 解决:Maven PKIX path building failed: sun.security.provider.certpath

    在构建SpringBoot项目时,maven下载依赖会报 PKIX path building failed: sun.security.provider.certpath的错误. 使用https:/ ...

  6. ELK收集主流应用日志

    1.收集nginx日志 学习背景:access.log,error.log目前日志混杂在一个es索引下. 改进filebeat配置 https://www.elastic.co/guide/en/be ...

  7. 请写出常用的linux指令

    a.cd /home 进入 '/ home' 目录' b.cd .. 返回上一级目录 c.cd ../.. 返回上两级目录 d.mkdir dir1 创建一个叫做 'dir1' 的目录' e.mkdi ...

  8. Mybatis 动态 sql 是做什么的?都有哪些动态 sql?能简述一下动态 sql 的执行原理不?

    a.Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能. b.Mybatis 提 供 了 9 种 动 态 sql 标 ...

  9. idea设置jdk和设置文件编码格式utf-8

    1.idea设置jdk 2.idea设置文件编码格式utf-8 create utf-8 files with NO BOM 不要更改,否则编译会出错误.

  10. C#开发的NoteNet桌面小贴士 - 开源研究系列文章 - 个人小作品

    十多年前编写过这个NoteNet小应用,不过当时用的是文本的保存方式,而且功能上也相对较多.这次重新编写这个小应用,用上新的技术和功能.现在先把源码发布出来,在另个系列的博文中( C#基于.net f ...