UIRecorder使用方法

介绍

UI Recorder 是一款零成本UI自动化录制工具,类似于Selenium IDE.
UI Recorder 要比Selenium IDE更加强大!
开源地址 官网地址

安装

以windows为例

安装nodejs

uirecorder要求nodejs版本号 >= v7.x,官网下载 node-v8.11.3-x64.msi 按向导完成nodejs安装,并完成环境变量设置,比如安装目录是:D:\Program Files\nodejs
检查:打开cmd

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:\Users\yueling>node -v
v8.11.3

C:\Users\yueling>npm -v
5.6.0

C:\Users\yueling>

改变原有环境变量

要先配置npm的全局模块的存放路径以及cache的路径,例如希望将以上两个文件夹放在NodeJS的主目录下,便在NodeJs下建立”node_global”及”node_cache”两个文件夹,输入以下命令改变npm配置

C:\Users\yueling>npm config set prefix "D:\Program Files\nodejs\node_global"
C:\Users\yueling>npm config set cache "D:\Program Files\nodejs\node_cache"

在系统环境变量添加系统变量NODE_PATH,输入路径D:\Program Files\nodejs\node_global\node_modules,此后所安装的模块都会安装到改路径下

安装cnpm

C:\Users\yueling>npm install -g cnpm --registry=https://registry.npm.taobao.org

设置环境变量

将D:\Program Files\nodejs\node_global添加到环境变量
检查:打开cmd

C:\Users\yueling>cnpm -v
[email protected] (D:\Program Files\nodejs\node_global\node_modules\cnpm\lib\parse_argv.js)
[email protected] (D:\Program Files\nodejs\node_global\node_modules\cnpm\node_modules\npm\lib\npm.js)
[email protected] (D:\Program Files\nodejs\node.exe)
[email protected] (D:\Program Files\nodejs\node_global\node_modules\cnpm\node_modules\npminstall\lib\index.js)
prefix=D:\Program Files\nodejs\node_global
win32 x64 6.1.7601
registry=https://registry.npm.taobao.org

C:\Users\yueling>

安装chrome

下载最新的chrome版本,需要注意——版本要和驱动相对应。

安装UIRecorder

C:\Users\yueling>npm install uirecorder mocha -g

webdriver安装

C:\Users\yueling>npm install selenium-standalone -g

下面这一步在初始化的时候也会安装,可以跳过这一步,使用项目中的selenium-standalone

C:\Users\yueling>selenium-standalone install --drivers.firefox.baseURL=http://npm.taobao.org/mirrors/geckodriver --baseURL=http://npm.taobao.org/mirrors/selenium --drivers.chrome.baseURL=http://npm.taobao.org/mirrors/chromedriver --drivers.ie.baseURL=http://npm.taobao.org/mirrors/selenium

示例

录制

打开cmd

C:\Users\yueling>cd /d d:\autotest
d:\autotest>mkdir uitest
d:\autotest>cd uitest
d:\autotest\uitest>uirecorder init
d:\autotest\uitest>uirecorder init
    __  ______   ____                           __
   / / / /  _/  / __ \___  _________  _________/ /__  _____
  / / / // /   / /_/ / _ \/ ___/ __ \/ ___/ __  / _ \/ ___/
 / /_/ // /   / _, _/  __/ /__/ /_/ / /  / /_/ /  __/ /
 \____/___/  /_/ |_|\___/\___/\____/_/   \__,_/\___/_/    v2.5.42

Official Site: http://uirecorder.com
------------------------------------------------------------------

? Path扩展属性配置,除id,name,class之外 data-id,data-name,type,data-type,role,data-role,data-value
? 属性值黑名单正则
? class值黑名单正则
? 断言前隐藏
? WebDriver域名或IP 127.0.0.1
? WebDriver端口号 4444
? 需要同时测试的浏览器列表 chrome, ie 11

config.json 文件保存成功
package.json 文件创建成功
README.md 文件创建成功
screenshots 文件夹创建成功
commons 文件夹创建成功
uploadfiles 文件夹创建成功
.editorconfig 文件创建成功
.gitignore 文件创建成功
install.sh 文件创建成功
run.bat 文件创建成功
run.sh 文件创建成功
hosts 文件创建成功
.vscode/launch.json 文件创建成功

