Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

栏目: Node.js · 发布时间: 5年前

内容简介:在上一期内容中,我们介绍了Node.js 结合 Cucumber开发多端的自动化,并发布了演示视频:这一期我们就主要介绍一下开发的详细步骤。通过本例学习,可以掌握如何同时测试Windows,Mobile,Web应用。
Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

在上一期内容中,我们介绍了Node.js 结合 Cucumber开发多端的自动化,并发布了演示视频: 如何做跨平台业务流程自动化(Windows,Moible,Web)

这一期我们就主要介绍一下开发的详细步骤。

主要目标

通过本例学习,可以掌握如何同时测试Windows,Mobile,Web应用。

环境配置

  • 操作系统:Windows 10
  • 开发语言:node.js
  • 编辑工具:CukeTest
  • 被测应用:Windows Outlook邮件
  • 桌面端:Windows 10 Mail

Mobile端:安卓应用商店搜索"Outlook" Web端: outlook.live.com/mail/

其它必要库

自动化Mobile端使用到Appium,请在本机安装好Appium 以及Android相关配置环境(具体请在网上查找相关资料)

自动化Web端需要使用到selenium-server,以及浏览器驱动,可以在npm.taobao.org/ 下载。

操作步骤

1. 创建项目

打开CukeTest,新建项目,【项目模板】选择 "Basic",【项目名】输入"OutlookTesting",【项目路径】输入自己的本地目录。点击【创建】

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

2. 安装项目依赖库

CukeTest本身自带的有操作Windows库的控件,所以我们只需要引用即可。针对Web端和Mobile端,我们使用开源的webdriver.io库作为实现库。具体api可以参考官方文档 webdriver.io/guide.html

【项目名】右键--【在命令行窗口打开】

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

在打开的命令行窗口输入

npm install webdriverio @types/webdriverio --save
复制代码

安装成功之后会有如下提示

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN outlooktesting@1.0.0 No repository field.

+ @types/webdriverio@4.13.0
+ webdriverio@4.14.0
added 155 packages from 192 contributors and audited 345 packages in 50.09s
found 0 vulnerabilities
复制代码

3. 创建驱动

分别为Windows,Mobile,Web 创建不同驱动。

features/support/web_driver.js

var webdriverio = require('webdriverio');// 设置浏览器信息
var options = {
    desiredCapabilities: {
        browserName: 'chrome'
    }};

//创建driver

function createDriver(){
    return webdriverio.remote(options)
}
exports.driver = createDriver();
复制代码

features/support/mobile_driver.js

const webdriverio = require('webdriverio');

//设置被测应用参数

let options = {
    desiredCapabilities: {
        platformName: "Android",
        deviceName: "9c83590", //设备序列串号 
        // platformVersion: "5.1", //系统平台版本
        appPackage: "com.microsoft.office.outlook", //package 名字
        appActivity: ".MainActivity", //启动activity 名字
        resetKeyboard: true,
        noReset: true,
        unicodeKeyboard: true
    },
    host: "127.0.0.1",
    port: 4723
}

//根据参数配置创建WebDriverIO实例;

function createDriver() {
    const client = webdriverio.remote(options);
    return client;
}

exports.app_driver = createDriver();
复制代码

创建Windows桌面应用模型文件features\support\Mail.tmodel

Windows驱动文件 features\support\win_driver.js

const { TestModel, Auto } = require("leanpro.win");

let path = require('path')

let tmodelfile = path.join(__dirname,'Mail.tmodel')

var model = TestModel.loadModel(tmodelfile);

exports.model = model;
复制代码

此时的目录结构为

│  package-lock.json
│  package.json
│
└─features
    │  feature1.feature
    │
    ├─step_definitions
    │      definitions1.js
    │
    └─support
            Mail.tmodel
            mobile_driver.js
            web_driver.js
            win_driver.js
复制代码

4. 编写测试场景

为了让我们的测试更有趣,这里虚拟了一个这样的剧本:

Jason作为公司的老板,开会需要用到一些培训文档,Carol作为公司职员,已经将培训文档做好并存储在公司电脑上。 Jason使用Windows桌面端 Mail向Carol发送邮件索要文档。 Carol在公司外边使用mobile收到邮件后利用mobile端回复Jason稍后会回到公司发送。 Carol回到公司后使用web端将文档作为附件发送给Jason。

利用这样的用户场景:可以将Windows,Mobile,Web 这三端的自动化连接起来。于是我们在feature文件中可以如下编辑:

features/feature1.feature

# language: zh-CN

功能: 同时自动化desktop,mobile,web
Outlook 应用分为移动端,Windows端和Web端。
Jason在Windows端给Carol发送邮件,Carol手机端收到邮件后回复Jason。
之后Carol在Web端给Jason发送一封带有附件的邮件。

  @desktop
  场景: Jason使用PC端Mail给Carol发送邮件索要文档
    假如打开Outlook桌面客户端
    当点击新建邮件
    并且在收件人,主题,收件内容中输入对应的信息
    同时点击发送邮件

  @mobile
  场景: Carol手机端回复Jason稍后发送
    假如打开手机端Outlook
    当打开收件箱窗口
    同时打开未读邮件
    同时答复框内回复对应内容并发送

  @web
  场景: Carol使用web端回复Jason
    假如用户Carol登录Outlook web页面
    当打开收件箱并打开最新一次的邮件
    那么回复Jason邮件并上传相关文档
复制代码

对应的可视化界面

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

5. 完善自动化脚本

在features/step_definitons 目录里分别创建mobileAction.js, webAction.js, windowsAction.js 分别存储3端的自动化脚本。

场景1中,实现对Windows桌面应用的自动化。

  1. 打开windowsAction.js, 点击场景1中每个操作步骤后的灰色按钮,在windwosAction.js中生成Windows应用操作的自动化代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^打开Outlook桌面客户端$/, async function () {
    return 'pending';
});

When(/^点击新建邮件$/, async function () {
    return 'pending';
});

When(/^在收件人,主题,收件内容中输入对应的信息$/, async function () {
    return 'pending';
});

When(/^点击发送邮件$/, async function () {
    return 'pending';
});

复制代码
  1. 打开tmodel文件,利用CukeTest自带的模型管理器选取Windows操作控件,具体选取方式可以参考视频教程 ke.qq.com/course/3473…
Node.js开发多端自动化步骤详解(Windows,Mobile,Web)
  1. Windows对象选取完成后实现windowsAction.js中定义的操作步骤。

引入Windows对象模型

const { model } = require('../support/win_driver');

const { Util } = require('leanpro.common');
复制代码
  1. 模型管理器中根据选取的对象控件复制对应的实现代码。最终代码 features/step_definitons/windowsAction.js
const { Given, When, Then } = require('cucumber');

const { model } = require('../support/win_driver');

const { Util } = require('leanpro.common');

Given(/^打开Outlook桌面客户端$/, async function () {
    await model.getButton("开始").click(0, 0, 1);
    await Util.delay(2000);
    await model.getListItem("Mail").click(0, 0, 1);

});

When(/^点击新建邮件$/, async function () {
    await Util.delay(2000)
    await model.getButton("New mail").click(0, 0, 1);

})

;When(/^在收件人,主题,收件内容中输入对应的信息$/, async function () {
    await model.getEdit("To:").clearAll();
    await model.getEdit("To:").set("carolseaver1@outlook.com");

    await model.getEdit("Subject").clearAll();
    await model.getEdit("Subject").set("培训大纲");

    let content = "hi,Carol:{ENTER}请把本次培训内容发送给我好吗?{ENTER}Jason Seaver"    
    
    await model.getDocument("消息").clearAll();
    await model.getDocument("消息").set(content);});

When(/^点击发送邮件$/, async function () {
    await model.getButton("Send").click(0, 0, 1);
    await Util.delay(1000)

});
复制代码

场景2中,实现对Mobile应用的自动化。

  1. 打开features/step_definitions/moblieAction.js, 点击feature的可视化界面中场景2中每个步骤后的灰色按钮,在mobileAction.js中生成手机端操作代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^打开手机端Outlook$/, async function () {
    return 'pending';
});

When(/^打开收件箱窗口$/, async function () {
    return 'pending';
})

;When(/^打开未读邮件$/, async function () {
    return 'pending';
});

When(/^答复框内回复对应内容并发送$/, async function () {
    return 'pending';
});

复制代码
  1. 引入手机端驱动
const { Util} = require('leanpro.common')

const { app_driver } = require('../support/mobile_driver')
复制代码

使用webdriver.io 相关api 实现自动化操作代码。最终代码 features/step_defintions/mobileAction.js

const { Given, When, Then } = require('cucumber')
const { Util} = require('leanpro.common')
const { app_driver } = require('../support/mobile_driver')

