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