Start install project dependencies...
--------------------------------------------

√ Installed 7 packages
√ Linked 197 latest versions
√ Run 0 scripts
deprecate mochawesome-uirecorder@1.5.22 › node-uuid@^1.4.1 Use uuid module instead
Recently updated (since 2018-07-17): 2 packages (detail see file d:\autotest\uitest\node_modules\.recently_updates.txt)
√ All packages installed (228 packages installed from npm registry, used 2m, speed 15.34kB/s, json 204(1.53MB), tarball 0B)

Start install webdriver dependencies...
--------------------------------------------


> uirecorderTest@1.0.0 installdriver d:\autotest\uitest
> selenium-standalone install --drivers.firefox.baseURL=http://npm.taobao.org/mirrors/geckodriver --baseURL=http://npm.taobao.org/mirrors/selenium --drivers.chrome.baseURL=http://npm.taobao.org/mirrors/chromedriver --drivers.ie.baseURL=http://npm.taobao.org/mirrors/selenium


----------

selenium-standalone installation starting

----------


---
selenium install:
from: http://npm.taobao.org/mirrors/selenium/3.12/selenium-server-standalone-3.12.0.jar
to: d:\autotest\uitest\node_modules\_selenium-standalone@6.15.1@selenium-standalone\.selenium\selenium-server\3.12.0-server.jar
---
chrome install:
from: http://npm.taobao.org/mirrors/chromedriver/2.40/chromedriver_win32.zip
to: d:\autotest\uitest\node_modules\_selenium-standalone@6.15.1@selenium-standalone\.selenium\chromedriver\2.40-x64-chromedriver
---
ie install:
from: http://npm.taobao.org/mirrors/selenium/3.12/IEDriverServer_x64_3.12.0.zip
to: d:\autotest\uitest\node_modules\_selenium-standalone@6.15.1@selenium-standalone\.selenium\iedriver\3.12.0-x64-IEDriverServer.exe
---
firefox install:
from: http://npm.taobao.org/mirrors/geckodriver/v0.20.1/geckodriver-v0.20.1-win64.zip
to: d:\autotest\uitest\node_modules\_selenium-standalone@6.15.1@selenium-standalone\.selenium\geckodriver\0.20.1-x64-geckodriver
---
edge install:
from: https://download.microsoft.com/download/F/8/A/F8AF50AB-3C3A-4BC4-8773-DC27B32988DD/MicrosoftWebDriver.exe
to: d:\autotest\uitest\node_modules\_selenium-standalone@6.15.1@selenium-standalone\.selenium\edgedriver\17134-MicrosoftEdgeDriver.exe

-----
selenium-standalone installation finished
-----

在cmd控制台输入uirecorder

d:\autotest\uitest>uirecorder
    __  ______   ____                           __
   / / / /  _/  / __ \___  _________  _________/ /__  _____
  / / / // /   / /_/ / _ \/ ___/ __ \/ ___/ __  / _ \/ ___/
 / /_/ // /   / _, _/  __/ /__/ /_/ / /  / /_/ /  __/ /
 \____/___/  /_/ |_|\___/\___/\____/_/   \__,_/\___/_/    v2.5.42

Official Site: http://uirecorder.com
------------------------------------------------------------------

? 测试脚本文件名: test.spec.js
? 打开同步校验浏览器? No
? 浏览器大小 (格式:1024 x 768): maximize

录制服务器监听在端口: 17725
[101228:102628:0724/104435.165:ERROR:install_util.cc(597)] Unable to read registry value HKLM\SOFTWARE\Policies\Google\Chrome\MachineLevelUserCloudPolicyEnrollmentToken for writing result=2

DevTools listening on ws://127.0.0.1:17729/devtools/browser/2060c6df-6ef6-46bd-9c88-b37d542fb64f
录制浏览器已开启
  url: https://www.baidu.com
  waitBody:
[101228:102580:0724/104456.783:ERROR:shader_disk_cache.cc(237)] Failed to create shader cache entry: -2
  click: wd ( #kw, 210, 7, 0 )
  sendKeys: helloworld{ENTER}
  expect: text, #content_left div[id="1"] > h3.c-gap-bottom-small > a, equal, helloworld_百度百科
  sleep: 1000
  click: helloworld_百度百科 ( #content_left div[id="1"] > h3.c-gap-bottom-small > a, 113, 7, 0 )
  switchWindow: 1
  waitBody:
  waitBody:
  click: span.cmn-baike-logo > em.cmn-icons_logo-du, 32, 32, 0
  waitBody:
  expect: val, #lemmaNum, notEqual, 1
  mouseMove: 分类 ( //a[text()="分类"], 21, 3 )
  click: 生活 ( dl.cat > dd:nth-child(2) > div:nth-child(6) > a, 10, 8, 0 )
  switchWindow: 2
  waitBody:
  expect: text, //h2[text()="生活频道"], equal, 生活频道

------------------------------------------------------------------

共录制18个步骤 (未经过校验)
录制脚本已保存: test.spec.js

录制服务器已关闭
录制浏览器已关闭

d:\autotest\uitest>dir

回放

回放并生成测试报告

d:\autotest\uitest>mocha test.spec.js --reporter mochawesome-uirecorder
[mochawesome] Generating report files...

  test.spec : chrome
    √ url: https://www.baidu.com (3919ms)
    √ waitBody:  (596ms)
    √ click: wd ( #kw, 210, 7, 0 ) (730ms)
    √ sendKeys: helloworld{ENTER}
    √ expect: text, #content_left div[id="1"] > h3.c-gap-bottom-small > a, equal, helloworld_百度百科sleep: 1000 (1002ms)
    √ click: helloworld_百度百科 ( #content_left div[id="1"] > h3.c-gap-bottom-small > a, 113, 7, 0 ) (815ms)
    √ switchWindow: 1 (3250ms)
    √ waitBody:  (601ms)
    √ waitBody:  (585ms)
    √ click: span.cmn-baike-logo > em.cmn-icons_logo-du, 32, 32, 0 (3886ms)
    √ waitBody:  (576ms)
    √ expect: val, #lemmaNum, notEqual, 1
    √ mouseMove: 分类 ( //a[text()="分类"], 21, 3 ) (734ms)
    √ click: 生活 ( dl.cat > dd:nth-child(2) > div:nth-child(6) > a, 10, 8, 0 ) (756ms)
    √ switchWindow: 2 (3084ms)
    √ waitBody:  (573ms)
    √ expect: text, //h2[text()="生活频道"], equal, 生活频道

  18 passing (42s)

[mochawesome] Report saved to reports\index.html
[mochawesome] Report saved to reports\index.xml

d:\autotest\uitest>cd /d d:\autotest

附录

脚本test.spec.js

const fs = require('fs');
const path = require('path');
const chai = require("chai");
const should = chai.should();
const JWebDriver = require('jwebdriver');
chai.use(JWebDriver.chaiSupportChainPromise);
const resemble = require('resemblejs-node');
resemble.outputSettings({
    errorType: 'flatDifferenceIntensity'
});

const rootPath = getRootPath();

module.exports = function(){

    let driver, testVars;

    before(function(){
        let self = this;
        driver = self.driver;
        testVars = self.testVars;
    });

    it('url: https://www.baidu.com', async function(){
        await driver.url(_(`https://www.baidu.com`));
    });

    it('waitBody: ', async function(){
        await driver.sleep(500).wait('body', 30000).html().then(function(code){
            isPageError(code).should.be.false;
        });
    });

    it('click: wd ( #kw, 210, 7, 0 )', async function(){
        await driver.sleep(300).wait('#kw', 30000)
               .sleep(300).mouseMove(210, 7).click(0);
    });

    it('sendKeys: helloworld{ENTER}', async function(){
        await driver.sendKeys('helloworld{ENTER}');
    });

    it('expect: text, #content_left div[id="1"] > h3.c-gap-bottom-small > a, equal, helloworld_百度百科', async function(){
        await driver.sleep(300).wait('#content_left div[id="1"] > h3.c-gap-bottom-small > a', 30000)
            .text()
            .should.not.be.a('error')
            .should.equal(_(`helloworld_百度百科`));
    });

    it('sleep: 1000', async function(){
        await driver.sleep(1000);
    });

    it('click: helloworld_百度百科 ( #content_left div[id="1"] > h3.c-gap-bottom-small > a, 113, 7, 0 )', async function(){
        await driver.sleep(300).wait('#content_left div[id="1"] > h3.c-gap-bottom-small > a', 30000)
               .sleep(300).mouseMove(113, 7).click(0);
    });

    it('switchWindow: 1', async function(){
        await driver.sleep(500).switchWindow(1);
    });

    it('waitBody: ', async function(){
        await driver.sleep(500).wait('body', 30000).html().then(function(code){
            isPageError(code).should.be.false;
        });
    });

    it('waitBody: ', async function(){
        await driver.sleep(500).wait('body', 30000).html().then(function(code){
            isPageError(code).should.be.false;
        });
    });

    it('click: span.cmn-baike-logo > em.cmn-icons_logo-du, 32, 32, 0', async function(){
        await driver.sleep(300).wait('span.cmn-baike-logo > em.cmn-icons_logo-du', 30000)
               .sleep(300).mouseMove(32, 32).click(0);
    });

    it('waitBody: ', async function(){
        await driver.sleep(500).wait('body', 30000).html().then(function(code){
            isPageError(code).should.be.false;
        });
    });

    it('expect: val, #lemmaNum, notEqual, 1', async function(){
        await driver.sleep(300).wait('#lemmaNum', 30000)
            .val()
            .should.not.be.a('error')
            .should.not.equal(_(`1`));
    });

    it('mouseMove: 分类 ( //a[text()="分类"], 21, 3 )', async function(){
        await driver.sleep(300).wait('//a[text()="分类"]', 30000)
               .sleep(300).mouseMove(21, 3);
    });

    it('click: 生活 ( dl.cat > dd:nth-child(2) > div:nth-child(6) > a, 10, 8, 0 )', async function(){
        await driver.sleep(300).wait('dl.cat > dd:nth-child(2) > div:nth-child(6) > a', 30000)
               .sleep(300).mouseMove(10, 8).click(0);
    });

    it('switchWindow: 2', async function(){
        await driver.sleep(500).switchWindow(2);
    });

    it('waitBody: ', async function(){
        await driver.sleep(500).wait('body', 30000).html().then(function(code){
            isPageError(code).should.be.false;
        });
    });

    it('expect: text, //h2[text()="生活频道"], equal, 生活频道', async function(){
        await driver.sleep(300).wait('//h2[text()="生活频道"]', 30000)
            .text()
            .should.not.be.a('error')
            .should.equal(_(`生活频道`));
    });

    function _(str){
        if(typeof str === 'string'){
            return str.replace(/\{\{(.+?)\}\}/g, function(all, key){
                return testVars[key] || '';
            });
        }
        else{
            return str;
        }
    }

};

if(module.parent && /mocha\.js/.test(module.parent.id)){
    runThisSpec();
}

function runThisSpec(){
    // read config
    let webdriver = process.env['webdriver'] || '';
    let proxy = process.env['wdproxy'] || '';
    let config = require(rootPath + '/config.json');
    let webdriverConfig = Object.assign({},config.webdriver);
    let host = webdriverConfig.host;
    let port = webdriverConfig.port || 4444;
    let match = webdriver.match(/([^\:]+)(?:\:(\d+))?/);
    if(match){
        host = match[1] || host;
        port = match[2] || port;
    }
    let testVars = config.vars;
    let browsers = webdriverConfig.browsers;
    browsers = browsers.replace(/^\s+|\s+$/g, '');
    delete webdriverConfig.host;
    delete webdriverConfig.port;
    delete webdriverConfig.browsers;

    // read hosts
    let hostsPath = rootPath + '/hosts';
    let hosts = '';
    if(fs.existsSync(hostsPath)){
        hosts = fs.readFileSync(hostsPath).toString();
    }
    let specName = path.relative(rootPath, __filename).replace(/\\/g,'/').replace(/\.js$/,'');

    browsers.split(/\s*,\s*/).forEach(function(browserName){
        let caseName = specName + ' : ' + browserName;

        let browserInfo = browserName.split(' ');
        browserName = browserInfo[0];
        let browserVersion = browserInfo[1];

        describe(caseName, function(){

            this.timeout(600000);
            this.slow(1000);

            let driver;
            before(function(){
                let self = this;
                let driver = new JWebDriver({
                    'host': host,
                    'port': port
                });
                let sessionConfig = Object.assign({}, webdriverConfig, {
                    'browserName': browserName,
                    'version': browserVersion,
                    'ie.ensureCleanSession': true,
                    'chromeOptions': {
                        'args': ['--enable-automation']
                    }
                });
                if(proxy){
                    sessionConfig.proxy = {
                        'proxyType': 'manual',
                        'httpProxy': proxy,
                        'sslProxy': proxy
                    }
                }
                else if(hosts){
                    sessionConfig.hosts = hosts;
                }
                self.driver = driver.session(sessionConfig).maximize().config({
                    pageloadTimeout: 30000, // page onload timeout
                    scriptTimeout: 5000, // sync script timeout
                    asyncScriptTimeout: 10000 // async script timeout
                });
                self.testVars = testVars;
                let casePath = path.dirname(caseName);
                self.screenshotPath = rootPath + '/screenshots/' + casePath;
                self.diffbasePath = rootPath + '/diffbase/' + casePath;
                self.caseName = caseName.replace(/.*\//g, '').replace(/\s*[:\.\:\-\s]\s*/g, '_');
                mkdirs(self.screenshotPath);
                mkdirs(self.diffbasePath);
                self.stepId = 0;
                return self.driver;
            });

            module.exports();

            beforeEach(function(){
                let self = this;
                self.stepId ++;
                if(self.skipAll){
                    self.skip();
                }
            });

            afterEach(async function(){
                let self = this;
                let currentTest = self.currentTest;
                let title = currentTest.title;
                if(currentTest.state === 'failed' && /^(url|waitBody|switchWindow|switchFrame):/.test(title)){
                    self.skipAll = true;
                }
                if(!/^(closeWindow):/.test(title)){
                    let filepath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId;
                    let driver = self.driver;
                    try{
                        // catch error when get alert msg
                        await driver.getScreenshot(filepath + '.png');
                        let url = await driver.url();
                        let html = await driver.source();
                        html = '<!--url: '+url+' -->\n' + html;
                        fs.writeFileSync(filepath + '.html', html);
                        let cookies = await driver.cookies();
                        fs.writeFileSync(filepath + '.cookie', JSON.stringify(cookies));
                    }
                    catch(e){}
                }
            });

            after(function(){
                return this.driver.close();
            });

        });
    });
}

function getRootPath(){
    let rootPath = path.resolve(__dirname);
    while(rootPath){
        if(fs.existsSync(rootPath + '/config.json')){
            break;
        }
        rootPath = rootPath.substring(0, rootPath.lastIndexOf(path.sep));
    }
    return rootPath;
}

function mkdirs(dirname){
    if(fs.existsSync(dirname)){
        return true;
    }else{
        if(mkdirs(path.dirname(dirname))){
            fs.mkdirSync(dirname);
            return true;
        }
    }
}

function callSpec(name){
    try{
        require(rootPath + '/' + name)();
    }
    catch(e){
        console.log(e)
        process.exit(1);
    }
}

function isPageError(code){
    return code == '' || / jscontent="errorCode" jstcache="\d+"|diagnoseConnectionAndRefresh|dnserror_unavailable_header|id="reportCertificateErrorRetry"|400 Bad Request|403 Forbidden|404 Not Found|500 Internal Server Error|502 Bad Gateway|503 Service Temporarily Unavailable|504 Gateway Time-out/i.test(code);
}

function catchError(error){

}

猜你喜欢

转载自blog.csdn.net/yue530tomtom/article/details/81188382