Given(/^打开手机端Outlook$/, async function () {
    // 手机客户端接收邮件需要5-10秒的延迟
    await Util.delay(5000)
    return true
});

When(/^打开收件箱窗口$/, async function () {
    await app_driver.click('~打开导航抽屉');
    await app_driver.click('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/drawer_item_title").index(1).text("收件箱")')});

Then(/^打开未读邮件$/, async function () {

    await app_driver.waitForExist('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/message_snippet_frontview").index(0).className("android.widget.LinearLayout")',20*1000);
    await app_driver.click('android=new UiSelector().resourceId("com.microsoft.office.outlook:id/message_snippet_frontview").index(0).className("android.widget.LinearLayout")')});Then(/^答复框内回复对应内容并发送$/, async function () {
    let loctor = 'new UiSelector().text("答复").index(1)'
    await app_driver.click('android='+loctor)
    await app_driver.clearElement('~邮件正文。')
    let content = `
    Hi,Jason:
        培训内容文档在我公司PC上保存,现在我在外边,稍后我到公司回复您。
    
    Carol Seaver
    `
    await app_driver.setValue('~邮件正文。',content);
    await app_driver.click('~发送');

});
复制代码

场景3中,实现对web应用的自动化。

  1. 打开features/step_definitions/webAction.js, 点击feature的可视化界面中场景3中每个步骤后的灰色按钮,在mobileAction.js中生成web端操作代码样例。
var { Given, When, Then } = require('cucumber')

Given(/^用户Carol登录Outlook web页面$/, async function () {
    return 'pending';
});

When(/^打开收件箱并打开最新一次的邮件$/, async function () {
    return 'pending';
});

Then(/^回复Jason邮件并上传相关文档$/, async function () {
    return 'pending';
});
复制代码
  1. 添加对web_driver 的引用:
const { driver } = require('../support/web_driver');
复制代码
  1. 根据webdriverio相关api 完成对应的操作。最终代码 features/step_definitions/webAction.js
var { Given, When, Then } = require('cucumber')
const { Auto } = require('leanpro.win')
const { Util } = require('leanpro.common')

const path = require('path')

const assert = require('assert');

const { driver } = require('../support/web_driver');

Given(/^用户Carol登录Outlook web页面$/, async function () {
    await driver.url("https://outlook.live.com/mail/inbox#");
    await driver.click('div.headerHero>a:last-child');
    await driver.setValue('#i0116','carolseaver1@outlook.com');
    await driver.click('#idSIButton9');
    await driver.setValue('#i0118','密码');
    await driver.waitForEnabled('#idSIButton9',20*1000)
    await driver.click('#idSIButton9');

});

When(/^打开收件箱并打开最新一次的邮件$/, async function () {
    await driver.waitForEnabled('div > div[role="option"] > div[draggable="true"] > div[tabindex="-1"]',15*1000);

    await driver.click('div > div[role="option"] > div[draggable="true"] > div[tabindex="-1"]' );

});

Then(/^回复Jason邮件并上传相关文档$/,{timeout:180*1000}, async function () {
    // await Util.delay(1000);

    let content = `
    hi,Jason:
        附件为本次培训内容大纲。请查收,谢谢。

    Carol Seaver
    `
    let bool = await driver.waitForEnabled('div[tabindex="-1"] > div > button[type="button"]> div >span',45*1000)
    
    console.log("ele",bool);
    if(bool==true){  
        console.log("get Text ===")
        let text = await driver.getText('div[tabindex="-1"] > div > button[type="button"]> div >span')

        console.log("text == ",text)
        if(text.includes('加载')){
            console.log('click loading')
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span');
            await Util.delay(1000)
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span')
        }else{
            await driver.click('div[tabindex="-1"] > div > button[type="button"]> div >span')
        }
    }
    // await driver.keys()
    // let input_area = await driver.element('div[dir="ltr"]');
    await driver.waitForExist('div[dir="ltr"]',20*1000);
    await driver.click('div[dir="ltr"]')
    // await driver.clearElement('div[dir="ltr"]')
    await driver.setValue('div[dir="ltr"]',content);

    await driver.waitForEnabled('button[name="附加"]',20*1000);
    await driver.click('button[name="附加"]');
    await Util.delay(500)
    await driver.waitForVisible('button[name="浏览此计算机"]',20*1000);
    await driver.click('button[name="浏览此计算机"]');

    await Util.delay(1500);
    let uplaodFilePane =await Auto.getPane({
        "className": "Chrome_WidgetWin_1",
        "name": "邮件 - Carol Seaver - Outlook - Google Chrome"
    }).getWindow({
        "className": "#32770",
        "title": "打开"
    }).getComboBox({
        "automationId": "1148",
        "name": "文件名(N):"
    }).getEdit({
        "automationId": "1148",
        "name": "文件名(N):"
    })

    let filepath = path.join(__dirname, '..', '..', 'files','培训大纲.md')
    await uplaodFilePane.clearAll();
    await uplaodFilePane.set(filepath);
    await Auto.getPane({
        "className": "Chrome_WidgetWin_1",
        "name": "邮件 - Carol Seaver - Outlook - Google Chrome"
    }).getWindow({
        "className": "#32770",
        "title": "打开"
    }).getButton({
        "automationId": "1",
        "name": "打开(O)"
    }).click(0, 0, 1);

    await driver.waitForEnabled('div.ms-Button-flexContainer> i[data-icon-name="Send"]',20*1000);
    await driver.click('div.ms-Button-flexContainer> i[data-icon-name="Send"]')
    await Util.delay(500);

});
复制代码

