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