设置hooks

  1. 打开features/support/hooks.js 文件,设置运行时:
const { BeforeAll, After, Before, AfterAll, setDefaultTimeout } = require('cucumber');

const cuketest = require('cuketest');

const { Util } = require('leanpro.win');

const { app_driver } = require('./mobile_driver');

const { model } = require('./win_driver');

const { driver } = require('./web_driver');

//set default step timeout

setDefaultTimeout(120 * 1000);

BeforeAll(async function () {
    await cuketest.minimize();
    await driver.init();
    await driver.windowHandleMaximize();
    await driver.timeouts(30 * 1000);
    await app_driver.init();
    await app_driver.timeouts(10000);

})

After({ tags: "@desktop" }, async function () {

    let screenshot = await model.getWindow("Window").takeScreenshot();
    this.attach(screenshot, 'image/png');
    await cuketest.delay(1000);
    await model.getWindow("Window").close();

});

After({ tags: "@mobile" }, async function () {

    let screenshot = await app_driver.saveScreenshot();
    this.attach(screenshot, 'image/png');
    await app_driver.end();});

After({ tags: "@web" }, async function () {

    let screenshot = await driver.saveScreenshot();
    this.attach(screenshot, 'image/png');
    //clean up cookies
    await driver.deleteCookie();
    await driver.end();
});

AfterAll(async function () {
    await cuketest.restore();})
复制代码

运行

  1. 启动appium

命令行中输入 appium

$ appium
[Appium] Welcome to Appium v1.9.1
[Appium] Appium REST http interface listener started on 0.0.0.0:4723 
复制代码
  1. 启动selenium-server
$ java -jar -Dwebdriver.chrome.driver=./chromedriver.exe selenium-server-standalone-3.141.0.jar14:53:29.932 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.0, revision: 2ecb7d9a14:53:30.135 INFO [GridLauncherV3.lambda$buildLaunchers$3] - Launching a standalone Selenium Server on port 44442018-11-08 14:53:30.260:INFO::main: Logging initialized @1318ms to org.seleniumhq.jetty9.util.log.StdErrLog14:53:30.728 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet14:53:31.564 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
复制代码

点击feature文件上每个场景后的运行按钮可以运行单个场景,点击运行项目,可以运行整个项目。运行项目后会生成对应的图文报表。

Node.js开发多端自动化步骤详解(Windows,Mobile,Web)

总结

依托强大的Node.js生态和大量的开源库。使用CukeTest配合开源的 工具 可以完成各类应用的自动化。既快速又免费,有兴趣的可以尝试一下噢。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Essential C++中文版

Essential C++中文版

李普曼 (Stanley B.Lippman) / 侯捷 / 电子工业出版社 / 2013-8-1 / CNY 65.00

本书以四个面向来表现C++的本质:procedural(面向过程的)、generic(泛型的)、object-based(基于对象的)、objectoriented(面向对象的)。全书围绕一系列逐渐繁复的程序问题,以及用以解决这些问题的语言特性来组织。循此方式,你将不只学到C++的功能和结构,也可学到它们的设计目的和基本原理。 本书适合那些已经开始从事软件设计,又抽不出太多时间学习新技术的程......一起来看看 《Essential C++中文版》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具